blob: 9ccf7e74864d43f3969f989144f04aedf7521027 [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"
Harvey Wu05d17c02021-09-15 08:46:59 +080022#include "entity_map_json.hpp"
Willy Tude54f482021-01-26 15:59:09 -080023
24#include <algorithm>
25#include <array>
26#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
28#include <chrono>
29#include <cmath>
30#include <cstring>
31#include <iostream>
32#include <ipmid/api.hpp>
33#include <ipmid/types.hpp>
34#include <ipmid/utils.hpp>
35#include <map>
36#include <memory>
37#include <optional>
38#include <phosphor-logging/log.hpp>
39#include <sdbusplus/bus.hpp>
40#include <stdexcept>
41#include <string>
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +000042#include <user_channel/channel_layer.hpp>
Willy Tude54f482021-01-26 15:59:09 -080043#include <utility>
44#include <variant>
45
Scron Chang2703b022021-07-06 15:47:45 +080046#ifdef FEATURE_HYBRID_SENSORS
47
48#include "sensordatahandler.hpp"
49namespace ipmi
50{
51namespace sensor
52{
53extern const IdInfoMap sensors;
54} // namespace sensor
55} // namespace ipmi
56#endif
adarshgrami042e9db2022-09-15 10:34:34 +053057namespace ipmi
58{
59namespace dcmi
60{
61// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
62static const std::map<uint8_t, uint8_t> validEntityId{
63 {0x40, 0x37}, {0x37, 0x40}, {0x41, 0x03},
64 {0x03, 0x41}, {0x42, 0x07}, {0x07, 0x42}};
65constexpr uint8_t temperatureSensorType = 0x01;
66constexpr uint8_t maxRecords = 8;
67} // namespace dcmi
68} // namespace ipmi
JeffLind950f412021-10-20 18:49:34 +080069constexpr std::array<const char*, 7> suffixes = {
70 "_Output_Voltage", "_Input_Voltage", "_Output_Current", "_Input_Current",
71 "_Output_Power", "_Input_Power", "_Temperature"};
Willy Tude54f482021-01-26 15:59:09 -080072namespace ipmi
73{
Hao Jiangd48c9212021-02-03 15:45:06 -080074
75using phosphor::logging::entry;
76using phosphor::logging::level;
77using phosphor::logging::log;
78
Willy Tude54f482021-01-26 15:59:09 -080079static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu9ab2f942020-07-15 17:56:21 -070080static constexpr int sensorMapSdrUpdatePeriod = 60;
Willy Tude54f482021-01-26 15:59:09 -080081
Willy Tu38e7a2b2021-03-29 15:09:56 -070082// BMC I2C address is generally at 0x20
83static constexpr uint8_t bmcI2CAddr = 0x20;
84
Willy Tude54f482021-01-26 15:59:09 -080085constexpr size_t maxSDRTotalSize =
86 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
87constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
88
89static uint16_t sdrReservationID;
90static uint32_t sdrLastAdd = noTimestamp;
91static uint32_t sdrLastRemove = noTimestamp;
92static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey6619ae42021-08-06 11:21:10 -070093
94// The IPMI spec defines four Logical Units (LUN), each capable of supporting
95// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
96// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
97// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
98// location.
99static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
100
101static constexpr size_t lun0MaxSensorNum = 0xfe;
102static constexpr size_t lun1MaxSensorNum = 0x1fe;
103static constexpr size_t lun3MaxSensorNum = 0x3fe;
Willy Tude54f482021-01-26 15:59:09 -0800104static constexpr int GENERAL_ERROR = -1;
105
Willy Tude54f482021-01-26 15:59:09 -0800106static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
107
108// Specify the comparison required to sort and find char* map objects
109struct CmpStr
110{
111 bool operator()(const char* a, const char* b) const
112 {
113 return std::strcmp(a, b) < 0;
114 }
115};
116const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
117 sensorUnits{{{"temperature", SensorUnits::degreesC},
118 {"voltage", SensorUnits::volts},
119 {"current", SensorUnits::amps},
120 {"fan_tach", SensorUnits::rpm},
121 {"power", SensorUnits::watts}}};
122
123void registerSensorFunctions() __attribute__((constructor));
124
Patrick Williams5d82f472022-07-22 19:26:53 -0500125static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800126 *getSdBus(),
127 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
128 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500129 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800130 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700131 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800132 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
133 std::chrono::system_clock::now().time_since_epoch())
134 .count();
135 });
136
Patrick Williams5d82f472022-07-22 19:26:53 -0500137static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800138 *getSdBus(),
139 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
140 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500141 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800142 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700143 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800144 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
145 std::chrono::system_clock::now().time_since_epoch())
146 .count();
147 });
148
149// this keeps track of deassertions for sensor event status command. A
150// deasertion can only happen if an assertion was seen first.
151static boost::container::flat_map<
152 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
153 thresholdDeassertMap;
154
Patrick Williams5d82f472022-07-22 19:26:53 -0500155static sdbusplus::bus::match_t thresholdChanged(
Willy Tude54f482021-01-26 15:59:09 -0800156 *getSdBus(),
157 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
158 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500159 [](sdbusplus::message_t& m) {
Willy Tude54f482021-01-26 15:59:09 -0800160 boost::container::flat_map<std::string, std::variant<bool, double>>
161 values;
162 m.read(std::string(), values);
163
164 auto findAssert =
165 std::find_if(values.begin(), values.end(), [](const auto& pair) {
166 return pair.first.find("Alarm") != std::string::npos;
167 });
168 if (findAssert != values.end())
169 {
170 auto ptr = std::get_if<bool>(&(findAssert->second));
171 if (ptr == nullptr)
172 {
173 phosphor::logging::log<phosphor::logging::level::ERR>(
174 "thresholdChanged: Assert non bool");
175 return;
176 }
177 if (*ptr)
178 {
179 phosphor::logging::log<phosphor::logging::level::INFO>(
180 "thresholdChanged: Assert",
181 phosphor::logging::entry("SENSOR=%s", m.get_path()));
182 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
183 }
184 else
185 {
186 auto& value =
187 thresholdDeassertMap[m.get_path()][findAssert->first];
188 if (value)
189 {
190 phosphor::logging::log<phosphor::logging::level::INFO>(
191 "thresholdChanged: deassert",
192 phosphor::logging::entry("SENSOR=%s", m.get_path()));
193 value = *ptr;
194 }
195 }
196 }
197 });
198
Hao Jiangd2afd052020-12-10 15:09:32 -0800199namespace sensor
200{
201static constexpr const char* vrInterface =
202 "xyz.openbmc_project.Control.VoltageRegulatorMode";
203static constexpr const char* sensorInterface =
204 "xyz.openbmc_project.Sensor.Value";
205} // namespace sensor
206
Willy Tude54f482021-01-26 15:59:09 -0800207static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
208 double& min)
209{
210 max = 127;
211 min = -128;
212
Hao Jiangd2afd052020-12-10 15:09:32 -0800213 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800214 auto critical =
215 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
216 auto warning =
217 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
218
219 if (sensorObject != sensorMap.end())
220 {
221 auto maxMap = sensorObject->second.find("MaxValue");
222 auto minMap = sensorObject->second.find("MinValue");
223
224 if (maxMap != sensorObject->second.end())
225 {
226 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
227 }
228 if (minMap != sensorObject->second.end())
229 {
230 min = std::visit(VariantToDoubleVisitor(), minMap->second);
231 }
232 }
233 if (critical != sensorMap.end())
234 {
235 auto lower = critical->second.find("CriticalLow");
236 auto upper = critical->second.find("CriticalHigh");
237 if (lower != critical->second.end())
238 {
239 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300240 if (std::isfinite(value))
241 {
242 min = std::min(value, min);
243 }
Willy Tude54f482021-01-26 15:59:09 -0800244 }
245 if (upper != critical->second.end())
246 {
247 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300248 if (std::isfinite(value))
249 {
250 max = std::max(value, max);
251 }
Willy Tude54f482021-01-26 15:59:09 -0800252 }
253 }
254 if (warning != sensorMap.end())
255 {
256
257 auto lower = warning->second.find("WarningLow");
258 auto upper = warning->second.find("WarningHigh");
259 if (lower != warning->second.end())
260 {
261 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300262 if (std::isfinite(value))
263 {
264 min = std::min(value, min);
265 }
Willy Tude54f482021-01-26 15:59:09 -0800266 }
267 if (upper != warning->second.end())
268 {
269 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300270 if (std::isfinite(value))
271 {
272 max = std::max(value, max);
273 }
Willy Tude54f482021-01-26 15:59:09 -0800274 }
275 }
276}
277
278static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700279 std::string sensorPath, DbusInterfaceMap& sensorMap,
280 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800281{
Scron Chang2703b022021-07-06 15:47:45 +0800282#ifdef FEATURE_HYBRID_SENSORS
283 if (auto sensor = findStaticSensor(sensorPath);
284 sensor != ipmi::sensor::sensors.end() &&
285 getSensorEventTypeFromPath(sensorPath) !=
286 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
287 {
288 // If the incoming sensor is a discrete sensor, it might fail in
289 // getManagedObjects(), return true, and use its own getFunc to get
290 // value.
291 return true;
292 }
293#endif
294
Willy Tude54f482021-01-26 15:59:09 -0800295 static boost::container::flat_map<
296 std::string, std::chrono::time_point<std::chrono::steady_clock>>
297 updateTimeMap;
298
299 auto updateFind = updateTimeMap.find(sensorConnection);
300 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
301 if (updateFind != updateTimeMap.end())
302 {
303 lastUpdate = updateFind->second;
304 }
305
306 auto now = std::chrono::steady_clock::now();
307
308 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700309 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800310 {
Willy Tude54f482021-01-26 15:59:09 -0800311 ObjectValueTree managedObjects;
Ed Tanous9a9ac0b2022-10-04 17:18:57 -0700312 boost::system::error_code ec =
313 getManagedObjects(ctx, sensorConnection.c_str(),
314 "/xyz/openbmc_project/sensors", managedObjects);
Willy Tude54f482021-01-26 15:59:09 -0800315 if (ec)
316 {
317 phosphor::logging::log<phosphor::logging::level::ERR>(
318 "GetMangagedObjects for getSensorMap failed",
319 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
320
321 return false;
322 }
323
324 SensorCache[sensorConnection] = managedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700325 // Update time after finish building the map which allow the
326 // data to be cached for updatePeriod plus the build time.
327 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800328 }
329 auto connection = SensorCache.find(sensorConnection);
330 if (connection == SensorCache.end())
331 {
332 return false;
333 }
334 auto path = connection->second.find(sensorPath);
335 if (path == connection->second.end())
336 {
337 return false;
338 }
339 sensorMap = path->second;
340
341 return true;
342}
343
Hao Jiangd2afd052020-12-10 15:09:32 -0800344namespace sensor
345{
Hao Jiangd48c9212021-02-03 15:45:06 -0800346// Read VR profiles from sensor(daemon) interface
347static std::optional<std::vector<std::string>>
348 getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object)
Hao Jiangd2afd052020-12-10 15:09:32 -0800349{
350 // get VR mode profiles from Supported Interface
Hao Jiangd48c9212021-02-03 15:45:06 -0800351 auto supportedProperty = object.find("Supported");
352 if (supportedProperty == object.end() ||
353 object.find("Selected") == object.end())
Hao Jiangd2afd052020-12-10 15:09:32 -0800354 {
355 phosphor::logging::log<phosphor::logging::level::ERR>(
356 "Missing the required Supported and Selected properties");
357 return std::nullopt;
358 }
359
360 const auto profilesPtr =
361 std::get_if<std::vector<std::string>>(&supportedProperty->second);
362
363 if (profilesPtr == nullptr)
364 {
365 phosphor::logging::log<phosphor::logging::level::ERR>(
366 "property is not array of string");
367 return std::nullopt;
368 }
Hao Jiangd48c9212021-02-03 15:45:06 -0800369 return *profilesPtr;
370}
371
372// Calculate VR Mode from input IPMI discrete event bytes
373static std::optional<std::string>
374 calculateVRMode(uint15_t assertOffset,
375 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
376{
377 // get VR mode profiles from Supported Interface
378 auto profiles = getSupportedVrProfiles(VRObject);
379 if (!profiles)
380 {
381 return std::nullopt;
382 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800383
384 // interpret IPMI cmd bits into profiles' index
385 long unsigned int index = 0;
386 // only one bit should be set and the highest bit should not be used.
387 if (assertOffset == 0 || assertOffset == (1u << 15) ||
388 (assertOffset & (assertOffset - 1)))
389 {
390 phosphor::logging::log<phosphor::logging::level::ERR>(
391 "IPMI cmd format incorrect",
392
393 phosphor::logging::entry("BYTES=%#02x",
394 static_cast<uint16_t>(assertOffset)));
395 return std::nullopt;
396 }
397
398 while (assertOffset != 1)
399 {
400 assertOffset >>= 1;
401 index++;
402 }
403
Hao Jiangd48c9212021-02-03 15:45:06 -0800404 if (index >= profiles->size())
Hao Jiangd2afd052020-12-10 15:09:32 -0800405 {
406 phosphor::logging::log<phosphor::logging::level::ERR>(
407 "profile index out of boundary");
408 return std::nullopt;
409 }
410
Hao Jiangd48c9212021-02-03 15:45:06 -0800411 return profiles->at(index);
Hao Jiangd2afd052020-12-10 15:09:32 -0800412}
413
414// Calculate sensor value from IPMI reading byte
415static std::optional<double>
416 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
417 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
418{
419 if (valueObject.find("Value") == valueObject.end())
420 {
421 phosphor::logging::log<phosphor::logging::level::ERR>(
422 "Missing the required Value property");
423 return std::nullopt;
424 }
425
426 double max = 0;
427 double min = 0;
428 getSensorMaxMin(sensorMap, max, min);
429
430 int16_t mValue = 0;
431 int16_t bValue = 0;
432 int8_t rExp = 0;
433 int8_t bExp = 0;
434 bool bSigned = false;
435
436 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
437 {
438 return std::nullopt;
439 }
440
441 double value = bSigned ? ((int8_t)reading) : reading;
442
443 value *= ((double)mValue);
444 value += ((double)bValue) * std::pow(10.0, bExp);
445 value *= std::pow(10.0, rExp);
446
447 return value;
448}
449
Willy Tu38e7a2b2021-03-29 15:09:56 -0700450// Extract file name from sensor path as the sensors SDR ID. Simplify the name
451// if it is too long.
452std::string parseSdrIdFromPath(const std::string& path)
453{
454 std::string name;
455 size_t nameStart = path.rfind("/");
456 if (nameStart != std::string::npos)
457 {
458 name = path.substr(nameStart + 1, std::string::npos - nameStart);
459 }
460
Willy Tu38e7a2b2021-03-29 15:09:56 -0700461 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
462 {
463 // try to not truncate by replacing common words
JeffLind950f412021-10-20 18:49:34 +0800464 for (const auto& suffix : suffixes)
Willy Tu38e7a2b2021-03-29 15:09:56 -0700465 {
JeffLind950f412021-10-20 18:49:34 +0800466 if (boost::ends_with(name, suffix))
467 {
468 boost::replace_all(name, suffix, "");
469 break;
470 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700471 }
Duke Du97014f52021-12-16 17:21:01 +0800472 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
473 {
474 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
475 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700476 }
JeffLind950f412021-10-20 18:49:34 +0800477 std::replace(name.begin(), name.end(), '_', ' ');
Willy Tu38e7a2b2021-03-29 15:09:56 -0700478 return name;
479}
480
Hao Jiangd48c9212021-02-03 15:45:06 -0800481bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection,
482 const std::string& path,
483 const ipmi::DbusInterfaceMap::mapped_type& object,
484 std::bitset<16>& assertions)
485{
486 auto profiles = sensor::getSupportedVrProfiles(object);
487 if (!profiles)
488 {
489 return false;
490 }
Willy Tu8366f0b2022-04-29 05:00:17 -0700491 std::string mode;
Hao Jiangd48c9212021-02-03 15:45:06 -0800492
493 auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface,
Willy Tu8366f0b2022-04-29 05:00:17 -0700494 "Selected", mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800495 if (ec)
496 {
497 log<level::ERR>("Failed to get property",
498 entry("PROPERTY=%s", "Selected"),
499 entry("PATH=%s", path.c_str()),
500 entry("INTERFACE=%s", sensor::sensorInterface),
501 entry("WHAT=%s", ec.message().c_str()));
502 return false;
503 }
504
Willy Tu8366f0b2022-04-29 05:00:17 -0700505 auto itr = std::find(profiles->begin(), profiles->end(), mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800506 if (itr == profiles->end())
507 {
508 using namespace phosphor::logging;
509 log<level::ERR>("VR mode doesn't match any of its profiles",
510 entry("PATH=%s", path.c_str()));
511 return false;
512 }
513 std::size_t index =
514 static_cast<std::size_t>(std::distance(profiles->begin(), itr));
515
Willy Tubef102a2022-06-09 15:36:09 -0700516 // map index to response event assertion bit.
517 if (index < 16)
Hao Jiangd48c9212021-02-03 15:45:06 -0800518 {
Willy Tubef102a2022-06-09 15:36:09 -0700519 assertions.set(index);
Hao Jiangd48c9212021-02-03 15:45:06 -0800520 }
521 else
522 {
523 log<level::ERR>("VR profile index reaches max assertion bit",
524 entry("PATH=%s", path.c_str()),
525 entry("INDEX=%uz", index));
526 return false;
527 }
528 if constexpr (debug)
529 {
530 std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path)
Willy Tu8366f0b2022-04-29 05:00:17 -0700531 << " mode is: [" << index << "] " << mode << std::endl;
Hao Jiangd48c9212021-02-03 15:45:06 -0800532 }
533 return true;
534}
Hao Jiangd2afd052020-12-10 15:09:32 -0800535} // namespace sensor
536
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000537ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
538 ipmi::message::Payload& p)
Willy Tude54f482021-01-26 15:59:09 -0800539{
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000540 constexpr const uint8_t validEnvmRev = 0x04;
541 constexpr const uint8_t lastSensorType = 0x2C;
542 constexpr const uint8_t oemReserved = 0xC0;
543
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700544 uint8_t sysgeneratorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000545 uint8_t evmRev = 0;
546 uint8_t sensorType = 0;
547 uint8_t sensorNum = 0;
548 uint8_t eventType = 0;
549 uint8_t eventData1 = 0;
550 std::optional<uint8_t> eventData2 = 0;
551 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700552 [[maybe_unused]] uint16_t generatorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000553 ipmi::ChannelInfo chInfo;
554
555 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
556 {
557 phosphor::logging::log<phosphor::logging::level::ERR>(
558 "Failed to get Channel Info",
559 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
560 return ipmi::responseUnspecifiedError();
561 }
562
563 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
564 ipmi::EChannelMediumType::systemInterface)
565 {
566
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700567 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000568 eventData1, eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700569 // Refer to IPMI Spec Table 32: SEL Event Records
570 generatorID = (ctx->channel << 12) // Channel
571 | (0x0 << 10) // Reserved
572 | (0x0 << 8) // 0x0 for sys-soft ID
573 | ((sysgeneratorID << 1) | 0x1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000574 }
575 else
576 {
577
578 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
579 eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700580 // Refer to IPMI Spec Table 32: SEL Event Records
581 generatorID = (ctx->channel << 12) // Channel
582 | (0x0 << 10) // Reserved
583 | ((ctx->lun & 0x3) << 8) // Lun
584 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000585 }
586
587 if (!p.fullyUnpacked())
588 {
589 return ipmi::responseReqDataLenInvalid();
590 }
591
592 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
593 if (evmRev != validEnvmRev)
594 {
595 return ipmi::responseInvalidFieldRequest();
596 }
597 if ((sensorType > lastSensorType) && (sensorType < oemReserved))
598 {
599 return ipmi::responseInvalidFieldRequest();
600 }
601
Willy Tude54f482021-01-26 15:59:09 -0800602 return ipmi::responseSuccess();
603}
604
Willy Tudbafbce2021-03-29 00:37:05 -0700605ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
Willy Tu11d68892022-01-20 10:37:34 -0800606 uint8_t sensorNumber, uint8_t,
Willy Tudbafbce2021-03-29 00:37:05 -0700607 uint8_t reading, uint15_t assertOffset,
Willy Tu11d68892022-01-20 10:37:34 -0800608 bool, uint15_t, bool, uint8_t, uint8_t,
609 uint8_t)
Willy Tudbafbce2021-03-29 00:37:05 -0700610{
611 std::string connection;
612 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -0700613 std::vector<std::string> interfaces;
614
615 ipmi::Cc status =
616 getSensorConnection(ctx, sensorNumber, connection, path, &interfaces);
Willy Tudbafbce2021-03-29 00:37:05 -0700617 if (status)
618 {
619 return ipmi::response(status);
620 }
621
Hao Jiangd2afd052020-12-10 15:09:32 -0800622 // we can tell the sensor type by its interface type
Hao Jiange39d4d82021-04-16 17:02:40 -0700623 if (std::find(interfaces.begin(), interfaces.end(),
624 sensor::sensorInterface) != interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700625 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700626 DbusInterfaceMap sensorMap;
627 if (!getSensorMap(ctx, connection, path, sensorMap))
628 {
629 return ipmi::responseResponseError();
630 }
631 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800632 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700633 {
634 return ipmi::responseResponseError();
635 }
636
Jie Yangf0a89942021-07-29 15:30:25 -0700637 // Only allow external SetSensor if write permission granted
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800638 if (!details::sdrWriteTable.getWritePermission((ctx->lun << 8) |
639 sensorNumber))
Jie Yangf0a89942021-07-29 15:30:25 -0700640 {
641 return ipmi::responseResponseError();
642 }
643
Hao Jiangd2afd052020-12-10 15:09:32 -0800644 auto value =
645 sensor::calculateValue(reading, sensorMap, sensorObject->second);
646 if (!value)
647 {
648 return ipmi::responseResponseError();
649 }
650
651 if constexpr (debug)
652 {
653 phosphor::logging::log<phosphor::logging::level::INFO>(
654 "IPMI SET_SENSOR",
655 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber),
656 phosphor::logging::entry("BYTE=%u", (unsigned int)reading),
657 phosphor::logging::entry("VALUE=%f", *value));
658 }
659
660 boost::system::error_code ec =
661 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
662 "Value", ipmi::Value(*value));
663
664 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500665 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800666 // callback functions for now (e.g. ipmiSetSensorReading).
667 if (ec)
668 {
669 using namespace phosphor::logging;
670 log<level::ERR>("Failed to set property",
671 entry("PROPERTY=%s", "Value"),
672 entry("PATH=%s", path.c_str()),
673 entry("INTERFACE=%s", sensor::sensorInterface),
674 entry("WHAT=%s", ec.message().c_str()));
675 return ipmi::responseResponseError();
676 }
677 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700678 }
679
Hao Jiange39d4d82021-04-16 17:02:40 -0700680 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
681 interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700682 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700683 DbusInterfaceMap sensorMap;
684 if (!getSensorMap(ctx, connection, path, sensorMap))
685 {
686 return ipmi::responseResponseError();
687 }
688 auto sensorObject = sensorMap.find(sensor::vrInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800689 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700690 {
691 return ipmi::responseResponseError();
692 }
693
Hao Jiangd2afd052020-12-10 15:09:32 -0800694 // VR sensors are treated as a special case and we will not check the
695 // write permission for VR sensors, since they always deemed writable
696 // and permission table are not applied to VR sensors.
697 auto vrMode =
698 sensor::calculateVRMode(assertOffset, sensorObject->second);
699 if (!vrMode)
700 {
701 return ipmi::responseResponseError();
702 }
703 boost::system::error_code ec = setDbusProperty(
704 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
705 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500706 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800707 // callback functions for now (e.g. ipmiSetSensorReading).
708 if (ec)
709 {
710 using namespace phosphor::logging;
711 log<level::ERR>("Failed to set property",
712 entry("PROPERTY=%s", "Selected"),
713 entry("PATH=%s", path.c_str()),
714 entry("INTERFACE=%s", sensor::sensorInterface),
715 entry("WHAT=%s", ec.message().c_str()));
716 return ipmi::responseResponseError();
717 }
718 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700719 }
720
Hao Jiangd2afd052020-12-10 15:09:32 -0800721 phosphor::logging::log<phosphor::logging::level::ERR>(
722 "unknown sensor type",
723 phosphor::logging::entry("PATH=%s", path.c_str()));
724 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700725}
726
Willy Tude54f482021-01-26 15:59:09 -0800727ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
728 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
729{
730 std::string connection;
731 std::string path;
732
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000733 if (sensnum == reservedSensorNumber)
734 {
735 return ipmi::responseInvalidFieldRequest();
736 }
737
Willy Tude54f482021-01-26 15:59:09 -0800738 auto status = getSensorConnection(ctx, sensnum, connection, path);
739 if (status)
740 {
741 return ipmi::response(status);
742 }
743
Scron Chang2703b022021-07-06 15:47:45 +0800744#ifdef FEATURE_HYBRID_SENSORS
745 if (auto sensor = findStaticSensor(path);
746 sensor != ipmi::sensor::sensors.end() &&
747 getSensorEventTypeFromPath(path) !=
748 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
749 {
750 if (ipmi::sensor::Mutability::Read !=
751 (sensor->second.mutability & ipmi::sensor::Mutability::Read))
752 {
753 return ipmi::responseIllegalCommand();
754 }
755
756 uint8_t operation;
757 try
758 {
759 ipmi::sensor::GetSensorResponse getResponse =
760 sensor->second.getFunc(sensor->second);
761
762 if (getResponse.readingOrStateUnavailable)
763 {
764 operation |= static_cast<uint8_t>(
765 IPMISensorReadingByte2::readingStateUnavailable);
766 }
767 if (getResponse.scanningEnabled)
768 {
769 operation |= static_cast<uint8_t>(
770 IPMISensorReadingByte2::sensorScanningEnable);
771 }
772 if (getResponse.allEventMessagesEnabled)
773 {
774 operation |= static_cast<uint8_t>(
775 IPMISensorReadingByte2::eventMessagesEnable);
776 }
777 return ipmi::responseSuccess(
778 getResponse.reading, operation,
779 getResponse.thresholdLevelsStates,
780 getResponse.discreteReadingSensorStates);
781 }
782 catch (const std::exception& e)
783 {
784 operation |= static_cast<uint8_t>(
785 IPMISensorReadingByte2::readingStateUnavailable);
786 return ipmi::responseSuccess(0, operation, 0, std::nullopt);
787 }
788 }
789#endif
790
Willy Tude54f482021-01-26 15:59:09 -0800791 DbusInterfaceMap sensorMap;
792 if (!getSensorMap(ctx, connection, path, sensorMap))
793 {
794 return ipmi::responseResponseError();
795 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800796 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800797
798 if (sensorObject == sensorMap.end() ||
799 sensorObject->second.find("Value") == sensorObject->second.end())
800 {
801 return ipmi::responseResponseError();
802 }
803 auto& valueVariant = sensorObject->second["Value"];
804 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
805
806 double max = 0;
807 double min = 0;
808 getSensorMaxMin(sensorMap, max, min);
809
810 int16_t mValue = 0;
811 int16_t bValue = 0;
812 int8_t rExp = 0;
813 int8_t bExp = 0;
814 bool bSigned = false;
815
816 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
817 {
818 return ipmi::responseResponseError();
819 }
820
821 uint8_t value =
822 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
823 uint8_t operation =
824 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
825 operation |=
826 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
827 bool notReading = std::isnan(reading);
828
829 if (!notReading)
830 {
831 auto availableObject =
832 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
833 if (availableObject != sensorMap.end())
834 {
835 auto findAvailable = availableObject->second.find("Available");
836 if (findAvailable != availableObject->second.end())
837 {
838 bool* available = std::get_if<bool>(&(findAvailable->second));
839 if (available && !(*available))
840 {
841 notReading = true;
842 }
843 }
844 }
845 }
846
847 if (notReading)
848 {
849 operation |= static_cast<uint8_t>(
850 IPMISensorReadingByte2::readingStateUnavailable);
851 }
852
Josh Lehana55c9532020-10-28 21:59:06 -0700853 if constexpr (details::enableInstrumentation)
854 {
855 int byteValue;
856 if (bSigned)
857 {
858 byteValue = static_cast<int>(static_cast<int8_t>(value));
859 }
860 else
861 {
862 byteValue = static_cast<int>(static_cast<uint8_t>(value));
863 }
864
865 // Keep stats on the reading just obtained, even if it is "NaN"
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800866 if (details::sdrStatsTable.updateReading((ctx->lun << 8) | sensnum,
867 reading, byteValue))
Josh Lehana55c9532020-10-28 21:59:06 -0700868 {
869 // This is the first reading, show the coefficients
870 double step = (max - min) / 255.0;
871 std::cerr << "IPMI sensor "
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800872 << details::sdrStatsTable.getName((ctx->lun << 8) |
873 sensnum)
Josh Lehana55c9532020-10-28 21:59:06 -0700874 << ": Range min=" << min << " max=" << max
875 << ", step=" << step
876 << ", Coefficients mValue=" << static_cast<int>(mValue)
877 << " rExp=" << static_cast<int>(rExp)
878 << " bValue=" << static_cast<int>(bValue)
879 << " bExp=" << static_cast<int>(bExp)
880 << " bSigned=" << static_cast<int>(bSigned) << "\n";
881 }
882 }
883
Willy Tude54f482021-01-26 15:59:09 -0800884 uint8_t thresholds = 0;
885
886 auto warningObject =
887 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
888 if (warningObject != sensorMap.end())
889 {
890 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
891 auto alarmLow = warningObject->second.find("WarningAlarmLow");
892 if (alarmHigh != warningObject->second.end())
893 {
894 if (std::get<bool>(alarmHigh->second))
895 {
896 thresholds |= static_cast<uint8_t>(
897 IPMISensorReadingByte3::upperNonCritical);
898 }
899 }
900 if (alarmLow != warningObject->second.end())
901 {
902 if (std::get<bool>(alarmLow->second))
903 {
904 thresholds |= static_cast<uint8_t>(
905 IPMISensorReadingByte3::lowerNonCritical);
906 }
907 }
908 }
909
910 auto criticalObject =
911 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
912 if (criticalObject != sensorMap.end())
913 {
914 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
915 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
916 if (alarmHigh != criticalObject->second.end())
917 {
918 if (std::get<bool>(alarmHigh->second))
919 {
920 thresholds |=
921 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
922 }
923 }
924 if (alarmLow != criticalObject->second.end())
925 {
926 if (std::get<bool>(alarmLow->second))
927 {
928 thresholds |=
929 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
930 }
931 }
932 }
933
934 // no discrete as of today so optional byte is never returned
935 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
936}
937
938/** @brief implements the Set Sensor threshold command
939 * @param sensorNumber - sensor number
940 * @param lowerNonCriticalThreshMask
941 * @param lowerCriticalThreshMask
942 * @param lowerNonRecovThreshMask
943 * @param upperNonCriticalThreshMask
944 * @param upperCriticalThreshMask
945 * @param upperNonRecovThreshMask
946 * @param reserved
947 * @param lowerNonCritical - lower non-critical threshold
948 * @param lowerCritical - Lower critical threshold
949 * @param lowerNonRecoverable - Lower non recovarable threshold
950 * @param upperNonCritical - Upper non-critical threshold
951 * @param upperCritical - Upper critical
952 * @param upperNonRecoverable - Upper Non-recoverable
953 *
954 * @returns IPMI completion code
955 */
956ipmi::RspType<> ipmiSenSetSensorThresholds(
957 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
958 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
959 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
960 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800961 uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
Willy Tude54f482021-01-26 15:59:09 -0800962 uint8_t upperNonCritical, uint8_t upperCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800963 [[maybe_unused]] uint8_t upperNonRecoverable)
Willy Tude54f482021-01-26 15:59:09 -0800964{
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000965 if (sensorNum == reservedSensorNumber || reserved)
Willy Tude54f482021-01-26 15:59:09 -0800966 {
967 return ipmi::responseInvalidFieldRequest();
968 }
969
970 // lower nc and upper nc not suppported on any sensor
971 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
972 {
973 return ipmi::responseInvalidFieldRequest();
974 }
975
976 // if none of the threshold mask are set, nothing to do
977 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
978 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
979 upperCriticalThreshMask | upperNonRecovThreshMask))
980 {
981 return ipmi::responseSuccess();
982 }
983
984 std::string connection;
985 std::string path;
986
987 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
988 if (status)
989 {
990 return ipmi::response(status);
991 }
992 DbusInterfaceMap sensorMap;
993 if (!getSensorMap(ctx, connection, path, sensorMap))
994 {
995 return ipmi::responseResponseError();
996 }
997
998 double max = 0;
999 double min = 0;
1000 getSensorMaxMin(sensorMap, max, min);
1001
1002 int16_t mValue = 0;
1003 int16_t bValue = 0;
1004 int8_t rExp = 0;
1005 int8_t bExp = 0;
1006 bool bSigned = false;
1007
1008 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1009 {
1010 return ipmi::responseResponseError();
1011 }
1012
1013 // store a vector of property name, value to set, and interface
1014 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
1015
1016 // define the indexes of the tuple
1017 constexpr uint8_t propertyName = 0;
1018 constexpr uint8_t thresholdValue = 1;
1019 constexpr uint8_t interface = 2;
1020 // verifiy all needed fields are present
1021 if (lowerCriticalThreshMask || upperCriticalThreshMask)
1022 {
1023 auto findThreshold =
1024 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1025 if (findThreshold == sensorMap.end())
1026 {
1027 return ipmi::responseInvalidFieldRequest();
1028 }
1029 if (lowerCriticalThreshMask)
1030 {
1031 auto findLower = findThreshold->second.find("CriticalLow");
1032 if (findLower == findThreshold->second.end())
1033 {
1034 return ipmi::responseInvalidFieldRequest();
1035 }
1036 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
1037 findThreshold->first);
1038 }
1039 if (upperCriticalThreshMask)
1040 {
1041 auto findUpper = findThreshold->second.find("CriticalHigh");
1042 if (findUpper == findThreshold->second.end())
1043 {
1044 return ipmi::responseInvalidFieldRequest();
1045 }
1046 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
1047 findThreshold->first);
1048 }
1049 }
1050 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
1051 {
1052 auto findThreshold =
1053 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1054 if (findThreshold == sensorMap.end())
1055 {
1056 return ipmi::responseInvalidFieldRequest();
1057 }
1058 if (lowerNonCriticalThreshMask)
1059 {
1060 auto findLower = findThreshold->second.find("WarningLow");
1061 if (findLower == findThreshold->second.end())
1062 {
1063 return ipmi::responseInvalidFieldRequest();
1064 }
1065 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
1066 findThreshold->first);
1067 }
1068 if (upperNonCriticalThreshMask)
1069 {
1070 auto findUpper = findThreshold->second.find("WarningHigh");
1071 if (findUpper == findThreshold->second.end())
1072 {
1073 return ipmi::responseInvalidFieldRequest();
1074 }
1075 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
1076 findThreshold->first);
1077 }
1078 }
1079 for (const auto& property : thresholdsToSet)
1080 {
1081 // from section 36.3 in the IPMI Spec, assume all linear
1082 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
1083 (bValue * std::pow(10.0, bExp))) *
1084 std::pow(10.0, rExp);
1085 setDbusProperty(
1086 *getSdBus(), connection, path, std::get<interface>(property),
1087 std::get<propertyName>(property), ipmi::Value(valueToSet));
1088 }
1089 return ipmi::responseSuccess();
1090}
1091
1092IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
1093{
1094 IPMIThresholds resp;
1095 auto warningInterface =
1096 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1097 auto criticalInterface =
1098 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1099
1100 if ((warningInterface != sensorMap.end()) ||
1101 (criticalInterface != sensorMap.end()))
1102 {
Hao Jiangd2afd052020-12-10 15:09:32 -08001103 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -08001104
1105 if (sensorPair == sensorMap.end())
1106 {
1107 // should not have been able to find a sensor not implementing
1108 // the sensor object
1109 throw std::runtime_error("Invalid sensor map");
1110 }
1111
1112 double max = 0;
1113 double min = 0;
1114 getSensorMaxMin(sensorMap, max, min);
1115
1116 int16_t mValue = 0;
1117 int16_t bValue = 0;
1118 int8_t rExp = 0;
1119 int8_t bExp = 0;
1120 bool bSigned = false;
1121
1122 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1123 {
1124 throw std::runtime_error("Invalid sensor atrributes");
1125 }
1126 if (warningInterface != sensorMap.end())
1127 {
1128 auto& warningMap = warningInterface->second;
1129
1130 auto warningHigh = warningMap.find("WarningHigh");
1131 auto warningLow = warningMap.find("WarningLow");
1132
1133 if (warningHigh != warningMap.end())
1134 {
1135
1136 double value =
1137 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001138 if (std::isfinite(value))
1139 {
1140 resp.warningHigh = scaleIPMIValueFromDouble(
1141 value, mValue, rExp, bValue, bExp, bSigned);
1142 }
Willy Tude54f482021-01-26 15:59:09 -08001143 }
1144 if (warningLow != warningMap.end())
1145 {
1146 double value =
1147 std::visit(VariantToDoubleVisitor(), warningLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001148 if (std::isfinite(value))
1149 {
1150 resp.warningLow = scaleIPMIValueFromDouble(
1151 value, mValue, rExp, bValue, bExp, bSigned);
1152 }
Willy Tude54f482021-01-26 15:59:09 -08001153 }
1154 }
1155 if (criticalInterface != sensorMap.end())
1156 {
1157 auto& criticalMap = criticalInterface->second;
1158
1159 auto criticalHigh = criticalMap.find("CriticalHigh");
1160 auto criticalLow = criticalMap.find("CriticalLow");
1161
1162 if (criticalHigh != criticalMap.end())
1163 {
1164 double value =
1165 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001166 if (std::isfinite(value))
1167 {
1168 resp.criticalHigh = scaleIPMIValueFromDouble(
1169 value, mValue, rExp, bValue, bExp, bSigned);
1170 }
Willy Tude54f482021-01-26 15:59:09 -08001171 }
1172 if (criticalLow != criticalMap.end())
1173 {
1174 double value =
1175 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001176 if (std::isfinite(value))
1177 {
1178 resp.criticalLow = scaleIPMIValueFromDouble(
1179 value, mValue, rExp, bValue, bExp, bSigned);
1180 }
Willy Tude54f482021-01-26 15:59:09 -08001181 }
1182 }
1183 }
1184 return resp;
1185}
1186
1187ipmi::RspType<uint8_t, // readable
1188 uint8_t, // lowerNCrit
1189 uint8_t, // lowerCrit
1190 uint8_t, // lowerNrecoverable
1191 uint8_t, // upperNC
1192 uint8_t, // upperCrit
1193 uint8_t> // upperNRecoverable
1194 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
1195{
1196 std::string connection;
1197 std::string path;
1198
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001199 if (sensorNumber == reservedSensorNumber)
1200 {
1201 return ipmi::responseInvalidFieldRequest();
1202 }
1203
Willy Tude54f482021-01-26 15:59:09 -08001204 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
1205 if (status)
1206 {
1207 return ipmi::response(status);
1208 }
1209
1210 DbusInterfaceMap sensorMap;
1211 if (!getSensorMap(ctx, connection, path, sensorMap))
1212 {
1213 return ipmi::responseResponseError();
1214 }
1215
1216 IPMIThresholds thresholdData;
1217 try
1218 {
1219 thresholdData = getIPMIThresholds(sensorMap);
1220 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001221 catch (const std::exception&)
Willy Tude54f482021-01-26 15:59:09 -08001222 {
1223 return ipmi::responseResponseError();
1224 }
1225
1226 uint8_t readable = 0;
1227 uint8_t lowerNC = 0;
1228 uint8_t lowerCritical = 0;
1229 uint8_t lowerNonRecoverable = 0;
1230 uint8_t upperNC = 0;
1231 uint8_t upperCritical = 0;
1232 uint8_t upperNonRecoverable = 0;
1233
1234 if (thresholdData.warningHigh)
1235 {
1236 readable |=
1237 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
1238 upperNC = *thresholdData.warningHigh;
1239 }
1240 if (thresholdData.warningLow)
1241 {
1242 readable |=
1243 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
1244 lowerNC = *thresholdData.warningLow;
1245 }
1246
1247 if (thresholdData.criticalHigh)
1248 {
1249 readable |=
1250 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
1251 upperCritical = *thresholdData.criticalHigh;
1252 }
1253 if (thresholdData.criticalLow)
1254 {
1255 readable |=
1256 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
1257 lowerCritical = *thresholdData.criticalLow;
1258 }
1259
1260 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
1261 lowerNonRecoverable, upperNC, upperCritical,
1262 upperNonRecoverable);
1263}
1264
1265/** @brief implements the get Sensor event enable command
1266 * @param sensorNumber - sensor number
1267 *
1268 * @returns IPMI completion code plus response data
1269 * - enabled - Sensor Event messages
1270 * - assertionEnabledLsb - Assertion event messages
1271 * - assertionEnabledMsb - Assertion event messages
1272 * - deassertionEnabledLsb - Deassertion event messages
1273 * - deassertionEnabledMsb - Deassertion event messages
1274 */
1275
1276ipmi::RspType<uint8_t, // enabled
1277 uint8_t, // assertionEnabledLsb
1278 uint8_t, // assertionEnabledMsb
1279 uint8_t, // deassertionEnabledLsb
1280 uint8_t> // deassertionEnabledMsb
1281 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
1282{
1283 std::string connection;
1284 std::string path;
1285
1286 uint8_t enabled = 0;
1287 uint8_t assertionEnabledLsb = 0;
1288 uint8_t assertionEnabledMsb = 0;
1289 uint8_t deassertionEnabledLsb = 0;
1290 uint8_t deassertionEnabledMsb = 0;
1291
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001292 if (sensorNum == reservedSensorNumber)
1293 {
1294 return ipmi::responseInvalidFieldRequest();
1295 }
1296
Willy Tude54f482021-01-26 15:59:09 -08001297 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1298 if (status)
1299 {
1300 return ipmi::response(status);
1301 }
1302
Scron Chang2703b022021-07-06 15:47:45 +08001303#ifdef FEATURE_HYBRID_SENSORS
1304 if (auto sensor = findStaticSensor(path);
1305 sensor != ipmi::sensor::sensors.end() &&
1306 getSensorEventTypeFromPath(path) !=
1307 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1308 {
1309 enabled = static_cast<uint8_t>(
1310 IPMISensorEventEnableByte2::sensorScanningEnable);
1311 uint16_t assertionEnabled = 0;
1312 for (auto& offsetValMap : sensor->second.propertyInterfaces.begin()
1313 ->second.begin()
1314 ->second.second)
1315 {
1316 assertionEnabled |= (1 << offsetValMap.first);
1317 }
1318 assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF));
1319 assertionEnabledMsb =
1320 static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF));
1321
1322 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1323 assertionEnabledMsb, deassertionEnabledLsb,
1324 deassertionEnabledMsb);
1325 }
1326#endif
1327
Willy Tude54f482021-01-26 15:59:09 -08001328 DbusInterfaceMap sensorMap;
1329 if (!getSensorMap(ctx, connection, path, sensorMap))
1330 {
1331 return ipmi::responseResponseError();
1332 }
1333
1334 auto warningInterface =
1335 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1336 auto criticalInterface =
1337 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1338 if ((warningInterface != sensorMap.end()) ||
1339 (criticalInterface != sensorMap.end()))
1340 {
1341 enabled = static_cast<uint8_t>(
1342 IPMISensorEventEnableByte2::sensorScanningEnable);
1343 if (warningInterface != sensorMap.end())
1344 {
1345 auto& warningMap = warningInterface->second;
1346
1347 auto warningHigh = warningMap.find("WarningHigh");
1348 auto warningLow = warningMap.find("WarningLow");
1349 if (warningHigh != warningMap.end())
1350 {
1351 assertionEnabledLsb |= static_cast<uint8_t>(
1352 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1353 deassertionEnabledLsb |= static_cast<uint8_t>(
1354 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
1355 }
1356 if (warningLow != warningMap.end())
1357 {
1358 assertionEnabledLsb |= static_cast<uint8_t>(
1359 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1360 deassertionEnabledLsb |= static_cast<uint8_t>(
1361 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
1362 }
1363 }
1364 if (criticalInterface != sensorMap.end())
1365 {
1366 auto& criticalMap = criticalInterface->second;
1367
1368 auto criticalHigh = criticalMap.find("CriticalHigh");
1369 auto criticalLow = criticalMap.find("CriticalLow");
1370
1371 if (criticalHigh != criticalMap.end())
1372 {
1373 assertionEnabledMsb |= static_cast<uint8_t>(
1374 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1375 deassertionEnabledMsb |= static_cast<uint8_t>(
1376 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1377 }
1378 if (criticalLow != criticalMap.end())
1379 {
1380 assertionEnabledLsb |= static_cast<uint8_t>(
1381 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1382 deassertionEnabledLsb |= static_cast<uint8_t>(
1383 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1384 }
1385 }
1386 }
1387
1388 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1389 assertionEnabledMsb, deassertionEnabledLsb,
1390 deassertionEnabledMsb);
1391}
1392
1393/** @brief implements the get Sensor event status command
1394 * @param sensorNumber - sensor number, FFh = reserved
1395 *
1396 * @returns IPMI completion code plus response data
1397 * - sensorEventStatus - Sensor Event messages state
1398 * - assertions - Assertion event messages
1399 * - deassertions - Deassertion event messages
1400 */
1401ipmi::RspType<uint8_t, // sensorEventStatus
1402 std::bitset<16>, // assertions
1403 std::bitset<16> // deassertion
1404 >
1405 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1406{
1407 if (sensorNum == reservedSensorNumber)
1408 {
1409 return ipmi::responseInvalidFieldRequest();
1410 }
1411
1412 std::string connection;
1413 std::string path;
1414 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1415 if (status)
1416 {
1417 phosphor::logging::log<phosphor::logging::level::ERR>(
1418 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1419 phosphor::logging::entry("SENSOR=%d", sensorNum));
1420 return ipmi::response(status);
1421 }
1422
Scron Chang2703b022021-07-06 15:47:45 +08001423#ifdef FEATURE_HYBRID_SENSORS
1424 if (auto sensor = findStaticSensor(path);
1425 sensor != ipmi::sensor::sensors.end() &&
1426 getSensorEventTypeFromPath(path) !=
1427 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1428 {
1429 auto response = ipmi::sensor::get::mapDbusToAssertion(
1430 sensor->second, path, sensor->second.sensorInterface);
1431 std::bitset<16> assertions;
1432 // deassertions are not used.
1433 std::bitset<16> deassertions = 0;
1434 uint8_t sensorEventStatus;
1435 if (response.readingOrStateUnavailable)
1436 {
1437 sensorEventStatus |= static_cast<uint8_t>(
1438 IPMISensorReadingByte2::readingStateUnavailable);
1439 }
1440 if (response.scanningEnabled)
1441 {
1442 sensorEventStatus |= static_cast<uint8_t>(
1443 IPMISensorReadingByte2::sensorScanningEnable);
1444 }
1445 if (response.allEventMessagesEnabled)
1446 {
1447 sensorEventStatus |= static_cast<uint8_t>(
1448 IPMISensorReadingByte2::eventMessagesEnable);
1449 }
1450 assertions |= response.discreteReadingSensorStates << 8;
1451 assertions |= response.thresholdLevelsStates;
1452 return ipmi::responseSuccess(sensorEventStatus, assertions,
1453 deassertions);
1454 }
1455#endif
1456
Willy Tude54f482021-01-26 15:59:09 -08001457 DbusInterfaceMap sensorMap;
1458 if (!getSensorMap(ctx, connection, path, sensorMap))
1459 {
1460 phosphor::logging::log<phosphor::logging::level::ERR>(
1461 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1462 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1463 return ipmi::responseResponseError();
1464 }
Hao Jiangd48c9212021-02-03 15:45:06 -08001465
1466 uint8_t sensorEventStatus =
1467 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1468 std::bitset<16> assertions = 0;
1469 std::bitset<16> deassertions = 0;
1470
1471 // handle VR typed sensor
1472 auto vrInterface = sensorMap.find(sensor::vrInterface);
1473 if (vrInterface != sensorMap.end())
1474 {
1475 if (!sensor::getVrEventStatus(ctx, connection, path,
1476 vrInterface->second, assertions))
1477 {
1478 return ipmi::responseResponseError();
1479 }
1480
1481 // both Event Message and Sensor Scanning are disable for VR.
1482 sensorEventStatus = 0;
1483 return ipmi::responseSuccess(sensorEventStatus, assertions,
1484 deassertions);
1485 }
1486
Willy Tude54f482021-01-26 15:59:09 -08001487 auto warningInterface =
1488 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1489 auto criticalInterface =
1490 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1491
Willy Tude54f482021-01-26 15:59:09 -08001492 std::optional<bool> criticalDeassertHigh =
1493 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1494 std::optional<bool> criticalDeassertLow =
1495 thresholdDeassertMap[path]["CriticalAlarmLow"];
1496 std::optional<bool> warningDeassertHigh =
1497 thresholdDeassertMap[path]["WarningAlarmHigh"];
1498 std::optional<bool> warningDeassertLow =
1499 thresholdDeassertMap[path]["WarningAlarmLow"];
1500
Willy Tude54f482021-01-26 15:59:09 -08001501 if (criticalDeassertHigh && !*criticalDeassertHigh)
1502 {
1503 deassertions.set(static_cast<size_t>(
1504 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1505 }
1506 if (criticalDeassertLow && !*criticalDeassertLow)
1507 {
1508 deassertions.set(static_cast<size_t>(
1509 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1510 }
1511 if (warningDeassertHigh && !*warningDeassertHigh)
1512 {
1513 deassertions.set(static_cast<size_t>(
1514 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1515 }
1516 if (warningDeassertLow && !*warningDeassertLow)
1517 {
1518 deassertions.set(static_cast<size_t>(
1519 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1520 }
1521 if ((warningInterface != sensorMap.end()) ||
1522 (criticalInterface != sensorMap.end()))
1523 {
1524 sensorEventStatus = static_cast<size_t>(
1525 IPMISensorEventEnableByte2::eventMessagesEnable);
1526 if (warningInterface != sensorMap.end())
1527 {
1528 auto& warningMap = warningInterface->second;
1529
1530 auto warningHigh = warningMap.find("WarningAlarmHigh");
1531 auto warningLow = warningMap.find("WarningAlarmLow");
1532 auto warningHighAlarm = false;
1533 auto warningLowAlarm = false;
1534
1535 if (warningHigh != warningMap.end())
1536 {
1537 warningHighAlarm = std::get<bool>(warningHigh->second);
1538 }
1539 if (warningLow != warningMap.end())
1540 {
1541 warningLowAlarm = std::get<bool>(warningLow->second);
1542 }
1543 if (warningHighAlarm)
1544 {
1545 assertions.set(
1546 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1547 upperNonCriticalGoingHigh));
1548 }
1549 if (warningLowAlarm)
1550 {
1551 assertions.set(
1552 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1553 lowerNonCriticalGoingLow));
1554 }
1555 }
1556 if (criticalInterface != sensorMap.end())
1557 {
1558 auto& criticalMap = criticalInterface->second;
1559
1560 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1561 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1562 auto criticalHighAlarm = false;
1563 auto criticalLowAlarm = false;
1564
1565 if (criticalHigh != criticalMap.end())
1566 {
1567 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1568 }
1569 if (criticalLow != criticalMap.end())
1570 {
1571 criticalLowAlarm = std::get<bool>(criticalLow->second);
1572 }
1573 if (criticalHighAlarm)
1574 {
1575 assertions.set(
1576 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1577 upperCriticalGoingHigh));
1578 }
1579 if (criticalLowAlarm)
1580 {
1581 assertions.set(static_cast<size_t>(
1582 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1583 }
1584 }
1585 }
1586
1587 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1588}
1589
Willy Tu38e7a2b2021-03-29 15:09:56 -07001590// Construct a type 1 SDR for threshold sensor.
Hao Jiange39d4d82021-04-16 17:02:40 -07001591void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1592 get_sdr::SensorDataFullRecord& record)
Willy Tude54f482021-01-26 15:59:09 -08001593{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001594 get_sdr::header::set_record_id(
1595 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1596
Willy Tu38e7a2b2021-03-29 15:09:56 -07001597 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1598 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1599
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001600 record.header.sdr_version = ipmiSdrVersion;
1601 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1602 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1603 sizeof(get_sdr::SensorDataRecordHeader);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001604 record.key.owner_id = bmcI2CAddr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001605 record.key.owner_lun = lun;
1606 record.key.sensor_number = sensornumber;
Hao Jiange39d4d82021-04-16 17:02:40 -07001607}
Willy Tu4eca2512022-06-20 21:14:51 -07001608bool constructSensorSdr(
1609 ipmi::Context::ptr ctx,
1610 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1611 uint16_t sensorNum, uint16_t recordID, const std::string& service,
1612 const std::string& path, get_sdr::SensorDataFullRecord& record)
Hao Jiange39d4d82021-04-16 17:02:40 -07001613{
Hao Jiange39d4d82021-04-16 17:02:40 -07001614 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1615
1616 DbusInterfaceMap sensorMap;
1617 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1618 {
1619 phosphor::logging::log<phosphor::logging::level::ERR>(
1620 "Failed to update sensor map for threshold sensor",
1621 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1622 phosphor::logging::entry("PATH=%s", path.c_str()));
1623 return false;
1624 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001625
1626 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1627 record.body.sensor_type = getSensorTypeFromPath(path);
1628 std::string type = getSensorTypeStringFromPath(path);
1629 auto typeCstr = type.c_str();
1630 auto findUnits = sensorUnits.find(typeCstr);
1631 if (findUnits != sensorUnits.end())
1632 {
1633 record.body.sensor_units_2_base =
1634 static_cast<uint8_t>(findUnits->second);
1635 } // else default 0x0 unspecified
1636
1637 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1638
Hao Jiangd2afd052020-12-10 15:09:32 -08001639 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001640 if (sensorObject == sensorMap.end())
1641 {
1642 phosphor::logging::log<phosphor::logging::level::ERR>(
1643 "getSensorDataRecord: sensorObject error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001644 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001645 }
1646
1647 uint8_t entityId = 0;
1648 uint8_t entityInstance = 0x01;
1649
1650 // follow the association chain to get the parent board's entityid and
1651 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001652 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, entityId,
1653 entityInstance);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001654
1655 record.body.entity_id = entityId;
1656 record.body.entity_instance = entityInstance;
1657
Shakeeb Pasha93889722021-10-14 10:20:13 +05301658 double max = 0;
1659 double min = 0;
1660 getSensorMaxMin(sensorMap, max, min);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001661
1662 int16_t mValue = 0;
1663 int8_t rExp = 0;
1664 int16_t bValue = 0;
1665 int8_t bExp = 0;
1666 bool bSigned = false;
1667
1668 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1669 {
1670 phosphor::logging::log<phosphor::logging::level::ERR>(
1671 "getSensorDataRecord: getSensorAttributes error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001672 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001673 }
1674
1675 // The record.body is a struct SensorDataFullRecordBody
1676 // from sensorhandler.hpp in phosphor-ipmi-host.
1677 // The meaning of these bits appears to come from
1678 // table 43.1 of the IPMI spec.
1679 // The above 5 sensor attributes are stuffed in as follows:
1680 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1681 // Byte 22-24 are for other purposes
1682 // Byte 25 = MMMMMMMM = LSB of M
1683 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1684 // Byte 27 = BBBBBBBB = LSB of B
1685 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1686 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1687 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1688
1689 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1690 record.body.m_lsb = mValue & 0xFF;
1691
1692 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1693 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1694
1695 // move the smallest bit of the MSB into place (bit 9)
1696 // the MSbs are bits 7:8 in m_msb_and_tolerance
1697 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1698
1699 record.body.b_lsb = bValue & 0xFF;
1700
1701 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1702 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1703
1704 // move the smallest bit of the MSB into place (bit 9)
1705 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1706 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1707
1708 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1709 uint8_t rExpBits = rExp & 0x07;
1710
1711 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1712 uint8_t bExpBits = bExp & 0x07;
1713
1714 // move rExp and bExp into place
1715 record.body.r_b_exponents =
1716 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1717
1718 // Set the analog reading byte interpretation accordingly
1719 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1720
1721 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1722 // These seem redundant, but derivable from the above 5 attributes
1723 // Original comment said "todo fill out rest of units"
1724
1725 // populate sensor name from path
Willy Tu38e7a2b2021-03-29 15:09:56 -07001726 auto name = sensor::parseSdrIdFromPath(path);
Paul Fertser51136982022-08-18 12:36:41 +00001727 get_sdr::body::set_id_strlen(name.size(), &record.body);
1728 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001729 std::strncpy(record.body.id_string, name.c_str(),
1730 sizeof(record.body.id_string));
1731
Josh Lehana55c9532020-10-28 21:59:06 -07001732 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001733 details::sdrStatsTable.updateName(sensorNum, name);
Josh Lehana55c9532020-10-28 21:59:06 -07001734
Jie Yangf0a89942021-07-29 15:30:25 -07001735 bool sensorSettable = false;
1736 auto mutability =
1737 sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability");
1738 if (mutability != sensorMap.end())
1739 {
1740 sensorSettable =
1741 mappedVariant<bool>(mutability->second, "Mutable", false);
1742 }
1743 get_sdr::body::init_settable_state(sensorSettable, &record.body);
1744
1745 // Grant write permission to sensors deemed externally settable
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001746 details::sdrWriteTable.setWritePermission(sensorNum, sensorSettable);
Willy Tu530e2772021-07-02 14:42:06 -07001747
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001748 IPMIThresholds thresholdData;
1749 try
1750 {
1751 thresholdData = getIPMIThresholds(sensorMap);
1752 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001753 catch (const std::exception&)
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001754 {
1755 phosphor::logging::log<phosphor::logging::level::ERR>(
1756 "getSensorDataRecord: getIPMIThresholds error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001757 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001758 }
1759
1760 if (thresholdData.criticalHigh)
1761 {
1762 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1763 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1764 IPMISensorEventEnableThresholds::criticalThreshold);
1765 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1766 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1767 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1768 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1769 record.body.discrete_reading_setting_mask[0] |=
1770 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1771 }
1772 if (thresholdData.warningHigh)
1773 {
1774 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1775 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1776 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1777 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1778 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1779 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1780 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1781 record.body.discrete_reading_setting_mask[0] |=
1782 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1783 }
1784 if (thresholdData.criticalLow)
1785 {
1786 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1787 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1788 IPMISensorEventEnableThresholds::criticalThreshold);
1789 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1790 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1791 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1792 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1793 record.body.discrete_reading_setting_mask[0] |=
1794 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1795 }
1796 if (thresholdData.warningLow)
1797 {
1798 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1799 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1800 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1801 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1802 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1803 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1804 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1805 record.body.discrete_reading_setting_mask[0] |=
1806 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1807 }
1808
1809 // everything that is readable is setable
1810 record.body.discrete_reading_setting_mask[1] =
1811 record.body.discrete_reading_setting_mask[0];
Willy Tu38e7a2b2021-03-29 15:09:56 -07001812 return true;
1813}
1814
Scron Chang2703b022021-07-06 15:47:45 +08001815#ifdef FEATURE_HYBRID_SENSORS
1816// Construct a type 1 SDR for discrete Sensor typed sensor.
Willy Tu11d68892022-01-20 10:37:34 -08001817void constructStaticSensorSdr(ipmi::Context::ptr, uint16_t sensorNum,
Scron Chang2703b022021-07-06 15:47:45 +08001818 uint16_t recordID,
1819 ipmi::sensor::IdInfoMap::const_iterator sensor,
1820 get_sdr::SensorDataFullRecord& record)
1821{
1822 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1823
1824 record.body.entity_id = sensor->second.entityType;
1825 record.body.sensor_type = sensor->second.sensorType;
1826 record.body.event_reading_type = sensor->second.sensorReadingType;
1827 record.body.entity_instance = sensor->second.instance;
1828 if (ipmi::sensor::Mutability::Write ==
1829 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
1830 {
1831 get_sdr::body::init_settable_state(true, &(record.body));
1832 }
1833
1834 auto id_string = sensor->second.sensorName;
1835
1836 if (id_string.empty())
1837 {
1838 id_string = sensor->second.sensorNameFunc(sensor->second);
1839 }
1840
1841 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
1842 {
1843 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH,
1844 &(record.body));
1845 }
1846 else
1847 {
1848 get_sdr::body::set_id_strlen(id_string.length(), &(record.body));
1849 }
Paul Fertser51136982022-08-18 12:36:41 +00001850 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Scron Chang2703b022021-07-06 15:47:45 +08001851 std::strncpy(record.body.id_string, id_string.c_str(),
1852 get_sdr::body::get_id_strlen(&(record.body)));
1853}
1854#endif
1855
Hao Jiange39d4d82021-04-16 17:02:40 -07001856// Construct type 3 SDR header and key (for VR and other discrete sensors)
1857void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1858 get_sdr::SensorDataEventRecord& record)
Willy Tu61992ad2021-03-29 15:33:20 -07001859{
1860 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1861 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1862
1863 get_sdr::header::set_record_id(
1864 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1865
1866 record.header.sdr_version = ipmiSdrVersion;
1867 record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD;
1868 record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) -
1869 sizeof(get_sdr::SensorDataRecordHeader);
1870 record.key.owner_id = bmcI2CAddr;
1871 record.key.owner_lun = lun;
1872 record.key.sensor_number = sensornumber;
1873
1874 record.body.entity_id = 0x00;
1875 record.body.entity_instance = 0x01;
Hao Jiange39d4d82021-04-16 17:02:40 -07001876}
Willy Tu61992ad2021-03-29 15:33:20 -07001877
Hao Jiange39d4d82021-04-16 17:02:40 -07001878// Construct a type 3 SDR for VR typed sensor(daemon).
Willy Tu4eca2512022-06-20 21:14:51 -07001879bool constructVrSdr(ipmi::Context::ptr ctx,
1880 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1881 uint16_t sensorNum, uint16_t recordID,
1882 const std::string& service, const std::string& path,
Hao Jiange39d4d82021-04-16 17:02:40 -07001883 get_sdr::SensorDataEventRecord& record)
1884{
Hao Jiange39d4d82021-04-16 17:02:40 -07001885 constructEventSdrHeaderKey(sensorNum, recordID, record);
1886
1887 DbusInterfaceMap sensorMap;
1888 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1889 {
1890 phosphor::logging::log<phosphor::logging::level::ERR>(
1891 "Failed to update sensor map for VR sensor",
1892 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1893 phosphor::logging::entry("PATH=%s", path.c_str()));
1894 return false;
1895 }
Willy Tu61992ad2021-03-29 15:33:20 -07001896 // follow the association chain to get the parent board's entityid and
1897 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001898 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap,
1899 record.body.entity_id,
Willy Tu61992ad2021-03-29 15:33:20 -07001900 record.body.entity_instance);
1901
1902 // Sensor type is hardcoded as a module/board type instead of parsing from
1903 // sensor path. This is because VR control is allocated in an independent
1904 // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by
1905 // types.
1906 static constexpr const uint8_t module_board_type = 0x15;
1907 record.body.sensor_type = module_board_type;
1908 record.body.event_reading_type = 0x00;
1909
1910 record.body.sensor_record_sharing_1 = 0x00;
1911 record.body.sensor_record_sharing_2 = 0x00;
1912
1913 // populate sensor name from path
1914 auto name = sensor::parseSdrIdFromPath(path);
1915 int nameSize = std::min(name.size(), sizeof(record.body.id_string));
Paul Fertser51136982022-08-18 12:36:41 +00001916 get_sdr::body::set_id_strlen(nameSize, &record.body);
1917 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Willy Tu61992ad2021-03-29 15:33:20 -07001918 std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string));
1919 std::memcpy(record.body.id_string, name.c_str(), nameSize);
1920
1921 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001922 details::sdrStatsTable.updateName(sensorNum, name);
Hao Jiange39d4d82021-04-16 17:02:40 -07001923
1924 return true;
Willy Tu61992ad2021-03-29 15:33:20 -07001925}
1926
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001927static inline uint16_t getNumberOfSensors()
1928{
1929 return std::min(getSensorTree().size(), maxIPMISensors);
1930}
1931
Willy Tu4eca2512022-06-20 21:14:51 -07001932static int getSensorDataRecord(
1933 ipmi::Context::ptr ctx,
1934 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1935 std::vector<uint8_t>& recordData, uint16_t recordID,
1936 uint8_t readBytes = std::numeric_limits<uint8_t>::max())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001937{
1938 size_t fruCount = 0;
1939 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1940 if (ret != ipmi::ccSuccess)
1941 {
1942 phosphor::logging::log<phosphor::logging::level::ERR>(
1943 "getSensorDataRecord: getFruSdrCount error");
1944 return GENERAL_ERROR;
1945 }
1946
Harvey Wu05d17c02021-09-15 08:46:59 +08001947 const auto& entityRecords =
1948 ipmi::sensor::EntityInfoMapContainer::getContainer()
1949 ->getIpmiEntityRecords();
1950 size_t entityCount = entityRecords.size();
1951
1952 size_t lastRecord = getNumberOfSensors() + fruCount +
1953 ipmi::storage::type12Count + entityCount - 1;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001954 if (recordID == lastRecordIndex)
1955 {
1956 recordID = lastRecord;
1957 }
1958 if (recordID > lastRecord)
1959 {
1960 phosphor::logging::log<phosphor::logging::level::ERR>(
1961 "getSensorDataRecord: recordID > lastRecord error");
1962 return GENERAL_ERROR;
1963 }
1964
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001965 if (recordID >= getNumberOfSensors())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001966 {
Harvey Wu05d17c02021-09-15 08:46:59 +08001967 size_t sdrIndex = recordID - getNumberOfSensors();
Willy Tu38e7a2b2021-03-29 15:09:56 -07001968
Harvey Wu05d17c02021-09-15 08:46:59 +08001969 if (sdrIndex >= fruCount + ipmi::storage::type12Count)
1970 {
1971 // handle type 8 entity map records
1972 ipmi::sensor::EntityInfoMap::const_iterator entity =
1973 entityRecords.find(static_cast<uint8_t>(
1974 sdrIndex - fruCount - ipmi::storage::type12Count));
1975 if (entity == entityRecords.end())
1976 {
1977 return IPMI_CC_SENSOR_INVALID;
1978 }
1979 recordData = ipmi::storage::getType8SDRs(entity, recordID);
1980 }
1981 else if (sdrIndex >= fruCount)
Willy Tu38e7a2b2021-03-29 15:09:56 -07001982 {
1983 // handle type 12 hardcoded records
Harvey Wu05d17c02021-09-15 08:46:59 +08001984 size_t type12Index = sdrIndex - fruCount;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001985 if (type12Index >= ipmi::storage::type12Count)
1986 {
1987 phosphor::logging::log<phosphor::logging::level::ERR>(
1988 "getSensorDataRecord: type12Index error");
1989 return GENERAL_ERROR;
1990 }
1991 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
1992 }
1993 else
1994 {
1995 // handle fru records
1996 get_sdr::SensorDataFruRecord data;
Harvey Wu05d17c02021-09-15 08:46:59 +08001997 ret = ipmi::storage::getFruSdrs(ctx, sdrIndex, data);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001998 if (ret != IPMI_CC_OK)
1999 {
2000 return GENERAL_ERROR;
2001 }
2002 data.header.record_id_msb = recordID >> 8;
2003 data.header.record_id_lsb = recordID & 0xFF;
2004 recordData.insert(recordData.end(), (uint8_t*)&data,
2005 ((uint8_t*)&data) + sizeof(data));
2006 }
2007
2008 return 0;
2009 }
2010
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002011 // Perform a incremental scan of the SDR Record ID's and translate the
2012 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
2013 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
2014 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
2015 // which has special meaning.
Willy Tu38e7a2b2021-03-29 15:09:56 -07002016 std::string connection;
2017 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -07002018 std::vector<std::string> interfaces;
Johnathan Manteyce982772021-07-28 15:08:30 -07002019 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002020 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyce982772021-07-28 15:08:30 -07002021 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002022 // LUN 0 has one reserved sensor number. Compensate here by adding one
2023 // to the record ID
2024 sensNumFromRecID = recordID + 1;
Johnathan Manteyce982772021-07-28 15:08:30 -07002025 ctx->lun = 1;
2026 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002027 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyce982772021-07-28 15:08:30 -07002028 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002029 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
2030 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
2031 // rules governing its use.
2032 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyce982772021-07-28 15:08:30 -07002033 ctx->lun = 3;
2034 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002035
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002036 auto status =
2037 getSensorConnection(ctx, static_cast<uint8_t>(sensNumFromRecID),
2038 connection, path, &interfaces);
Willy Tu38e7a2b2021-03-29 15:09:56 -07002039 if (status)
2040 {
2041 phosphor::logging::log<phosphor::logging::level::ERR>(
2042 "getSensorDataRecord: getSensorConnection error");
2043 return GENERAL_ERROR;
2044 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002045 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002046 // Return an error on LUN 2 assingments, and any sensor number beyond the
2047 // range of LUN 3
2048 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
2049 (sensorNum > lun3MaxSensorNum))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002050 {
2051 phosphor::logging::log<phosphor::logging::level::ERR>(
2052 "getSensorDataRecord: invalidSensorNumber");
2053 return GENERAL_ERROR;
2054 }
Johnathan Manteyce982772021-07-28 15:08:30 -07002055 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
2056 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
2057
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002058 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
2059 (lun != ctx->lun))
Johnathan Manteyce982772021-07-28 15:08:30 -07002060 {
2061 phosphor::logging::log<phosphor::logging::level::ERR>(
2062 "getSensorDataRecord: sensor record mismatch");
2063 return GENERAL_ERROR;
2064 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002065
Willy Tu38e7a2b2021-03-29 15:09:56 -07002066 // Construct full record (SDR type 1) for the threshold sensors
Hao Jiange39d4d82021-04-16 17:02:40 -07002067 if (std::find(interfaces.begin(), interfaces.end(),
2068 sensor::sensorInterface) != interfaces.end())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002069 {
Willy Tu11d68892022-01-20 10:37:34 -08002070 get_sdr::SensorDataFullRecord record = {};
Willy Tu38e7a2b2021-03-29 15:09:56 -07002071
Hao Jiange39d4d82021-04-16 17:02:40 -07002072 // If the request doesn't read SDR body, construct only header and key
2073 // part to avoid additional DBus transaction.
2074 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2075 {
2076 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2077 }
Willy Tu4eca2512022-06-20 21:14:51 -07002078 else if (!constructSensorSdr(ctx, ipmiDecoratorPaths, sensorNum,
2079 recordID, connection, path, record))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002080 {
2081 return GENERAL_ERROR;
2082 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002083
Willy Tu38e7a2b2021-03-29 15:09:56 -07002084 recordData.insert(recordData.end(), (uint8_t*)&record,
2085 ((uint8_t*)&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002086
2087 return 0;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002088 }
Willy Tu61992ad2021-03-29 15:33:20 -07002089
Scron Chang2703b022021-07-06 15:47:45 +08002090#ifdef FEATURE_HYBRID_SENSORS
2091 if (auto sensor = findStaticSensor(path);
2092 sensor != ipmi::sensor::sensors.end() &&
2093 getSensorEventTypeFromPath(path) !=
2094 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
2095 {
Willy Tu11d68892022-01-20 10:37:34 -08002096 get_sdr::SensorDataFullRecord record = {};
Scron Chang2703b022021-07-06 15:47:45 +08002097
2098 // If the request doesn't read SDR body, construct only header and key
2099 // part to avoid additional DBus transaction.
2100 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2101 {
2102 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2103 }
2104 else
2105 {
2106 constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record);
2107 }
2108
2109 recordData.insert(recordData.end(), (uint8_t*)&record,
2110 ((uint8_t*)&record) + sizeof(record));
2111
2112 return 0;
2113 }
2114#endif
2115
Willy Tu61992ad2021-03-29 15:33:20 -07002116 // Contruct SDR type 3 record for VR sensor (daemon)
Hao Jiange39d4d82021-04-16 17:02:40 -07002117 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
2118 interfaces.end())
Willy Tu61992ad2021-03-29 15:33:20 -07002119 {
Willy Tu11d68892022-01-20 10:37:34 -08002120 get_sdr::SensorDataEventRecord record = {};
Willy Tu61992ad2021-03-29 15:33:20 -07002121
Hao Jiange39d4d82021-04-16 17:02:40 -07002122 // If the request doesn't read SDR body, construct only header and key
2123 // part to avoid additional DBus transaction.
2124 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2125 {
2126 constructEventSdrHeaderKey(sensorNum, recordID, record);
2127 }
Willy Tu4eca2512022-06-20 21:14:51 -07002128 else if (!constructVrSdr(ctx, ipmiDecoratorPaths, sensorNum, recordID,
2129 connection, path, record))
Hao Jiange39d4d82021-04-16 17:02:40 -07002130 {
2131 return GENERAL_ERROR;
2132 }
Willy Tu61992ad2021-03-29 15:33:20 -07002133 recordData.insert(recordData.end(), (uint8_t*)&record,
2134 ((uint8_t*)&record) + sizeof(record));
2135 }
2136
Willy Tude54f482021-01-26 15:59:09 -08002137 return 0;
2138}
2139
2140/** @brief implements the get SDR Info command
2141 * @param count - Operation
2142 *
2143 * @returns IPMI completion code plus response data
2144 * - sdrCount - sensor/SDR count
2145 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
2146 */
2147static ipmi::RspType<uint8_t, // respcount
2148 uint8_t, // dynamic population flags
2149 uint32_t // last time a sensor was added
2150 >
2151 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
2152 std::optional<uint8_t> count)
2153{
2154 auto& sensorTree = getSensorTree();
2155 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002156 uint16_t recordID = 0;
2157 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08002158 // Sensors are dynamically allocated, and there is at least one LUN
2159 uint8_t lunsAndDynamicPopulation = 0x80;
2160 constexpr uint8_t getSdrCount = 0x01;
2161 constexpr uint8_t getSensorCount = 0x00;
2162
2163 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
2164 {
2165 return ipmi::responseResponseError();
2166 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002167 uint16_t numSensors = getNumberOfSensors();
Willy Tude54f482021-01-26 15:59:09 -08002168 if (count.value_or(0) == getSdrCount)
2169 {
Willy Tu4eca2512022-06-20 21:14:51 -07002170 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2171
Willy Tude54f482021-01-26 15:59:09 -08002172 // Count the number of Type 1 SDR entries assigned to the LUN
Willy Tu4eca2512022-06-20 21:14:51 -07002173 while (!getSensorDataRecord(
2174 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2175 record, recordID++))
Willy Tude54f482021-01-26 15:59:09 -08002176 {
2177 get_sdr::SensorDataRecordHeader* hdr =
2178 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002179 record.data());
Willy Tude54f482021-01-26 15:59:09 -08002180 if (hdr && hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
2181 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002182 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08002183 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002184 record.data());
2185 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08002186 {
2187 sdrCount++;
2188 }
2189 }
2190 }
2191 }
2192 else if (count.value_or(0) == getSensorCount)
2193 {
2194 // Return the number of sensors attached to the LUN
2195 if ((ctx->lun == 0) && (numSensors > 0))
2196 {
2197 sdrCount =
2198 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
2199 }
2200 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
2201 {
2202 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
2203 ? maxSensorsPerLUN
2204 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
2205 }
2206 else if (ctx->lun == 3)
2207 {
2208 if (numSensors <= maxIPMISensors)
2209 {
2210 sdrCount =
2211 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
2212 }
2213 else
2214 {
2215 // error
2216 throw std::out_of_range(
2217 "Maximum number of IPMI sensors exceeded.");
2218 }
2219 }
2220 }
2221 else
2222 {
2223 return ipmi::responseInvalidFieldRequest();
2224 }
2225
2226 // Get Sensor count. This returns the number of sensors
2227 if (numSensors > 0)
2228 {
2229 lunsAndDynamicPopulation |= 1;
2230 }
2231 if (numSensors > maxSensorsPerLUN)
2232 {
2233 lunsAndDynamicPopulation |= 2;
2234 }
2235 if (numSensors >= (maxSensorsPerLUN * 2))
2236 {
2237 lunsAndDynamicPopulation |= 8;
2238 }
2239 if (numSensors > maxIPMISensors)
2240 {
2241 // error
2242 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
2243 }
2244
2245 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
2246 sdrLastAdd);
2247}
2248
2249/* end sensor commands */
2250
2251/* storage commands */
2252
2253ipmi::RspType<uint8_t, // sdr version
2254 uint16_t, // record count
2255 uint16_t, // free space
2256 uint32_t, // most recent addition
2257 uint32_t, // most recent erase
2258 uint8_t // operationSupport
2259 >
2260 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
2261{
2262 auto& sensorTree = getSensorTree();
2263 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002264 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002265 {
2266 return ipmi::responseResponseError();
2267 }
2268
2269 size_t fruCount = 0;
2270 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2271 if (ret != ipmi::ccSuccess)
2272 {
2273 return ipmi::response(ret);
2274 }
2275
2276 uint16_t recordCount =
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002277 getNumberOfSensors() + fruCount + ipmi::storage::type12Count;
Willy Tude54f482021-01-26 15:59:09 -08002278
2279 uint8_t operationSupport = static_cast<uint8_t>(
2280 SdrRepositoryInfoOps::overflow); // write not supported
2281
2282 operationSupport |=
2283 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
2284 operationSupport |= static_cast<uint8_t>(
2285 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
2286 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
2287 unspecifiedFreeSpace, sdrLastAdd,
2288 sdrLastRemove, operationSupport);
2289}
2290
2291/** @brief implements the get SDR allocation info command
2292 *
2293 * @returns IPMI completion code plus response data
2294 * - allocUnits - Number of possible allocation units
2295 * - allocUnitSize - Allocation unit size in bytes.
2296 * - allocUnitFree - Number of free allocation units
2297 * - allocUnitLargestFree - Largest free block in allocation units
2298 * - maxRecordSize - Maximum record size in allocation units.
2299 */
2300ipmi::RspType<uint16_t, // allocUnits
2301 uint16_t, // allocUnitSize
2302 uint16_t, // allocUnitFree
2303 uint16_t, // allocUnitLargestFree
2304 uint8_t // maxRecordSize
2305 >
2306 ipmiStorageGetSDRAllocationInfo()
2307{
2308 // 0000h unspecified number of alloc units
2309 constexpr uint16_t allocUnits = 0;
2310
2311 constexpr uint16_t allocUnitFree = 0;
2312 constexpr uint16_t allocUnitLargestFree = 0;
2313 // only allow one block at a time
2314 constexpr uint8_t maxRecordSize = 1;
2315
2316 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
2317 allocUnitLargestFree, maxRecordSize);
2318}
2319
2320/** @brief implements the reserve SDR command
2321 * @returns IPMI completion code plus response data
2322 * - sdrReservationID
2323 */
2324ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
2325{
2326 sdrReservationID++;
2327 if (sdrReservationID == 0)
2328 {
2329 sdrReservationID++;
2330 }
2331
2332 return ipmi::responseSuccess(sdrReservationID);
2333}
2334
2335ipmi::RspType<uint16_t, // next record ID
2336 std::vector<uint8_t> // payload
2337 >
2338 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
2339 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
2340{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002341 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08002342 // reservation required for partial reads with non zero offset into
2343 // record
2344 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
2345 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002346 phosphor::logging::log<phosphor::logging::level::ERR>(
2347 "ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08002348 return ipmi::responseInvalidReservationId();
2349 }
Willy Tude54f482021-01-26 15:59:09 -08002350 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2351 if (ret != ipmi::ccSuccess)
2352 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002353 phosphor::logging::log<phosphor::logging::level::ERR>(
2354 "ipmiStorageGetSDR: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08002355 return ipmi::response(ret);
2356 }
2357
Harvey Wu05d17c02021-09-15 08:46:59 +08002358 const auto& entityRecords =
2359 ipmi::sensor::EntityInfoMapContainer::getContainer()
2360 ->getIpmiEntityRecords();
2361 int entityCount = entityRecords.size();
2362
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002363 auto& sensorTree = getSensorTree();
Harvey Wu05d17c02021-09-15 08:46:59 +08002364 size_t lastRecord = getNumberOfSensors() + fruCount +
2365 ipmi::storage::type12Count + entityCount - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002366 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
2367
2368 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002369 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002370 phosphor::logging::log<phosphor::logging::level::ERR>(
2371 "ipmiStorageGetSDR: getSensorSubtree error");
2372 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08002373 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002374
Willy Tu4eca2512022-06-20 21:14:51 -07002375 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2376
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002377 std::vector<uint8_t> record;
Willy Tu4eca2512022-06-20 21:14:51 -07002378 if (getSensorDataRecord(
2379 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2380 record, recordID, offset + bytesToRead))
Willy Tude54f482021-01-26 15:59:09 -08002381 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002382 phosphor::logging::log<phosphor::logging::level::ERR>(
2383 "ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08002384 return ipmi::responseInvalidFieldRequest();
2385 }
Willy Tude54f482021-01-26 15:59:09 -08002386 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002387 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08002388 if (!hdr)
2389 {
2390 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002391 "ipmiStorageGetSDR: record header is null");
2392 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002393 }
2394
2395 size_t sdrLength =
2396 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
2397 if (sdrLength < (offset + bytesToRead))
2398 {
2399 bytesToRead = sdrLength - offset;
2400 }
2401
2402 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
2403 if (!respStart)
2404 {
2405 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002406 "ipmiStorageGetSDR: record is null");
2407 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002408 }
2409
2410 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002411
Willy Tude54f482021-01-26 15:59:09 -08002412 return ipmi::responseSuccess(nextRecordId, recordData);
2413}
adarshgrami042e9db2022-09-15 10:34:34 +05302414namespace dcmi
2415{
2416
2417ipmi::RspType<uint8_t, // No of instances for requested id
2418 uint8_t, // No of record ids in the response
2419 std::vector<uint16_t> // SDR Record ID corresponding to the Entity
2420 // IDs
2421 >
2422 getSensorInfo(ipmi::Context::ptr ctx, uint8_t sensorType, uint8_t entityId,
Willy Tu0679e4b2022-11-11 14:34:33 -08002423 uint8_t entityInstance,
2424 [[maybe_unused]] uint8_t instanceStart)
adarshgrami042e9db2022-09-15 10:34:34 +05302425{
2426 auto match = ipmi::dcmi::validEntityId.find(entityId);
2427 if (match == ipmi::dcmi::validEntityId.end())
2428 {
2429 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId));
2430
2431 return ipmi::responseInvalidFieldRequest();
2432 }
2433
2434 if (sensorType != ipmi::dcmi::temperatureSensorType)
2435 {
2436 log<level::ERR>("Invalid sensor type",
2437 entry("SENSOR_TYPE=%d", sensorType));
2438
2439 return ipmi::responseInvalidFieldRequest();
2440 }
2441 auto& sensorTree = getSensorTree();
2442 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
2443 {
2444 return ipmi::responseUnspecifiedError();
2445 }
2446
2447 std::vector<uint16_t> sensorRec{};
2448 uint8_t numInstances = 0;
2449
Willy Tu0679e4b2022-11-11 14:34:33 -08002450 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
adarshgrami042e9db2022-09-15 10:34:34 +05302451 for (const auto& sensor : sensorTree)
2452 {
2453 auto sensorTypeValue = getSensorTypeFromPath(sensor.first);
2454 if (sensorTypeValue != ipmi::dcmi::temperatureSensorType)
2455 {
2456 continue;
2457 }
2458 const auto& connection = sensor.second.begin()->first;
2459
2460 DbusInterfaceMap sensorMap;
2461 if (!getSensorMap(ctx, connection, sensor.first, sensorMap,
2462 sensorMapSdrUpdatePeriod))
2463 {
2464 phosphor::logging::log<phosphor::logging::level::ERR>(
2465 "Failed to update sensor map for threshold sensor",
2466 phosphor::logging::entry("SERVICE=%s", connection.c_str()),
2467 phosphor::logging::entry("PATH=%s", sensor.first.c_str()));
2468 continue;
2469 }
2470 uint8_t entityIdValue = 0;
2471 uint8_t entityInstanceValue = 0;
Willy Tu0679e4b2022-11-11 14:34:33 -08002472 updateIpmiFromAssociation(
2473 sensor.first,
2474 ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2475 sensorMap, entityIdValue, entityInstanceValue);
adarshgrami042e9db2022-09-15 10:34:34 +05302476 if (!entityInstance)
2477 {
2478 if (entityIdValue == match->first || entityIdValue == match->second)
2479 {
2480 auto recordId = getSensorNumberFromPath(sensor.first);
2481 if (recordId != invalidSensorNumber)
2482 {
2483 numInstances++;
2484 if (numInstances <= ipmi::dcmi::maxRecords)
2485 {
2486 sensorRec.push_back(recordId);
2487 }
2488 }
2489 }
2490 }
2491 else
2492 {
2493 if (entityIdValue == match->first || entityIdValue == match->second)
2494 {
2495 if (entityInstance == entityInstanceValue)
2496 {
2497 auto recordId = getSensorNumberFromPath(sensor.first);
2498 if ((recordId != invalidSensorNumber) && sensorRec.empty())
2499 {
2500 sensorRec.push_back(recordId);
2501 }
2502 }
2503 numInstances++;
2504 }
2505 }
2506 }
2507 if (sensorRec.empty())
2508 {
2509 return ipmi::responseSensorInvalid();
2510 }
2511 uint8_t numRecords = sensorRec.size();
2512 return ipmi::responseSuccess(numInstances, numRecords, sensorRec);
2513}
2514} // namespace dcmi
2515
Willy Tude54f482021-01-26 15:59:09 -08002516/* end storage commands */
2517
2518void registerSensorFunctions()
2519{
2520 // <Platform Event>
2521 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2522 ipmi::sensor_event::cmdPlatformEvent,
2523 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
2524
Willy Tudbafbce2021-03-29 00:37:05 -07002525 // <Set Sensor Reading and Event Status>
2526 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2527 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
2528 ipmi::Privilege::Operator, ipmiSetSensorReading);
Willy Tudbafbce2021-03-29 00:37:05 -07002529
Willy Tude54f482021-01-26 15:59:09 -08002530 // <Get Sensor Reading>
2531 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2532 ipmi::sensor_event::cmdGetSensorReading,
2533 ipmi::Privilege::User, ipmiSenGetSensorReading);
2534
2535 // <Get Sensor Threshold>
2536 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2537 ipmi::sensor_event::cmdGetSensorThreshold,
2538 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
2539
2540 // <Set Sensor Threshold>
2541 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2542 ipmi::sensor_event::cmdSetSensorThreshold,
2543 ipmi::Privilege::Operator,
2544 ipmiSenSetSensorThresholds);
2545
2546 // <Get Sensor Event Enable>
2547 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2548 ipmi::sensor_event::cmdGetSensorEventEnable,
2549 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
2550
2551 // <Get Sensor Event Status>
2552 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2553 ipmi::sensor_event::cmdGetSensorEventStatus,
2554 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
2555
2556 // register all storage commands for both Sensor and Storage command
2557 // versions
2558
2559 // <Get SDR Repository Info>
2560 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2561 ipmi::storage::cmdGetSdrRepositoryInfo,
2562 ipmi::Privilege::User,
2563 ipmiStorageGetSDRRepositoryInfo);
2564
2565 // <Get Device SDR Info>
2566 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2567 ipmi::sensor_event::cmdGetDeviceSdrInfo,
2568 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
2569
2570 // <Get SDR Allocation Info>
2571 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2572 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
2573 ipmi::Privilege::User,
2574 ipmiStorageGetSDRAllocationInfo);
2575
2576 // <Reserve SDR Repo>
2577 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2578 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
2579 ipmi::Privilege::User, ipmiStorageReserveSDR);
2580
2581 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2582 ipmi::storage::cmdReserveSdrRepository,
2583 ipmi::Privilege::User, ipmiStorageReserveSDR);
2584
2585 // <Get Sdr>
2586 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2587 ipmi::sensor_event::cmdGetDeviceSdr,
2588 ipmi::Privilege::User, ipmiStorageGetSDR);
2589
2590 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2591 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
2592 ipmiStorageGetSDR);
adarshgrami042e9db2022-09-15 10:34:34 +05302593 // <Get DCMI Sensor Info>
2594 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
2595 ipmi::dcmi::cmdGetDcmiSensorInfo,
2596 ipmi::Privilege::User,
2597 ipmi::dcmi::getSensorInfo);
Willy Tude54f482021-01-26 15:59:09 -08002598}
2599} // namespace ipmi