blob: a3b838f1577141824b6f2434431a7eaf8bfa330f [file] [log] [blame]
Willy Tude54f482021-01-26 15:59:09 -08001/*
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
17#include "dbus-sdr/sensorcommands.hpp"
18
19#include "dbus-sdr/sdrutils.hpp"
20#include "dbus-sdr/sensorutils.hpp"
21#include "dbus-sdr/storagecommands.hpp"
22
23#include <algorithm>
24#include <array>
25#include <boost/algorithm/string.hpp>
26#include <boost/container/flat_map.hpp>
27#include <chrono>
28#include <cmath>
29#include <cstring>
30#include <iostream>
31#include <ipmid/api.hpp>
32#include <ipmid/types.hpp>
33#include <ipmid/utils.hpp>
34#include <map>
35#include <memory>
36#include <optional>
37#include <phosphor-logging/log.hpp>
38#include <sdbusplus/bus.hpp>
39#include <stdexcept>
40#include <string>
41#include <utility>
42#include <variant>
43
44namespace ipmi
45{
Willy Tude54f482021-01-26 15:59:09 -080046static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu9ab2f942020-07-15 17:56:21 -070047static constexpr int sensorMapSdrUpdatePeriod = 60;
Willy Tude54f482021-01-26 15:59:09 -080048
49constexpr size_t maxSDRTotalSize =
50 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
51constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
52
53static uint16_t sdrReservationID;
54static uint32_t sdrLastAdd = noTimestamp;
55static uint32_t sdrLastRemove = noTimestamp;
56static constexpr size_t lastRecordIndex = 0xFFFF;
57static constexpr int GENERAL_ERROR = -1;
58
Willy Tude54f482021-01-26 15:59:09 -080059static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
60
61// Specify the comparison required to sort and find char* map objects
62struct CmpStr
63{
64 bool operator()(const char* a, const char* b) const
65 {
66 return std::strcmp(a, b) < 0;
67 }
68};
69const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
70 sensorUnits{{{"temperature", SensorUnits::degreesC},
71 {"voltage", SensorUnits::volts},
72 {"current", SensorUnits::amps},
73 {"fan_tach", SensorUnits::rpm},
74 {"power", SensorUnits::watts}}};
75
76void registerSensorFunctions() __attribute__((constructor));
77
78static sdbusplus::bus::match::match sensorAdded(
79 *getSdBus(),
80 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
81 "sensors/'",
82 [](sdbusplus::message::message& m) {
83 getSensorTree().clear();
84 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
85 std::chrono::system_clock::now().time_since_epoch())
86 .count();
87 });
88
89static sdbusplus::bus::match::match sensorRemoved(
90 *getSdBus(),
91 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
92 "sensors/'",
93 [](sdbusplus::message::message& m) {
94 getSensorTree().clear();
95 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
96 std::chrono::system_clock::now().time_since_epoch())
97 .count();
98 });
99
100// this keeps track of deassertions for sensor event status command. A
101// deasertion can only happen if an assertion was seen first.
102static boost::container::flat_map<
103 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
104 thresholdDeassertMap;
105
106static sdbusplus::bus::match::match thresholdChanged(
107 *getSdBus(),
108 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
109 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
110 [](sdbusplus::message::message& m) {
111 boost::container::flat_map<std::string, std::variant<bool, double>>
112 values;
113 m.read(std::string(), values);
114
115 auto findAssert =
116 std::find_if(values.begin(), values.end(), [](const auto& pair) {
117 return pair.first.find("Alarm") != std::string::npos;
118 });
119 if (findAssert != values.end())
120 {
121 auto ptr = std::get_if<bool>(&(findAssert->second));
122 if (ptr == nullptr)
123 {
124 phosphor::logging::log<phosphor::logging::level::ERR>(
125 "thresholdChanged: Assert non bool");
126 return;
127 }
128 if (*ptr)
129 {
130 phosphor::logging::log<phosphor::logging::level::INFO>(
131 "thresholdChanged: Assert",
132 phosphor::logging::entry("SENSOR=%s", m.get_path()));
133 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
134 }
135 else
136 {
137 auto& value =
138 thresholdDeassertMap[m.get_path()][findAssert->first];
139 if (value)
140 {
141 phosphor::logging::log<phosphor::logging::level::INFO>(
142 "thresholdChanged: deassert",
143 phosphor::logging::entry("SENSOR=%s", m.get_path()));
144 value = *ptr;
145 }
146 }
147 }
148 });
149
Hao Jiangd2afd052020-12-10 15:09:32 -0800150namespace sensor
151{
152static constexpr const char* vrInterface =
153 "xyz.openbmc_project.Control.VoltageRegulatorMode";
154static constexpr const char* sensorInterface =
155 "xyz.openbmc_project.Sensor.Value";
156} // namespace sensor
157
Willy Tude54f482021-01-26 15:59:09 -0800158static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
159 double& min)
160{
161 max = 127;
162 min = -128;
163
Hao Jiangd2afd052020-12-10 15:09:32 -0800164 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800165 auto critical =
166 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
167 auto warning =
168 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
169
170 if (sensorObject != sensorMap.end())
171 {
172 auto maxMap = sensorObject->second.find("MaxValue");
173 auto minMap = sensorObject->second.find("MinValue");
174
175 if (maxMap != sensorObject->second.end())
176 {
177 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
178 }
179 if (minMap != sensorObject->second.end())
180 {
181 min = std::visit(VariantToDoubleVisitor(), minMap->second);
182 }
183 }
184 if (critical != sensorMap.end())
185 {
186 auto lower = critical->second.find("CriticalLow");
187 auto upper = critical->second.find("CriticalHigh");
188 if (lower != critical->second.end())
189 {
190 double value = std::visit(VariantToDoubleVisitor(), lower->second);
191 min = std::min(value, min);
192 }
193 if (upper != critical->second.end())
194 {
195 double value = std::visit(VariantToDoubleVisitor(), upper->second);
196 max = std::max(value, max);
197 }
198 }
199 if (warning != sensorMap.end())
200 {
201
202 auto lower = warning->second.find("WarningLow");
203 auto upper = warning->second.find("WarningHigh");
204 if (lower != warning->second.end())
205 {
206 double value = std::visit(VariantToDoubleVisitor(), lower->second);
207 min = std::min(value, min);
208 }
209 if (upper != warning->second.end())
210 {
211 double value = std::visit(VariantToDoubleVisitor(), upper->second);
212 max = std::max(value, max);
213 }
214 }
215}
216
217static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700218 std::string sensorPath, DbusInterfaceMap& sensorMap,
219 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800220{
221 static boost::container::flat_map<
222 std::string, std::chrono::time_point<std::chrono::steady_clock>>
223 updateTimeMap;
224
225 auto updateFind = updateTimeMap.find(sensorConnection);
226 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
227 if (updateFind != updateTimeMap.end())
228 {
229 lastUpdate = updateFind->second;
230 }
231
232 auto now = std::chrono::steady_clock::now();
233
234 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700235 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800236 {
Willy Tude54f482021-01-26 15:59:09 -0800237 ObjectValueTree managedObjects;
238 boost::system::error_code ec = getManagedObjects(
239 ctx, sensorConnection.c_str(), "/", managedObjects);
240 if (ec)
241 {
242 phosphor::logging::log<phosphor::logging::level::ERR>(
243 "GetMangagedObjects for getSensorMap failed",
244 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
245
246 return false;
247 }
248
249 SensorCache[sensorConnection] = managedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700250 // Update time after finish building the map which allow the
251 // data to be cached for updatePeriod plus the build time.
252 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800253 }
254 auto connection = SensorCache.find(sensorConnection);
255 if (connection == SensorCache.end())
256 {
257 return false;
258 }
259 auto path = connection->second.find(sensorPath);
260 if (path == connection->second.end())
261 {
262 return false;
263 }
264 sensorMap = path->second;
265
266 return true;
267}
268
Hao Jiangd2afd052020-12-10 15:09:32 -0800269namespace sensor
270{
271// Calculate VR Mode from input IPMI discrete event bytes
272static std::optional<std::string>
273 calculateVRMode(uint15_t assertOffset,
274 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
275{
276 // get VR mode profiles from Supported Interface
277 auto supportedProperty = VRObject.find("Supported");
278 if (supportedProperty == VRObject.end() ||
279 VRObject.find("Selected") == VRObject.end())
280 {
281 phosphor::logging::log<phosphor::logging::level::ERR>(
282 "Missing the required Supported and Selected properties");
283 return std::nullopt;
284 }
285
286 const auto profilesPtr =
287 std::get_if<std::vector<std::string>>(&supportedProperty->second);
288
289 if (profilesPtr == nullptr)
290 {
291 phosphor::logging::log<phosphor::logging::level::ERR>(
292 "property is not array of string");
293 return std::nullopt;
294 }
295
296 // interpret IPMI cmd bits into profiles' index
297 long unsigned int index = 0;
298 // only one bit should be set and the highest bit should not be used.
299 if (assertOffset == 0 || assertOffset == (1u << 15) ||
300 (assertOffset & (assertOffset - 1)))
301 {
302 phosphor::logging::log<phosphor::logging::level::ERR>(
303 "IPMI cmd format incorrect",
304
305 phosphor::logging::entry("BYTES=%#02x",
306 static_cast<uint16_t>(assertOffset)));
307 return std::nullopt;
308 }
309
310 while (assertOffset != 1)
311 {
312 assertOffset >>= 1;
313 index++;
314 }
315
316 if (index >= profilesPtr->size())
317 {
318 phosphor::logging::log<phosphor::logging::level::ERR>(
319 "profile index out of boundary");
320 return std::nullopt;
321 }
322
323 return profilesPtr->at(index);
324}
325
326// Calculate sensor value from IPMI reading byte
327static std::optional<double>
328 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
329 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
330{
331 if (valueObject.find("Value") == valueObject.end())
332 {
333 phosphor::logging::log<phosphor::logging::level::ERR>(
334 "Missing the required Value property");
335 return std::nullopt;
336 }
337
338 double max = 0;
339 double min = 0;
340 getSensorMaxMin(sensorMap, max, min);
341
342 int16_t mValue = 0;
343 int16_t bValue = 0;
344 int8_t rExp = 0;
345 int8_t bExp = 0;
346 bool bSigned = false;
347
348 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
349 {
350 return std::nullopt;
351 }
352
353 double value = bSigned ? ((int8_t)reading) : reading;
354
355 value *= ((double)mValue);
356 value += ((double)bValue) * std::pow(10.0, bExp);
357 value *= std::pow(10.0, rExp);
358
359 return value;
360}
361
362} // namespace sensor
363
Willy Tude54f482021-01-26 15:59:09 -0800364ipmi::RspType<> ipmiSenPlatformEvent(uint8_t generatorID, uint8_t evmRev,
365 uint8_t sensorType, uint8_t sensorNum,
366 uint8_t eventType, uint8_t eventData1,
367 std::optional<uint8_t> eventData2,
368 std::optional<uint8_t> eventData3)
369{
370 return ipmi::responseSuccess();
371}
372
Willy Tudbafbce2021-03-29 00:37:05 -0700373ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
374 uint8_t sensorNumber, uint8_t operation,
375 uint8_t reading, uint15_t assertOffset,
376 bool resvd1, uint15_t deassertOffset,
377 bool resvd2, uint8_t eventData1,
378 uint8_t eventData2, uint8_t eventData3)
379{
380 std::string connection;
381 std::string path;
382 ipmi::Cc status = getSensorConnection(ctx, sensorNumber, connection, path);
383 if (status)
384 {
385 return ipmi::response(status);
386 }
387
388 DbusInterfaceMap sensorMap;
389 if (!getSensorMap(ctx, connection, path, sensorMap))
390 {
391 return ipmi::responseResponseError();
392 }
Willy Tudbafbce2021-03-29 00:37:05 -0700393
Hao Jiangd2afd052020-12-10 15:09:32 -0800394 // we can tell the sensor type by its interface type
395 auto sensorObject = sensorMap.find(sensor::sensorInterface);
396 if (sensorObject != sensorMap.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700397 {
Hao Jiangd2afd052020-12-10 15:09:32 -0800398 auto value =
399 sensor::calculateValue(reading, sensorMap, sensorObject->second);
400 if (!value)
401 {
402 return ipmi::responseResponseError();
403 }
404
405 if constexpr (debug)
406 {
407 phosphor::logging::log<phosphor::logging::level::INFO>(
408 "IPMI SET_SENSOR",
409 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber),
410 phosphor::logging::entry("BYTE=%u", (unsigned int)reading),
411 phosphor::logging::entry("VALUE=%f", *value));
412 }
413
414 boost::system::error_code ec =
415 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
416 "Value", ipmi::Value(*value));
417
418 // setDbusProperty intended to resolve dbus exception/rc within the
419 // function but failed to achieve that. Catch SdBusError in the ipmi
420 // callback functions for now (e.g. ipmiSetSensorReading).
421 if (ec)
422 {
423 using namespace phosphor::logging;
424 log<level::ERR>("Failed to set property",
425 entry("PROPERTY=%s", "Value"),
426 entry("PATH=%s", path.c_str()),
427 entry("INTERFACE=%s", sensor::sensorInterface),
428 entry("WHAT=%s", ec.message().c_str()));
429 return ipmi::responseResponseError();
430 }
431 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700432 }
433
Hao Jiangd2afd052020-12-10 15:09:32 -0800434 sensorObject = sensorMap.find(sensor::vrInterface);
435 if (sensorObject != sensorMap.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700436 {
Hao Jiangd2afd052020-12-10 15:09:32 -0800437 // VR sensors are treated as a special case and we will not check the
438 // write permission for VR sensors, since they always deemed writable
439 // and permission table are not applied to VR sensors.
440 auto vrMode =
441 sensor::calculateVRMode(assertOffset, sensorObject->second);
442 if (!vrMode)
443 {
444 return ipmi::responseResponseError();
445 }
446 boost::system::error_code ec = setDbusProperty(
447 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
448 // setDbusProperty intended to resolve dbus exception/rc within the
449 // function but failed to achieve that. Catch SdBusError in the ipmi
450 // callback functions for now (e.g. ipmiSetSensorReading).
451 if (ec)
452 {
453 using namespace phosphor::logging;
454 log<level::ERR>("Failed to set property",
455 entry("PROPERTY=%s", "Selected"),
456 entry("PATH=%s", path.c_str()),
457 entry("INTERFACE=%s", sensor::sensorInterface),
458 entry("WHAT=%s", ec.message().c_str()));
459 return ipmi::responseResponseError();
460 }
461 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700462 }
463
Hao Jiangd2afd052020-12-10 15:09:32 -0800464 phosphor::logging::log<phosphor::logging::level::ERR>(
465 "unknown sensor type",
466 phosphor::logging::entry("PATH=%s", path.c_str()));
467 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700468}
469
Willy Tude54f482021-01-26 15:59:09 -0800470ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
471 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
472{
473 std::string connection;
474 std::string path;
475
476 auto status = getSensorConnection(ctx, sensnum, connection, path);
477 if (status)
478 {
479 return ipmi::response(status);
480 }
481
482 DbusInterfaceMap sensorMap;
483 if (!getSensorMap(ctx, connection, path, sensorMap))
484 {
485 return ipmi::responseResponseError();
486 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800487 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800488
489 if (sensorObject == sensorMap.end() ||
490 sensorObject->second.find("Value") == sensorObject->second.end())
491 {
492 return ipmi::responseResponseError();
493 }
494 auto& valueVariant = sensorObject->second["Value"];
495 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
496
497 double max = 0;
498 double min = 0;
499 getSensorMaxMin(sensorMap, max, min);
500
501 int16_t mValue = 0;
502 int16_t bValue = 0;
503 int8_t rExp = 0;
504 int8_t bExp = 0;
505 bool bSigned = false;
506
507 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
508 {
509 return ipmi::responseResponseError();
510 }
511
512 uint8_t value =
513 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
514 uint8_t operation =
515 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
516 operation |=
517 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
518 bool notReading = std::isnan(reading);
519
520 if (!notReading)
521 {
522 auto availableObject =
523 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
524 if (availableObject != sensorMap.end())
525 {
526 auto findAvailable = availableObject->second.find("Available");
527 if (findAvailable != availableObject->second.end())
528 {
529 bool* available = std::get_if<bool>(&(findAvailable->second));
530 if (available && !(*available))
531 {
532 notReading = true;
533 }
534 }
535 }
536 }
537
538 if (notReading)
539 {
540 operation |= static_cast<uint8_t>(
541 IPMISensorReadingByte2::readingStateUnavailable);
542 }
543
Josh Lehana55c9532020-10-28 21:59:06 -0700544 if constexpr (details::enableInstrumentation)
545 {
546 int byteValue;
547 if (bSigned)
548 {
549 byteValue = static_cast<int>(static_cast<int8_t>(value));
550 }
551 else
552 {
553 byteValue = static_cast<int>(static_cast<uint8_t>(value));
554 }
555
556 // Keep stats on the reading just obtained, even if it is "NaN"
557 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
558 {
559 // This is the first reading, show the coefficients
560 double step = (max - min) / 255.0;
561 std::cerr << "IPMI sensor "
562 << details::sdrStatsTable.getName(sensnum)
563 << ": Range min=" << min << " max=" << max
564 << ", step=" << step
565 << ", Coefficients mValue=" << static_cast<int>(mValue)
566 << " rExp=" << static_cast<int>(rExp)
567 << " bValue=" << static_cast<int>(bValue)
568 << " bExp=" << static_cast<int>(bExp)
569 << " bSigned=" << static_cast<int>(bSigned) << "\n";
570 }
571 }
572
Willy Tude54f482021-01-26 15:59:09 -0800573 uint8_t thresholds = 0;
574
575 auto warningObject =
576 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
577 if (warningObject != sensorMap.end())
578 {
579 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
580 auto alarmLow = warningObject->second.find("WarningAlarmLow");
581 if (alarmHigh != warningObject->second.end())
582 {
583 if (std::get<bool>(alarmHigh->second))
584 {
585 thresholds |= static_cast<uint8_t>(
586 IPMISensorReadingByte3::upperNonCritical);
587 }
588 }
589 if (alarmLow != warningObject->second.end())
590 {
591 if (std::get<bool>(alarmLow->second))
592 {
593 thresholds |= static_cast<uint8_t>(
594 IPMISensorReadingByte3::lowerNonCritical);
595 }
596 }
597 }
598
599 auto criticalObject =
600 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
601 if (criticalObject != sensorMap.end())
602 {
603 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
604 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
605 if (alarmHigh != criticalObject->second.end())
606 {
607 if (std::get<bool>(alarmHigh->second))
608 {
609 thresholds |=
610 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
611 }
612 }
613 if (alarmLow != criticalObject->second.end())
614 {
615 if (std::get<bool>(alarmLow->second))
616 {
617 thresholds |=
618 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
619 }
620 }
621 }
622
623 // no discrete as of today so optional byte is never returned
624 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
625}
626
627/** @brief implements the Set Sensor threshold command
628 * @param sensorNumber - sensor number
629 * @param lowerNonCriticalThreshMask
630 * @param lowerCriticalThreshMask
631 * @param lowerNonRecovThreshMask
632 * @param upperNonCriticalThreshMask
633 * @param upperCriticalThreshMask
634 * @param upperNonRecovThreshMask
635 * @param reserved
636 * @param lowerNonCritical - lower non-critical threshold
637 * @param lowerCritical - Lower critical threshold
638 * @param lowerNonRecoverable - Lower non recovarable threshold
639 * @param upperNonCritical - Upper non-critical threshold
640 * @param upperCritical - Upper critical
641 * @param upperNonRecoverable - Upper Non-recoverable
642 *
643 * @returns IPMI completion code
644 */
645ipmi::RspType<> ipmiSenSetSensorThresholds(
646 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
647 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
648 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
649 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
650 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
651 uint8_t upperNonCritical, uint8_t upperCritical,
652 uint8_t upperNonRecoverable)
653{
654 if (reserved)
655 {
656 return ipmi::responseInvalidFieldRequest();
657 }
658
659 // lower nc and upper nc not suppported on any sensor
660 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
661 {
662 return ipmi::responseInvalidFieldRequest();
663 }
664
665 // if none of the threshold mask are set, nothing to do
666 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
667 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
668 upperCriticalThreshMask | upperNonRecovThreshMask))
669 {
670 return ipmi::responseSuccess();
671 }
672
673 std::string connection;
674 std::string path;
675
676 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
677 if (status)
678 {
679 return ipmi::response(status);
680 }
681 DbusInterfaceMap sensorMap;
682 if (!getSensorMap(ctx, connection, path, sensorMap))
683 {
684 return ipmi::responseResponseError();
685 }
686
687 double max = 0;
688 double min = 0;
689 getSensorMaxMin(sensorMap, max, min);
690
691 int16_t mValue = 0;
692 int16_t bValue = 0;
693 int8_t rExp = 0;
694 int8_t bExp = 0;
695 bool bSigned = false;
696
697 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
698 {
699 return ipmi::responseResponseError();
700 }
701
702 // store a vector of property name, value to set, and interface
703 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
704
705 // define the indexes of the tuple
706 constexpr uint8_t propertyName = 0;
707 constexpr uint8_t thresholdValue = 1;
708 constexpr uint8_t interface = 2;
709 // verifiy all needed fields are present
710 if (lowerCriticalThreshMask || upperCriticalThreshMask)
711 {
712 auto findThreshold =
713 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
714 if (findThreshold == sensorMap.end())
715 {
716 return ipmi::responseInvalidFieldRequest();
717 }
718 if (lowerCriticalThreshMask)
719 {
720 auto findLower = findThreshold->second.find("CriticalLow");
721 if (findLower == findThreshold->second.end())
722 {
723 return ipmi::responseInvalidFieldRequest();
724 }
725 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
726 findThreshold->first);
727 }
728 if (upperCriticalThreshMask)
729 {
730 auto findUpper = findThreshold->second.find("CriticalHigh");
731 if (findUpper == findThreshold->second.end())
732 {
733 return ipmi::responseInvalidFieldRequest();
734 }
735 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
736 findThreshold->first);
737 }
738 }
739 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
740 {
741 auto findThreshold =
742 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
743 if (findThreshold == sensorMap.end())
744 {
745 return ipmi::responseInvalidFieldRequest();
746 }
747 if (lowerNonCriticalThreshMask)
748 {
749 auto findLower = findThreshold->second.find("WarningLow");
750 if (findLower == findThreshold->second.end())
751 {
752 return ipmi::responseInvalidFieldRequest();
753 }
754 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
755 findThreshold->first);
756 }
757 if (upperNonCriticalThreshMask)
758 {
759 auto findUpper = findThreshold->second.find("WarningHigh");
760 if (findUpper == findThreshold->second.end())
761 {
762 return ipmi::responseInvalidFieldRequest();
763 }
764 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
765 findThreshold->first);
766 }
767 }
768 for (const auto& property : thresholdsToSet)
769 {
770 // from section 36.3 in the IPMI Spec, assume all linear
771 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
772 (bValue * std::pow(10.0, bExp))) *
773 std::pow(10.0, rExp);
774 setDbusProperty(
775 *getSdBus(), connection, path, std::get<interface>(property),
776 std::get<propertyName>(property), ipmi::Value(valueToSet));
777 }
778 return ipmi::responseSuccess();
779}
780
781IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
782{
783 IPMIThresholds resp;
784 auto warningInterface =
785 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
786 auto criticalInterface =
787 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
788
789 if ((warningInterface != sensorMap.end()) ||
790 (criticalInterface != sensorMap.end()))
791 {
Hao Jiangd2afd052020-12-10 15:09:32 -0800792 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800793
794 if (sensorPair == sensorMap.end())
795 {
796 // should not have been able to find a sensor not implementing
797 // the sensor object
798 throw std::runtime_error("Invalid sensor map");
799 }
800
801 double max = 0;
802 double min = 0;
803 getSensorMaxMin(sensorMap, max, min);
804
805 int16_t mValue = 0;
806 int16_t bValue = 0;
807 int8_t rExp = 0;
808 int8_t bExp = 0;
809 bool bSigned = false;
810
811 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
812 {
813 throw std::runtime_error("Invalid sensor atrributes");
814 }
815 if (warningInterface != sensorMap.end())
816 {
817 auto& warningMap = warningInterface->second;
818
819 auto warningHigh = warningMap.find("WarningHigh");
820 auto warningLow = warningMap.find("WarningLow");
821
822 if (warningHigh != warningMap.end())
823 {
824
825 double value =
826 std::visit(VariantToDoubleVisitor(), warningHigh->second);
827 resp.warningHigh = scaleIPMIValueFromDouble(
828 value, mValue, rExp, bValue, bExp, bSigned);
829 }
830 if (warningLow != warningMap.end())
831 {
832 double value =
833 std::visit(VariantToDoubleVisitor(), warningLow->second);
834 resp.warningLow = scaleIPMIValueFromDouble(
835 value, mValue, rExp, bValue, bExp, bSigned);
836 }
837 }
838 if (criticalInterface != sensorMap.end())
839 {
840 auto& criticalMap = criticalInterface->second;
841
842 auto criticalHigh = criticalMap.find("CriticalHigh");
843 auto criticalLow = criticalMap.find("CriticalLow");
844
845 if (criticalHigh != criticalMap.end())
846 {
847 double value =
848 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
849 resp.criticalHigh = scaleIPMIValueFromDouble(
850 value, mValue, rExp, bValue, bExp, bSigned);
851 }
852 if (criticalLow != criticalMap.end())
853 {
854 double value =
855 std::visit(VariantToDoubleVisitor(), criticalLow->second);
856 resp.criticalLow = scaleIPMIValueFromDouble(
857 value, mValue, rExp, bValue, bExp, bSigned);
858 }
859 }
860 }
861 return resp;
862}
863
864ipmi::RspType<uint8_t, // readable
865 uint8_t, // lowerNCrit
866 uint8_t, // lowerCrit
867 uint8_t, // lowerNrecoverable
868 uint8_t, // upperNC
869 uint8_t, // upperCrit
870 uint8_t> // upperNRecoverable
871 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
872{
873 std::string connection;
874 std::string path;
875
876 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
877 if (status)
878 {
879 return ipmi::response(status);
880 }
881
882 DbusInterfaceMap sensorMap;
883 if (!getSensorMap(ctx, connection, path, sensorMap))
884 {
885 return ipmi::responseResponseError();
886 }
887
888 IPMIThresholds thresholdData;
889 try
890 {
891 thresholdData = getIPMIThresholds(sensorMap);
892 }
893 catch (std::exception&)
894 {
895 return ipmi::responseResponseError();
896 }
897
898 uint8_t readable = 0;
899 uint8_t lowerNC = 0;
900 uint8_t lowerCritical = 0;
901 uint8_t lowerNonRecoverable = 0;
902 uint8_t upperNC = 0;
903 uint8_t upperCritical = 0;
904 uint8_t upperNonRecoverable = 0;
905
906 if (thresholdData.warningHigh)
907 {
908 readable |=
909 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
910 upperNC = *thresholdData.warningHigh;
911 }
912 if (thresholdData.warningLow)
913 {
914 readable |=
915 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
916 lowerNC = *thresholdData.warningLow;
917 }
918
919 if (thresholdData.criticalHigh)
920 {
921 readable |=
922 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
923 upperCritical = *thresholdData.criticalHigh;
924 }
925 if (thresholdData.criticalLow)
926 {
927 readable |=
928 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
929 lowerCritical = *thresholdData.criticalLow;
930 }
931
932 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
933 lowerNonRecoverable, upperNC, upperCritical,
934 upperNonRecoverable);
935}
936
937/** @brief implements the get Sensor event enable command
938 * @param sensorNumber - sensor number
939 *
940 * @returns IPMI completion code plus response data
941 * - enabled - Sensor Event messages
942 * - assertionEnabledLsb - Assertion event messages
943 * - assertionEnabledMsb - Assertion event messages
944 * - deassertionEnabledLsb - Deassertion event messages
945 * - deassertionEnabledMsb - Deassertion event messages
946 */
947
948ipmi::RspType<uint8_t, // enabled
949 uint8_t, // assertionEnabledLsb
950 uint8_t, // assertionEnabledMsb
951 uint8_t, // deassertionEnabledLsb
952 uint8_t> // deassertionEnabledMsb
953 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
954{
955 std::string connection;
956 std::string path;
957
958 uint8_t enabled = 0;
959 uint8_t assertionEnabledLsb = 0;
960 uint8_t assertionEnabledMsb = 0;
961 uint8_t deassertionEnabledLsb = 0;
962 uint8_t deassertionEnabledMsb = 0;
963
964 auto status = getSensorConnection(ctx, sensorNum, connection, path);
965 if (status)
966 {
967 return ipmi::response(status);
968 }
969
970 DbusInterfaceMap sensorMap;
971 if (!getSensorMap(ctx, connection, path, sensorMap))
972 {
973 return ipmi::responseResponseError();
974 }
975
976 auto warningInterface =
977 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
978 auto criticalInterface =
979 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
980 if ((warningInterface != sensorMap.end()) ||
981 (criticalInterface != sensorMap.end()))
982 {
983 enabled = static_cast<uint8_t>(
984 IPMISensorEventEnableByte2::sensorScanningEnable);
985 if (warningInterface != sensorMap.end())
986 {
987 auto& warningMap = warningInterface->second;
988
989 auto warningHigh = warningMap.find("WarningHigh");
990 auto warningLow = warningMap.find("WarningLow");
991 if (warningHigh != warningMap.end())
992 {
993 assertionEnabledLsb |= static_cast<uint8_t>(
994 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
995 deassertionEnabledLsb |= static_cast<uint8_t>(
996 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
997 }
998 if (warningLow != warningMap.end())
999 {
1000 assertionEnabledLsb |= static_cast<uint8_t>(
1001 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1002 deassertionEnabledLsb |= static_cast<uint8_t>(
1003 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
1004 }
1005 }
1006 if (criticalInterface != sensorMap.end())
1007 {
1008 auto& criticalMap = criticalInterface->second;
1009
1010 auto criticalHigh = criticalMap.find("CriticalHigh");
1011 auto criticalLow = criticalMap.find("CriticalLow");
1012
1013 if (criticalHigh != criticalMap.end())
1014 {
1015 assertionEnabledMsb |= static_cast<uint8_t>(
1016 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1017 deassertionEnabledMsb |= static_cast<uint8_t>(
1018 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1019 }
1020 if (criticalLow != criticalMap.end())
1021 {
1022 assertionEnabledLsb |= static_cast<uint8_t>(
1023 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1024 deassertionEnabledLsb |= static_cast<uint8_t>(
1025 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1026 }
1027 }
1028 }
1029
1030 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1031 assertionEnabledMsb, deassertionEnabledLsb,
1032 deassertionEnabledMsb);
1033}
1034
1035/** @brief implements the get Sensor event status command
1036 * @param sensorNumber - sensor number, FFh = reserved
1037 *
1038 * @returns IPMI completion code plus response data
1039 * - sensorEventStatus - Sensor Event messages state
1040 * - assertions - Assertion event messages
1041 * - deassertions - Deassertion event messages
1042 */
1043ipmi::RspType<uint8_t, // sensorEventStatus
1044 std::bitset<16>, // assertions
1045 std::bitset<16> // deassertion
1046 >
1047 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1048{
1049 if (sensorNum == reservedSensorNumber)
1050 {
1051 return ipmi::responseInvalidFieldRequest();
1052 }
1053
1054 std::string connection;
1055 std::string path;
1056 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1057 if (status)
1058 {
1059 phosphor::logging::log<phosphor::logging::level::ERR>(
1060 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1061 phosphor::logging::entry("SENSOR=%d", sensorNum));
1062 return ipmi::response(status);
1063 }
1064
1065 DbusInterfaceMap sensorMap;
1066 if (!getSensorMap(ctx, connection, path, sensorMap))
1067 {
1068 phosphor::logging::log<phosphor::logging::level::ERR>(
1069 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1070 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1071 return ipmi::responseResponseError();
1072 }
1073 auto warningInterface =
1074 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1075 auto criticalInterface =
1076 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1077
1078 uint8_t sensorEventStatus =
1079 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1080
1081 std::optional<bool> criticalDeassertHigh =
1082 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1083 std::optional<bool> criticalDeassertLow =
1084 thresholdDeassertMap[path]["CriticalAlarmLow"];
1085 std::optional<bool> warningDeassertHigh =
1086 thresholdDeassertMap[path]["WarningAlarmHigh"];
1087 std::optional<bool> warningDeassertLow =
1088 thresholdDeassertMap[path]["WarningAlarmLow"];
1089
1090 std::bitset<16> assertions = 0;
1091 std::bitset<16> deassertions = 0;
1092
1093 if (criticalDeassertHigh && !*criticalDeassertHigh)
1094 {
1095 deassertions.set(static_cast<size_t>(
1096 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1097 }
1098 if (criticalDeassertLow && !*criticalDeassertLow)
1099 {
1100 deassertions.set(static_cast<size_t>(
1101 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1102 }
1103 if (warningDeassertHigh && !*warningDeassertHigh)
1104 {
1105 deassertions.set(static_cast<size_t>(
1106 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1107 }
1108 if (warningDeassertLow && !*warningDeassertLow)
1109 {
1110 deassertions.set(static_cast<size_t>(
1111 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1112 }
1113 if ((warningInterface != sensorMap.end()) ||
1114 (criticalInterface != sensorMap.end()))
1115 {
1116 sensorEventStatus = static_cast<size_t>(
1117 IPMISensorEventEnableByte2::eventMessagesEnable);
1118 if (warningInterface != sensorMap.end())
1119 {
1120 auto& warningMap = warningInterface->second;
1121
1122 auto warningHigh = warningMap.find("WarningAlarmHigh");
1123 auto warningLow = warningMap.find("WarningAlarmLow");
1124 auto warningHighAlarm = false;
1125 auto warningLowAlarm = false;
1126
1127 if (warningHigh != warningMap.end())
1128 {
1129 warningHighAlarm = std::get<bool>(warningHigh->second);
1130 }
1131 if (warningLow != warningMap.end())
1132 {
1133 warningLowAlarm = std::get<bool>(warningLow->second);
1134 }
1135 if (warningHighAlarm)
1136 {
1137 assertions.set(
1138 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1139 upperNonCriticalGoingHigh));
1140 }
1141 if (warningLowAlarm)
1142 {
1143 assertions.set(
1144 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1145 lowerNonCriticalGoingLow));
1146 }
1147 }
1148 if (criticalInterface != sensorMap.end())
1149 {
1150 auto& criticalMap = criticalInterface->second;
1151
1152 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1153 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1154 auto criticalHighAlarm = false;
1155 auto criticalLowAlarm = false;
1156
1157 if (criticalHigh != criticalMap.end())
1158 {
1159 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1160 }
1161 if (criticalLow != criticalMap.end())
1162 {
1163 criticalLowAlarm = std::get<bool>(criticalLow->second);
1164 }
1165 if (criticalHighAlarm)
1166 {
1167 assertions.set(
1168 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1169 upperCriticalGoingHigh));
1170 }
1171 if (criticalLowAlarm)
1172 {
1173 assertions.set(static_cast<size_t>(
1174 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1175 }
1176 }
1177 }
1178
1179 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1180}
1181
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001182static int getSensorDataRecord(ipmi::Context::ptr ctx,
1183 std::vector<uint8_t>& recordData,
1184 uint16_t recordID)
Willy Tude54f482021-01-26 15:59:09 -08001185{
1186 auto& sensorTree = getSensorTree();
Willy Tude54f482021-01-26 15:59:09 -08001187 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08001188 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1189 if (ret != ipmi::ccSuccess)
1190 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001191 phosphor::logging::log<phosphor::logging::level::ERR>(
1192 "getSensorDataRecord: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08001193 return GENERAL_ERROR;
1194 }
1195
1196 size_t lastRecord =
1197 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001198 if (recordID == lastRecordIndex)
Willy Tude54f482021-01-26 15:59:09 -08001199 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001200 recordID = lastRecord;
1201 }
1202 if (recordID > lastRecord)
1203 {
1204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 "getSensorDataRecord: recordID > lastRecord error");
Willy Tude54f482021-01-26 15:59:09 -08001206 return GENERAL_ERROR;
1207 }
1208
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001209 if (recordID >= sensorTree.size())
Willy Tude54f482021-01-26 15:59:09 -08001210 {
1211 size_t fruIndex = recordID - sensorTree.size();
Willy Tude54f482021-01-26 15:59:09 -08001212 if (fruIndex >= fruCount)
1213 {
1214 // handle type 12 hardcoded records
1215 size_t type12Index = fruIndex - fruCount;
1216 if (type12Index >= ipmi::storage::type12Count)
1217 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "getSensorDataRecord: type12Index error");
Willy Tude54f482021-01-26 15:59:09 -08001220 return GENERAL_ERROR;
1221 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001222 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
Willy Tude54f482021-01-26 15:59:09 -08001223 }
1224 else
1225 {
1226 // handle fru records
1227 get_sdr::SensorDataFruRecord data;
1228 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1229 if (ret != IPMI_CC_OK)
1230 {
1231 return GENERAL_ERROR;
1232 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001233 data.header.record_id_msb = recordID >> 8;
1234 data.header.record_id_lsb = recordID & 0xFF;
1235 recordData.insert(recordData.end(),
1236 reinterpret_cast<uint8_t*>(&data),
1237 reinterpret_cast<uint8_t*>(&data) + sizeof(data));
Willy Tude54f482021-01-26 15:59:09 -08001238 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001239
1240 return 0;
1241 }
1242
1243 std::string connection;
1244 std::string path;
1245 auto status = getSensorConnection(ctx, recordID, connection, path);
1246 if (status)
1247 {
1248 phosphor::logging::log<phosphor::logging::level::ERR>(
1249 "getSensorDataRecord: getSensorConnection error");
1250 return GENERAL_ERROR;
1251 }
1252 DbusInterfaceMap sensorMap;
1253 if (!getSensorMap(ctx, connection, path, sensorMap, sensorMapUpdatePeriod))
1254 {
1255 phosphor::logging::log<phosphor::logging::level::ERR>(
1256 "getSensorDataRecord: getSensorMap error");
1257 return GENERAL_ERROR;
1258 }
1259 uint16_t sensorNum = getSensorNumberFromPath(path);
1260 if (sensorNum == invalidSensorNumber)
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "getSensorDataRecord: invalidSensorNumber");
1264 return GENERAL_ERROR;
1265 }
1266 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1267 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1268
1269 get_sdr::SensorDataFullRecord record = {0};
1270
1271 get_sdr::header::set_record_id(
1272 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1273
1274 record.header.sdr_version = ipmiSdrVersion;
1275 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1276 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1277 sizeof(get_sdr::SensorDataRecordHeader);
1278 record.key.owner_id = 0x20;
1279 record.key.owner_lun = lun;
1280 record.key.sensor_number = sensornumber;
1281
1282 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1283 record.body.sensor_type = getSensorTypeFromPath(path);
1284 std::string type = getSensorTypeStringFromPath(path);
1285 auto typeCstr = type.c_str();
1286 auto findUnits = sensorUnits.find(typeCstr);
1287 if (findUnits != sensorUnits.end())
1288 {
1289 record.body.sensor_units_2_base =
1290 static_cast<uint8_t>(findUnits->second);
1291 } // else default 0x0 unspecified
1292
1293 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1294
Hao Jiangd2afd052020-12-10 15:09:32 -08001295 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001296 if (sensorObject == sensorMap.end())
1297 {
1298 phosphor::logging::log<phosphor::logging::level::ERR>(
1299 "getSensorDataRecord: sensorObject error");
1300 return GENERAL_ERROR;
1301 }
1302
1303 uint8_t entityId = 0;
1304 uint8_t entityInstance = 0x01;
1305
1306 // follow the association chain to get the parent board's entityid and
1307 // entityInstance
1308 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1309
1310 record.body.entity_id = entityId;
1311 record.body.entity_instance = entityInstance;
1312
1313 auto maxObject = sensorObject->second.find("MaxValue");
1314 auto minObject = sensorObject->second.find("MinValue");
1315
1316 // If min and/or max are left unpopulated,
1317 // then default to what a signed byte would be, namely (-128,127) range.
1318 auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
1319 auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
1320 if (maxObject != sensorObject->second.end())
1321 {
1322 max = std::visit(VariantToDoubleVisitor(), maxObject->second);
1323 }
1324
1325 if (minObject != sensorObject->second.end())
1326 {
1327 min = std::visit(VariantToDoubleVisitor(), minObject->second);
1328 }
1329
1330 int16_t mValue = 0;
1331 int8_t rExp = 0;
1332 int16_t bValue = 0;
1333 int8_t bExp = 0;
1334 bool bSigned = false;
1335
1336 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1337 {
1338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "getSensorDataRecord: getSensorAttributes error");
1340 return GENERAL_ERROR;
1341 }
1342
1343 // The record.body is a struct SensorDataFullRecordBody
1344 // from sensorhandler.hpp in phosphor-ipmi-host.
1345 // The meaning of these bits appears to come from
1346 // table 43.1 of the IPMI spec.
1347 // The above 5 sensor attributes are stuffed in as follows:
1348 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1349 // Byte 22-24 are for other purposes
1350 // Byte 25 = MMMMMMMM = LSB of M
1351 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1352 // Byte 27 = BBBBBBBB = LSB of B
1353 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1354 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1355 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1356
1357 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1358 record.body.m_lsb = mValue & 0xFF;
1359
1360 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1361 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1362
1363 // move the smallest bit of the MSB into place (bit 9)
1364 // the MSbs are bits 7:8 in m_msb_and_tolerance
1365 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1366
1367 record.body.b_lsb = bValue & 0xFF;
1368
1369 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1370 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1371
1372 // move the smallest bit of the MSB into place (bit 9)
1373 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1374 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1375
1376 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1377 uint8_t rExpBits = rExp & 0x07;
1378
1379 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1380 uint8_t bExpBits = bExp & 0x07;
1381
1382 // move rExp and bExp into place
1383 record.body.r_b_exponents =
1384 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1385
1386 // Set the analog reading byte interpretation accordingly
1387 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1388
1389 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1390 // These seem redundant, but derivable from the above 5 attributes
1391 // Original comment said "todo fill out rest of units"
1392
1393 // populate sensor name from path
1394 std::string name;
1395 size_t nameStart = path.rfind("/");
1396 if (nameStart != std::string::npos)
1397 {
1398 name = path.substr(nameStart + 1, std::string::npos - nameStart);
1399 }
1400
1401 std::replace(name.begin(), name.end(), '_', ' ');
1402 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
1403 {
1404 // try to not truncate by replacing common words
1405 constexpr std::array<std::pair<const char*, const char*>, 2>
1406 replaceWords = {std::make_pair("Output", "Out"),
1407 std::make_pair("Input", "In")};
1408 for (const auto& [find, replace] : replaceWords)
1409 {
1410 boost::replace_all(name, find, replace);
1411 }
1412
1413 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
1414 }
1415 record.body.id_string_info = name.size();
1416 std::strncpy(record.body.id_string, name.c_str(),
1417 sizeof(record.body.id_string));
1418
Josh Lehana55c9532020-10-28 21:59:06 -07001419 // Remember the sensor name, as determined for this sensor number
1420 details::sdrStatsTable.updateName(sensornumber, name);
1421
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001422 IPMIThresholds thresholdData;
1423 try
1424 {
1425 thresholdData = getIPMIThresholds(sensorMap);
1426 }
1427 catch (std::exception&)
1428 {
1429 phosphor::logging::log<phosphor::logging::level::ERR>(
1430 "getSensorDataRecord: getIPMIThresholds error");
1431 return GENERAL_ERROR;
1432 }
1433
1434 if (thresholdData.criticalHigh)
1435 {
1436 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1437 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1438 IPMISensorEventEnableThresholds::criticalThreshold);
1439 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1440 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1441 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1442 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1443 record.body.discrete_reading_setting_mask[0] |=
1444 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1445 }
1446 if (thresholdData.warningHigh)
1447 {
1448 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1449 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1450 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1451 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1452 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1453 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1454 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1455 record.body.discrete_reading_setting_mask[0] |=
1456 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1457 }
1458 if (thresholdData.criticalLow)
1459 {
1460 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1461 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1462 IPMISensorEventEnableThresholds::criticalThreshold);
1463 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1464 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1465 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1466 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1467 record.body.discrete_reading_setting_mask[0] |=
1468 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1469 }
1470 if (thresholdData.warningLow)
1471 {
1472 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1473 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1474 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1475 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1476 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1477 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1478 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1479 record.body.discrete_reading_setting_mask[0] |=
1480 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1481 }
1482
1483 // everything that is readable is setable
1484 record.body.discrete_reading_setting_mask[1] =
1485 record.body.discrete_reading_setting_mask[0];
1486 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
1487 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Willy Tude54f482021-01-26 15:59:09 -08001488 return 0;
1489}
1490
1491/** @brief implements the get SDR Info command
1492 * @param count - Operation
1493 *
1494 * @returns IPMI completion code plus response data
1495 * - sdrCount - sensor/SDR count
1496 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1497 */
1498static ipmi::RspType<uint8_t, // respcount
1499 uint8_t, // dynamic population flags
1500 uint32_t // last time a sensor was added
1501 >
1502 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1503 std::optional<uint8_t> count)
1504{
1505 auto& sensorTree = getSensorTree();
1506 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001507 uint16_t recordID = 0;
1508 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08001509 // Sensors are dynamically allocated, and there is at least one LUN
1510 uint8_t lunsAndDynamicPopulation = 0x80;
1511 constexpr uint8_t getSdrCount = 0x01;
1512 constexpr uint8_t getSensorCount = 0x00;
1513
1514 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
1515 {
1516 return ipmi::responseResponseError();
1517 }
Willy Tude54f482021-01-26 15:59:09 -08001518 uint16_t numSensors = sensorTree.size();
1519 if (count.value_or(0) == getSdrCount)
1520 {
1521 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001522 while (!getSensorDataRecord(ctx, record, recordID++))
Willy Tude54f482021-01-26 15:59:09 -08001523 {
1524 get_sdr::SensorDataRecordHeader* hdr =
1525 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001526 record.data());
Willy Tude54f482021-01-26 15:59:09 -08001527 if (hdr && hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
1528 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001529 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08001530 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001531 record.data());
1532 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08001533 {
1534 sdrCount++;
1535 }
1536 }
1537 }
1538 }
1539 else if (count.value_or(0) == getSensorCount)
1540 {
1541 // Return the number of sensors attached to the LUN
1542 if ((ctx->lun == 0) && (numSensors > 0))
1543 {
1544 sdrCount =
1545 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
1546 }
1547 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
1548 {
1549 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
1550 ? maxSensorsPerLUN
1551 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
1552 }
1553 else if (ctx->lun == 3)
1554 {
1555 if (numSensors <= maxIPMISensors)
1556 {
1557 sdrCount =
1558 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
1559 }
1560 else
1561 {
1562 // error
1563 throw std::out_of_range(
1564 "Maximum number of IPMI sensors exceeded.");
1565 }
1566 }
1567 }
1568 else
1569 {
1570 return ipmi::responseInvalidFieldRequest();
1571 }
1572
1573 // Get Sensor count. This returns the number of sensors
1574 if (numSensors > 0)
1575 {
1576 lunsAndDynamicPopulation |= 1;
1577 }
1578 if (numSensors > maxSensorsPerLUN)
1579 {
1580 lunsAndDynamicPopulation |= 2;
1581 }
1582 if (numSensors >= (maxSensorsPerLUN * 2))
1583 {
1584 lunsAndDynamicPopulation |= 8;
1585 }
1586 if (numSensors > maxIPMISensors)
1587 {
1588 // error
1589 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
1590 }
1591
1592 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
1593 sdrLastAdd);
1594}
1595
1596/* end sensor commands */
1597
1598/* storage commands */
1599
1600ipmi::RspType<uint8_t, // sdr version
1601 uint16_t, // record count
1602 uint16_t, // free space
1603 uint32_t, // most recent addition
1604 uint32_t, // most recent erase
1605 uint8_t // operationSupport
1606 >
1607 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
1608{
1609 auto& sensorTree = getSensorTree();
1610 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001611 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08001612 {
1613 return ipmi::responseResponseError();
1614 }
1615
1616 size_t fruCount = 0;
1617 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1618 if (ret != ipmi::ccSuccess)
1619 {
1620 return ipmi::response(ret);
1621 }
1622
1623 uint16_t recordCount =
1624 sensorTree.size() + fruCount + ipmi::storage::type12Count;
1625
1626 uint8_t operationSupport = static_cast<uint8_t>(
1627 SdrRepositoryInfoOps::overflow); // write not supported
1628
1629 operationSupport |=
1630 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
1631 operationSupport |= static_cast<uint8_t>(
1632 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
1633 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
1634 unspecifiedFreeSpace, sdrLastAdd,
1635 sdrLastRemove, operationSupport);
1636}
1637
1638/** @brief implements the get SDR allocation info command
1639 *
1640 * @returns IPMI completion code plus response data
1641 * - allocUnits - Number of possible allocation units
1642 * - allocUnitSize - Allocation unit size in bytes.
1643 * - allocUnitFree - Number of free allocation units
1644 * - allocUnitLargestFree - Largest free block in allocation units
1645 * - maxRecordSize - Maximum record size in allocation units.
1646 */
1647ipmi::RspType<uint16_t, // allocUnits
1648 uint16_t, // allocUnitSize
1649 uint16_t, // allocUnitFree
1650 uint16_t, // allocUnitLargestFree
1651 uint8_t // maxRecordSize
1652 >
1653 ipmiStorageGetSDRAllocationInfo()
1654{
1655 // 0000h unspecified number of alloc units
1656 constexpr uint16_t allocUnits = 0;
1657
1658 constexpr uint16_t allocUnitFree = 0;
1659 constexpr uint16_t allocUnitLargestFree = 0;
1660 // only allow one block at a time
1661 constexpr uint8_t maxRecordSize = 1;
1662
1663 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
1664 allocUnitLargestFree, maxRecordSize);
1665}
1666
1667/** @brief implements the reserve SDR command
1668 * @returns IPMI completion code plus response data
1669 * - sdrReservationID
1670 */
1671ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
1672{
1673 sdrReservationID++;
1674 if (sdrReservationID == 0)
1675 {
1676 sdrReservationID++;
1677 }
1678
1679 return ipmi::responseSuccess(sdrReservationID);
1680}
1681
1682ipmi::RspType<uint16_t, // next record ID
1683 std::vector<uint8_t> // payload
1684 >
1685 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
1686 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
1687{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001688 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08001689 // reservation required for partial reads with non zero offset into
1690 // record
1691 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
1692 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001693 phosphor::logging::log<phosphor::logging::level::ERR>(
1694 "ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08001695 return ipmi::responseInvalidReservationId();
1696 }
Willy Tude54f482021-01-26 15:59:09 -08001697 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1698 if (ret != ipmi::ccSuccess)
1699 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001700 phosphor::logging::log<phosphor::logging::level::ERR>(
1701 "ipmiStorageGetSDR: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08001702 return ipmi::response(ret);
1703 }
1704
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001705 auto& sensorTree = getSensorTree();
Willy Tude54f482021-01-26 15:59:09 -08001706 size_t lastRecord =
1707 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001708 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
1709
1710 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08001711 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001712 phosphor::logging::log<phosphor::logging::level::ERR>(
1713 "ipmiStorageGetSDR: getSensorSubtree error");
1714 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08001715 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001716
1717 std::vector<uint8_t> record;
1718 if (getSensorDataRecord(ctx, record, recordID))
Willy Tude54f482021-01-26 15:59:09 -08001719 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001720 phosphor::logging::log<phosphor::logging::level::ERR>(
1721 "ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08001722 return ipmi::responseInvalidFieldRequest();
1723 }
Willy Tude54f482021-01-26 15:59:09 -08001724 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001725 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08001726 if (!hdr)
1727 {
1728 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001729 "ipmiStorageGetSDR: record header is null");
1730 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08001731 }
1732
1733 size_t sdrLength =
1734 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
1735 if (sdrLength < (offset + bytesToRead))
1736 {
1737 bytesToRead = sdrLength - offset;
1738 }
1739
1740 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
1741 if (!respStart)
1742 {
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001744 "ipmiStorageGetSDR: record is null");
1745 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08001746 }
1747
1748 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001749
Willy Tude54f482021-01-26 15:59:09 -08001750 return ipmi::responseSuccess(nextRecordId, recordData);
1751}
1752/* end storage commands */
1753
1754void registerSensorFunctions()
1755{
1756 // <Platform Event>
1757 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1758 ipmi::sensor_event::cmdPlatformEvent,
1759 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
1760
Willy Tudbafbce2021-03-29 00:37:05 -07001761#ifdef FEATURE_DYNAMIC_SENSORS_WRITE
1762 // <Set Sensor Reading and Event Status>
1763 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1764 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
1765 ipmi::Privilege::Operator, ipmiSetSensorReading);
1766#endif
1767
Willy Tude54f482021-01-26 15:59:09 -08001768 // <Get Sensor Reading>
1769 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1770 ipmi::sensor_event::cmdGetSensorReading,
1771 ipmi::Privilege::User, ipmiSenGetSensorReading);
1772
1773 // <Get Sensor Threshold>
1774 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1775 ipmi::sensor_event::cmdGetSensorThreshold,
1776 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
1777
1778 // <Set Sensor Threshold>
1779 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1780 ipmi::sensor_event::cmdSetSensorThreshold,
1781 ipmi::Privilege::Operator,
1782 ipmiSenSetSensorThresholds);
1783
1784 // <Get Sensor Event Enable>
1785 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1786 ipmi::sensor_event::cmdGetSensorEventEnable,
1787 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
1788
1789 // <Get Sensor Event Status>
1790 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1791 ipmi::sensor_event::cmdGetSensorEventStatus,
1792 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
1793
1794 // register all storage commands for both Sensor and Storage command
1795 // versions
1796
1797 // <Get SDR Repository Info>
1798 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1799 ipmi::storage::cmdGetSdrRepositoryInfo,
1800 ipmi::Privilege::User,
1801 ipmiStorageGetSDRRepositoryInfo);
1802
1803 // <Get Device SDR Info>
1804 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1805 ipmi::sensor_event::cmdGetDeviceSdrInfo,
1806 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
1807
1808 // <Get SDR Allocation Info>
1809 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1810 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
1811 ipmi::Privilege::User,
1812 ipmiStorageGetSDRAllocationInfo);
1813
1814 // <Reserve SDR Repo>
1815 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1816 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
1817 ipmi::Privilege::User, ipmiStorageReserveSDR);
1818
1819 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1820 ipmi::storage::cmdReserveSdrRepository,
1821 ipmi::Privilege::User, ipmiStorageReserveSDR);
1822
1823 // <Get Sdr>
1824 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
1825 ipmi::sensor_event::cmdGetDeviceSdr,
1826 ipmi::Privilege::User, ipmiStorageGetSDR);
1827
1828 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
1829 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
1830 ipmiStorageGetSDR);
1831}
1832} // namespace ipmi