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 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data()); 160 161 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 162 sensorInfo.sensorPath); 163 164 auto propValue = ipmi::getDbusProperty( 165 bus, service, sensorInfo.sensorPath, 166 sensorInfo.propertyInterfaces.begin()->first, 167 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 168 169 setAssertionBytes(static_cast<uint16_t>(std::get<T>(propValue)), 170 responseData); 171 172 return response; 173 } 174 175 /** @brief Map the Dbus info to the reading field in the Get sensor reading 176 * command response 177 * 178 * @tparam T - type of the dbus property related to sensor. 179 * @param[in] sensorInfo - Dbus info related to sensor. 180 * 181 * @return Response for get sensor reading command. 182 */ 183 template <typename T> 184 GetSensorResponse readingData(const Info& sensorInfo) 185 { 186 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 187 GetSensorResponse response{}; 188 auto responseData = reinterpret_cast<GetReadingResponse*>(response.data()); 189 190 enableScanning(responseData); 191 192 auto service = ipmi::getService(bus, sensorInfo.sensorInterface, 193 sensorInfo.sensorPath); 194 195 #ifdef UPDATE_FUNCTIONAL_ON_FAIL 196 // Check the OperationalStatus interface for functional property 197 if (sensorInfo.propertyInterfaces.begin()->first == 198 "xyz.openbmc_project.Sensor.Value") 199 { 200 bool functional = true; 201 try 202 { 203 auto funcValue = ipmi::getDbusProperty( 204 bus, service, sensorInfo.sensorPath, 205 "xyz.openbmc_project.State.Decorator.OperationalStatus", 206 "Functional"); 207 functional = std::get<bool>(funcValue); 208 } 209 catch (...) 210 { 211 // No-op if Functional property could not be found since this 212 // check is only valid for Sensor.Value read for hwmonio 213 } 214 if (!functional) 215 { 216 throw SensorFunctionalError(); 217 } 218 } 219 #endif 220 221 auto propValue = ipmi::getDbusProperty( 222 bus, service, sensorInfo.sensorPath, 223 sensorInfo.propertyInterfaces.begin()->first, 224 sensorInfo.propertyInterfaces.begin()->second.begin()->first); 225 226 double value = std::get<T>(propValue) * 227 std::pow(10, sensorInfo.scale - sensorInfo.exponentR); 228 229 auto rawData = static_cast<uint8_t>((value - sensorInfo.scaledOffset) / 230 sensorInfo.coefficientM); 231 232 setReading(rawData, responseData); 233 234 return response; 235 } 236 237 } // namespace get 238 239 namespace set 240 { 241 242 /** @brief Make a DBus message for a Dbus call 243 * @param[in] updateInterface - Interface name 244 * @param[in] sensorPath - Path of the sensor 245 * @param[in] command - command to be executed 246 * @param[in] sensorInterface - DBus interface of sensor 247 * @return a dbus message 248 */ 249 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 250 const std::string& sensorPath, 251 const std::string& command, 252 const std::string& sensorInterface); 253 254 /** @brief Update d-bus based on assertion type sensor data 255 * @param[in] cmdData - input sensor data 256 * @param[in] sensorInfo - sensor d-bus info 257 * @return a IPMI error code 258 */ 259 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 260 const Info& sensorInfo); 261 262 /** @brief Update d-bus based on a reading assertion 263 * @tparam T - type of d-bus property mapping this sensor 264 * @param[in] cmdData - input sensor data 265 * @param[in] sensorInfo - sensor d-bus info 266 * @return a IPMI error code 267 */ 268 template <typename T> 269 ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData, 270 const Info& sensorInfo) 271 { 272 auto msg = 273 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 274 "Set", sensorInfo.sensorInterface); 275 276 const auto& interface = sensorInfo.propertyInterfaces.begin(); 277 msg.append(interface->first); 278 for (const auto& property : interface->second) 279 { 280 msg.append(property.first); 281 std::variant<T> value = 282 (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7; 283 msg.append(value); 284 } 285 return updateToDbus(msg); 286 } 287 288 /** @brief Update d-bus based on a discrete reading 289 * @param[in] cmdData - input sensor data 290 * @param[in] sensorInfo - sensor d-bus info 291 * @return an IPMI error code 292 */ 293 template <typename T> 294 ipmi_ret_t readingData(const SetSensorReadingReq& cmdData, 295 const Info& sensorInfo) 296 { 297 T raw_value = 298 (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset; 299 300 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale); 301 302 auto msg = 303 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath, 304 "Set", sensorInfo.sensorInterface); 305 306 const auto& interface = sensorInfo.propertyInterfaces.begin(); 307 msg.append(interface->first); 308 309 for (const auto& property : interface->second) 310 { 311 msg.append(property.first); 312 std::variant<T> value = raw_value; 313 msg.append(value); 314 } 315 return updateToDbus(msg); 316 } 317 318 /** @brief Update d-bus based on eventdata type sensor data 319 * @param[in] cmdData - input sensor data 320 * @param[in] sensorInfo - sensor d-bus info 321 * @return a IPMI error code 322 */ 323 ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo, 324 uint8_t data); 325 326 /** @brief Update d-bus based on eventdata1 type sensor data 327 * @param[in] cmdData - input sensor data 328 * @param[in] sensorInfo - sensor d-bus info 329 * @return a IPMI error code 330 */ 331 inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData, 332 const Info& sensorInfo) 333 { 334 return eventdata(cmdData, sensorInfo, cmdData.eventData1); 335 } 336 337 /** @brief Update d-bus based on eventdata2 type sensor data 338 * @param[in] cmdData - input sensor data 339 * @param[in] sensorInfo - sensor d-bus info 340 * @return a IPMI error code 341 */ 342 inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData, 343 const Info& sensorInfo) 344 { 345 return eventdata(cmdData, sensorInfo, cmdData.eventData2); 346 } 347 348 /** @brief Update d-bus based on eventdata3 type sensor data 349 * @param[in] cmdData - input sensor data 350 * @param[in] sensorInfo - sensor d-bus info 351 * @return a IPMI error code 352 */ 353 inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData, 354 const Info& sensorInfo) 355 { 356 return eventdata(cmdData, sensorInfo, cmdData.eventData3); 357 } 358 359 } // namespace set 360 361 namespace notify 362 { 363 364 /** @brief Make a DBus message for a Dbus call 365 * @param[in] updateInterface - Interface name 366 * @param[in] sensorPath - Path of the sensor 367 * @param[in] command - command to be executed 368 * @param[in] sensorInterface - DBus interface of sensor 369 * @return a dbus message 370 */ 371 IpmiUpdateData makeDbusMsg(const std::string& updateInterface, 372 const std::string& sensorPath, 373 const std::string& command, 374 const std::string& sensorInterface); 375 376 /** @brief Update d-bus based on assertion type sensor data 377 * @param[in] interfaceMap - sensor interface 378 * @param[in] cmdData - input sensor data 379 * @param[in] sensorInfo - sensor d-bus info 380 * @return a IPMI error code 381 */ 382 ipmi_ret_t assertion(const SetSensorReadingReq& cmdData, 383 const Info& sensorInfo); 384 385 } // namespace notify 386 387 namespace inventory 388 { 389 390 namespace get 391 { 392 393 /** 394 * @brief Map the Dbus info to sensor's assertion status in the Get sensor 395 * reading command response. 396 * 397 * @param[in] sensorInfo - Dbus info related to sensor. 398 * 399 * @return Response for get sensor reading command. 400 */ 401 GetSensorResponse assertion(const Info& sensorInfo); 402 403 } // namespace get 404 405 } // namespace inventory 406 } // namespace sensor 407 } // namespace ipmi 408