blob: 7cbd29f4bf7e55ccbdc768a9ae1c3715b0102d01 [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
Scron Chang2703b022021-07-06 15:47:45 +080044#ifdef FEATURE_HYBRID_SENSORS
45
46#include "sensordatahandler.hpp"
47namespace ipmi
48{
49namespace sensor
50{
51extern const IdInfoMap sensors;
52} // namespace sensor
53} // namespace ipmi
54#endif
55
JeffLind950f412021-10-20 18:49:34 +080056constexpr std::array<const char*, 7> suffixes = {
57 "_Output_Voltage", "_Input_Voltage", "_Output_Current", "_Input_Current",
58 "_Output_Power", "_Input_Power", "_Temperature"};
Willy Tude54f482021-01-26 15:59:09 -080059namespace ipmi
60{
Hao Jiangd48c9212021-02-03 15:45:06 -080061
62using phosphor::logging::entry;
63using phosphor::logging::level;
64using phosphor::logging::log;
65
Willy Tude54f482021-01-26 15:59:09 -080066static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu9ab2f942020-07-15 17:56:21 -070067static constexpr int sensorMapSdrUpdatePeriod = 60;
Willy Tude54f482021-01-26 15:59:09 -080068
Willy Tu38e7a2b2021-03-29 15:09:56 -070069// BMC I2C address is generally at 0x20
70static constexpr uint8_t bmcI2CAddr = 0x20;
71
Willy Tude54f482021-01-26 15:59:09 -080072constexpr size_t maxSDRTotalSize =
73 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
74constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
75
76static uint16_t sdrReservationID;
77static uint32_t sdrLastAdd = noTimestamp;
78static uint32_t sdrLastRemove = noTimestamp;
79static constexpr size_t lastRecordIndex = 0xFFFF;
80static constexpr int GENERAL_ERROR = -1;
81
Willy Tude54f482021-01-26 15:59:09 -080082static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
83
84// Specify the comparison required to sort and find char* map objects
85struct CmpStr
86{
87 bool operator()(const char* a, const char* b) const
88 {
89 return std::strcmp(a, b) < 0;
90 }
91};
92const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
93 sensorUnits{{{"temperature", SensorUnits::degreesC},
94 {"voltage", SensorUnits::volts},
95 {"current", SensorUnits::amps},
96 {"fan_tach", SensorUnits::rpm},
97 {"power", SensorUnits::watts}}};
98
99void registerSensorFunctions() __attribute__((constructor));
100
101static sdbusplus::bus::match::match sensorAdded(
102 *getSdBus(),
103 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
104 "sensors/'",
105 [](sdbusplus::message::message& m) {
106 getSensorTree().clear();
107 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
108 std::chrono::system_clock::now().time_since_epoch())
109 .count();
110 });
111
112static sdbusplus::bus::match::match sensorRemoved(
113 *getSdBus(),
114 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
115 "sensors/'",
116 [](sdbusplus::message::message& m) {
117 getSensorTree().clear();
118 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
119 std::chrono::system_clock::now().time_since_epoch())
120 .count();
121 });
122
123// this keeps track of deassertions for sensor event status command. A
124// deasertion can only happen if an assertion was seen first.
125static boost::container::flat_map<
126 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
127 thresholdDeassertMap;
128
129static sdbusplus::bus::match::match thresholdChanged(
130 *getSdBus(),
131 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
132 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
133 [](sdbusplus::message::message& m) {
134 boost::container::flat_map<std::string, std::variant<bool, double>>
135 values;
136 m.read(std::string(), values);
137
138 auto findAssert =
139 std::find_if(values.begin(), values.end(), [](const auto& pair) {
140 return pair.first.find("Alarm") != std::string::npos;
141 });
142 if (findAssert != values.end())
143 {
144 auto ptr = std::get_if<bool>(&(findAssert->second));
145 if (ptr == nullptr)
146 {
147 phosphor::logging::log<phosphor::logging::level::ERR>(
148 "thresholdChanged: Assert non bool");
149 return;
150 }
151 if (*ptr)
152 {
153 phosphor::logging::log<phosphor::logging::level::INFO>(
154 "thresholdChanged: Assert",
155 phosphor::logging::entry("SENSOR=%s", m.get_path()));
156 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
157 }
158 else
159 {
160 auto& value =
161 thresholdDeassertMap[m.get_path()][findAssert->first];
162 if (value)
163 {
164 phosphor::logging::log<phosphor::logging::level::INFO>(
165 "thresholdChanged: deassert",
166 phosphor::logging::entry("SENSOR=%s", m.get_path()));
167 value = *ptr;
168 }
169 }
170 }
171 });
172
Hao Jiangd2afd052020-12-10 15:09:32 -0800173namespace sensor
174{
175static constexpr const char* vrInterface =
176 "xyz.openbmc_project.Control.VoltageRegulatorMode";
177static constexpr const char* sensorInterface =
178 "xyz.openbmc_project.Sensor.Value";
179} // namespace sensor
180
Willy Tude54f482021-01-26 15:59:09 -0800181static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
182 double& min)
183{
184 max = 127;
185 min = -128;
186
Hao Jiangd2afd052020-12-10 15:09:32 -0800187 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800188 auto critical =
189 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
190 auto warning =
191 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
192
193 if (sensorObject != sensorMap.end())
194 {
195 auto maxMap = sensorObject->second.find("MaxValue");
196 auto minMap = sensorObject->second.find("MinValue");
197
198 if (maxMap != sensorObject->second.end())
199 {
200 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
201 }
202 if (minMap != sensorObject->second.end())
203 {
204 min = std::visit(VariantToDoubleVisitor(), minMap->second);
205 }
206 }
207 if (critical != sensorMap.end())
208 {
209 auto lower = critical->second.find("CriticalLow");
210 auto upper = critical->second.find("CriticalHigh");
211 if (lower != critical->second.end())
212 {
213 double value = std::visit(VariantToDoubleVisitor(), lower->second);
214 min = std::min(value, min);
215 }
216 if (upper != critical->second.end())
217 {
218 double value = std::visit(VariantToDoubleVisitor(), upper->second);
219 max = std::max(value, max);
220 }
221 }
222 if (warning != sensorMap.end())
223 {
224
225 auto lower = warning->second.find("WarningLow");
226 auto upper = warning->second.find("WarningHigh");
227 if (lower != warning->second.end())
228 {
229 double value = std::visit(VariantToDoubleVisitor(), lower->second);
230 min = std::min(value, min);
231 }
232 if (upper != warning->second.end())
233 {
234 double value = std::visit(VariantToDoubleVisitor(), upper->second);
235 max = std::max(value, max);
236 }
237 }
238}
239
240static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700241 std::string sensorPath, DbusInterfaceMap& sensorMap,
242 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800243{
Scron Chang2703b022021-07-06 15:47:45 +0800244#ifdef FEATURE_HYBRID_SENSORS
245 if (auto sensor = findStaticSensor(sensorPath);
246 sensor != ipmi::sensor::sensors.end() &&
247 getSensorEventTypeFromPath(sensorPath) !=
248 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
249 {
250 // If the incoming sensor is a discrete sensor, it might fail in
251 // getManagedObjects(), return true, and use its own getFunc to get
252 // value.
253 return true;
254 }
255#endif
256
Willy Tude54f482021-01-26 15:59:09 -0800257 static boost::container::flat_map<
258 std::string, std::chrono::time_point<std::chrono::steady_clock>>
259 updateTimeMap;
260
261 auto updateFind = updateTimeMap.find(sensorConnection);
262 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
263 if (updateFind != updateTimeMap.end())
264 {
265 lastUpdate = updateFind->second;
266 }
267
268 auto now = std::chrono::steady_clock::now();
269
270 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700271 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800272 {
Willy Tude54f482021-01-26 15:59:09 -0800273 ObjectValueTree managedObjects;
274 boost::system::error_code ec = getManagedObjects(
275 ctx, sensorConnection.c_str(), "/", managedObjects);
276 if (ec)
277 {
278 phosphor::logging::log<phosphor::logging::level::ERR>(
279 "GetMangagedObjects for getSensorMap failed",
280 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
281
282 return false;
283 }
284
285 SensorCache[sensorConnection] = managedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700286 // Update time after finish building the map which allow the
287 // data to be cached for updatePeriod plus the build time.
288 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800289 }
290 auto connection = SensorCache.find(sensorConnection);
291 if (connection == SensorCache.end())
292 {
293 return false;
294 }
295 auto path = connection->second.find(sensorPath);
296 if (path == connection->second.end())
297 {
298 return false;
299 }
300 sensorMap = path->second;
301
302 return true;
303}
304
Hao Jiangd2afd052020-12-10 15:09:32 -0800305namespace sensor
306{
Hao Jiangd48c9212021-02-03 15:45:06 -0800307// Read VR profiles from sensor(daemon) interface
308static std::optional<std::vector<std::string>>
309 getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object)
Hao Jiangd2afd052020-12-10 15:09:32 -0800310{
311 // get VR mode profiles from Supported Interface
Hao Jiangd48c9212021-02-03 15:45:06 -0800312 auto supportedProperty = object.find("Supported");
313 if (supportedProperty == object.end() ||
314 object.find("Selected") == object.end())
Hao Jiangd2afd052020-12-10 15:09:32 -0800315 {
316 phosphor::logging::log<phosphor::logging::level::ERR>(
317 "Missing the required Supported and Selected properties");
318 return std::nullopt;
319 }
320
321 const auto profilesPtr =
322 std::get_if<std::vector<std::string>>(&supportedProperty->second);
323
324 if (profilesPtr == nullptr)
325 {
326 phosphor::logging::log<phosphor::logging::level::ERR>(
327 "property is not array of string");
328 return std::nullopt;
329 }
Hao Jiangd48c9212021-02-03 15:45:06 -0800330 return *profilesPtr;
331}
332
333// Calculate VR Mode from input IPMI discrete event bytes
334static std::optional<std::string>
335 calculateVRMode(uint15_t assertOffset,
336 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
337{
338 // get VR mode profiles from Supported Interface
339 auto profiles = getSupportedVrProfiles(VRObject);
340 if (!profiles)
341 {
342 return std::nullopt;
343 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800344
345 // interpret IPMI cmd bits into profiles' index
346 long unsigned int index = 0;
347 // only one bit should be set and the highest bit should not be used.
348 if (assertOffset == 0 || assertOffset == (1u << 15) ||
349 (assertOffset & (assertOffset - 1)))
350 {
351 phosphor::logging::log<phosphor::logging::level::ERR>(
352 "IPMI cmd format incorrect",
353
354 phosphor::logging::entry("BYTES=%#02x",
355 static_cast<uint16_t>(assertOffset)));
356 return std::nullopt;
357 }
358
359 while (assertOffset != 1)
360 {
361 assertOffset >>= 1;
362 index++;
363 }
364
Hao Jiangd48c9212021-02-03 15:45:06 -0800365 if (index >= profiles->size())
Hao Jiangd2afd052020-12-10 15:09:32 -0800366 {
367 phosphor::logging::log<phosphor::logging::level::ERR>(
368 "profile index out of boundary");
369 return std::nullopt;
370 }
371
Hao Jiangd48c9212021-02-03 15:45:06 -0800372 return profiles->at(index);
Hao Jiangd2afd052020-12-10 15:09:32 -0800373}
374
375// Calculate sensor value from IPMI reading byte
376static std::optional<double>
377 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
378 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
379{
380 if (valueObject.find("Value") == valueObject.end())
381 {
382 phosphor::logging::log<phosphor::logging::level::ERR>(
383 "Missing the required Value property");
384 return std::nullopt;
385 }
386
387 double max = 0;
388 double min = 0;
389 getSensorMaxMin(sensorMap, max, min);
390
391 int16_t mValue = 0;
392 int16_t bValue = 0;
393 int8_t rExp = 0;
394 int8_t bExp = 0;
395 bool bSigned = false;
396
397 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
398 {
399 return std::nullopt;
400 }
401
402 double value = bSigned ? ((int8_t)reading) : reading;
403
404 value *= ((double)mValue);
405 value += ((double)bValue) * std::pow(10.0, bExp);
406 value *= std::pow(10.0, rExp);
407
408 return value;
409}
410
Willy Tu38e7a2b2021-03-29 15:09:56 -0700411// Extract file name from sensor path as the sensors SDR ID. Simplify the name
412// if it is too long.
413std::string parseSdrIdFromPath(const std::string& path)
414{
415 std::string name;
416 size_t nameStart = path.rfind("/");
417 if (nameStart != std::string::npos)
418 {
419 name = path.substr(nameStart + 1, std::string::npos - nameStart);
420 }
421
Willy Tu38e7a2b2021-03-29 15:09:56 -0700422 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
423 {
424 // try to not truncate by replacing common words
JeffLind950f412021-10-20 18:49:34 +0800425 for (const auto& suffix : suffixes)
Willy Tu38e7a2b2021-03-29 15:09:56 -0700426 {
JeffLind950f412021-10-20 18:49:34 +0800427 if (boost::ends_with(name, suffix))
428 {
429 boost::replace_all(name, suffix, "");
430 break;
431 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700432 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700433 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
434 }
JeffLind950f412021-10-20 18:49:34 +0800435 std::replace(name.begin(), name.end(), '_', ' ');
Willy Tu38e7a2b2021-03-29 15:09:56 -0700436 return name;
437}
438
Hao Jiangd48c9212021-02-03 15:45:06 -0800439bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection,
440 const std::string& path,
441 const ipmi::DbusInterfaceMap::mapped_type& object,
442 std::bitset<16>& assertions)
443{
444 auto profiles = sensor::getSupportedVrProfiles(object);
445 if (!profiles)
446 {
447 return false;
448 }
449 ipmi::Value modeVariant;
450
451 auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface,
452 "Selected", modeVariant);
453 if (ec)
454 {
455 log<level::ERR>("Failed to get property",
456 entry("PROPERTY=%s", "Selected"),
457 entry("PATH=%s", path.c_str()),
458 entry("INTERFACE=%s", sensor::sensorInterface),
459 entry("WHAT=%s", ec.message().c_str()));
460 return false;
461 }
462
463 auto mode = std::get_if<std::string>(&modeVariant);
464 if (mode == nullptr)
465 {
466 log<level::ERR>("property is not a string",
467 entry("PROPERTY=%s", "Selected"),
468 entry("PATH=%s", path.c_str()),
469 entry("INTERFACE=%s", sensor::sensorInterface));
470 return false;
471 }
472
473 auto itr = std::find(profiles->begin(), profiles->end(), *mode);
474 if (itr == profiles->end())
475 {
476 using namespace phosphor::logging;
477 log<level::ERR>("VR mode doesn't match any of its profiles",
478 entry("PATH=%s", path.c_str()));
479 return false;
480 }
481 std::size_t index =
482 static_cast<std::size_t>(std::distance(profiles->begin(), itr));
483
484 // map index to reponse event assertion bit.
485 if (index < 8)
486 {
487 assertions.set(1u << index);
488 }
489 else if (index < 15)
490 {
491 assertions.set(1u << (index - 8));
492 }
493 else
494 {
495 log<level::ERR>("VR profile index reaches max assertion bit",
496 entry("PATH=%s", path.c_str()),
497 entry("INDEX=%uz", index));
498 return false;
499 }
500 if constexpr (debug)
501 {
502 std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path)
503 << " mode is: [" << index << "] " << *mode << std::endl;
504 }
505 return true;
506}
Hao Jiangd2afd052020-12-10 15:09:32 -0800507} // namespace sensor
508
Willy Tude54f482021-01-26 15:59:09 -0800509ipmi::RspType<> ipmiSenPlatformEvent(uint8_t generatorID, uint8_t evmRev,
510 uint8_t sensorType, uint8_t sensorNum,
511 uint8_t eventType, uint8_t eventData1,
512 std::optional<uint8_t> eventData2,
513 std::optional<uint8_t> eventData3)
514{
515 return ipmi::responseSuccess();
516}
517
Willy Tudbafbce2021-03-29 00:37:05 -0700518ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
519 uint8_t sensorNumber, uint8_t operation,
520 uint8_t reading, uint15_t assertOffset,
521 bool resvd1, uint15_t deassertOffset,
522 bool resvd2, uint8_t eventData1,
523 uint8_t eventData2, uint8_t eventData3)
524{
525 std::string connection;
526 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -0700527 std::vector<std::string> interfaces;
528
529 ipmi::Cc status =
530 getSensorConnection(ctx, sensorNumber, connection, path, &interfaces);
Willy Tudbafbce2021-03-29 00:37:05 -0700531 if (status)
532 {
533 return ipmi::response(status);
534 }
535
Hao Jiangd2afd052020-12-10 15:09:32 -0800536 // we can tell the sensor type by its interface type
Hao Jiange39d4d82021-04-16 17:02:40 -0700537 if (std::find(interfaces.begin(), interfaces.end(),
538 sensor::sensorInterface) != interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700539 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700540 DbusInterfaceMap sensorMap;
541 if (!getSensorMap(ctx, connection, path, sensorMap))
542 {
543 return ipmi::responseResponseError();
544 }
545 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800546 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700547 {
548 return ipmi::responseResponseError();
549 }
550
Jie Yangf0a89942021-07-29 15:30:25 -0700551 // Only allow external SetSensor if write permission granted
552 if (!details::sdrWriteTable.getWritePermission(sensorNumber))
553 {
554 return ipmi::responseResponseError();
555 }
556
Hao Jiangd2afd052020-12-10 15:09:32 -0800557 auto value =
558 sensor::calculateValue(reading, sensorMap, sensorObject->second);
559 if (!value)
560 {
561 return ipmi::responseResponseError();
562 }
563
564 if constexpr (debug)
565 {
566 phosphor::logging::log<phosphor::logging::level::INFO>(
567 "IPMI SET_SENSOR",
568 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber),
569 phosphor::logging::entry("BYTE=%u", (unsigned int)reading),
570 phosphor::logging::entry("VALUE=%f", *value));
571 }
572
573 boost::system::error_code ec =
574 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
575 "Value", ipmi::Value(*value));
576
577 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500578 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800579 // callback functions for now (e.g. ipmiSetSensorReading).
580 if (ec)
581 {
582 using namespace phosphor::logging;
583 log<level::ERR>("Failed to set property",
584 entry("PROPERTY=%s", "Value"),
585 entry("PATH=%s", path.c_str()),
586 entry("INTERFACE=%s", sensor::sensorInterface),
587 entry("WHAT=%s", ec.message().c_str()));
588 return ipmi::responseResponseError();
589 }
590 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700591 }
592
Hao Jiange39d4d82021-04-16 17:02:40 -0700593 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
594 interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700595 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700596 DbusInterfaceMap sensorMap;
597 if (!getSensorMap(ctx, connection, path, sensorMap))
598 {
599 return ipmi::responseResponseError();
600 }
601 auto sensorObject = sensorMap.find(sensor::vrInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800602 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700603 {
604 return ipmi::responseResponseError();
605 }
606
Hao Jiangd2afd052020-12-10 15:09:32 -0800607 // VR sensors are treated as a special case and we will not check the
608 // write permission for VR sensors, since they always deemed writable
609 // and permission table are not applied to VR sensors.
610 auto vrMode =
611 sensor::calculateVRMode(assertOffset, sensorObject->second);
612 if (!vrMode)
613 {
614 return ipmi::responseResponseError();
615 }
616 boost::system::error_code ec = setDbusProperty(
617 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
618 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500619 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800620 // callback functions for now (e.g. ipmiSetSensorReading).
621 if (ec)
622 {
623 using namespace phosphor::logging;
624 log<level::ERR>("Failed to set property",
625 entry("PROPERTY=%s", "Selected"),
626 entry("PATH=%s", path.c_str()),
627 entry("INTERFACE=%s", sensor::sensorInterface),
628 entry("WHAT=%s", ec.message().c_str()));
629 return ipmi::responseResponseError();
630 }
631 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700632 }
633
Hao Jiangd2afd052020-12-10 15:09:32 -0800634 phosphor::logging::log<phosphor::logging::level::ERR>(
635 "unknown sensor type",
636 phosphor::logging::entry("PATH=%s", path.c_str()));
637 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700638}
639
Willy Tude54f482021-01-26 15:59:09 -0800640ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
641 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
642{
643 std::string connection;
644 std::string path;
645
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000646 if (sensnum == reservedSensorNumber)
647 {
648 return ipmi::responseInvalidFieldRequest();
649 }
650
Willy Tude54f482021-01-26 15:59:09 -0800651 auto status = getSensorConnection(ctx, sensnum, connection, path);
652 if (status)
653 {
654 return ipmi::response(status);
655 }
656
Scron Chang2703b022021-07-06 15:47:45 +0800657#ifdef FEATURE_HYBRID_SENSORS
658 if (auto sensor = findStaticSensor(path);
659 sensor != ipmi::sensor::sensors.end() &&
660 getSensorEventTypeFromPath(path) !=
661 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
662 {
663 if (ipmi::sensor::Mutability::Read !=
664 (sensor->second.mutability & ipmi::sensor::Mutability::Read))
665 {
666 return ipmi::responseIllegalCommand();
667 }
668
669 uint8_t operation;
670 try
671 {
672 ipmi::sensor::GetSensorResponse getResponse =
673 sensor->second.getFunc(sensor->second);
674
675 if (getResponse.readingOrStateUnavailable)
676 {
677 operation |= static_cast<uint8_t>(
678 IPMISensorReadingByte2::readingStateUnavailable);
679 }
680 if (getResponse.scanningEnabled)
681 {
682 operation |= static_cast<uint8_t>(
683 IPMISensorReadingByte2::sensorScanningEnable);
684 }
685 if (getResponse.allEventMessagesEnabled)
686 {
687 operation |= static_cast<uint8_t>(
688 IPMISensorReadingByte2::eventMessagesEnable);
689 }
690 return ipmi::responseSuccess(
691 getResponse.reading, operation,
692 getResponse.thresholdLevelsStates,
693 getResponse.discreteReadingSensorStates);
694 }
695 catch (const std::exception& e)
696 {
697 operation |= static_cast<uint8_t>(
698 IPMISensorReadingByte2::readingStateUnavailable);
699 return ipmi::responseSuccess(0, operation, 0, std::nullopt);
700 }
701 }
702#endif
703
Willy Tude54f482021-01-26 15:59:09 -0800704 DbusInterfaceMap sensorMap;
705 if (!getSensorMap(ctx, connection, path, sensorMap))
706 {
707 return ipmi::responseResponseError();
708 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800709 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800710
711 if (sensorObject == sensorMap.end() ||
712 sensorObject->second.find("Value") == sensorObject->second.end())
713 {
714 return ipmi::responseResponseError();
715 }
716 auto& valueVariant = sensorObject->second["Value"];
717 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
718
719 double max = 0;
720 double min = 0;
721 getSensorMaxMin(sensorMap, max, min);
722
723 int16_t mValue = 0;
724 int16_t bValue = 0;
725 int8_t rExp = 0;
726 int8_t bExp = 0;
727 bool bSigned = false;
728
729 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
730 {
731 return ipmi::responseResponseError();
732 }
733
734 uint8_t value =
735 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
736 uint8_t operation =
737 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
738 operation |=
739 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
740 bool notReading = std::isnan(reading);
741
742 if (!notReading)
743 {
744 auto availableObject =
745 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
746 if (availableObject != sensorMap.end())
747 {
748 auto findAvailable = availableObject->second.find("Available");
749 if (findAvailable != availableObject->second.end())
750 {
751 bool* available = std::get_if<bool>(&(findAvailable->second));
752 if (available && !(*available))
753 {
754 notReading = true;
755 }
756 }
757 }
758 }
759
760 if (notReading)
761 {
762 operation |= static_cast<uint8_t>(
763 IPMISensorReadingByte2::readingStateUnavailable);
764 }
765
Josh Lehana55c9532020-10-28 21:59:06 -0700766 if constexpr (details::enableInstrumentation)
767 {
768 int byteValue;
769 if (bSigned)
770 {
771 byteValue = static_cast<int>(static_cast<int8_t>(value));
772 }
773 else
774 {
775 byteValue = static_cast<int>(static_cast<uint8_t>(value));
776 }
777
778 // Keep stats on the reading just obtained, even if it is "NaN"
779 if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
780 {
781 // This is the first reading, show the coefficients
782 double step = (max - min) / 255.0;
783 std::cerr << "IPMI sensor "
784 << details::sdrStatsTable.getName(sensnum)
785 << ": Range min=" << min << " max=" << max
786 << ", step=" << step
787 << ", Coefficients mValue=" << static_cast<int>(mValue)
788 << " rExp=" << static_cast<int>(rExp)
789 << " bValue=" << static_cast<int>(bValue)
790 << " bExp=" << static_cast<int>(bExp)
791 << " bSigned=" << static_cast<int>(bSigned) << "\n";
792 }
793 }
794
Willy Tude54f482021-01-26 15:59:09 -0800795 uint8_t thresholds = 0;
796
797 auto warningObject =
798 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
799 if (warningObject != sensorMap.end())
800 {
801 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
802 auto alarmLow = warningObject->second.find("WarningAlarmLow");
803 if (alarmHigh != warningObject->second.end())
804 {
805 if (std::get<bool>(alarmHigh->second))
806 {
807 thresholds |= static_cast<uint8_t>(
808 IPMISensorReadingByte3::upperNonCritical);
809 }
810 }
811 if (alarmLow != warningObject->second.end())
812 {
813 if (std::get<bool>(alarmLow->second))
814 {
815 thresholds |= static_cast<uint8_t>(
816 IPMISensorReadingByte3::lowerNonCritical);
817 }
818 }
819 }
820
821 auto criticalObject =
822 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
823 if (criticalObject != sensorMap.end())
824 {
825 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
826 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
827 if (alarmHigh != criticalObject->second.end())
828 {
829 if (std::get<bool>(alarmHigh->second))
830 {
831 thresholds |=
832 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
833 }
834 }
835 if (alarmLow != criticalObject->second.end())
836 {
837 if (std::get<bool>(alarmLow->second))
838 {
839 thresholds |=
840 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
841 }
842 }
843 }
844
845 // no discrete as of today so optional byte is never returned
846 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
847}
848
849/** @brief implements the Set Sensor threshold command
850 * @param sensorNumber - sensor number
851 * @param lowerNonCriticalThreshMask
852 * @param lowerCriticalThreshMask
853 * @param lowerNonRecovThreshMask
854 * @param upperNonCriticalThreshMask
855 * @param upperCriticalThreshMask
856 * @param upperNonRecovThreshMask
857 * @param reserved
858 * @param lowerNonCritical - lower non-critical threshold
859 * @param lowerCritical - Lower critical threshold
860 * @param lowerNonRecoverable - Lower non recovarable threshold
861 * @param upperNonCritical - Upper non-critical threshold
862 * @param upperCritical - Upper critical
863 * @param upperNonRecoverable - Upper Non-recoverable
864 *
865 * @returns IPMI completion code
866 */
867ipmi::RspType<> ipmiSenSetSensorThresholds(
868 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
869 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
870 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
871 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
872 uint8_t lowerCritical, uint8_t lowerNonRecoverable,
873 uint8_t upperNonCritical, uint8_t upperCritical,
874 uint8_t upperNonRecoverable)
875{
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000876 if (sensorNum == reservedSensorNumber || reserved)
Willy Tude54f482021-01-26 15:59:09 -0800877 {
878 return ipmi::responseInvalidFieldRequest();
879 }
880
881 // lower nc and upper nc not suppported on any sensor
882 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
883 {
884 return ipmi::responseInvalidFieldRequest();
885 }
886
887 // if none of the threshold mask are set, nothing to do
888 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
889 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
890 upperCriticalThreshMask | upperNonRecovThreshMask))
891 {
892 return ipmi::responseSuccess();
893 }
894
895 std::string connection;
896 std::string path;
897
898 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
899 if (status)
900 {
901 return ipmi::response(status);
902 }
903 DbusInterfaceMap sensorMap;
904 if (!getSensorMap(ctx, connection, path, sensorMap))
905 {
906 return ipmi::responseResponseError();
907 }
908
909 double max = 0;
910 double min = 0;
911 getSensorMaxMin(sensorMap, max, min);
912
913 int16_t mValue = 0;
914 int16_t bValue = 0;
915 int8_t rExp = 0;
916 int8_t bExp = 0;
917 bool bSigned = false;
918
919 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
920 {
921 return ipmi::responseResponseError();
922 }
923
924 // store a vector of property name, value to set, and interface
925 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
926
927 // define the indexes of the tuple
928 constexpr uint8_t propertyName = 0;
929 constexpr uint8_t thresholdValue = 1;
930 constexpr uint8_t interface = 2;
931 // verifiy all needed fields are present
932 if (lowerCriticalThreshMask || upperCriticalThreshMask)
933 {
934 auto findThreshold =
935 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
936 if (findThreshold == sensorMap.end())
937 {
938 return ipmi::responseInvalidFieldRequest();
939 }
940 if (lowerCriticalThreshMask)
941 {
942 auto findLower = findThreshold->second.find("CriticalLow");
943 if (findLower == findThreshold->second.end())
944 {
945 return ipmi::responseInvalidFieldRequest();
946 }
947 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
948 findThreshold->first);
949 }
950 if (upperCriticalThreshMask)
951 {
952 auto findUpper = findThreshold->second.find("CriticalHigh");
953 if (findUpper == findThreshold->second.end())
954 {
955 return ipmi::responseInvalidFieldRequest();
956 }
957 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
958 findThreshold->first);
959 }
960 }
961 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
962 {
963 auto findThreshold =
964 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
965 if (findThreshold == sensorMap.end())
966 {
967 return ipmi::responseInvalidFieldRequest();
968 }
969 if (lowerNonCriticalThreshMask)
970 {
971 auto findLower = findThreshold->second.find("WarningLow");
972 if (findLower == findThreshold->second.end())
973 {
974 return ipmi::responseInvalidFieldRequest();
975 }
976 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
977 findThreshold->first);
978 }
979 if (upperNonCriticalThreshMask)
980 {
981 auto findUpper = findThreshold->second.find("WarningHigh");
982 if (findUpper == findThreshold->second.end())
983 {
984 return ipmi::responseInvalidFieldRequest();
985 }
986 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
987 findThreshold->first);
988 }
989 }
990 for (const auto& property : thresholdsToSet)
991 {
992 // from section 36.3 in the IPMI Spec, assume all linear
993 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
994 (bValue * std::pow(10.0, bExp))) *
995 std::pow(10.0, rExp);
996 setDbusProperty(
997 *getSdBus(), connection, path, std::get<interface>(property),
998 std::get<propertyName>(property), ipmi::Value(valueToSet));
999 }
1000 return ipmi::responseSuccess();
1001}
1002
1003IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
1004{
1005 IPMIThresholds resp;
1006 auto warningInterface =
1007 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1008 auto criticalInterface =
1009 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1010
1011 if ((warningInterface != sensorMap.end()) ||
1012 (criticalInterface != sensorMap.end()))
1013 {
Hao Jiangd2afd052020-12-10 15:09:32 -08001014 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -08001015
1016 if (sensorPair == sensorMap.end())
1017 {
1018 // should not have been able to find a sensor not implementing
1019 // the sensor object
1020 throw std::runtime_error("Invalid sensor map");
1021 }
1022
1023 double max = 0;
1024 double min = 0;
1025 getSensorMaxMin(sensorMap, max, min);
1026
1027 int16_t mValue = 0;
1028 int16_t bValue = 0;
1029 int8_t rExp = 0;
1030 int8_t bExp = 0;
1031 bool bSigned = false;
1032
1033 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1034 {
1035 throw std::runtime_error("Invalid sensor atrributes");
1036 }
1037 if (warningInterface != sensorMap.end())
1038 {
1039 auto& warningMap = warningInterface->second;
1040
1041 auto warningHigh = warningMap.find("WarningHigh");
1042 auto warningLow = warningMap.find("WarningLow");
1043
1044 if (warningHigh != warningMap.end())
1045 {
1046
1047 double value =
1048 std::visit(VariantToDoubleVisitor(), warningHigh->second);
1049 resp.warningHigh = scaleIPMIValueFromDouble(
1050 value, mValue, rExp, bValue, bExp, bSigned);
1051 }
1052 if (warningLow != warningMap.end())
1053 {
1054 double value =
1055 std::visit(VariantToDoubleVisitor(), warningLow->second);
1056 resp.warningLow = scaleIPMIValueFromDouble(
1057 value, mValue, rExp, bValue, bExp, bSigned);
1058 }
1059 }
1060 if (criticalInterface != sensorMap.end())
1061 {
1062 auto& criticalMap = criticalInterface->second;
1063
1064 auto criticalHigh = criticalMap.find("CriticalHigh");
1065 auto criticalLow = criticalMap.find("CriticalLow");
1066
1067 if (criticalHigh != criticalMap.end())
1068 {
1069 double value =
1070 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
1071 resp.criticalHigh = scaleIPMIValueFromDouble(
1072 value, mValue, rExp, bValue, bExp, bSigned);
1073 }
1074 if (criticalLow != criticalMap.end())
1075 {
1076 double value =
1077 std::visit(VariantToDoubleVisitor(), criticalLow->second);
1078 resp.criticalLow = scaleIPMIValueFromDouble(
1079 value, mValue, rExp, bValue, bExp, bSigned);
1080 }
1081 }
1082 }
1083 return resp;
1084}
1085
1086ipmi::RspType<uint8_t, // readable
1087 uint8_t, // lowerNCrit
1088 uint8_t, // lowerCrit
1089 uint8_t, // lowerNrecoverable
1090 uint8_t, // upperNC
1091 uint8_t, // upperCrit
1092 uint8_t> // upperNRecoverable
1093 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
1094{
1095 std::string connection;
1096 std::string path;
1097
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001098 if (sensorNumber == reservedSensorNumber)
1099 {
1100 return ipmi::responseInvalidFieldRequest();
1101 }
1102
Willy Tude54f482021-01-26 15:59:09 -08001103 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
1104 if (status)
1105 {
1106 return ipmi::response(status);
1107 }
1108
1109 DbusInterfaceMap sensorMap;
1110 if (!getSensorMap(ctx, connection, path, sensorMap))
1111 {
1112 return ipmi::responseResponseError();
1113 }
1114
1115 IPMIThresholds thresholdData;
1116 try
1117 {
1118 thresholdData = getIPMIThresholds(sensorMap);
1119 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001120 catch (const std::exception&)
Willy Tude54f482021-01-26 15:59:09 -08001121 {
1122 return ipmi::responseResponseError();
1123 }
1124
1125 uint8_t readable = 0;
1126 uint8_t lowerNC = 0;
1127 uint8_t lowerCritical = 0;
1128 uint8_t lowerNonRecoverable = 0;
1129 uint8_t upperNC = 0;
1130 uint8_t upperCritical = 0;
1131 uint8_t upperNonRecoverable = 0;
1132
1133 if (thresholdData.warningHigh)
1134 {
1135 readable |=
1136 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
1137 upperNC = *thresholdData.warningHigh;
1138 }
1139 if (thresholdData.warningLow)
1140 {
1141 readable |=
1142 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
1143 lowerNC = *thresholdData.warningLow;
1144 }
1145
1146 if (thresholdData.criticalHigh)
1147 {
1148 readable |=
1149 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
1150 upperCritical = *thresholdData.criticalHigh;
1151 }
1152 if (thresholdData.criticalLow)
1153 {
1154 readable |=
1155 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
1156 lowerCritical = *thresholdData.criticalLow;
1157 }
1158
1159 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
1160 lowerNonRecoverable, upperNC, upperCritical,
1161 upperNonRecoverable);
1162}
1163
1164/** @brief implements the get Sensor event enable command
1165 * @param sensorNumber - sensor number
1166 *
1167 * @returns IPMI completion code plus response data
1168 * - enabled - Sensor Event messages
1169 * - assertionEnabledLsb - Assertion event messages
1170 * - assertionEnabledMsb - Assertion event messages
1171 * - deassertionEnabledLsb - Deassertion event messages
1172 * - deassertionEnabledMsb - Deassertion event messages
1173 */
1174
1175ipmi::RspType<uint8_t, // enabled
1176 uint8_t, // assertionEnabledLsb
1177 uint8_t, // assertionEnabledMsb
1178 uint8_t, // deassertionEnabledLsb
1179 uint8_t> // deassertionEnabledMsb
1180 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
1181{
1182 std::string connection;
1183 std::string path;
1184
1185 uint8_t enabled = 0;
1186 uint8_t assertionEnabledLsb = 0;
1187 uint8_t assertionEnabledMsb = 0;
1188 uint8_t deassertionEnabledLsb = 0;
1189 uint8_t deassertionEnabledMsb = 0;
1190
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001191 if (sensorNum == reservedSensorNumber)
1192 {
1193 return ipmi::responseInvalidFieldRequest();
1194 }
1195
Willy Tude54f482021-01-26 15:59:09 -08001196 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1197 if (status)
1198 {
1199 return ipmi::response(status);
1200 }
1201
Scron Chang2703b022021-07-06 15:47:45 +08001202#ifdef FEATURE_HYBRID_SENSORS
1203 if (auto sensor = findStaticSensor(path);
1204 sensor != ipmi::sensor::sensors.end() &&
1205 getSensorEventTypeFromPath(path) !=
1206 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1207 {
1208 enabled = static_cast<uint8_t>(
1209 IPMISensorEventEnableByte2::sensorScanningEnable);
1210 uint16_t assertionEnabled = 0;
1211 for (auto& offsetValMap : sensor->second.propertyInterfaces.begin()
1212 ->second.begin()
1213 ->second.second)
1214 {
1215 assertionEnabled |= (1 << offsetValMap.first);
1216 }
1217 assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF));
1218 assertionEnabledMsb =
1219 static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF));
1220
1221 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1222 assertionEnabledMsb, deassertionEnabledLsb,
1223 deassertionEnabledMsb);
1224 }
1225#endif
1226
Willy Tude54f482021-01-26 15:59:09 -08001227 DbusInterfaceMap sensorMap;
1228 if (!getSensorMap(ctx, connection, path, sensorMap))
1229 {
1230 return ipmi::responseResponseError();
1231 }
1232
1233 auto warningInterface =
1234 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1235 auto criticalInterface =
1236 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1237 if ((warningInterface != sensorMap.end()) ||
1238 (criticalInterface != sensorMap.end()))
1239 {
1240 enabled = static_cast<uint8_t>(
1241 IPMISensorEventEnableByte2::sensorScanningEnable);
1242 if (warningInterface != sensorMap.end())
1243 {
1244 auto& warningMap = warningInterface->second;
1245
1246 auto warningHigh = warningMap.find("WarningHigh");
1247 auto warningLow = warningMap.find("WarningLow");
1248 if (warningHigh != warningMap.end())
1249 {
1250 assertionEnabledLsb |= static_cast<uint8_t>(
1251 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1252 deassertionEnabledLsb |= static_cast<uint8_t>(
1253 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
1254 }
1255 if (warningLow != warningMap.end())
1256 {
1257 assertionEnabledLsb |= static_cast<uint8_t>(
1258 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1259 deassertionEnabledLsb |= static_cast<uint8_t>(
1260 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
1261 }
1262 }
1263 if (criticalInterface != sensorMap.end())
1264 {
1265 auto& criticalMap = criticalInterface->second;
1266
1267 auto criticalHigh = criticalMap.find("CriticalHigh");
1268 auto criticalLow = criticalMap.find("CriticalLow");
1269
1270 if (criticalHigh != criticalMap.end())
1271 {
1272 assertionEnabledMsb |= static_cast<uint8_t>(
1273 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1274 deassertionEnabledMsb |= static_cast<uint8_t>(
1275 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1276 }
1277 if (criticalLow != criticalMap.end())
1278 {
1279 assertionEnabledLsb |= static_cast<uint8_t>(
1280 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1281 deassertionEnabledLsb |= static_cast<uint8_t>(
1282 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1283 }
1284 }
1285 }
1286
1287 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1288 assertionEnabledMsb, deassertionEnabledLsb,
1289 deassertionEnabledMsb);
1290}
1291
1292/** @brief implements the get Sensor event status command
1293 * @param sensorNumber - sensor number, FFh = reserved
1294 *
1295 * @returns IPMI completion code plus response data
1296 * - sensorEventStatus - Sensor Event messages state
1297 * - assertions - Assertion event messages
1298 * - deassertions - Deassertion event messages
1299 */
1300ipmi::RspType<uint8_t, // sensorEventStatus
1301 std::bitset<16>, // assertions
1302 std::bitset<16> // deassertion
1303 >
1304 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1305{
1306 if (sensorNum == reservedSensorNumber)
1307 {
1308 return ipmi::responseInvalidFieldRequest();
1309 }
1310
1311 std::string connection;
1312 std::string path;
1313 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1314 if (status)
1315 {
1316 phosphor::logging::log<phosphor::logging::level::ERR>(
1317 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1318 phosphor::logging::entry("SENSOR=%d", sensorNum));
1319 return ipmi::response(status);
1320 }
1321
Scron Chang2703b022021-07-06 15:47:45 +08001322#ifdef FEATURE_HYBRID_SENSORS
1323 if (auto sensor = findStaticSensor(path);
1324 sensor != ipmi::sensor::sensors.end() &&
1325 getSensorEventTypeFromPath(path) !=
1326 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1327 {
1328 auto response = ipmi::sensor::get::mapDbusToAssertion(
1329 sensor->second, path, sensor->second.sensorInterface);
1330 std::bitset<16> assertions;
1331 // deassertions are not used.
1332 std::bitset<16> deassertions = 0;
1333 uint8_t sensorEventStatus;
1334 if (response.readingOrStateUnavailable)
1335 {
1336 sensorEventStatus |= static_cast<uint8_t>(
1337 IPMISensorReadingByte2::readingStateUnavailable);
1338 }
1339 if (response.scanningEnabled)
1340 {
1341 sensorEventStatus |= static_cast<uint8_t>(
1342 IPMISensorReadingByte2::sensorScanningEnable);
1343 }
1344 if (response.allEventMessagesEnabled)
1345 {
1346 sensorEventStatus |= static_cast<uint8_t>(
1347 IPMISensorReadingByte2::eventMessagesEnable);
1348 }
1349 assertions |= response.discreteReadingSensorStates << 8;
1350 assertions |= response.thresholdLevelsStates;
1351 return ipmi::responseSuccess(sensorEventStatus, assertions,
1352 deassertions);
1353 }
1354#endif
1355
Willy Tude54f482021-01-26 15:59:09 -08001356 DbusInterfaceMap sensorMap;
1357 if (!getSensorMap(ctx, connection, path, sensorMap))
1358 {
1359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1361 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1362 return ipmi::responseResponseError();
1363 }
Hao Jiangd48c9212021-02-03 15:45:06 -08001364
1365 uint8_t sensorEventStatus =
1366 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1367 std::bitset<16> assertions = 0;
1368 std::bitset<16> deassertions = 0;
1369
1370 // handle VR typed sensor
1371 auto vrInterface = sensorMap.find(sensor::vrInterface);
1372 if (vrInterface != sensorMap.end())
1373 {
1374 if (!sensor::getVrEventStatus(ctx, connection, path,
1375 vrInterface->second, assertions))
1376 {
1377 return ipmi::responseResponseError();
1378 }
1379
1380 // both Event Message and Sensor Scanning are disable for VR.
1381 sensorEventStatus = 0;
1382 return ipmi::responseSuccess(sensorEventStatus, assertions,
1383 deassertions);
1384 }
1385
Willy Tude54f482021-01-26 15:59:09 -08001386 auto warningInterface =
1387 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1388 auto criticalInterface =
1389 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1390
Willy Tude54f482021-01-26 15:59:09 -08001391 std::optional<bool> criticalDeassertHigh =
1392 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1393 std::optional<bool> criticalDeassertLow =
1394 thresholdDeassertMap[path]["CriticalAlarmLow"];
1395 std::optional<bool> warningDeassertHigh =
1396 thresholdDeassertMap[path]["WarningAlarmHigh"];
1397 std::optional<bool> warningDeassertLow =
1398 thresholdDeassertMap[path]["WarningAlarmLow"];
1399
Willy Tude54f482021-01-26 15:59:09 -08001400 if (criticalDeassertHigh && !*criticalDeassertHigh)
1401 {
1402 deassertions.set(static_cast<size_t>(
1403 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1404 }
1405 if (criticalDeassertLow && !*criticalDeassertLow)
1406 {
1407 deassertions.set(static_cast<size_t>(
1408 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1409 }
1410 if (warningDeassertHigh && !*warningDeassertHigh)
1411 {
1412 deassertions.set(static_cast<size_t>(
1413 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1414 }
1415 if (warningDeassertLow && !*warningDeassertLow)
1416 {
1417 deassertions.set(static_cast<size_t>(
1418 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1419 }
1420 if ((warningInterface != sensorMap.end()) ||
1421 (criticalInterface != sensorMap.end()))
1422 {
1423 sensorEventStatus = static_cast<size_t>(
1424 IPMISensorEventEnableByte2::eventMessagesEnable);
1425 if (warningInterface != sensorMap.end())
1426 {
1427 auto& warningMap = warningInterface->second;
1428
1429 auto warningHigh = warningMap.find("WarningAlarmHigh");
1430 auto warningLow = warningMap.find("WarningAlarmLow");
1431 auto warningHighAlarm = false;
1432 auto warningLowAlarm = false;
1433
1434 if (warningHigh != warningMap.end())
1435 {
1436 warningHighAlarm = std::get<bool>(warningHigh->second);
1437 }
1438 if (warningLow != warningMap.end())
1439 {
1440 warningLowAlarm = std::get<bool>(warningLow->second);
1441 }
1442 if (warningHighAlarm)
1443 {
1444 assertions.set(
1445 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1446 upperNonCriticalGoingHigh));
1447 }
1448 if (warningLowAlarm)
1449 {
1450 assertions.set(
1451 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1452 lowerNonCriticalGoingLow));
1453 }
1454 }
1455 if (criticalInterface != sensorMap.end())
1456 {
1457 auto& criticalMap = criticalInterface->second;
1458
1459 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1460 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1461 auto criticalHighAlarm = false;
1462 auto criticalLowAlarm = false;
1463
1464 if (criticalHigh != criticalMap.end())
1465 {
1466 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1467 }
1468 if (criticalLow != criticalMap.end())
1469 {
1470 criticalLowAlarm = std::get<bool>(criticalLow->second);
1471 }
1472 if (criticalHighAlarm)
1473 {
1474 assertions.set(
1475 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1476 upperCriticalGoingHigh));
1477 }
1478 if (criticalLowAlarm)
1479 {
1480 assertions.set(static_cast<size_t>(
1481 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1482 }
1483 }
1484 }
1485
1486 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1487}
1488
Willy Tu38e7a2b2021-03-29 15:09:56 -07001489// Construct a type 1 SDR for threshold sensor.
Hao Jiange39d4d82021-04-16 17:02:40 -07001490void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1491 get_sdr::SensorDataFullRecord& record)
Willy Tude54f482021-01-26 15:59:09 -08001492{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001493 get_sdr::header::set_record_id(
1494 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1495
Willy Tu38e7a2b2021-03-29 15:09:56 -07001496 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1497 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1498
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001499 record.header.sdr_version = ipmiSdrVersion;
1500 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1501 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1502 sizeof(get_sdr::SensorDataRecordHeader);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001503 record.key.owner_id = bmcI2CAddr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001504 record.key.owner_lun = lun;
1505 record.key.sensor_number = sensornumber;
Hao Jiange39d4d82021-04-16 17:02:40 -07001506}
1507bool constructSensorSdr(ipmi::Context::ptr ctx, uint16_t sensorNum,
1508 uint16_t recordID, const std::string& service,
1509 const std::string& path,
1510 get_sdr::SensorDataFullRecord& record)
1511{
1512 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1513 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1514
1515 DbusInterfaceMap sensorMap;
1516 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1517 {
1518 phosphor::logging::log<phosphor::logging::level::ERR>(
1519 "Failed to update sensor map for threshold sensor",
1520 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1521 phosphor::logging::entry("PATH=%s", path.c_str()));
1522 return false;
1523 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001524
1525 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1526 record.body.sensor_type = getSensorTypeFromPath(path);
1527 std::string type = getSensorTypeStringFromPath(path);
1528 auto typeCstr = type.c_str();
1529 auto findUnits = sensorUnits.find(typeCstr);
1530 if (findUnits != sensorUnits.end())
1531 {
1532 record.body.sensor_units_2_base =
1533 static_cast<uint8_t>(findUnits->second);
1534 } // else default 0x0 unspecified
1535
1536 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1537
Hao Jiangd2afd052020-12-10 15:09:32 -08001538 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001539 if (sensorObject == sensorMap.end())
1540 {
1541 phosphor::logging::log<phosphor::logging::level::ERR>(
1542 "getSensorDataRecord: sensorObject error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001543 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001544 }
1545
1546 uint8_t entityId = 0;
1547 uint8_t entityInstance = 0x01;
1548
1549 // follow the association chain to get the parent board's entityid and
1550 // entityInstance
1551 updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
1552
1553 record.body.entity_id = entityId;
1554 record.body.entity_instance = entityInstance;
1555
Shakeeb Pasha93889722021-10-14 10:20:13 +05301556 double max = 0;
1557 double min = 0;
1558 getSensorMaxMin(sensorMap, max, min);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001559
1560 int16_t mValue = 0;
1561 int8_t rExp = 0;
1562 int16_t bValue = 0;
1563 int8_t bExp = 0;
1564 bool bSigned = false;
1565
1566 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1567 {
1568 phosphor::logging::log<phosphor::logging::level::ERR>(
1569 "getSensorDataRecord: getSensorAttributes error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001570 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001571 }
1572
1573 // The record.body is a struct SensorDataFullRecordBody
1574 // from sensorhandler.hpp in phosphor-ipmi-host.
1575 // The meaning of these bits appears to come from
1576 // table 43.1 of the IPMI spec.
1577 // The above 5 sensor attributes are stuffed in as follows:
1578 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1579 // Byte 22-24 are for other purposes
1580 // Byte 25 = MMMMMMMM = LSB of M
1581 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1582 // Byte 27 = BBBBBBBB = LSB of B
1583 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1584 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1585 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1586
1587 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1588 record.body.m_lsb = mValue & 0xFF;
1589
1590 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1591 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1592
1593 // move the smallest bit of the MSB into place (bit 9)
1594 // the MSbs are bits 7:8 in m_msb_and_tolerance
1595 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1596
1597 record.body.b_lsb = bValue & 0xFF;
1598
1599 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1600 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1601
1602 // move the smallest bit of the MSB into place (bit 9)
1603 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1604 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1605
1606 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1607 uint8_t rExpBits = rExp & 0x07;
1608
1609 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1610 uint8_t bExpBits = bExp & 0x07;
1611
1612 // move rExp and bExp into place
1613 record.body.r_b_exponents =
1614 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1615
1616 // Set the analog reading byte interpretation accordingly
1617 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1618
1619 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1620 // These seem redundant, but derivable from the above 5 attributes
1621 // Original comment said "todo fill out rest of units"
1622
1623 // populate sensor name from path
Willy Tu38e7a2b2021-03-29 15:09:56 -07001624 auto name = sensor::parseSdrIdFromPath(path);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001625 record.body.id_string_info = name.size();
1626 std::strncpy(record.body.id_string, name.c_str(),
1627 sizeof(record.body.id_string));
1628
Josh Lehana55c9532020-10-28 21:59:06 -07001629 // Remember the sensor name, as determined for this sensor number
1630 details::sdrStatsTable.updateName(sensornumber, name);
1631
Jie Yangf0a89942021-07-29 15:30:25 -07001632 bool sensorSettable = false;
1633 auto mutability =
1634 sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability");
1635 if (mutability != sensorMap.end())
1636 {
1637 sensorSettable =
1638 mappedVariant<bool>(mutability->second, "Mutable", false);
1639 }
1640 get_sdr::body::init_settable_state(sensorSettable, &record.body);
1641
1642 // Grant write permission to sensors deemed externally settable
1643 details::sdrWriteTable.setWritePermission(sensornumber, sensorSettable);
Willy Tu530e2772021-07-02 14:42:06 -07001644
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001645 IPMIThresholds thresholdData;
1646 try
1647 {
1648 thresholdData = getIPMIThresholds(sensorMap);
1649 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001650 catch (const std::exception&)
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001651 {
1652 phosphor::logging::log<phosphor::logging::level::ERR>(
1653 "getSensorDataRecord: getIPMIThresholds error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001654 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001655 }
1656
1657 if (thresholdData.criticalHigh)
1658 {
1659 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1660 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1661 IPMISensorEventEnableThresholds::criticalThreshold);
1662 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1663 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1664 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1665 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1666 record.body.discrete_reading_setting_mask[0] |=
1667 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1668 }
1669 if (thresholdData.warningHigh)
1670 {
1671 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1672 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1673 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1674 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1675 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1676 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1677 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1678 record.body.discrete_reading_setting_mask[0] |=
1679 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1680 }
1681 if (thresholdData.criticalLow)
1682 {
1683 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1684 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1685 IPMISensorEventEnableThresholds::criticalThreshold);
1686 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1687 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1688 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1689 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1690 record.body.discrete_reading_setting_mask[0] |=
1691 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1692 }
1693 if (thresholdData.warningLow)
1694 {
1695 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1696 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1697 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1698 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1699 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1700 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1701 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1702 record.body.discrete_reading_setting_mask[0] |=
1703 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1704 }
1705
1706 // everything that is readable is setable
1707 record.body.discrete_reading_setting_mask[1] =
1708 record.body.discrete_reading_setting_mask[0];
Willy Tu38e7a2b2021-03-29 15:09:56 -07001709 return true;
1710}
1711
Scron Chang2703b022021-07-06 15:47:45 +08001712#ifdef FEATURE_HYBRID_SENSORS
1713// Construct a type 1 SDR for discrete Sensor typed sensor.
1714void constructStaticSensorSdr(ipmi::Context::ptr ctx, uint16_t sensorNum,
1715 uint16_t recordID,
1716 ipmi::sensor::IdInfoMap::const_iterator sensor,
1717 get_sdr::SensorDataFullRecord& record)
1718{
1719 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1720
1721 record.body.entity_id = sensor->second.entityType;
1722 record.body.sensor_type = sensor->second.sensorType;
1723 record.body.event_reading_type = sensor->second.sensorReadingType;
1724 record.body.entity_instance = sensor->second.instance;
1725 if (ipmi::sensor::Mutability::Write ==
1726 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
1727 {
1728 get_sdr::body::init_settable_state(true, &(record.body));
1729 }
1730
1731 auto id_string = sensor->second.sensorName;
1732
1733 if (id_string.empty())
1734 {
1735 id_string = sensor->second.sensorNameFunc(sensor->second);
1736 }
1737
1738 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
1739 {
1740 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH,
1741 &(record.body));
1742 }
1743 else
1744 {
1745 get_sdr::body::set_id_strlen(id_string.length(), &(record.body));
1746 }
1747 std::strncpy(record.body.id_string, id_string.c_str(),
1748 get_sdr::body::get_id_strlen(&(record.body)));
1749}
1750#endif
1751
Hao Jiange39d4d82021-04-16 17:02:40 -07001752// Construct type 3 SDR header and key (for VR and other discrete sensors)
1753void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1754 get_sdr::SensorDataEventRecord& record)
Willy Tu61992ad2021-03-29 15:33:20 -07001755{
1756 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1757 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1758
1759 get_sdr::header::set_record_id(
1760 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1761
1762 record.header.sdr_version = ipmiSdrVersion;
1763 record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD;
1764 record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) -
1765 sizeof(get_sdr::SensorDataRecordHeader);
1766 record.key.owner_id = bmcI2CAddr;
1767 record.key.owner_lun = lun;
1768 record.key.sensor_number = sensornumber;
1769
1770 record.body.entity_id = 0x00;
1771 record.body.entity_instance = 0x01;
Hao Jiange39d4d82021-04-16 17:02:40 -07001772}
Willy Tu61992ad2021-03-29 15:33:20 -07001773
Hao Jiange39d4d82021-04-16 17:02:40 -07001774// Construct a type 3 SDR for VR typed sensor(daemon).
1775bool constructVrSdr(ipmi::Context::ptr ctx, uint16_t sensorNum,
1776 uint16_t recordID, const std::string& service,
1777 const std::string& path,
1778 get_sdr::SensorDataEventRecord& record)
1779{
1780 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1781 constructEventSdrHeaderKey(sensorNum, recordID, record);
1782
1783 DbusInterfaceMap sensorMap;
1784 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1785 {
1786 phosphor::logging::log<phosphor::logging::level::ERR>(
1787 "Failed to update sensor map for VR sensor",
1788 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1789 phosphor::logging::entry("PATH=%s", path.c_str()));
1790 return false;
1791 }
Willy Tu61992ad2021-03-29 15:33:20 -07001792 // follow the association chain to get the parent board's entityid and
1793 // entityInstance
1794 updateIpmiFromAssociation(path, sensorMap, record.body.entity_id,
1795 record.body.entity_instance);
1796
1797 // Sensor type is hardcoded as a module/board type instead of parsing from
1798 // sensor path. This is because VR control is allocated in an independent
1799 // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by
1800 // types.
1801 static constexpr const uint8_t module_board_type = 0x15;
1802 record.body.sensor_type = module_board_type;
1803 record.body.event_reading_type = 0x00;
1804
1805 record.body.sensor_record_sharing_1 = 0x00;
1806 record.body.sensor_record_sharing_2 = 0x00;
1807
1808 // populate sensor name from path
1809 auto name = sensor::parseSdrIdFromPath(path);
1810 int nameSize = std::min(name.size(), sizeof(record.body.id_string));
1811 record.body.id_string_info = nameSize;
1812 std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string));
1813 std::memcpy(record.body.id_string, name.c_str(), nameSize);
1814
1815 // Remember the sensor name, as determined for this sensor number
1816 details::sdrStatsTable.updateName(sensornumber, name);
Hao Jiange39d4d82021-04-16 17:02:40 -07001817
1818 return true;
Willy Tu61992ad2021-03-29 15:33:20 -07001819}
1820
Hao Jiange39d4d82021-04-16 17:02:40 -07001821static int
1822 getSensorDataRecord(ipmi::Context::ptr ctx,
1823 std::vector<uint8_t>& recordData, uint16_t recordID,
1824 uint8_t readBytes = std::numeric_limits<uint8_t>::max())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001825{
1826 size_t fruCount = 0;
1827 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1828 if (ret != ipmi::ccSuccess)
1829 {
1830 phosphor::logging::log<phosphor::logging::level::ERR>(
1831 "getSensorDataRecord: getFruSdrCount error");
1832 return GENERAL_ERROR;
1833 }
1834
1835 auto& sensorTree = getSensorTree();
1836 size_t lastRecord =
1837 sensorTree.size() + fruCount + ipmi::storage::type12Count + -1;
1838 if (recordID == lastRecordIndex)
1839 {
1840 recordID = lastRecord;
1841 }
1842 if (recordID > lastRecord)
1843 {
1844 phosphor::logging::log<phosphor::logging::level::ERR>(
1845 "getSensorDataRecord: recordID > lastRecord error");
1846 return GENERAL_ERROR;
1847 }
1848
1849 if (recordID >= sensorTree.size())
1850 {
1851 size_t fruIndex = recordID - sensorTree.size();
1852
1853 if (fruIndex >= fruCount)
1854 {
1855 // handle type 12 hardcoded records
1856 size_t type12Index = fruIndex - fruCount;
1857 if (type12Index >= ipmi::storage::type12Count)
1858 {
1859 phosphor::logging::log<phosphor::logging::level::ERR>(
1860 "getSensorDataRecord: type12Index error");
1861 return GENERAL_ERROR;
1862 }
1863 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
1864 }
1865 else
1866 {
1867 // handle fru records
1868 get_sdr::SensorDataFruRecord data;
1869 ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
1870 if (ret != IPMI_CC_OK)
1871 {
1872 return GENERAL_ERROR;
1873 }
1874 data.header.record_id_msb = recordID >> 8;
1875 data.header.record_id_lsb = recordID & 0xFF;
1876 recordData.insert(recordData.end(), (uint8_t*)&data,
1877 ((uint8_t*)&data) + sizeof(data));
1878 }
1879
1880 return 0;
1881 }
1882
1883 std::string connection;
1884 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -07001885 std::vector<std::string> interfaces;
1886
1887 auto status =
1888 getSensorConnection(ctx, recordID, connection, path, &interfaces);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001889 if (status)
1890 {
1891 phosphor::logging::log<phosphor::logging::level::ERR>(
1892 "getSensorDataRecord: getSensorConnection error");
1893 return GENERAL_ERROR;
1894 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07001895 uint16_t sensorNum = getSensorNumberFromPath(path);
1896 if (sensorNum == invalidSensorNumber)
1897 {
1898 phosphor::logging::log<phosphor::logging::level::ERR>(
1899 "getSensorDataRecord: invalidSensorNumber");
1900 return GENERAL_ERROR;
1901 }
1902
Willy Tu38e7a2b2021-03-29 15:09:56 -07001903 // Construct full record (SDR type 1) for the threshold sensors
Hao Jiange39d4d82021-04-16 17:02:40 -07001904 if (std::find(interfaces.begin(), interfaces.end(),
1905 sensor::sensorInterface) != interfaces.end())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001906 {
1907 get_sdr::SensorDataFullRecord record = {0};
1908
Hao Jiange39d4d82021-04-16 17:02:40 -07001909 // If the request doesn't read SDR body, construct only header and key
1910 // part to avoid additional DBus transaction.
1911 if (readBytes <= sizeof(record.header) + sizeof(record.key))
1912 {
1913 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1914 }
1915 else if (!constructSensorSdr(ctx, sensorNum, recordID, connection, path,
1916 record))
Willy Tu38e7a2b2021-03-29 15:09:56 -07001917 {
1918 return GENERAL_ERROR;
1919 }
Hao Jiange39d4d82021-04-16 17:02:40 -07001920
Willy Tu38e7a2b2021-03-29 15:09:56 -07001921 recordData.insert(recordData.end(), (uint8_t*)&record,
1922 ((uint8_t*)&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07001923
1924 return 0;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001925 }
Willy Tu61992ad2021-03-29 15:33:20 -07001926
Scron Chang2703b022021-07-06 15:47:45 +08001927#ifdef FEATURE_HYBRID_SENSORS
1928 if (auto sensor = findStaticSensor(path);
1929 sensor != ipmi::sensor::sensors.end() &&
1930 getSensorEventTypeFromPath(path) !=
1931 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1932 {
1933 get_sdr::SensorDataFullRecord record = {0};
1934
1935 // If the request doesn't read SDR body, construct only header and key
1936 // part to avoid additional DBus transaction.
1937 if (readBytes <= sizeof(record.header) + sizeof(record.key))
1938 {
1939 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1940 }
1941 else
1942 {
1943 constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record);
1944 }
1945
1946 recordData.insert(recordData.end(), (uint8_t*)&record,
1947 ((uint8_t*)&record) + sizeof(record));
1948
1949 return 0;
1950 }
1951#endif
1952
Willy Tu61992ad2021-03-29 15:33:20 -07001953 // Contruct SDR type 3 record for VR sensor (daemon)
Hao Jiange39d4d82021-04-16 17:02:40 -07001954 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
1955 interfaces.end())
Willy Tu61992ad2021-03-29 15:33:20 -07001956 {
1957 get_sdr::SensorDataEventRecord record = {0};
1958
Hao Jiange39d4d82021-04-16 17:02:40 -07001959 // If the request doesn't read SDR body, construct only header and key
1960 // part to avoid additional DBus transaction.
1961 if (readBytes <= sizeof(record.header) + sizeof(record.key))
1962 {
1963 constructEventSdrHeaderKey(sensorNum, recordID, record);
1964 }
1965 else if (!constructVrSdr(ctx, sensorNum, recordID, connection, path,
1966 record))
1967 {
1968 return GENERAL_ERROR;
1969 }
Willy Tu61992ad2021-03-29 15:33:20 -07001970 recordData.insert(recordData.end(), (uint8_t*)&record,
1971 ((uint8_t*)&record) + sizeof(record));
1972 }
1973
Willy Tude54f482021-01-26 15:59:09 -08001974 return 0;
1975}
1976
1977/** @brief implements the get SDR Info command
1978 * @param count - Operation
1979 *
1980 * @returns IPMI completion code plus response data
1981 * - sdrCount - sensor/SDR count
1982 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
1983 */
1984static ipmi::RspType<uint8_t, // respcount
1985 uint8_t, // dynamic population flags
1986 uint32_t // last time a sensor was added
1987 >
1988 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
1989 std::optional<uint8_t> count)
1990{
1991 auto& sensorTree = getSensorTree();
1992 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001993 uint16_t recordID = 0;
1994 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08001995 // Sensors are dynamically allocated, and there is at least one LUN
1996 uint8_t lunsAndDynamicPopulation = 0x80;
1997 constexpr uint8_t getSdrCount = 0x01;
1998 constexpr uint8_t getSensorCount = 0x00;
1999
2000 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
2001 {
2002 return ipmi::responseResponseError();
2003 }
Willy Tude54f482021-01-26 15:59:09 -08002004 uint16_t numSensors = sensorTree.size();
2005 if (count.value_or(0) == getSdrCount)
2006 {
2007 // Count the number of Type 1 SDR entries assigned to the LUN
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002008 while (!getSensorDataRecord(ctx, record, recordID++))
Willy Tude54f482021-01-26 15:59:09 -08002009 {
2010 get_sdr::SensorDataRecordHeader* hdr =
2011 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002012 record.data());
Willy Tude54f482021-01-26 15:59:09 -08002013 if (hdr && hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
2014 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002015 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08002016 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002017 record.data());
2018 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08002019 {
2020 sdrCount++;
2021 }
2022 }
2023 }
2024 }
2025 else if (count.value_or(0) == getSensorCount)
2026 {
2027 // Return the number of sensors attached to the LUN
2028 if ((ctx->lun == 0) && (numSensors > 0))
2029 {
2030 sdrCount =
2031 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
2032 }
2033 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
2034 {
2035 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
2036 ? maxSensorsPerLUN
2037 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
2038 }
2039 else if (ctx->lun == 3)
2040 {
2041 if (numSensors <= maxIPMISensors)
2042 {
2043 sdrCount =
2044 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
2045 }
2046 else
2047 {
2048 // error
2049 throw std::out_of_range(
2050 "Maximum number of IPMI sensors exceeded.");
2051 }
2052 }
2053 }
2054 else
2055 {
2056 return ipmi::responseInvalidFieldRequest();
2057 }
2058
2059 // Get Sensor count. This returns the number of sensors
2060 if (numSensors > 0)
2061 {
2062 lunsAndDynamicPopulation |= 1;
2063 }
2064 if (numSensors > maxSensorsPerLUN)
2065 {
2066 lunsAndDynamicPopulation |= 2;
2067 }
2068 if (numSensors >= (maxSensorsPerLUN * 2))
2069 {
2070 lunsAndDynamicPopulation |= 8;
2071 }
2072 if (numSensors > maxIPMISensors)
2073 {
2074 // error
2075 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
2076 }
2077
2078 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
2079 sdrLastAdd);
2080}
2081
2082/* end sensor commands */
2083
2084/* storage commands */
2085
2086ipmi::RspType<uint8_t, // sdr version
2087 uint16_t, // record count
2088 uint16_t, // free space
2089 uint32_t, // most recent addition
2090 uint32_t, // most recent erase
2091 uint8_t // operationSupport
2092 >
2093 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
2094{
2095 auto& sensorTree = getSensorTree();
2096 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002097 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002098 {
2099 return ipmi::responseResponseError();
2100 }
2101
2102 size_t fruCount = 0;
2103 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2104 if (ret != ipmi::ccSuccess)
2105 {
2106 return ipmi::response(ret);
2107 }
2108
2109 uint16_t recordCount =
2110 sensorTree.size() + fruCount + ipmi::storage::type12Count;
2111
2112 uint8_t operationSupport = static_cast<uint8_t>(
2113 SdrRepositoryInfoOps::overflow); // write not supported
2114
2115 operationSupport |=
2116 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
2117 operationSupport |= static_cast<uint8_t>(
2118 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
2119 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
2120 unspecifiedFreeSpace, sdrLastAdd,
2121 sdrLastRemove, operationSupport);
2122}
2123
2124/** @brief implements the get SDR allocation info command
2125 *
2126 * @returns IPMI completion code plus response data
2127 * - allocUnits - Number of possible allocation units
2128 * - allocUnitSize - Allocation unit size in bytes.
2129 * - allocUnitFree - Number of free allocation units
2130 * - allocUnitLargestFree - Largest free block in allocation units
2131 * - maxRecordSize - Maximum record size in allocation units.
2132 */
2133ipmi::RspType<uint16_t, // allocUnits
2134 uint16_t, // allocUnitSize
2135 uint16_t, // allocUnitFree
2136 uint16_t, // allocUnitLargestFree
2137 uint8_t // maxRecordSize
2138 >
2139 ipmiStorageGetSDRAllocationInfo()
2140{
2141 // 0000h unspecified number of alloc units
2142 constexpr uint16_t allocUnits = 0;
2143
2144 constexpr uint16_t allocUnitFree = 0;
2145 constexpr uint16_t allocUnitLargestFree = 0;
2146 // only allow one block at a time
2147 constexpr uint8_t maxRecordSize = 1;
2148
2149 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
2150 allocUnitLargestFree, maxRecordSize);
2151}
2152
2153/** @brief implements the reserve SDR command
2154 * @returns IPMI completion code plus response data
2155 * - sdrReservationID
2156 */
2157ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
2158{
2159 sdrReservationID++;
2160 if (sdrReservationID == 0)
2161 {
2162 sdrReservationID++;
2163 }
2164
2165 return ipmi::responseSuccess(sdrReservationID);
2166}
2167
2168ipmi::RspType<uint16_t, // next record ID
2169 std::vector<uint8_t> // payload
2170 >
2171 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
2172 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
2173{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002174 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08002175 // reservation required for partial reads with non zero offset into
2176 // record
2177 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
2178 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08002181 return ipmi::responseInvalidReservationId();
2182 }
Willy Tude54f482021-01-26 15:59:09 -08002183 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2184 if (ret != ipmi::ccSuccess)
2185 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002186 phosphor::logging::log<phosphor::logging::level::ERR>(
2187 "ipmiStorageGetSDR: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08002188 return ipmi::response(ret);
2189 }
2190
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002191 auto& sensorTree = getSensorTree();
Willy Tude54f482021-01-26 15:59:09 -08002192 size_t lastRecord =
2193 sensorTree.size() + fruCount + ipmi::storage::type12Count - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002194 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
2195
2196 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002197 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002198 phosphor::logging::log<phosphor::logging::level::ERR>(
2199 "ipmiStorageGetSDR: getSensorSubtree error");
2200 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08002201 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002202
2203 std::vector<uint8_t> record;
Hao Jiange39d4d82021-04-16 17:02:40 -07002204 if (getSensorDataRecord(ctx, record, recordID, offset + bytesToRead))
Willy Tude54f482021-01-26 15:59:09 -08002205 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002206 phosphor::logging::log<phosphor::logging::level::ERR>(
2207 "ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08002208 return ipmi::responseInvalidFieldRequest();
2209 }
Willy Tude54f482021-01-26 15:59:09 -08002210 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002211 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08002212 if (!hdr)
2213 {
2214 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002215 "ipmiStorageGetSDR: record header is null");
2216 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002217 }
2218
2219 size_t sdrLength =
2220 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
2221 if (sdrLength < (offset + bytesToRead))
2222 {
2223 bytesToRead = sdrLength - offset;
2224 }
2225
2226 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
2227 if (!respStart)
2228 {
2229 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002230 "ipmiStorageGetSDR: record is null");
2231 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002232 }
2233
2234 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002235
Willy Tude54f482021-01-26 15:59:09 -08002236 return ipmi::responseSuccess(nextRecordId, recordData);
2237}
2238/* end storage commands */
2239
2240void registerSensorFunctions()
2241{
2242 // <Platform Event>
2243 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2244 ipmi::sensor_event::cmdPlatformEvent,
2245 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
2246
Willy Tudbafbce2021-03-29 00:37:05 -07002247 // <Set Sensor Reading and Event Status>
2248 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2249 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
2250 ipmi::Privilege::Operator, ipmiSetSensorReading);
Willy Tudbafbce2021-03-29 00:37:05 -07002251
Willy Tude54f482021-01-26 15:59:09 -08002252 // <Get Sensor Reading>
2253 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2254 ipmi::sensor_event::cmdGetSensorReading,
2255 ipmi::Privilege::User, ipmiSenGetSensorReading);
2256
2257 // <Get Sensor Threshold>
2258 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2259 ipmi::sensor_event::cmdGetSensorThreshold,
2260 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
2261
2262 // <Set Sensor Threshold>
2263 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2264 ipmi::sensor_event::cmdSetSensorThreshold,
2265 ipmi::Privilege::Operator,
2266 ipmiSenSetSensorThresholds);
2267
2268 // <Get Sensor Event Enable>
2269 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2270 ipmi::sensor_event::cmdGetSensorEventEnable,
2271 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
2272
2273 // <Get Sensor Event Status>
2274 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2275 ipmi::sensor_event::cmdGetSensorEventStatus,
2276 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
2277
2278 // register all storage commands for both Sensor and Storage command
2279 // versions
2280
2281 // <Get SDR Repository Info>
2282 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2283 ipmi::storage::cmdGetSdrRepositoryInfo,
2284 ipmi::Privilege::User,
2285 ipmiStorageGetSDRRepositoryInfo);
2286
2287 // <Get Device SDR Info>
2288 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2289 ipmi::sensor_event::cmdGetDeviceSdrInfo,
2290 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
2291
2292 // <Get SDR Allocation Info>
2293 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2294 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
2295 ipmi::Privilege::User,
2296 ipmiStorageGetSDRAllocationInfo);
2297
2298 // <Reserve SDR Repo>
2299 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2300 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
2301 ipmi::Privilege::User, ipmiStorageReserveSDR);
2302
2303 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2304 ipmi::storage::cmdReserveSdrRepository,
2305 ipmi::Privilege::User, ipmiStorageReserveSDR);
2306
2307 // <Get Sdr>
2308 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2309 ipmi::sensor_event::cmdGetDeviceSdr,
2310 ipmi::Privilege::User, ipmiStorageGetSDR);
2311
2312 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2313 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
2314 ipmiStorageGetSDR);
2315}
2316} // namespace ipmi