1 #pragma once
2
3 #include "config.h"
4
5 #include "sensorhandler.hpp"
6
7 #include <ipmid/api.hpp>
8 #include <ipmid/types.hpp>
9 #include <ipmid/utils.hpp>
10 #include <phosphor-logging/elog-errors.hpp>
11 #include <phosphor-logging/lg2.hpp>
12 #include <sdbusplus/message/types.hpp>
13 #include <xyz/openbmc_project/Sensor/Threshold/Critical/common.hpp>
14 #include <xyz/openbmc_project/Sensor/Threshold/Warning/common.hpp>
15 #include <xyz/openbmc_project/Sensor/Value/common.hpp>
16
17 #include <cmath>
18
19 #ifdef FEATURE_SENSORS_CACHE
20
21 extern ipmi::sensor::SensorCacheMap sensorCacheMap;
22
23 // The signal's message type is 0x04 from DBus spec:
24 // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-messages
25 static constexpr auto msgTypeSignal = 0x04;
26
27 #endif
28
29 namespace ipmi
30 {
31 namespace sensor
32 {
33
34 using Assertion = uint16_t;
35 using Deassertion = uint16_t;
36 using AssertionSet = std::pair<Assertion, Deassertion>;
37 using Service = std::string;
38 using Path = std::string;
39 using Interface = std::string;
40 using ServicePath = std::pair<Path, Service>;
41 using Interfaces = std::vector<Interface>;
42 using MapperResponseType = std::map<Path, std::map<Service, Interfaces>>;
43 using PropertyMap = ipmi::PropertyMap;
44
45 using SensorValue = sdbusplus::common::xyz::openbmc_project::sensor::Value;
46 using SensorThresholdWarning =
47 sdbusplus::common::xyz::openbmc_project::sensor::threshold::Warning;
48 using SensorThresholdCritical =
49 sdbusplus::common::xyz::openbmc_project::sensor::threshold::Critical;
50
51 using namespace phosphor::logging;
52
53 /** @brief Make assertion set from input data
54 * @param[in] cmdData - Input sensor data
55 * @return pair of assertion and deassertion set
56 */
57 AssertionSet getAssertionSet(const SetSensorReadingReq& cmdData);
58
59 /** @brief send the message to DBus
60 * @param[in] msg - message to send
61 * @return failure status in IPMI error code
62 */
63 ipmi::Cc updateToDbus(IpmiUpdateData& msg);
64
65 namespace get
66 {
67
68 /** @brief Populate sensor name from the D-Bus property associated with the
69 * sensor. In the example entry from the yaml, the name of the D-bus
70 * property "AttemptsLeft" is the sensor name.
71 *
72 * 0x07:
73 * sensorType: 195
74 * path: /xyz/openbmc_project/state/host0
75 * sensorReadingType: 0x6F
76 * serviceInterface: org.freedesktop.DBus.Properties
77 * readingType: readingAssertion
78 * sensorNamePattern: nameProperty
79 * interfaces:
80 * xyz.openbmc_project.Control.Boot.RebootAttempts:
81 * AttemptsLeft:
82 * Offsets:
83 * 0xFF:
84 * type: uint32_t
85 *
86 *
87 * @param[in] sensorInfo - Dbus info related to sensor.
88 *
89 * @return On success return the sensor name for the sensor.
90 */
nameProperty(const Info & sensorInfo)91 inline SensorName nameProperty(const Info& sensorInfo)
92 {
93 return sensorInfo.propertyInterfaces.begin()->second.begin()->first;
94 }
95
96 /** @brief Populate sensor name from the D-Bus object associated with the
97 * sensor. If the object path is /system/chassis/motherboard/dimm0 then
98 * the leaf dimm0 is considered as the sensor name.
99 *
100 * @param[in] sensorInfo - Dbus info related to sensor.
101 *
102 * @return On success return the sensor name for the sensor.
103 */
nameLeaf(const Info & sensorInfo)104 inline SensorName nameLeaf(const Info& sensorInfo)
105 {
106 return sensorInfo.sensorPath.substr(
107 sensorInfo.sensorPath.find_last_of('/') + 1,
108 sensorInfo.sensorPath.length());
109 }
110
111 /** @brief Populate sensor name from the D-Bus object associated with the
112 * sensor and the property.
113 * If the object path is /xyz/openbmc_project/inventory/Fan0 and
114 * the property is Present, the leaf Fan0 and the Property is
115 * joined to Fan0_Present as the sensor name.
116 *
117 * @param[in] sensorInfo - Dbus info related to sensor.
118 *
119 * @return On success return the sensor name for the sensor.
120 */
nameLeafProperty(const Info & sensorInfo)121 inline SensorName nameLeafProperty(const Info& sensorInfo)
122 {
123 return nameLeaf(sensorInfo) + "_" + nameProperty(sensorInfo);
124 }
125
126 /** @brief Populate sensor name from the D-Bus object associated with the
127 * sensor. If the object path is /system/chassis/motherboard/cpu0/core0
128 * then the sensor name is cpu0_core0. The leaf and the parent is put
129 * together to get the sensor name.
130 *
131 * @param[in] sensorInfo - Dbus info related to sensor.
132 *
133 * @return On success return the sensor name for the sensor.
134 */
135 SensorName nameParentLeaf(const Info& sensorInfo);
136
137 /**
138 * @brief Helper function to map the dbus info to sensor's assertion status
139 * for the get sensor reading command.
140 *
141 * @param[in] sensorInfo - Dbus info related to sensor.
142 * @param[in] path - Dbus object path.
143 * @param[in] interface - Dbus interface.
144 *
145 * @return Response for get sensor reading command.
146 */
147 GetSensorResponse mapDbusToAssertion(const Info& sensorInfo,
148 const InstancePath& path,
149 const DbusInterface& interface);
150
151 #ifndef FEATURE_SENSORS_CACHE
152 /**
153 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
154 * reading command response.
155 *
156 * @param[in] sensorInfo - Dbus info related to sensor.
157 *
158 * @return Response for get sensor reading command.
159 */
160 GetSensorResponse assertion(const Info& sensorInfo);
161
162 /**
163 * @brief Maps the Dbus info to the reading field in the Get sensor reading
164 * command response.
165 *
166 * @param[in] sensorInfo - Dbus info related to sensor.
167 *
168 * @return Response for get sensor reading command.
169 */
170 GetSensorResponse eventdata2(const Info& sensorInfo);
171
172 /**
173 * @brief readingAssertion is a case where the entire assertion state field
174 * serves as the sensor value.
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>
readingAssertion(const Info & sensorInfo)182 GetSensorResponse readingAssertion(const Info& sensorInfo)
183 {
184 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
185 GetSensorResponse response{};
186
187 enableScanning(response);
188 try
189 {
190 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
191 sensorInfo.sensorPath);
192 auto propValue = ipmi::getDbusProperty(
193 bus, service, sensorInfo.sensorPath,
194 sensorInfo.propertyInterfaces.begin()->first,
195 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
196
197 setAssertionBytes(static_cast<uint16_t>(std::get<T>(propValue)),
198 response);
199 }
200 catch (const std::exception& e)
201 {
202 lg2::error(
203 "Failed to call readingAssertion, path: {PATH}, interface: {INTERFACE}: {ERROR}",
204 "PATH", sensorInfo.sensorPath, "INTERFACE",
205 sensorInfo.sensorInterface, "ERROR", e);
206 }
207
208 return response;
209 }
210
211 /** @brief Map the Dbus info to the reading field in the Get sensor reading
212 * command response
213 *
214 * @tparam T - type of the dbus property related to sensor.
215 * @param[in] sensorInfo - Dbus info related to sensor.
216 *
217 * @return Response for get sensor reading command.
218 */
219 template <typename T>
readingData(const Info & sensorInfo)220 GetSensorResponse readingData(const Info& sensorInfo)
221 {
222 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
223
224 GetSensorResponse response{};
225
226 enableScanning(response);
227
228 auto service = ipmi::getService(bus, sensorInfo.sensorInterface,
229 sensorInfo.sensorPath);
230
231 #ifdef UPDATE_FUNCTIONAL_ON_FAIL
232 // Check the OperationalStatus interface for functional property
233 if (sensorInfo.propertyInterfaces.begin()->first == SensorValue::interface)
234 {
235 bool functional = true;
236 try
237 {
238 auto funcValue = ipmi::getDbusProperty(
239 bus, service, sensorInfo.sensorPath,
240 "xyz.openbmc_project.State.Decorator.OperationalStatus",
241 "Functional");
242 functional = std::get<bool>(funcValue);
243 }
244 catch (...)
245 {
246 // No-op if Functional property could not be found since this
247 // check is only valid for Sensor.Value read for hwmonio
248 }
249 if (!functional)
250 {
251 throw SensorFunctionalError();
252 }
253 }
254 #endif
255
256 double value{};
257 try
258 {
259 auto propValue = ipmi::getDbusProperty(
260 bus, service, sensorInfo.sensorPath,
261 sensorInfo.propertyInterfaces.begin()->first,
262 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
263
264 value = std::get<T>(propValue) *
265 std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
266 }
267 catch (const std::exception& e)
268 {
269 lg2::error(
270 "Failed to call readingData, path: {PATH}, interface: {INTERFACE}: {ERROR}",
271 "PATH", sensorInfo.sensorPath, "INTERFACE",
272 sensorInfo.sensorInterface, "ERROR", e);
273 return response;
274 }
275
276 int32_t rawData =
277 (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
278
279 constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
280 constexpr uint8_t signedDataFormat = 0x80;
281 // if sensorUnits1 [7:6] = 10b, sensor is signed
282 int32_t minClamp;
283 int32_t maxClamp;
284 if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
285 {
286 minClamp = std::numeric_limits<int8_t>::lowest();
287 maxClamp = std::numeric_limits<int8_t>::max();
288 }
289 else
290 {
291 minClamp = std::numeric_limits<uint8_t>::lowest();
292 maxClamp = std::numeric_limits<uint8_t>::max();
293 }
294 setReading(static_cast<uint8_t>(std::clamp(rawData, minClamp, maxClamp)),
295 response);
296
297 if (!std::isfinite(value))
298 {
299 response.readingOrStateUnavailable = 1;
300 }
301
302 bool critAlarmHigh;
303 try
304 {
305 critAlarmHigh = std::get<bool>(ipmi::getDbusProperty(
306 bus, service, sensorInfo.sensorPath,
307 SensorThresholdCritical::interface,
308 SensorThresholdCritical::property_names::critical_alarm_high));
309 }
310 catch (const std::exception& e)
311 {
312 critAlarmHigh = false;
313 }
314 bool critAlarmLow;
315 try
316 {
317 critAlarmLow = std::get<bool>(ipmi::getDbusProperty(
318 bus, service, sensorInfo.sensorPath,
319 SensorThresholdCritical::interface,
320 SensorThresholdCritical::property_names::critical_alarm_low));
321 }
322 catch (const std::exception& e)
323 {
324 critAlarmLow = false;
325 }
326 bool warningAlarmHigh;
327 try
328 {
329 warningAlarmHigh = std::get<bool>(ipmi::getDbusProperty(
330 bus, service, sensorInfo.sensorPath,
331 SensorThresholdWarning::interface,
332 SensorThresholdWarning::property_names::warning_alarm_high));
333 }
334 catch (const std::exception& e)
335 {
336 warningAlarmHigh = false;
337 }
338 bool warningAlarmLow;
339 try
340 {
341 warningAlarmLow = std::get<bool>(ipmi::getDbusProperty(
342 bus, service, sensorInfo.sensorPath,
343 SensorThresholdWarning::interface,
344 SensorThresholdWarning::property_names::warning_alarm_low));
345 }
346 catch (const std::exception& e)
347 {
348 warningAlarmLow = false;
349 }
350 response.thresholdLevelsStates =
351 0xC0 | (static_cast<uint8_t>(warningAlarmLow) << 0) |
352 (static_cast<uint8_t>(critAlarmLow) << 1) |
353 (static_cast<uint8_t>(warningAlarmHigh) << 3) |
354 (static_cast<uint8_t>(critAlarmHigh) << 4);
355 return response;
356 }
357
358 #else
359
360 /**
361 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
362 * reading command response.
363 *
364 * @param[in] id - The sensor id
365 * @param[in] sensorInfo - Dbus info related to sensor.
366 * @param[in] msg - Dbus message from match callback.
367 *
368 * @return Response for get sensor reading command.
369 */
370 std::optional<GetSensorResponse> assertion(uint8_t id, const Info& sensorInfo,
371 const PropertyMap& properties);
372
373 /**
374 * @brief Maps the Dbus info to the reading field in the Get sensor reading
375 * command response.
376 *
377 * @param[in] id - The sensor id
378 * @param[in] sensorInfo - Dbus info related to sensor.
379 * @param[in] msg - Dbus message from match callback.
380 *
381 * @return Response for get sensor reading command.
382 */
383 std::optional<GetSensorResponse> eventdata2(uint8_t id, const Info& sensorInfo,
384 const PropertyMap& properties);
385
386 /**
387 * @brief readingAssertion is a case where the entire assertion state field
388 * serves as the sensor value.
389 *
390 * @tparam T - type of the dbus property related to sensor.
391 * @param[in] id - The sensor id
392 * @param[in] sensorInfo - Dbus info related to sensor.
393 * @param[in] msg - Dbus message from match callback.
394 *
395 * @return Response for get sensor reading command.
396 */
397 template <typename T>
readingAssertion(uint8_t id,const Info & sensorInfo,const PropertyMap & properties)398 std::optional<GetSensorResponse> readingAssertion(
399 uint8_t id, const Info& sensorInfo, const PropertyMap& properties)
400 {
401 GetSensorResponse response{};
402 enableScanning(response);
403
404 auto iter = properties.find(
405 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
406 if (iter == properties.end())
407 {
408 return {};
409 }
410
411 setAssertionBytes(static_cast<uint16_t>(std::get<T>(iter->second)),
412 response);
413
414 if (!sensorCacheMap[id].has_value())
415 {
416 sensorCacheMap[id] = SensorData{};
417 }
418 sensorCacheMap[id]->response = response;
419 return response;
420 }
421
422 /** @brief Get sensor reading from the dbus message from match
423 *
424 * @tparam T - type of the dbus property related to sensor.
425 * @param[in] id - The sensor id
426 * @param[in] sensorInfo - Dbus info related to sensor.
427 * @param[in] msg - Dbus message from match callback.
428 *
429 * @return Response for get sensor reading command.
430 */
431 template <typename T>
readingData(uint8_t id,const Info & sensorInfo,const PropertyMap & properties)432 std::optional<GetSensorResponse> readingData(uint8_t id, const Info& sensorInfo,
433 const PropertyMap& properties)
434 {
435 auto iter = properties.find("Functional");
436 if (iter != properties.end())
437 {
438 sensorCacheMap[id]->functional = std::get<bool>(iter->second);
439 }
440 iter = properties.find("Available");
441 if (iter != properties.end())
442 {
443 sensorCacheMap[id]->available = std::get<bool>(iter->second);
444 }
445 #ifdef UPDATE_FUNCTIONAL_ON_FAIL
446 if (sensorCacheMap[id])
447 {
448 if (!sensorCacheMap[id]->functional)
449 {
450 throw SensorFunctionalError();
451 }
452 }
453 #endif
454
455 GetSensorResponse response{};
456
457 enableScanning(response);
458
459 iter = properties.find(
460 sensorInfo.propertyInterfaces.begin()->second.begin()->first);
461 if (iter == properties.end())
462 {
463 return {};
464 }
465
466 double value = std::get<T>(iter->second) *
467 std::pow(10, sensorInfo.scale - sensorInfo.exponentR);
468 int32_t rawData =
469 (value - sensorInfo.scaledOffset) / sensorInfo.coefficientM;
470
471 constexpr uint8_t sensorUnitsSignedBits = 2 << 6;
472 constexpr uint8_t signedDataFormat = 0x80;
473 // if sensorUnits1 [7:6] = 10b, sensor is signed
474 if ((sensorInfo.sensorUnits1 & sensorUnitsSignedBits) == signedDataFormat)
475 {
476 if (rawData > std::numeric_limits<int8_t>::max() ||
477 rawData < std::numeric_limits<int8_t>::lowest())
478 {
479 lg2::error("Value out of range");
480 throw std::out_of_range("Value out of range");
481 }
482 setReading(static_cast<int8_t>(rawData), response);
483 }
484 else
485 {
486 if (rawData > std::numeric_limits<uint8_t>::max() ||
487 rawData < std::numeric_limits<uint8_t>::lowest())
488 {
489 lg2::error("Value out of range");
490 throw std::out_of_range("Value out of range");
491 }
492 setReading(static_cast<uint8_t>(rawData), response);
493 }
494
495 if (!std::isfinite(value))
496 {
497 response.readingOrStateUnavailable = 1;
498 }
499
500 if (!sensorCacheMap[id].has_value())
501 {
502 sensorCacheMap[id] = SensorData{};
503 }
504 sensorCacheMap[id]->response = response;
505
506 return response;
507 }
508
509 #endif // FEATURE_SENSORS_CACHE
510
511 } // namespace get
512
513 namespace set
514 {
515
516 /** @brief Make a DBus message for a Dbus call
517 * @param[in] updateInterface - Interface name
518 * @param[in] sensorPath - Path of the sensor
519 * @param[in] command - command to be executed
520 * @param[in] sensorInterface - DBus interface of sensor
521 * @return a dbus message
522 */
523 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
524 const std::string& sensorPath,
525 const std::string& command,
526 const std::string& sensorInterface);
527
528 /** @brief Update d-bus based on assertion type sensor data
529 * @param[in] cmdData - input sensor data
530 * @param[in] sensorInfo - sensor d-bus info
531 * @return a IPMI error code
532 */
533 ipmi::Cc assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo);
534
535 /** @brief Update d-bus based on a reading assertion
536 * @tparam T - type of d-bus property mapping this sensor
537 * @param[in] cmdData - input sensor data
538 * @param[in] sensorInfo - sensor d-bus info
539 * @return a IPMI error code
540 */
541 template <typename T>
readingAssertion(const SetSensorReadingReq & cmdData,const Info & sensorInfo)542 ipmi::Cc readingAssertion(const SetSensorReadingReq& cmdData,
543 const Info& sensorInfo)
544 {
545 auto msg =
546 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
547 "Set", sensorInfo.sensorInterface);
548
549 const auto& interface = sensorInfo.propertyInterfaces.begin();
550 msg.append(interface->first);
551 for (const auto& property : interface->second)
552 {
553 msg.append(property.first);
554 std::variant<T> value = static_cast<T>(
555 (cmdData.assertOffset8_14 << 8) | cmdData.assertOffset0_7);
556 msg.append(value);
557 }
558 return updateToDbus(msg);
559 }
560
561 /** @brief Update d-bus based on a discrete reading
562 * @param[in] cmdData - input sensor data
563 * @param[in] sensorInfo - sensor d-bus info
564 * @return an IPMI error code
565 */
566 template <typename T>
readingData(const SetSensorReadingReq & cmdData,const Info & sensorInfo)567 ipmi::Cc readingData(const SetSensorReadingReq& cmdData, const Info& sensorInfo)
568 {
569 T raw_value = (sensorInfo.coefficientM * cmdData.reading) +
570 sensorInfo.scaledOffset;
571
572 raw_value *= std::pow(10, sensorInfo.exponentR - sensorInfo.scale);
573
574 auto msg =
575 makeDbusMsg("org.freedesktop.DBus.Properties", sensorInfo.sensorPath,
576 "Set", sensorInfo.sensorInterface);
577
578 const auto& interface = sensorInfo.propertyInterfaces.begin();
579 msg.append(interface->first);
580
581 for (const auto& property : interface->second)
582 {
583 msg.append(property.first);
584 std::variant<T> value = raw_value;
585 msg.append(value);
586 }
587 return updateToDbus(msg);
588 }
589
590 /** @brief Update d-bus based on eventdata type sensor data
591 * @param[in] cmdData - input sensor data
592 * @param[in] sensorInfo - sensor d-bus info
593 * @return a IPMI error code
594 */
595 ipmi::Cc eventdata(const SetSensorReadingReq& cmdData, const Info& sensorInfo,
596 uint8_t data);
597
598 /** @brief Update d-bus based on eventdata1 type sensor data
599 * @param[in] cmdData - input sensor data
600 * @param[in] sensorInfo - sensor d-bus info
601 * @return a IPMI error code
602 */
eventdata1(const SetSensorReadingReq & cmdData,const Info & sensorInfo)603 inline ipmi::Cc eventdata1(const SetSensorReadingReq& cmdData,
604 const Info& sensorInfo)
605 {
606 return eventdata(cmdData, sensorInfo, cmdData.eventData1);
607 }
608
609 /** @brief Update d-bus based on eventdata2 type sensor data
610 * @param[in] cmdData - input sensor data
611 * @param[in] sensorInfo - sensor d-bus info
612 * @return a IPMI error code
613 */
eventdata2(const SetSensorReadingReq & cmdData,const Info & sensorInfo)614 inline ipmi::Cc eventdata2(const SetSensorReadingReq& cmdData,
615 const Info& sensorInfo)
616 {
617 return eventdata(cmdData, sensorInfo, cmdData.eventData2);
618 }
619
620 /** @brief Update d-bus based on eventdata3 type sensor data
621 * @param[in] cmdData - input sensor data
622 * @param[in] sensorInfo - sensor d-bus info
623 * @return a IPMI error code
624 */
eventdata3(const SetSensorReadingReq & cmdData,const Info & sensorInfo)625 inline ipmi::Cc eventdata3(const SetSensorReadingReq& cmdData,
626 const Info& sensorInfo)
627 {
628 return eventdata(cmdData, sensorInfo, cmdData.eventData3);
629 }
630
631 } // namespace set
632
633 namespace notify
634 {
635
636 /** @brief Make a DBus message for a Dbus call
637 * @param[in] updateInterface - Interface name
638 * @param[in] sensorPath - Path of the sensor
639 * @param[in] command - command to be executed
640 * @param[in] sensorInterface - DBus interface of sensor
641 * @return a dbus message
642 */
643 IpmiUpdateData makeDbusMsg(const std::string& updateInterface,
644 const std::string& sensorPath,
645 const std::string& command,
646 const std::string& sensorInterface);
647
648 /** @brief Update d-bus based on assertion type sensor data
649 * @param[in] interfaceMap - sensor interface
650 * @param[in] cmdData - input sensor data
651 * @param[in] sensorInfo - sensor d-bus info
652 * @return a IPMI error code
653 */
654 ipmi::Cc assertion(const SetSensorReadingReq& cmdData, const Info& sensorInfo);
655
656 } // namespace notify
657
658 namespace inventory
659 {
660
661 namespace get
662 {
663
664 #ifndef FEATURE_SENSORS_CACHE
665
666 /**
667 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
668 * reading command response.
669 *
670 * @param[in] sensorInfo - Dbus info related to sensor.
671 *
672 * @return Response for get sensor reading command.
673 */
674 GetSensorResponse assertion(const Info& sensorInfo);
675
676 #else
677
678 /**
679 * @brief Map the Dbus info to sensor's assertion status in the Get sensor
680 * reading command response.
681 *
682 * @param[in] id - The sensor id
683 * @param[in] sensorInfo - Dbus info related to sensor.
684 * @param[in] msg - Dbus message from match callback.
685 *
686 * @return Response for get sensor reading command.
687 */
688 std::optional<GetSensorResponse> assertion(uint8_t id, const Info& sensorInfo,
689 const PropertyMap& properties);
690
691 #endif
692
693 } // namespace get
694
695 } // namespace inventory
696 } // namespace sensor
697 } // namespace ipmi
698