blob: 3ec1a4de392a7d9d46e0b35e308240431cc0b51a [file] [log] [blame]
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -05001#pragma once
2
Brandon Kim9cf85622019-06-19 12:05:08 -07003#include "config.h"
4
Patrick Venture46470a32018-09-07 19:26:25 -07005#include "sensorhandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006
Patrick Venture586d35b2018-09-07 19:56:18 -07007#include <cmath>
Vernon Mauerye08fbff2019-04-03 09:19:34 -07008#include <ipmid/api.hpp>
Vernon Mauery33250242019-03-12 16:49:26 -07009#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070010#include <ipmid/utils.hpp>
Tony Leec5324252019-10-31 17:24:16 +080011#include <phosphor-logging/elog-errors.hpp>
12#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070013#include <sdbusplus/message/types.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070014
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050015namespace ipmi
16{
17namespace sensor
18{
19
20using Assertion = uint16_t;
21using Deassertion = uint16_t;
22using AssertionSet = std::pair<Assertion, Deassertion>;
23
24using Service = std::string;
25using Path = std::string;
26using Interface = std::string;
27
28using ServicePath = std::pair<Path, Service>;
29
30using Interfaces = std::vector<Interface>;
31
32using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>;
Tony Leec5324252019-10-31 17:24:16 +080033using namespace phosphor::logging;
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050034
35/** @brief get the D-Bus service and service path
36 * @param[in] bus - The Dbus bus object
37 * @param[in] interface - interface to the service
38 * @param[in] path - interested path in the list of objects
39 * @return pair of service path and service
40 */
41ServicePath getServiceAndPath(sdbusplus::bus::bus& bus,
42 const std::string& interface,
43 const std::string& path = std::string());
44
45/** @brief Make assertion set from input data
46 * @param[in] cmdData - Input sensor data
47 * @return pair of assertion and deassertion set
48 */
49AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData);
50
51/** @brief send the message to DBus
52 * @param[in] msg - message to send
53 * @return failure status in IPMI error code
54 */
Dhruvaraj Subhashchandran2a444d02017-08-07 01:45:14 -050055ipmi_ret_t updateToDbus(IpmiUpdateData& msg);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -050056
Tom Joseph816e92b2017-09-06 19:23:00 +053057namespace get
58{
59
Tom Josephb0adbcd2018-01-24 11:51:29 +053060/** @brief Populate sensor name from the D-Bus property associated with the
61 * sensor. In the example entry from the yaml, the name of the D-bus
62 * property "AttemptsLeft" is the sensor name.
63 *
64 * 0x07:
65 * sensorType: 195
66 * path: /xyz/openbmc_project/state/host0
67 * sensorReadingType: 0x6F
68 * serviceInterface: org.freedesktop.DBus.Properties
69 * readingType: readingAssertion
70 * sensorNamePattern: nameProperty
71 * interfaces:
72 * xyz.openbmc_project.Control.Boot.RebootAttempts:
73 * AttemptsLeft:
74 * Offsets:
75 * 0xFF:
76 * type: uint32_t
77 *
78 *
79 * @param[in] sensorInfo - Dbus info related to sensor.
80 *
81 * @return On success return the sensor name for the sensor.
82 */
83inline SensorName nameProperty(const Info& sensorInfo)
84{
85 return sensorInfo.propertyInterfaces.begin()->second.begin()->first;
86}
87
88/** @brief Populate sensor name from the D-Bus object associated with the
89 * sensor. If the object path is /system/chassis/motherboard/dimm0 then
90 * the leaf dimm0 is considered as the sensor name.
91 *
92 * @param[in] sensorInfo - Dbus info related to sensor.
93 *
94 * @return On success return the sensor name for the sensor.
95 */
96inline SensorName nameLeaf(const Info& sensorInfo)
97{
98 return sensorInfo.sensorPath.substr(
Patrick Venture0b02be92018-08-31 11:55:55 -070099 sensorInfo.sensorPath.find_last_of('/') + 1,
100 sensorInfo.sensorPath.length());
Tom Josephb0adbcd2018-01-24 11:51:29 +0530101}
102
103/** @brief Populate sensor name from the D-Bus object associated with the
104 * sensor. If the object path is /system/chassis/motherboard/cpu0/core0
105 * then the sensor name is cpu0_core0. The leaf and the parent is put
106 * together to get the sensor name.
107 *
108 * @param[in] sensorInfo - Dbus info related to sensor.
109 *
110 * @return On success return the sensor name for the sensor.
111 */
112SensorName nameParentLeaf(const Info& sensorInfo);
113
Tom Joseph816e92b2017-09-06 19:23:00 +0530114/**
115 * @brief Helper function to map the dbus info to sensor's assertion status
116 * for the get sensor reading command.
117 *
118 * @param[in] sensorInfo - Dbus info related to sensor.
119 * @param[in] path - Dbus object path.
120 * @param[in] interface - Dbus interface.
121 *
122 * @return Response for get sensor reading command.
123 */
124GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
125 const InstancePath& path,
126 const DbusInterface& interface);
127
128/**
129 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
130 * reading command response.
131 *
132 * @param[in] sensorInfo - Dbus info related to sensor.
133 *
134 * @return Response for get sensor reading command.
135 */
136GetSensorResponse assertion(const Info& sensorInfo);
137
Tom Josephe4014fc2017-09-06 23:57:36 +0530138/**
139 * @brief Maps the Dbus info to the reading field in the Get sensor reading
140 * command response.
141 *
142 * @param[in] sensorInfo - Dbus info related to sensor.
143 *
144 * @return Response for get sensor reading command.
145 */
146GetSensorResponse eventdata2(const Info& sensorInfo);
147
Tom Joseph295f17e2017-09-07 00:09:46 +0530148/**
149 * @brief readingAssertion is a case where the entire assertion state field
150 * serves as the sensor value.
151 *
152 * @tparam T - type of the dbus property related to sensor.
153 * @param[in] sensorInfo - Dbus info related to sensor.
154 *
155 * @return Response for get sensor reading command.
156 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700157template <typename T>
Tom Joseph295f17e2017-09-07 00:09:46 +0530158GetSensorResponse readingAssertion(const Info& sensorInfo)
159{
160 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700161 GetSensorResponse response{};
Tom Joseph295f17e2017-09-07 00:09:46 +0530162
Jeremy Kerr3dc35582020-05-17 15:47:07 +0800163 enableScanning(&response);
164
Patrick Venture0b02be92018-08-31 11:55:55 -0700165 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
Tom Joseph295f17e2017-09-07 00:09:46 +0530166 sensorInfo.sensorPath);
167
168 auto propValue = ipmi::getDbusProperty(
Patrick Venture0b02be92018-08-31 11:55:55 -0700169 bus, service, sensorInfo.sensorPath,
170 sensorInfo.propertyInterfaces.begin()->first,
171 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
Tom Joseph295f17e2017-09-07 00:09:46 +0530172
Sui Chen4cc42552019-09-11 10:28:35 -0700173 setAssertionBytes(static_cast<uint16_t>(std::get<T>(propValue)), &response);
Tom Joseph295f17e2017-09-07 00:09:46 +0530174
175 return response;
176}
177
Tom Josephe05b2922017-09-07 00:43:16 +0530178/** @brief Map the Dbus info to the reading field in the Get sensor reading
179 * command response
180 *
181 * @tparam T - type of the dbus property related to sensor.
182 * @param[in] sensorInfo - Dbus info related to sensor.
183 *
184 * @return Response for get sensor reading command.
185 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700186template <typename T>
Tom Josephe05b2922017-09-07 00:43:16 +0530187GetSensorResponse readingData(const Info& sensorInfo)
188{
189 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe05b2922017-09-07 00:43:16 +0530190
Sui Chen4cc42552019-09-11 10:28:35 -0700191 GetSensorResponse response{};
192
193 enableScanning(&response);
Tom Josephe05b2922017-09-07 00:43:16 +0530194
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
Tom Josephe05b2922017-09-07 00:43:16 +0530196 sensorInfo.sensorPath);
197
Brandon Kim9cf85622019-06-19 12:05:08 -0700198#ifdef UPDATE_FUNCTIONAL_ON_FAIL
199 // Check the OperationalStatus interface for functional property
200 if (sensorInfo.propertyInterfaces.begin()->first ==
201 "xyz.openbmc_project.Sensor.Value")
202 {
203 bool functional = true;
204 try
205 {
206 auto funcValue = ipmi::getDbusProperty(
207 bus, service, sensorInfo.sensorPath,
208 "xyz.openbmc_project.State.Decorator.OperationalStatus",
209 "Functional");
210 functional = std::get<bool>(funcValue);
211 }
212 catch (...)
213 {
214 // No-op if Functional property could not be found since this
215 // check is only valid for Sensor.Value read for hwmonio
216 }
217 if (!functional)
218 {
219 throw SensorFunctionalError();
220 }
221 }
222#endif
223
Tom Josephe05b2922017-09-07 00:43:16 +0530224 auto propValue = ipmi::getDbusProperty(
Patrick Venture0b02be92018-08-31 11:55:55 -0700225 bus, service, sensorInfo.sensorPath,
226 sensorInfo.propertyInterfaces.begin()->first,
227 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
Tom Josephe05b2922017-09-07 00:43:16 +0530228
Vernon Maueryf442e112019-04-09 11:44:36 -0700229 double value = std::get<T>(propValue) *
Patrick Venture586d35b2018-09-07 19:56:18 -0700230 std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
Tony Leec5324252019-10-31 17:24:16 +0800231 int32_t rawData =
232 (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
Tom Josephe05b2922017-09-07 00:43:16 +0530233
Tony Leec5324252019-10-31 17:24:16 +0800234 constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
235 constexpr uint8_t signedDataFormat = 0x80;
236 // if sensorUnits1 [7:6] = 10b, sensor is signed
237 if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
238 {
239 if (rawData > std::numeric_limits<int8_t>::max() ||
240 rawData < std::numeric_limits<int8_t>::lowest())
241 {
242 log<level::ERR>("Value out of range");
243 throw std::out_of_range("Value out of range");
244 }
245 setReading(static_cast<int8_t>(rawData), &response);
246 }
247 else
248 {
249 if (rawData > std::numeric_limits<uint8_t>::max() ||
250 rawData < std::numeric_limits<uint8_t>::lowest())
251 {
252 log<level::ERR>("Value out of range");
253 throw std::out_of_range("Value out of range");
254 }
255 setReading(static_cast<uint8_t>(rawData), &response);
256 }
Tom Josephe05b2922017-09-07 00:43:16 +0530257
Konstantin Aladyshevf93b29c2021-05-05 14:49:14 +0300258 if (!std::isfinite(value))
259 {
260 response.readingOrStateUnavailable = 1;
261 }
262
Tom Josephe05b2922017-09-07 00:43:16 +0530263 return response;
264}
265
Patrick Venture0b02be92018-08-31 11:55:55 -0700266} // namespace get
Tom Joseph816e92b2017-09-06 19:23:00 +0530267
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500268namespace set
269{
270
271/** @brief Make a DBus message for a Dbus call
272 * @param[in] updateInterface - Interface name
273 * @param[in] sensorPath - Path of the sensor
274 * @param[in] command - command to be executed
275 * @param[in] sensorInterface - DBus interface of sensor
276 * @return a dbus message
277 */
278IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
279 const std::string& sensorPath,
280 const std::string& command,
281 const std::string& sensorInterface);
282
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500283/** @brief Update d-bus based on assertion type sensor data
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500284 * @param[in] cmdData - input sensor data
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500285 * @param[in] sensorInfo - sensor d-bus info
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500286 * @return a IPMI error code
287 */
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500288ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
289 const Info& sensorInfo);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500290
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500291/** @brief Update d-bus based on a reading assertion
292 * @tparam T - type of d-bus property mapping this sensor
293 * @param[in] cmdData - input sensor data
294 * @param[in] sensorInfo - sensor d-bus info
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500295 * @return a IPMI error code
296 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700297template <typename T>
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500298ipmi_ret_t readingAssertion(const SetSensorReadingReq& cmdData,
299 const Info& sensorInfo)
300{
Patrick Venture0b02be92018-08-31 11:55:55 -0700301 auto msg =
302 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
303 "Set", sensorInfo.sensorInterface);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500304
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500305 const auto& interface = sensorInfo.propertyInterfaces.begin();
306 msg.append(interface->first);
307 for (const auto& property : interface->second)
308 {
309 msg.append(property.first);
Andrew Geissler6467ed22020-05-16 16:03:53 -0500310 std::variant<T> value = static_cast<T>((cmdData.assertOffset8_14 << 8) |
311 cmdData.assertOffset0_7);
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500312 msg.append(value);
313 }
314 return updateToDbus(msg);
315}
316
Emily Shaffercc941e12017-06-14 13:06:26 -0700317/** @brief Update d-bus based on a discrete reading
318 * @param[in] cmdData - input sensor data
319 * @param[in] sensorInfo - sensor d-bus info
320 * @return an IPMI error code
321 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700322template <typename T>
Emily Shaffercc941e12017-06-14 13:06:26 -0700323ipmi_ret_t readingData(const SetSensorReadingReq& cmdData,
324 const Info& sensorInfo)
325{
Patrick Venture0b02be92018-08-31 11:55:55 -0700326 T raw_value =
327 (sensorInfo.coefficientM * cmdData.reading) + sensorInfo.scaledOffset;
Tom Joseph22102152018-03-02 18:46:39 +0530328
Patrick Venture586d35b2018-09-07 19:56:18 -0700329 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale);
Tom Joseph22102152018-03-02 18:46:39 +0530330
Patrick Venture0b02be92018-08-31 11:55:55 -0700331 auto msg =
332 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
333 "Set", sensorInfo.sensorInterface);
Emily Shaffercc941e12017-06-14 13:06:26 -0700334
335 const auto& interface = sensorInfo.propertyInterfaces.begin();
336 msg.append(interface->first);
337
Emily Shaffercc941e12017-06-14 13:06:26 -0700338 for (const auto& property : interface->second)
339 {
340 msg.append(property.first);
Vernon Mauery16b86932019-05-01 08:36:11 -0700341 std::variant<T> value = raw_value;
Emily Shaffercc941e12017-06-14 13:06:26 -0700342 msg.append(value);
343 }
344 return updateToDbus(msg);
345}
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500346
347/** @brief Update d-bus based on eventdata type sensor data
348 * @param[in] cmdData - input sensor data
349 * @param[in] sensorInfo - sensor d-bus info
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500350 * @return a IPMI error code
351 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700352ipmi_ret_t eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500353 uint8_t data);
354
355/** @brief Update d-bus based on eventdata1 type sensor data
356 * @param[in] cmdData - input sensor data
357 * @param[in] sensorInfo - sensor d-bus info
358 * @return a IPMI error code
359 */
360inline ipmi_ret_t eventdata1(const SetSensorReadingReq& cmdData,
361 const Info& sensorInfo)
362{
363 return eventdata(cmdData, sensorInfo, cmdData.eventData1);
364}
365
366/** @brief Update d-bus based on eventdata2 type sensor data
367 * @param[in] cmdData - input sensor data
368 * @param[in] sensorInfo - sensor d-bus info
369 * @return a IPMI error code
370 */
371inline ipmi_ret_t eventdata2(const SetSensorReadingReq& cmdData,
372 const Info& sensorInfo)
373{
374 return eventdata(cmdData, sensorInfo, cmdData.eventData2);
375}
376
377/** @brief Update d-bus based on eventdata3 type sensor data
378 * @param[in] cmdData - input sensor data
379 * @param[in] sensorInfo - sensor d-bus info
380 * @return a IPMI error code
381 */
382inline ipmi_ret_t eventdata3(const SetSensorReadingReq& cmdData,
383 const Info& sensorInfo)
384{
385 return eventdata(cmdData, sensorInfo, cmdData.eventData3);
386}
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500387
Patrick Venture0b02be92018-08-31 11:55:55 -0700388} // namespace set
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500389
390namespace notify
391{
392
393/** @brief Make a DBus message for a Dbus call
394 * @param[in] updateInterface - Interface name
395 * @param[in] sensorPath - Path of the sensor
396 * @param[in] command - command to be executed
397 * @param[in] sensorInterface - DBus interface of sensor
398 * @return a dbus message
399 */
400IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
401 const std::string& sensorPath,
402 const std::string& command,
403 const std::string& sensorInterface);
404
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500405/** @brief Update d-bus based on assertion type sensor data
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500406 * @param[in] interfaceMap - sensor interface
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500407 * @param[in] cmdData - input sensor data
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500408 * @param[in] sensorInfo - sensor d-bus info
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500409 * @return a IPMI error code
410 */
Deepak Kodihalli1bb0d382017-08-12 02:01:27 -0500411ipmi_ret_t assertion(const SetSensorReadingReq& cmdData,
412 const Info& sensorInfo);
Dhruvaraj Subhashchandrane0af7202017-07-12 06:35:20 -0500413
Patrick Venture0b02be92018-08-31 11:55:55 -0700414} // namespace notify
Tom Joseph816e92b2017-09-06 19:23:00 +0530415
416namespace inventory
417{
418
419namespace get
420{
421
422/**
423 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
424 * reading command response.
425 *
426 * @param[in] sensorInfo - Dbus info related to sensor.
427 *
428 * @return Response for get sensor reading command.
429 */
430GetSensorResponse assertion(const Info& sensorInfo);
431
432} // namespace get
433
434} // namespace inventory
Patrick Venture0b02be92018-08-31 11:55:55 -0700435} // namespace sensor
436} // namespace ipmi