1 #pragma once 2 3 #include "config.h" 4 5 #include "sensorhandler.hpp" 6 7 #include <cmath> 8 #include <ipmid/api.hpp> 9 #include <ipmid/types.hpp> 10 #include <ipmid/utils.hpp> 11 #include <sdbusplus/message/types.hpp> 12 13 namespace ipmi 14 { 15 namespace sensor 16 { 17 18 using Assertion = uint16_t; 19 using Deassertion = uint16_t; 20 using AssertionSet = std::pair<Assertion, Deassertion>; 21 22 using Service = std::string; 23 using Path = std::string; 24 using Interface = std::string; 25 26 using ServicePath = std::pair<Path, Service>; 27 28 using Interfaces = std::vector<Interface>; 29 30 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>; 31 32 /** @brief get the D-Bus service and service path 33 * @param[in] bus - The Dbus bus object 34 * @param[in] interface - interface to the service 35 * @param[in] path - interested path in the list of objects 36 * @return pair of service path and service 37 */ 38 ServicePath getServiceAndPath(sdbusplus::bus::bus& bus, 39 const std::string& interface, 40 const std::string& path = std::string()); 41 42 /** @brief Make assertion set from input data 43 * @param[in] cmdData - Input sensor data 44 * @return pair of assertion and deassertion set 45 */ 46 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData); 47 48 /** @brief send the message to DBus 49 * @param[in] msg - message to send 50 * @return failure status in IPMI error code 51 */ 52 ipmi_ret_t updateToDbus(IpmiUpdateData& msg); 53 54 namespace get 55 { 56 57 /** @brief Populate sensor name from the D-Bus property associated with the 58 * sensor. In the example entry from the yaml, the name of the D-bus 59 * property "AttemptsLeft" is the sensor name. 60 * 61 * 0x07: 62 * sensorType: 195 63 * path: /xyz/openbmc_project/state/host0 64 * sensorReadingType: 0x6F 65 * serviceInterface: org.freedesktop.DBus.Properties 66 * readingType: readingAssertion 67 * sensorNamePattern: nameProperty 68 * interfaces: 69 * xyz.openbmc_project.Control.Boot.RebootAttempts: 70 * AttemptsLeft: 71 * Offsets: 72 * 0xFF: 73 * type: uint32_t 74 * 75 * 76 * @param[in] sensorInfo - Dbus info related to sensor. 77 * 78 * @return On success return the sensor name for the sensor. 79 */ 80 inline SensorName nameProperty(const Info& sensorInfo) 81 { 82 return sensorInfo.propertyInterfaces.begin()->second.begin()->first; 83 } 84 85 /** @brief Populate sensor name from the D-Bus object associated with the 86 * sensor. If the object path is /system/chassis/motherboard/dimm0 then 87 * the leaf dimm0 is considered as the sensor name. 88 * 89 * @param[in] sensorInfo - Dbus info related to sensor. 90 * 91 * @return On success return the sensor name for the sensor. 92 */ 93 inline SensorName nameLeaf(const Info& sensorInfo) 94 { 95 return sensorInfo.sensorPath.substr( 96 sensorInfo.sensorPath.find_last_of('/') + 1, 97 sensorInfo.sensorPath.length()); 98 } 99 100 /** @brief Populate sensor name from the D-Bus object associated with the 101 * sensor. If the object path is /system/chassis/motherboard/cpu0/core0 102 * then the sensor name is cpu0_core0. The leaf and the parent is put 103 * together to get the sensor name. 104 * 105 * @param[in] sensorInfo - Dbus info related to sensor. 106 * 107 * @return On success return the sensor name for the sensor. 108 */ 109 SensorName nameParentLeaf(const Info& sensorInfo); 110 111 /** 112 * @brief Helper function to map the dbus info to sensor's assertion status 113 * for the get sensor reading command. 114 * 115 * @param[in] sensorInfo - Dbus info related to sensor. 116 * @param[in] path - Dbus object path. 117 * @param[in] interface - Dbus interface. 118 * 119 * @return Response for get sensor reading command. 120 */ 121 GetSensorResponse mapDbusToAssertion(const Info& sensorInfo, 122 const InstancePath& path, 123 const DbusInterface& interface); 124 125 /** 126 * @brief Map the Dbus info to sensor's assertion status in the Get sensor 127 * reading command response. 128 * 129 * @param[in] sensorInfo - Dbus info related to sensor. 130 * 131 * @return Response for get sensor reading command. 132 */ 133 GetSensorResponse assertion(const Info& sensorInfo); 134 135 /** 136 * @brief Maps the Dbus info to the reading field in the Get sensor reading 137 * command response. 138 * 139 * @param[in] sensorInfo - Dbus info related to sensor. 140 * 141 * @return Response for get sensor reading command. 142 */ 143 GetSensorResponse eventdata2(const Info& sensorInfo); 144 145 /** 146 * @brief readingAssertion is a case where the entire assertion state field 147 * serves as the sensor value. 148 * 149 * @tparam T - type of the dbus property related to sensor. 150 * @param[in] sensorInfo - Dbus info related to sensor. 151 * 152 * @return Response for get sensor reading command. 153 */ 154 template <typename T> 155 GetSensorResponse readingAssertion(const Info& sensorInfo) 156 { 157 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 158 GetSensorResponse response{}; 159 160 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 161 sensorInfo.sensorPath); 162 163 auto propValue = ipmi::getDbusProperty( 164 bus, service, sensorInfo.sensorPath, 165 sensorInfo.propertyInterfaces.begin()->first, 166 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 167 168 setAssertionBytes(static_cast<uint16_t>(std::get<T>(propValue)), &response); 169 170 return response; 171 } 172 173 /** @brief Map the Dbus info to the reading field in the Get sensor reading 174 * command response 175 * 176 * @tparam T - type of the dbus property related to sensor. 177 * @param[in] sensorInfo - Dbus info related to sensor. 178 * 179 * @return Response for get sensor reading command. 180 */ 181 template <typename T> 182 GetSensorResponse readingData(const Info& sensorInfo) 183 { 184 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 185 186 GetSensorResponse response{}; 187 188 enableScanning(&response); 189 190 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 191 sensorInfo.sensorPath); 192 193 #ifdef UPDATE_FUNCTIONAL_ON_FAIL 194 // Check the OperationalStatus interface for functional property 195 if (sensorInfo.propertyInterfaces.begin()->first == 196 "xyz.openbmc_project.Sensor.Value") 197 { 198 bool functional = true; 199 try 200 { 201 auto funcValue = ipmi::getDbusProperty( 202 bus, service, sensorInfo.sensorPath, 203 "xyz.openbmc_project.State.Decorator.OperationalStatus", 204 "Functional"); 205 functional = std::get<bool>(funcValue); 206 } 207 catch (...) 208 { 209 // No-op if Functional property could not be found since this 210 // check is only valid for Sensor.Value read for hwmonio 211 } 212 if (!functional) 213 { 214 throw SensorFunctionalError(); 215 } 216 } 217 #endif 218 219 auto propValue = ipmi::getDbusProperty( 220 bus, service, sensorInfo.sensorPath, 221 sensorInfo.propertyInterfaces.begin()->first, 222 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 223 224 double value = std::get<T>(propValue) * 225 std::pow(10, sensorInfo.scale - sensorInfo.exponentR); 226 227 auto rawData = static_cast<uint8_t>((value - sensorInfo.scaledOffset) / 228 sensorInfo.coefficientM); 229 setReading(rawData, &response); 230 231 return response; 232 } 233 234 } // namespace get 235 236 namespace set 237 { 238 239 /** @brief Make a DBus message for a Dbus call 240 * @param[in] updateInterface - Interface name 241 * @param[in] sensorPath - Path of the sensor 242 * @param[in] command - command to be executed 243 * @param[in] sensorInterface - DBus interface of sensor 244 * @return a dbus message 245 */ 246 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 247 const std::string& sensorPath, 248 const std::string& command, 249 const std::string& sensorInterface); 250 251 /** @brief Update d-bus based on assertion type sensor data 252 * @param[in] cmdData - input sensor data 253 * @param[in] sensorInfo - sensor d-bus info 254 * @return a IPMI error code 255 */ 256 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 257 const Info& sensorInfo); 258 259 /** @brief Update d-bus based on a reading assertion 260 * @tparam T - type of d-bus property mapping this sensor 261 * @param[in] cmdData - input sensor data 262 * @param[in] sensorInfo - sensor d-bus info 263 * @return a IPMI error code 264 */ 265 template <typename T> 266 ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData, 267 const Info& sensorInfo) 268 { 269 auto msg = 270 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 271 "Set", sensorInfo.sensorInterface); 272 273 const auto& interface = sensorInfo.propertyInterfaces.begin(); 274 msg.append(interface->first); 275 for (const auto& property : interface->second) 276 { 277 msg.append(property.first); 278 std::variant<T> value = 279 (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7; 280 msg.append(value); 281 } 282 return updateToDbus(msg); 283 } 284 285 /** @brief Update d-bus based on a discrete reading 286 * @param[in] cmdData - input sensor data 287 * @param[in] sensorInfo - sensor d-bus info 288 * @return an IPMI error code 289 */ 290 template <typename T> 291 ipmi_ret_t readingData(const SetSensorReadingReq& cmdData, 292 const Info& sensorInfo) 293 { 294 T raw_value = 295 (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset; 296 297 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale); 298 299 auto msg = 300 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 301 "Set", sensorInfo.sensorInterface); 302 303 const auto& interface = sensorInfo.propertyInterfaces.begin(); 304 msg.append(interface->first); 305 306 for (const auto& property : interface->second) 307 { 308 msg.append(property.first); 309 std::variant<T> value = raw_value; 310 msg.append(value); 311 } 312 return updateToDbus(msg); 313 } 314 315 /** @brief Update d-bus based on eventdata type sensor data 316 * @param[in] cmdData - input sensor data 317 * @param[in] sensorInfo - sensor d-bus info 318 * @return a IPMI error code 319 */ 320 ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo, 321 uint8_t data); 322 323 /** @brief Update d-bus based on eventdata1 type sensor data 324 * @param[in] cmdData - input sensor data 325 * @param[in] sensorInfo - sensor d-bus info 326 * @return a IPMI error code 327 */ 328 inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData, 329 const Info& sensorInfo) 330 { 331 return eventdata(cmdData, sensorInfo, cmdData.eventData1); 332 } 333 334 /** @brief Update d-bus based on eventdata2 type sensor data 335 * @param[in] cmdData - input sensor data 336 * @param[in] sensorInfo - sensor d-bus info 337 * @return a IPMI error code 338 */ 339 inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData, 340 const Info& sensorInfo) 341 { 342 return eventdata(cmdData, sensorInfo, cmdData.eventData2); 343 } 344 345 /** @brief Update d-bus based on eventdata3 type sensor data 346 * @param[in] cmdData - input sensor data 347 * @param[in] sensorInfo - sensor d-bus info 348 * @return a IPMI error code 349 */ 350 inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData, 351 const Info& sensorInfo) 352 { 353 return eventdata(cmdData, sensorInfo, cmdData.eventData3); 354 } 355 356 } // namespace set 357 358 namespace notify 359 { 360 361 /** @brief Make a DBus message for a Dbus call 362 * @param[in] updateInterface - Interface name 363 * @param[in] sensorPath - Path of the sensor 364 * @param[in] command - command to be executed 365 * @param[in] sensorInterface - DBus interface of sensor 366 * @return a dbus message 367 */ 368 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 369 const std::string& sensorPath, 370 const std::string& command, 371 const std::string& sensorInterface); 372 373 /** @brief Update d-bus based on assertion type sensor data 374 * @param[in] interfaceMap - sensor interface 375 * @param[in] cmdData - input sensor data 376 * @param[in] sensorInfo - sensor d-bus info 377 * @return a IPMI error code 378 */ 379 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 380 const Info& sensorInfo); 381 382 } // namespace notify 383 384 namespace inventory 385 { 386 387 namespace get 388 { 389 390 /** 391 * @brief Map the Dbus info to sensor's assertion status in the Get sensor 392 * reading command response. 393 * 394 * @param[in] sensorInfo - Dbus info related to sensor. 395 * 396 * @return Response for get sensor reading command. 397 */ 398 GetSensorResponse assertion(const Info& sensorInfo); 399 400 } // namespace get 401 402 } // namespace inventory 403 } // namespace sensor 404 } // namespace ipmi 405