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