blob: 1666d0b0b5cf2dd8914c095178ca70dbdbe8dc85 [file] [log] [blame]
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080017#include <ipmid/api.h>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070018
19#include <boost/algorithm/string.hpp>
20#include <boost/container/flat_map.hpp>
21#include <chrono>
22#include <cmath>
23#include <commandutils.hpp>
24#include <iostream>
25#include <phosphor-ipmi-host/utils.hpp>
26#include <phosphor-logging/log.hpp>
27#include <sdbusplus/bus.hpp>
28#include <sdrutils.hpp>
29#include <sensorcommands.hpp>
30#include <sensorutils.hpp>
31#include <storagecommands.hpp>
32#include <string>
33
34namespace ipmi
35{
36using ManagedObjectType =
37 std::map<sdbusplus::message::object_path,
38 std::map<std::string, std::map<std::string, DbusVariant>>>;
39
40using SensorMap = std::map<std::string, std::map<std::string, DbusVariant>>;
James Feist14fde842018-12-06 10:19:40 -080041namespace variant_ns = sdbusplus::message::variant_ns;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070042
43static constexpr int sensorListUpdatePeriod = 10;
44static constexpr int sensorMapUpdatePeriod = 2;
45
46constexpr size_t maxSDRTotalSize =
47 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
48constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
49
50static uint16_t sdrReservationID;
51static uint32_t sdrLastAdd = noTimestamp;
52static uint32_t sdrLastRemove = noTimestamp;
53
Richard Marian Thomaiyar01fbcb52018-11-19 22:04:34 +053054SensorSubTree sensorTree;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070055static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
56
Jason M. Bills17add592018-11-12 14:30:12 -080057// Specify the comparison required to sort and find char* map objects
58struct CmpStr
59{
60 bool operator()(const char *a, const char *b) const
61 {
62 return std::strcmp(a, b) < 0;
63 }
64};
65const static boost::container::flat_map<const char *, SensorUnits, CmpStr>
66 sensorUnits{{{"temperature", SensorUnits::degreesC},
67 {"voltage", SensorUnits::volts},
68 {"current", SensorUnits::amps},
69 {"fan_tach", SensorUnits::rpm},
70 {"power", SensorUnits::watts}}};
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070071
72void registerSensorFunctions() __attribute__((constructor));
73static sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
74
75static sdbusplus::bus::match::match sensorAdded(
76 dbus,
77 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
78 "sensors/'",
79 [](sdbusplus::message::message &m) {
80 sensorTree.clear();
81 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
82 std::chrono::system_clock::now().time_since_epoch())
83 .count();
84 });
85
86static sdbusplus::bus::match::match sensorRemoved(
87 dbus,
88 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
89 "sensors/'",
90 [](sdbusplus::message::message &m) {
91 sensorTree.clear();
92 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
93 std::chrono::system_clock::now().time_since_epoch())
94 .count();
95 });
96
James Feist392786a2019-03-19 13:36:10 -070097// this keeps track of deassertions for sensor event status command. A
98// deasertion can only happen if an assertion was seen first.
99static boost::container::flat_map<
100 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
101 thresholdDeassertMap;
102
103static sdbusplus::bus::match::match thresholdChanged(
104 dbus,
105 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
106 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
107 [](sdbusplus::message::message &m) {
108 boost::container::flat_map<std::string, std::variant<bool, double>>
109 values;
110 m.read(std::string(), values);
111
112 auto findAssert =
113 std::find_if(values.begin(), values.end(), [](const auto &pair) {
114 return pair.first.find("Alarm") != std::string::npos;
115 });
116 if (findAssert != values.end())
117 {
118 auto ptr = std::get_if<bool>(&(findAssert->second));
119 if (ptr == nullptr)
120 {
121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "thresholdChanged: Assert non bool");
123 return;
124 }
125 if (*ptr)
126 {
127 phosphor::logging::log<phosphor::logging::level::INFO>(
128 "thresholdChanged: Assert",
129 phosphor::logging::entry("SENSOR=%s", m.get_path()));
130 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
131 }
132 else
133 {
134 auto &value =
135 thresholdDeassertMap[m.get_path()][findAssert->first];
136 if (value)
137 {
138 phosphor::logging::log<phosphor::logging::level::INFO>(
139 "thresholdChanged: deassert",
140 phosphor::logging::entry("SENSOR=%s", m.get_path()));
141 value = *ptr;
142 }
143 }
144 }
145 });
146
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700147static void
148 getSensorMaxMin(const std::map<std::string, DbusVariant> &sensorPropertyMap,
149 double &max, double &min)
150{
151 auto maxMap = sensorPropertyMap.find("MaxValue");
152 auto minMap = sensorPropertyMap.find("MinValue");
153 max = 127;
154 min = -128;
155
156 if (maxMap != sensorPropertyMap.end())
157 {
James Feist14fde842018-12-06 10:19:40 -0800158 max = variant_ns::visit(VariantToDoubleVisitor(), maxMap->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700159 }
160 if (minMap != sensorPropertyMap.end())
161 {
James Feist14fde842018-12-06 10:19:40 -0800162 min = variant_ns::visit(VariantToDoubleVisitor(), minMap->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700163 }
164}
165
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700166static bool getSensorMap(std::string sensorConnection, std::string sensorPath,
167 SensorMap &sensorMap)
168{
169 static boost::container::flat_map<
170 std::string, std::chrono::time_point<std::chrono::steady_clock>>
171 updateTimeMap;
172
173 auto updateFind = updateTimeMap.find(sensorConnection);
174 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
175 if (updateFind != updateTimeMap.end())
176 {
177 lastUpdate = updateFind->second;
178 }
179
180 auto now = std::chrono::steady_clock::now();
181
182 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
183 .count() > sensorMapUpdatePeriod)
184 {
185 updateTimeMap[sensorConnection] = now;
186
187 auto managedObj = dbus.new_method_call(
188 sensorConnection.c_str(), "/", "org.freedesktop.DBus.ObjectManager",
189 "GetManagedObjects");
190
191 ManagedObjectType managedObjects;
192 try
193 {
194 auto reply = dbus.call(managedObj);
195 reply.read(managedObjects);
196 }
197 catch (sdbusplus::exception_t &)
198 {
199 phosphor::logging::log<phosphor::logging::level::ERR>(
200 "Error getting managed objects from connection",
201 phosphor::logging::entry("CONNECTION=%s",
202 sensorConnection.c_str()));
203 return false;
204 }
205
206 SensorCache[sensorConnection] = managedObjects;
207 }
208 auto connection = SensorCache.find(sensorConnection);
209 if (connection == SensorCache.end())
210 {
211 return false;
212 }
213 auto path = connection->second.find(sensorPath);
214 if (path == connection->second.end())
215 {
216 return false;
217 }
218 sensorMap = path->second;
219
220 return true;
221}
222
223/* sensor commands */
224ipmi_ret_t ipmiSensorWildcardHandler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
225 ipmi_request_t request,
226 ipmi_response_t response,
227 ipmi_data_len_t dataLen,
228 ipmi_context_t context)
229{
230 *dataLen = 0;
231 printCommand(+netfn, +cmd);
232 return IPMI_CC_INVALID;
233}
234
235ipmi_ret_t ipmiSenGetSensorReading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
236 ipmi_request_t request,
237 ipmi_response_t response,
238 ipmi_data_len_t dataLen,
239 ipmi_context_t context)
240{
241 if (*dataLen != 1)
242 {
243 *dataLen = 0;
244 return IPMI_CC_REQ_DATA_LEN_INVALID;
245 }
246 *dataLen = 0; // default to 0 in case of an error
247
248 uint8_t sensnum = *(static_cast<uint8_t *>(request));
249
250 std::string connection;
251 std::string path;
252
253 auto status = getSensorConnection(sensnum, connection, path);
254 if (status)
255 {
256 return status;
257 }
258
259 SensorMap sensorMap;
260 if (!getSensorMap(connection, path, sensorMap))
261 {
262 return IPMI_CC_RESPONSE_ERROR;
263 }
264 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
265
266 if (sensorObject == sensorMap.end() ||
267 sensorObject->second.find("Value") == sensorObject->second.end())
268 {
269 return IPMI_CC_RESPONSE_ERROR;
270 }
271 auto &value = sensorObject->second["Value"];
James Feist14fde842018-12-06 10:19:40 -0800272 double reading = variant_ns::visit(VariantToDoubleVisitor(), value);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700273
274 double max;
275 double min;
276 getSensorMaxMin(sensorObject->second, max, min);
277
278 int16_t mValue = 0;
279 int16_t bValue = 0;
280 int8_t rExp = 0;
281 int8_t bExp = 0;
282 bool bSigned = false;
283
284 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
285 {
286 return IPMI_CC_RESPONSE_ERROR;
287 }
288
289 SensorReadingResp *msgReply = static_cast<SensorReadingResp *>(response);
290 *dataLen = sizeof(SensorReadingResp);
291
292 msgReply->value =
293 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
294 msgReply->operation =
295 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
James Feist81a95c12019-03-01 15:08:28 -0800296 msgReply->operation |=
297 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700298 msgReply->indication[0] = 0; // ignore for non-threshold sensors
299 msgReply->indication[1] = 0;
300
301 return IPMI_CC_OK;
302}
303
304ipmi_ret_t ipmiSenSetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
305 ipmi_request_t request,
306 ipmi_response_t response,
307 ipmi_data_len_t dataLen,
308 ipmi_context_t context)
309{
310 if (*dataLen != 8)
311 {
312 *dataLen = 0;
313 return IPMI_CC_REQ_DATA_LEN_INVALID;
314 }
315 *dataLen = 0;
316
317 SensorThresholdReq *req = static_cast<SensorThresholdReq *>(request);
318
319 // upper two bits reserved
320 if (req->mask & 0xC0)
321 {
322 return IPMI_CC_INVALID_FIELD_REQUEST;
323 }
324
325 // lower nc and upper nc not suppported on any sensor
326 if ((req->mask & static_cast<uint8_t>(
327 SensorThresholdReqEnable::setLowerNonRecoverable)) ||
328 (req->mask & static_cast<uint8_t>(
329 SensorThresholdReqEnable::setUpperNonRecoverable)))
330 {
331 return IPMI_CC_INVALID_FIELD_REQUEST;
332 }
333
334 // if no bits are set in the mask, nothing to do
335 if (!(req->mask))
336 {
337 return IPMI_CC_OK;
338 }
339
340 std::string connection;
341 std::string path;
342
343 ipmi_ret_t status = getSensorConnection(req->sensorNum, connection, path);
344 if (status)
345 {
346 return status;
347 }
348 SensorMap sensorMap;
349 if (!getSensorMap(connection, path, sensorMap))
350 {
351 return IPMI_CC_RESPONSE_ERROR;
352 }
353
354 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
355
356 if (sensorObject == sensorMap.end())
357 {
358 return IPMI_CC_RESPONSE_ERROR;
359 }
360 double max = 0;
361 double min = 0;
362 getSensorMaxMin(sensorObject->second, max, min);
363
364 int16_t mValue = 0;
365 int16_t bValue = 0;
366 int8_t rExp = 0;
367 int8_t bExp = 0;
368 bool bSigned = false;
369
370 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
371 {
372 return IPMI_CC_RESPONSE_ERROR;
373 }
374
375 bool setLowerCritical =
376 req->mask &
377 static_cast<uint8_t>(SensorThresholdReqEnable::setLowerCritical);
378 bool setUpperCritical =
379 req->mask &
380 static_cast<uint8_t>(SensorThresholdReqEnable::setUpperCritical);
381
382 bool setLowerWarning =
383 req->mask &
384 static_cast<uint8_t>(SensorThresholdReqEnable::setLowerNonCritical);
385 bool setUpperWarning =
386 req->mask &
387 static_cast<uint8_t>(SensorThresholdReqEnable::setUpperNonCritical);
388
389 // store a vector of property name, value to set, and interface
390 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
391
392 // define the indexes of the tuple
393 constexpr uint8_t propertyName = 0;
394 constexpr uint8_t thresholdValue = 1;
395 constexpr uint8_t interface = 2;
396 // verifiy all needed fields are present
397 if (setLowerCritical || setUpperCritical)
398 {
399 auto findThreshold =
400 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
401 if (findThreshold == sensorMap.end())
402 {
403 return IPMI_CC_INVALID_FIELD_REQUEST;
404 }
405 if (setLowerCritical)
406 {
407 auto findLower = findThreshold->second.find("CriticalLow");
408 if (findLower == findThreshold->second.end())
409 {
410 return IPMI_CC_INVALID_FIELD_REQUEST;
411 }
412 thresholdsToSet.emplace_back("CriticalLow", req->lowerCritical,
413 findThreshold->first);
414 }
415 if (setUpperCritical)
416 {
417 auto findUpper = findThreshold->second.find("CriticalHigh");
418 if (findUpper == findThreshold->second.end())
419 {
420 return IPMI_CC_INVALID_FIELD_REQUEST;
421 }
422 thresholdsToSet.emplace_back("CriticalHigh", req->upperCritical,
423 findThreshold->first);
424 }
425 }
426 if (setLowerWarning || setUpperWarning)
427 {
428 auto findThreshold =
429 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
430 if (findThreshold == sensorMap.end())
431 {
432 return IPMI_CC_INVALID_FIELD_REQUEST;
433 }
434 if (setLowerWarning)
435 {
436 auto findLower = findThreshold->second.find("WarningLow");
437 if (findLower == findThreshold->second.end())
438 {
439 return IPMI_CC_INVALID_FIELD_REQUEST;
440 }
441 thresholdsToSet.emplace_back("WarningLow", req->lowerNonCritical,
442 findThreshold->first);
443 }
444 if (setUpperWarning)
445 {
446 auto findUpper = findThreshold->second.find("WarningHigh");
447 if (findUpper == findThreshold->second.end())
448 {
449 return IPMI_CC_INVALID_FIELD_REQUEST;
450 }
451 thresholdsToSet.emplace_back("WarningHigh", req->upperNonCritical,
452 findThreshold->first);
453 }
454 }
455
456 for (const auto &property : thresholdsToSet)
457 {
458 // from section 36.3 in the IPMI Spec, assume all linear
459 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
460 (bValue * std::pow(10, bExp))) *
461 std::pow(10, rExp);
462 setDbusProperty(dbus, connection, path, std::get<interface>(property),
463 std::get<propertyName>(property),
464 ipmi::Value(valueToSet));
465 }
466
467 return IPMI_CC_OK;
468}
469
470ipmi_ret_t ipmiSenGetSensorThresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
471 ipmi_request_t request,
472 ipmi_response_t response,
473 ipmi_data_len_t dataLen,
474 ipmi_context_t context)
475{
476 if (*dataLen != 1)
477 {
478 *dataLen = 0;
479 return IPMI_CC_REQ_DATA_LEN_INVALID;
480 }
481 *dataLen = 0; // default to 0 in case of an error
482
483 uint8_t sensnum = *(static_cast<uint8_t *>(request));
484
485 std::string connection;
486 std::string path;
487
488 auto status = getSensorConnection(sensnum, connection, path);
489 if (status)
490 {
491 return status;
492 }
493
494 SensorMap sensorMap;
495 if (!getSensorMap(connection, path, sensorMap))
496 {
497 return IPMI_CC_RESPONSE_ERROR;
498 }
499
500 // zero out response buff
501 auto responseClear = static_cast<uint8_t *>(response);
502 std::fill(responseClear, responseClear + sizeof(SensorThresholdResp), 0);
503
504 auto warningInterface =
505 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
506 auto criticalInterface =
507 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
508
509 if ((warningInterface != sensorMap.end()) ||
510 (criticalInterface != sensorMap.end()))
511 {
512 auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
513
514 if (sensorPair == sensorMap.end())
515 {
516 // should not have been able to find a sensor not implementing
517 // the sensor object
518 return IPMI_CC_RESPONSE_ERROR;
519 }
520
521 double max;
522 double min;
523 getSensorMaxMin(sensorPair->second, max, min);
524
525 int16_t mValue = 0;
526 int16_t bValue = 0;
527 int8_t rExp = 0;
528 int8_t bExp = 0;
529 bool bSigned = false;
530
531 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
532 {
533 return IPMI_CC_RESPONSE_ERROR;
534 }
535
536 auto msgReply = static_cast<SensorThresholdResp *>(response);
537
538 if (warningInterface != sensorMap.end())
539 {
540 auto &warningMap = warningInterface->second;
541
542 auto warningHigh = warningMap.find("WarningHigh");
543 auto warningLow = warningMap.find("WarningLow");
544
545 if (warningHigh != warningMap.end())
546 {
547 msgReply->readable |=
548 1 << static_cast<int>(
549 IPMIhresholdRespBits::upperNonCritical);
James Feist14fde842018-12-06 10:19:40 -0800550 double value = variant_ns::visit(VariantToDoubleVisitor(),
551 warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700552 msgReply->uppernc = scaleIPMIValueFromDouble(
553 value, mValue, rExp, bValue, bExp, bSigned);
554 }
555 if (warningLow != warningMap.end())
556 {
557 msgReply->readable |=
558 1 << static_cast<int>(
559 IPMIhresholdRespBits::lowerNonCritical);
James Feist14fde842018-12-06 10:19:40 -0800560 double value = variant_ns::visit(VariantToDoubleVisitor(),
561 warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700562 msgReply->lowernc = scaleIPMIValueFromDouble(
563 value, mValue, rExp, bValue, bExp, bSigned);
564 }
565 }
566 if (criticalInterface != sensorMap.end())
567 {
568 auto &criticalMap = criticalInterface->second;
569
570 auto criticalHigh = criticalMap.find("CriticalHigh");
571 auto criticalLow = criticalMap.find("CriticalLow");
572
573 if (criticalHigh != criticalMap.end())
574 {
575 msgReply->readable |=
576 1 << static_cast<int>(IPMIhresholdRespBits::upperCritical);
James Feist14fde842018-12-06 10:19:40 -0800577 double value = variant_ns::visit(VariantToDoubleVisitor(),
578 criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700579 msgReply->uppercritical = scaleIPMIValueFromDouble(
580 value, mValue, rExp, bValue, bExp, bSigned);
581 }
582 if (criticalLow != criticalMap.end())
583 {
584 msgReply->readable |=
585 1 << static_cast<int>(IPMIhresholdRespBits::lowerCritical);
James Feist14fde842018-12-06 10:19:40 -0800586 double value = variant_ns::visit(VariantToDoubleVisitor(),
587 criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700588 msgReply->lowercritical = scaleIPMIValueFromDouble(
589 value, mValue, rExp, bValue, bExp, bSigned);
590 }
591 }
592 }
593
594 *dataLen = sizeof(SensorThresholdResp);
595 return IPMI_CC_OK;
596}
597
598ipmi_ret_t ipmiSenGetSensorEventEnable(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
599 ipmi_request_t request,
600 ipmi_response_t response,
601 ipmi_data_len_t dataLen,
602 ipmi_context_t context)
603{
604 if (*dataLen != 1)
605 {
606 *dataLen = 0;
607 return IPMI_CC_REQ_DATA_LEN_INVALID;
608 }
609 *dataLen = 0; // default to 0 in case of an error
610
611 uint8_t sensnum = *(static_cast<uint8_t *>(request));
612
613 std::string connection;
614 std::string path;
615
616 auto status = getSensorConnection(sensnum, connection, path);
617 if (status)
618 {
619 return status;
620 }
621
622 SensorMap sensorMap;
623 if (!getSensorMap(connection, path, sensorMap))
624 {
625 return IPMI_CC_RESPONSE_ERROR;
626 }
627
628 auto warningInterface =
629 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
630 auto criticalInterface =
631 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
632
633 if ((warningInterface != sensorMap.end()) ||
634 (criticalInterface != sensorMap.end()))
635 {
636 // zero out response buff
637 auto responseClear = static_cast<uint8_t *>(response);
638 std::fill(responseClear, responseClear + sizeof(SensorEventEnableResp),
639 0);
640
641 // assume all threshold sensors
642 auto resp = static_cast<SensorEventEnableResp *>(response);
643
644 resp->enabled = static_cast<uint8_t>(
645 IPMISensorEventEnableByte2::sensorScanningEnable);
646 if (warningInterface != sensorMap.end())
647 {
648 auto &warningMap = warningInterface->second;
649
650 auto warningHigh = warningMap.find("WarningHigh");
651 auto warningLow = warningMap.find("WarningLow");
652 if (warningHigh != warningMap.end())
653 {
654 resp->assertionEnabledLSB |= static_cast<uint8_t>(
655 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
656 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
657 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
658 }
659 if (warningLow != warningMap.end())
660 {
661 resp->assertionEnabledLSB |= static_cast<uint8_t>(
662 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
663 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
664 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
665 }
666 }
667 if (criticalInterface != sensorMap.end())
668 {
669 auto &criticalMap = criticalInterface->second;
670
671 auto criticalHigh = criticalMap.find("CriticalHigh");
672 auto criticalLow = criticalMap.find("CriticalLow");
673
674 if (criticalHigh != criticalMap.end())
675 {
676 resp->assertionEnabledMSB |= static_cast<uint8_t>(
677 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
678 resp->deassertionEnabledMSB |= static_cast<uint8_t>(
679 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
680 }
681 if (criticalLow != criticalMap.end())
682 {
683 resp->assertionEnabledLSB |= static_cast<uint8_t>(
684 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
685 resp->deassertionEnabledLSB |= static_cast<uint8_t>(
686 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
687 }
688 }
689 *dataLen =
690 sizeof(SensorEventEnableResp); // todo only return needed bytes
691 }
692 // no thresholds enabled
693 else
694 {
695 *dataLen = 1;
696 auto resp = static_cast<uint8_t *>(response);
697 *resp = static_cast<uint8_t>(
698 IPMISensorEventEnableByte2::eventMessagesEnable);
699 *resp |= static_cast<uint8_t>(
700 IPMISensorEventEnableByte2::sensorScanningEnable);
701 }
702 return IPMI_CC_OK;
703}
704
705ipmi_ret_t ipmiSenGetSensorEventStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
706 ipmi_request_t request,
707 ipmi_response_t response,
708 ipmi_data_len_t dataLen,
709 ipmi_context_t context)
710{
711 if (*dataLen != 1)
712 {
713 *dataLen = 0;
714 return IPMI_CC_REQ_DATA_LEN_INVALID;
715 }
716 *dataLen = 0; // default to 0 in case of an error
717
718 uint8_t sensnum = *(static_cast<uint8_t *>(request));
719
720 std::string connection;
721 std::string path;
722
723 auto status = getSensorConnection(sensnum, connection, path);
724 if (status)
725 {
726 return status;
727 }
728
729 SensorMap sensorMap;
730 if (!getSensorMap(connection, path, sensorMap))
731 {
732 return IPMI_CC_RESPONSE_ERROR;
733 }
734
735 auto warningInterface =
736 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
737 auto criticalInterface =
738 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
739
740 // zero out response buff
741 auto responseClear = static_cast<uint8_t *>(response);
742 std::fill(responseClear, responseClear + sizeof(SensorEventStatusResp), 0);
743 auto resp = static_cast<SensorEventStatusResp *>(response);
744 resp->enabled =
745 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
746
James Feist392786a2019-03-19 13:36:10 -0700747 std::optional<bool> criticalDeassertHigh =
748 thresholdDeassertMap[path]["CriticalAlarmHigh"];
749 std::optional<bool> criticalDeassertLow =
750 thresholdDeassertMap[path]["CriticalAlarmLow"];
751 std::optional<bool> warningDeassertHigh =
752 thresholdDeassertMap[path]["WarningAlarmHigh"];
753 std::optional<bool> warningDeassertLow =
754 thresholdDeassertMap[path]["WarningAlarmLow"];
755
756 if (criticalDeassertHigh && !*criticalDeassertHigh)
757 {
758 resp->deassertionsMSB |= static_cast<uint8_t>(
759 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
760 }
761 if (criticalDeassertLow && !*criticalDeassertLow)
762 {
763 resp->deassertionsMSB |= static_cast<uint8_t>(
764 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
765 }
766 if (warningDeassertHigh && !*warningDeassertHigh)
767 {
768 resp->deassertionsLSB |= static_cast<uint8_t>(
769 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
770 }
771 if (warningDeassertLow && !*warningDeassertLow)
772 {
773 resp->deassertionsLSB |= static_cast<uint8_t>(
774 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
775 }
776
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700777 if ((warningInterface != sensorMap.end()) ||
778 (criticalInterface != sensorMap.end()))
779 {
780 resp->enabled = static_cast<uint8_t>(
781 IPMISensorEventEnableByte2::eventMessagesEnable);
782 if (warningInterface != sensorMap.end())
783 {
784 auto &warningMap = warningInterface->second;
785
786 auto warningHigh = warningMap.find("WarningAlarmHigh");
787 auto warningLow = warningMap.find("WarningAlarmLow");
788 auto warningHighAlarm = false;
789 auto warningLowAlarm = false;
790
791 if (warningHigh != warningMap.end())
792 {
James Feist880b7332018-12-06 11:14:02 -0800793 warningHighAlarm = sdbusplus::message::variant_ns::get<bool>(
794 warningHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700795 }
796 if (warningLow != warningMap.end())
797 {
James Feist880b7332018-12-06 11:14:02 -0800798 warningLowAlarm = sdbusplus::message::variant_ns::get<bool>(
799 warningLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700800 }
801 if (warningHighAlarm)
802 {
803 resp->assertionsLSB |= static_cast<uint8_t>(
804 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
805 }
806 if (warningLowAlarm)
807 {
808 resp->assertionsLSB |= 1; // lower nc going low
809 }
810 }
811 if (criticalInterface != sensorMap.end())
812 {
813 auto &criticalMap = criticalInterface->second;
814
815 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
816 auto criticalLow = criticalMap.find("CriticalAlarmLow");
817 auto criticalHighAlarm = false;
818 auto criticalLowAlarm = false;
819
820 if (criticalHigh != criticalMap.end())
821 {
James Feist880b7332018-12-06 11:14:02 -0800822 criticalHighAlarm = sdbusplus::message::variant_ns::get<bool>(
823 criticalHigh->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700824 }
825 if (criticalLow != criticalMap.end())
826 {
James Feist880b7332018-12-06 11:14:02 -0800827 criticalLowAlarm = sdbusplus::message::variant_ns::get<bool>(
828 criticalLow->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700829 }
830 if (criticalHighAlarm)
831 {
832 resp->assertionsMSB |= static_cast<uint8_t>(
833 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
834 }
835 if (criticalLowAlarm)
836 {
837 resp->assertionsLSB |= static_cast<uint8_t>(
838 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
839 }
840 }
841 *dataLen = sizeof(SensorEventStatusResp);
842 }
843
844 // no thresholds enabled, don't need assertionMSB
845 else
846 {
847 *dataLen = sizeof(SensorEventStatusResp) - 1;
848 }
849
850 return IPMI_CC_OK;
851}
852
853/* end sensor commands */
854
855/* storage commands */
856
857ipmi_ret_t ipmiStorageGetSDRRepositoryInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
858 ipmi_request_t request,
859 ipmi_response_t response,
860 ipmi_data_len_t dataLen,
861 ipmi_context_t context)
862{
863 printCommand(+netfn, +cmd);
864
865 if (*dataLen)
866 {
867 *dataLen = 0;
868 return IPMI_CC_REQ_DATA_LEN_INVALID;
869 }
870 *dataLen = 0; // default to 0 in case of an error
871
872 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
873 {
874 return IPMI_CC_RESPONSE_ERROR;
875 }
876
877 // zero out response buff
878 auto responseClear = static_cast<uint8_t *>(response);
879 std::fill(responseClear, responseClear + sizeof(GetSDRInfoResp), 0);
880
881 auto resp = static_cast<GetSDRInfoResp *>(response);
882 resp->sdrVersion = ipmiSdrVersion;
883 uint16_t recordCount = sensorTree.size();
884
885 // todo: for now, sdr count is number of sensors
886 resp->recordCountLS = recordCount & 0xFF;
887 resp->recordCountMS = recordCount >> 8;
888
889 // free space unspcified
890 resp->freeSpace[0] = 0xFF;
891 resp->freeSpace[1] = 0xFF;
892
893 resp->mostRecentAddition = sdrLastAdd;
894 resp->mostRecentErase = sdrLastRemove;
895 resp->operationSupport = static_cast<uint8_t>(
896 SdrRepositoryInfoOps::overflow); // write not supported
897 resp->operationSupport |=
898 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
899 resp->operationSupport |= static_cast<uint8_t>(
900 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
901 *dataLen = sizeof(GetSDRInfoResp);
902 return IPMI_CC_OK;
903}
904
905ipmi_ret_t ipmiStorageGetSDRAllocationInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
906 ipmi_request_t request,
907 ipmi_response_t response,
908 ipmi_data_len_t dataLen,
909 ipmi_context_t context)
910{
911 if (*dataLen)
912 {
913 *dataLen = 0;
914 return IPMI_CC_REQ_DATA_LEN_INVALID;
915 }
916 *dataLen = 0; // default to 0 in case of an error
917 GetAllocInfoResp *resp = static_cast<GetAllocInfoResp *>(response);
918
919 // 0000h unspecified number of alloc units
920 resp->allocUnitsLSB = 0;
921 resp->allocUnitsMSB = 0;
922
923 // max unit size is size of max record
924 resp->allocUnitSizeLSB = maxSDRTotalSize & 0xFF;
925 resp->allocUnitSizeMSB = maxSDRTotalSize >> 8;
926 // read only sdr, no free alloc blocks
927 resp->allocUnitFreeLSB = 0;
928 resp->allocUnitFreeMSB = 0;
929 resp->allocUnitLargestFreeLSB = 0;
930 resp->allocUnitLargestFreeMSB = 0;
931 // only allow one block at a time
932 resp->maxRecordSize = 1;
933
934 *dataLen = sizeof(GetAllocInfoResp);
935
936 return IPMI_CC_OK;
937}
938
939ipmi_ret_t ipmiStorageReserveSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
940 ipmi_request_t request,
941 ipmi_response_t response,
942 ipmi_data_len_t dataLen,
943 ipmi_context_t context)
944{
945 printCommand(+netfn, +cmd);
946
947 if (*dataLen)
948 {
949 *dataLen = 0;
950 return IPMI_CC_REQ_DATA_LEN_INVALID;
951 }
952 *dataLen = 0; // default to 0 in case of an error
953 sdrReservationID++;
James Feista80cb902019-02-14 13:05:25 -0800954 if (sdrReservationID == 0)
955 {
956 sdrReservationID++;
957 }
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700958 *dataLen = 2;
959 auto resp = static_cast<uint8_t *>(response);
960 resp[0] = sdrReservationID & 0xFF;
961 resp[1] = sdrReservationID >> 8;
962
963 return IPMI_CC_OK;
964}
965
966ipmi_ret_t ipmiStorageGetSDR(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
967 ipmi_request_t request, ipmi_response_t response,
968 ipmi_data_len_t dataLen, ipmi_context_t context)
969{
970 printCommand(+netfn, +cmd);
971
972 if (*dataLen != 6)
973 {
974 *dataLen = 0;
975 return IPMI_CC_REQ_DATA_LEN_INVALID;
976 }
977 auto requestedSize = *dataLen;
978 *dataLen = 0; // default to 0 in case of an error
979
980 constexpr uint16_t lastRecordIndex = 0xFFFF;
981 auto req = static_cast<GetSDRReq *>(request);
982
983 // reservation required for partial reads with non zero offset into
984 // record
James Feista80cb902019-02-14 13:05:25 -0800985 if ((sdrReservationID == 0 || req->reservationID != sdrReservationID) &&
986 req->offset)
Jason M. Bills3f7c5e42018-10-03 14:00:41 -0700987 {
988 return IPMI_CC_INVALID_RESERVATION_ID;
989 }
990
991 if (sensorTree.empty() && !getSensorSubtree(sensorTree))
992 {
993 return IPMI_CC_RESPONSE_ERROR;
994 }
995
996 size_t fruCount = 0;
997 ipmi_ret_t ret = ipmi::storage::getFruSdrCount(fruCount);
998 if (ret != IPMI_CC_OK)
999 {
1000 return ret;
1001 }
1002
1003 size_t lastRecord = sensorTree.size() + fruCount - 1;
1004 if (req->recordID == lastRecordIndex)
1005 {
1006 req->recordID = lastRecord;
1007 }
1008 if (req->recordID > lastRecord)
1009 {
1010 return IPMI_CC_INVALID_FIELD_REQUEST;
1011 }
1012
1013 uint16_t nextRecord =
John Wang7e7ed8b2019-03-20 10:35:02 +08001014 lastRecord > req->recordID ? req->recordID + 1 : 0XFFFF;
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001015
1016 auto responseClear = static_cast<uint8_t *>(response);
1017 std::fill(responseClear, responseClear + requestedSize, 0);
1018
1019 auto resp = static_cast<get_sdr::GetSdrResp *>(response);
1020 resp->next_record_id_lsb = nextRecord & 0xFF;
1021 resp->next_record_id_msb = nextRecord >> 8;
1022
1023 if (req->recordID >= sensorTree.size())
1024 {
1025 size_t fruIndex = req->recordID - sensorTree.size();
1026 if (fruIndex >= fruCount)
1027 {
1028 return IPMI_CC_INVALID_FIELD_REQUEST;
1029 }
1030 get_sdr::SensorDataFruRecord data;
1031 if (req->offset > sizeof(data))
1032 {
1033 return IPMI_CC_INVALID_FIELD_REQUEST;
1034 }
1035 ret = ipmi::storage::getFruSdrs(fruIndex, data);
1036 if (ret != IPMI_CC_OK)
1037 {
1038 return ret;
1039 }
1040 data.header.record_id_msb = req->recordID << 8;
1041 data.header.record_id_lsb = req->recordID & 0xFF;
1042 if (sizeof(data) < (req->offset + req->bytesToRead))
1043 {
1044 req->bytesToRead = sizeof(data) - req->offset;
1045 }
1046 *dataLen = req->bytesToRead + 2; // next record
1047 std::memcpy(&resp->record_data, (char *)&data + req->offset,
1048 req->bytesToRead);
1049 return IPMI_CC_OK;
1050 }
1051
1052 std::string connection;
1053 std::string path;
1054 uint16_t sensorIndex = req->recordID;
1055 for (const auto &sensor : sensorTree)
1056 {
1057 if (sensorIndex-- == 0)
1058 {
1059 if (!sensor.second.size())
1060 {
1061 return IPMI_CC_RESPONSE_ERROR;
1062 }
1063 connection = sensor.second.begin()->first;
1064 path = sensor.first;
1065 break;
1066 }
1067 }
1068
1069 SensorMap sensorMap;
1070 if (!getSensorMap(connection, path, sensorMap))
1071 {
1072 return IPMI_CC_RESPONSE_ERROR;
1073 }
1074 uint8_t sensornumber = (req->recordID & 0xFF);
1075 get_sdr::SensorDataFullRecord record = {0};
1076
1077 record.header.record_id_msb = req->recordID << 8;
1078 record.header.record_id_lsb = req->recordID & 0xFF;
1079 record.header.sdr_version = ipmiSdrVersion;
1080 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1081 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1082 sizeof(get_sdr::SensorDataRecordHeader);
1083 record.key.owner_id = 0x20;
1084 record.key.owner_lun = 0x0;
1085 record.key.sensor_number = sensornumber;
1086
1087 record.body.entity_id = 0x0;
1088 record.body.entity_instance = 0x01;
James Feist7086a882019-03-13 10:46:00 -07001089 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001090 record.body.sensor_type = getSensorTypeFromPath(path);
1091 std::string type = getSensorTypeStringFromPath(path);
1092 auto typeCstr = type.c_str();
1093 auto findUnits = sensorUnits.find(typeCstr);
1094 if (findUnits != sensorUnits.end())
1095 {
1096 record.body.sensor_units_2_base =
1097 static_cast<uint8_t>(findUnits->second);
1098 } // else default 0x0 unspecified
1099
1100 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1101
1102 auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
1103 if (sensorObject == sensorMap.end())
1104 {
1105 return IPMI_CC_RESPONSE_ERROR;
1106 }
1107
1108 auto maxObject = sensorObject->second.find("MaxValue");
1109 auto minObject = sensorObject->second.find("MinValue");
1110 double max = 128;
1111 double min = -127;
1112 if (maxObject != sensorObject->second.end())
1113 {
James Feist14fde842018-12-06 10:19:40 -08001114 max = variant_ns::visit(VariantToDoubleVisitor(), maxObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001115 }
1116
1117 if (minObject != sensorObject->second.end())
1118 {
James Feist14fde842018-12-06 10:19:40 -08001119 min = variant_ns::visit(VariantToDoubleVisitor(), minObject->second);
Jason M. Bills3f7c5e42018-10-03 14:00:41 -07001120 }
1121
1122 int16_t mValue;
1123 int8_t rExp;
1124 int16_t bValue;
1125 int8_t bExp;
1126 bool bSigned;
1127
1128 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1129 {
1130 return IPMI_CC_RESPONSE_ERROR;
1131 }
1132
1133 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1134 record.body.m_lsb = mValue & 0xFF;
1135
1136 // move the smallest bit of the MSB into place (bit 9)
1137 // the MSbs are bits 7:8 in m_msb_and_tolerance
1138 uint8_t mMsb = (mValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1139
1140 // assign the negative
1141 if (mValue < 0)
1142 {
1143 mMsb |= (1 << 7);
1144 }
1145 record.body.m_msb_and_tolerance = mMsb;
1146
1147 record.body.b_lsb = bValue & 0xFF;
1148
1149 // move the smallest bit of the MSB into place
1150 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1151 uint8_t bMsb = (bValue & (1 << 8)) > 0 ? (1 << 6) : 0;
1152
1153 // assign the negative
1154 if (bValue < 0)
1155 {
1156 bMsb |= (1 << 7);
1157 }
1158 record.body.b_msb_and_accuracy_lsb = bMsb;
1159
1160 record.body.r_b_exponents = bExp & 0x7;
1161 if (bExp < 0)
1162 {
1163 record.body.r_b_exponents |= 1 << 3;
1164 }
1165 record.body.r_b_exponents = (rExp & 0x7) << 4;
1166 if (rExp < 0)
1167 {
1168 record.body.r_b_exponents |= 1 << 7;
1169 }
1170
1171 // todo fill out rest of units
1172 if (bSigned)
1173 {
1174 record.body.sensor_units_1 = 1 << 7;
1175 }
1176
1177 // populate sensor name from path
1178 std::string name;
1179 size_t nameStart = path.rfind("/");
1180 if (nameStart != std::string::npos)
1181 {
1182 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1183 }
1184
1185 std::replace(name.begin(), name.end(), '_', ' ');
1186 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1187 {
1188 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1189 }
1190 record.body.id_string_info = name.size();
1191 std::strncpy(record.body.id_string, name.c_str(),
1192 sizeof(record.body.id_string));
1193
1194 if (sizeof(get_sdr::SensorDataFullRecord) <
1195 (req->offset + req->bytesToRead))
1196 {
1197 req->bytesToRead = sizeof(get_sdr::SensorDataFullRecord) - req->offset;
1198 }
1199
1200 *dataLen =
1201 2 + req->bytesToRead; // bytesToRead + MSB and LSB of next record id
1202
1203 std::memcpy(&resp->record_data, (char *)&record + req->offset,
1204 req->bytesToRead);
1205
1206 return IPMI_CC_OK;
1207}
1208/* end storage commands */
1209
1210void registerSensorFunctions()
1211{
1212 // get firmware version information
1213 ipmiPrintAndRegister(NETFUN_SENSOR, IPMI_CMD_WILDCARD, nullptr,
1214 ipmiSensorWildcardHandler, PRIVILEGE_USER);
1215
1216 // <Get Sensor Type>
1217 ipmiPrintAndRegister(
1218 NETFUN_SENSOR,
1219 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorType),
1220 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_USER);
1221
1222 // <Set Sensor Reading and Event Status>
1223 ipmiPrintAndRegister(
1224 NETFUN_SENSOR,
1225 static_cast<ipmi_cmd_t>(
1226 IPMINetfnSensorCmds::ipmiCmdSetSensorReadingAndEventStatus),
1227 nullptr, ipmiSensorWildcardHandler, PRIVILEGE_OPERATOR);
1228
1229 // <Get Sensor Reading>
1230 ipmiPrintAndRegister(
1231 NETFUN_SENSOR,
1232 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorReading),
1233 nullptr, ipmiSenGetSensorReading, PRIVILEGE_USER);
1234
1235 // <Get Sensor Threshold>
1236 ipmiPrintAndRegister(
1237 NETFUN_SENSOR,
1238 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetSensorThreshold),
1239 nullptr, ipmiSenGetSensorThresholds, PRIVILEGE_USER);
1240
1241 ipmiPrintAndRegister(
1242 NETFUN_SENSOR,
1243 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdSetSensorThreshold),
1244 nullptr, ipmiSenSetSensorThresholds, PRIVILEGE_OPERATOR);
1245
1246 // <Get Sensor Event Enable>
1247 ipmiPrintAndRegister(NETFUN_SENSOR,
1248 static_cast<ipmi_cmd_t>(
1249 IPMINetfnSensorCmds::ipmiCmdGetSensorEventEnable),
1250 nullptr, ipmiSenGetSensorEventEnable, PRIVILEGE_USER);
1251
1252 // <Get Sensor Event Status>
1253 ipmiPrintAndRegister(NETFUN_SENSOR,
1254 static_cast<ipmi_cmd_t>(
1255 IPMINetfnSensorCmds::ipmiCmdGetSensorEventStatus),
1256 nullptr, ipmiSenGetSensorEventStatus, PRIVILEGE_USER);
1257
1258 // register all storage commands for both Sensor and Storage command
1259 // versions
1260
1261 // <Get SDR Repository Info>
1262 ipmiPrintAndRegister(
1263 NETFUN_STORAGE,
1264 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetRepositoryInfo),
1265 nullptr, ipmiStorageGetSDRRepositoryInfo, PRIVILEGE_USER);
1266
1267 // <Get SDR Allocation Info>
1268 ipmiPrintAndRegister(NETFUN_STORAGE,
1269 static_cast<ipmi_cmd_t>(
1270 IPMINetfnStorageCmds::ipmiCmdGetSDRAllocationInfo),
1271 nullptr, ipmiStorageGetSDRAllocationInfo,
1272 PRIVILEGE_USER);
1273
1274 // <Reserve SDR Repo>
1275 ipmiPrintAndRegister(NETFUN_SENSOR,
1276 static_cast<ipmi_cmd_t>(
1277 IPMINetfnSensorCmds::ipmiCmdReserveDeviceSDRRepo),
1278 nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
1279
1280 ipmiPrintAndRegister(
1281 NETFUN_STORAGE,
1282 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdReserveSDR),
1283 nullptr, ipmiStorageReserveSDR, PRIVILEGE_USER);
1284
1285 // <Get Sdr>
1286 ipmiPrintAndRegister(
1287 NETFUN_SENSOR,
1288 static_cast<ipmi_cmd_t>(IPMINetfnSensorCmds::ipmiCmdGetDeviceSDR),
1289 nullptr, ipmiStorageGetSDR, PRIVILEGE_USER);
1290
1291 ipmiPrintAndRegister(
1292 NETFUN_STORAGE,
1293 static_cast<ipmi_cmd_t>(IPMINetfnStorageCmds::ipmiCmdGetSDR), nullptr,
1294 ipmiStorageGetSDR, PRIVILEGE_USER);
1295 return;
1296}
1297} // namespace ipmi