blob: 6517fddb392dea039f22adbbaa6f0ac8d2253dbf [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
Alexander Hansenc2c26f92023-07-17 09:38:43 +020017#include "config.h"
18
Willy Tude54f482021-01-26 15:59:09 -080019#include "dbus-sdr/sensorcommands.hpp"
20
21#include "dbus-sdr/sdrutils.hpp"
22#include "dbus-sdr/sensorutils.hpp"
23#include "dbus-sdr/storagecommands.hpp"
24
Willy Tude54f482021-01-26 15:59:09 -080025#include <boost/algorithm/string.hpp>
26#include <boost/container/flat_map.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050027#include <ipmid/api.hpp>
Vernon Mauery9cf08382023-04-28 14:00:11 -070028#include <ipmid/entity_map_json.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050029#include <ipmid/types.hpp>
30#include <ipmid/utils.hpp>
George Liude6694e2024-07-17 15:22:25 +080031#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050032#include <sdbusplus/bus.hpp>
33#include <user_channel/channel_layer.hpp>
34
35#include <algorithm>
36#include <array>
Willy Tude54f482021-01-26 15:59:09 -080037#include <chrono>
38#include <cmath>
39#include <cstring>
Willy Tu62e3ca82024-01-31 17:28:34 +000040#include <format>
Willy Tude54f482021-01-26 15:59:09 -080041#include <iostream>
Willy Tude54f482021-01-26 15:59:09 -080042#include <map>
Willy Tude54f482021-01-26 15:59:09 -080043#include <optional>
Willy Tude54f482021-01-26 15:59:09 -080044#include <stdexcept>
45#include <string>
46#include <utility>
47#include <variant>
48
Scron Chang2703b022021-07-06 15:47:45 +080049#ifdef FEATURE_HYBRID_SENSORS
50
51#include "sensordatahandler.hpp"
52namespace ipmi
53{
54namespace sensor
55{
56extern const IdInfoMap sensors;
57} // namespace sensor
58} // namespace ipmi
59#endif
adarshgrami042e9db2022-09-15 10:34:34 +053060namespace ipmi
61{
62namespace dcmi
63{
64// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
65static const std::map<uint8_t, uint8_t> validEntityId{
66 {0x40, 0x37}, {0x37, 0x40}, {0x41, 0x03},
67 {0x03, 0x41}, {0x42, 0x07}, {0x07, 0x42}};
68constexpr uint8_t temperatureSensorType = 0x01;
69constexpr uint8_t maxRecords = 8;
70} // namespace dcmi
71} // namespace ipmi
JeffLind950f412021-10-20 18:49:34 +080072constexpr std::array<const char*, 7> suffixes = {
73 "_Output_Voltage", "_Input_Voltage", "_Output_Current", "_Input_Current",
74 "_Output_Power", "_Input_Power", "_Temperature"};
Willy Tude54f482021-01-26 15:59:09 -080075namespace ipmi
76{
Hao Jiangd48c9212021-02-03 15:45:06 -080077
78using phosphor::logging::entry;
79using phosphor::logging::level;
80using phosphor::logging::log;
81
Willy Tude54f482021-01-26 15:59:09 -080082static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu9ab2f942020-07-15 17:56:21 -070083static constexpr int sensorMapSdrUpdatePeriod = 60;
Willy Tude54f482021-01-26 15:59:09 -080084
Willy Tu38e7a2b2021-03-29 15:09:56 -070085// BMC I2C address is generally at 0x20
86static constexpr uint8_t bmcI2CAddr = 0x20;
87
Willy Tude54f482021-01-26 15:59:09 -080088constexpr size_t maxSDRTotalSize =
89 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
90constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
91
92static uint16_t sdrReservationID;
93static uint32_t sdrLastAdd = noTimestamp;
94static uint32_t sdrLastRemove = noTimestamp;
95static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey6619ae42021-08-06 11:21:10 -070096
97// The IPMI spec defines four Logical Units (LUN), each capable of supporting
98// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
99// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
Harvey Wu75893062023-03-22 17:17:31 +0800100// number of IPMI sensors are LUN 0 + LUN 1 + LUN 3, less the reserved
Johnathan Mantey6619ae42021-08-06 11:21:10 -0700101// location.
102static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
103
Harvey Wu75893062023-03-22 17:17:31 +0800104static constexpr uint8_t lun0 = 0x0;
105static constexpr uint8_t lun1 = 0x1;
106static constexpr uint8_t lun3 = 0x3;
107
Johnathan Mantey6619ae42021-08-06 11:21:10 -0700108static constexpr size_t lun0MaxSensorNum = 0xfe;
109static constexpr size_t lun1MaxSensorNum = 0x1fe;
110static constexpr size_t lun3MaxSensorNum = 0x3fe;
Willy Tude54f482021-01-26 15:59:09 -0800111static constexpr int GENERAL_ERROR = -1;
112
Willy Tude54f482021-01-26 15:59:09 -0800113static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
114
115// Specify the comparison required to sort and find char* map objects
116struct CmpStr
117{
118 bool operator()(const char* a, const char* b) const
119 {
120 return std::strcmp(a, b) < 0;
121 }
122};
123const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
124 sensorUnits{{{"temperature", SensorUnits::degreesC},
125 {"voltage", SensorUnits::volts},
126 {"current", SensorUnits::amps},
127 {"fan_tach", SensorUnits::rpm},
Johnathan Mantey7b037272024-06-17 12:12:40 -0700128 {"power", SensorUnits::watts},
129 {"energy", SensorUnits::joules}}};
Willy Tude54f482021-01-26 15:59:09 -0800130
131void registerSensorFunctions() __attribute__((constructor));
132
Patrick Williams5d82f472022-07-22 19:26:53 -0500133static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800134 *getSdBus(),
135 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
136 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500137 [](sdbusplus::message_t&) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500138 getSensorTree().clear();
139 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
140 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
141 std::chrono::system_clock::now().time_since_epoch())
142 .count();
Patrick Williams369824e2023-10-20 11:18:23 -0500143});
Willy Tude54f482021-01-26 15:59:09 -0800144
Patrick Williams5d82f472022-07-22 19:26:53 -0500145static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800146 *getSdBus(),
147 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
148 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500149 [](sdbusplus::message_t&) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500150 getSensorTree().clear();
151 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
152 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
153 std::chrono::system_clock::now().time_since_epoch())
154 .count();
Patrick Williams369824e2023-10-20 11:18:23 -0500155});
Willy Tude54f482021-01-26 15:59:09 -0800156
Johnathan Mantey777cfaf2024-06-13 10:45:47 -0700157ipmi_ret_t getSensorConnection(ipmi::Context::ptr ctx, uint8_t sensnum,
158 std::string& connection, std::string& path,
159 std::vector<std::string>* interfaces)
160{
161 auto& sensorTree = getSensorTree();
162 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
163 {
164 return IPMI_CC_RESPONSE_ERROR;
165 }
166
167 if (ctx == nullptr)
168 {
169 return IPMI_CC_RESPONSE_ERROR;
170 }
171
172 path = getPathFromSensorNumber((ctx->lun << 8) | sensnum);
173 if (path.empty())
174 {
175 return IPMI_CC_INVALID_FIELD_REQUEST;
176 }
177
178 for (const auto& sensor : sensorTree)
179 {
180 if (path == sensor.first)
181 {
182 connection = sensor.second.begin()->first;
183 if (interfaces)
184 *interfaces = sensor.second.begin()->second;
185 break;
186 }
187 }
188
189 return 0;
190}
191
192SensorSubTree& getSensorTree()
193{
194 static SensorSubTree sensorTree;
195 return sensorTree;
196}
197
Willy Tude54f482021-01-26 15:59:09 -0800198// this keeps track of deassertions for sensor event status command. A
199// deasertion can only happen if an assertion was seen first.
200static boost::container::flat_map<
201 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
202 thresholdDeassertMap;
203
Patrick Williams5d82f472022-07-22 19:26:53 -0500204static sdbusplus::bus::match_t thresholdChanged(
Willy Tude54f482021-01-26 15:59:09 -0800205 *getSdBus(),
206 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
207 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500208 [](sdbusplus::message_t& m) {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500209 boost::container::flat_map<std::string, std::variant<bool, double>> values;
210 m.read(std::string(), values);
Willy Tude54f482021-01-26 15:59:09 -0800211
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500212 auto findAssert = std::find_if(values.begin(), values.end(),
213 [](const auto& pair) {
214 return pair.first.find("Alarm") != std::string::npos;
215 });
216 if (findAssert != values.end())
217 {
218 auto ptr = std::get_if<bool>(&(findAssert->second));
219 if (ptr == nullptr)
Willy Tude54f482021-01-26 15:59:09 -0800220 {
George Liude6694e2024-07-17 15:22:25 +0800221 lg2::error("thresholdChanged: Assert non bool");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500222 return;
223 }
224 if (*ptr)
225 {
George Liude6694e2024-07-17 15:22:25 +0800226 lg2::info("thresholdChanged: Assert, sensor path: {SENSOR_PATH}",
227 "SENSOR_PATH", m.get_path());
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500228 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
229 }
230 else
231 {
232 auto& value = thresholdDeassertMap[m.get_path()][findAssert->first];
233 if (value)
Willy Tude54f482021-01-26 15:59:09 -0800234 {
George Liude6694e2024-07-17 15:22:25 +0800235 lg2::info(
236 "thresholdChanged: deassert, sensor path: {SENSOR_PATH}",
237 "SENSOR_PATH", m.get_path());
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500238 value = *ptr;
Willy Tude54f482021-01-26 15:59:09 -0800239 }
240 }
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500241 }
Patrick Williams369824e2023-10-20 11:18:23 -0500242});
Willy Tude54f482021-01-26 15:59:09 -0800243
Hao Jiangd2afd052020-12-10 15:09:32 -0800244namespace sensor
245{
246static constexpr const char* vrInterface =
247 "xyz.openbmc_project.Control.VoltageRegulatorMode";
248static constexpr const char* sensorInterface =
249 "xyz.openbmc_project.Sensor.Value";
250} // namespace sensor
251
Willy Tude54f482021-01-26 15:59:09 -0800252static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
253 double& min)
254{
255 max = 127;
256 min = -128;
257
Hao Jiangd2afd052020-12-10 15:09:32 -0800258 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800259 auto critical =
260 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
261 auto warning =
262 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
263
264 if (sensorObject != sensorMap.end())
265 {
266 auto maxMap = sensorObject->second.find("MaxValue");
267 auto minMap = sensorObject->second.find("MinValue");
268
269 if (maxMap != sensorObject->second.end())
270 {
271 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
272 }
273 if (minMap != sensorObject->second.end())
274 {
275 min = std::visit(VariantToDoubleVisitor(), minMap->second);
276 }
277 }
278 if (critical != sensorMap.end())
279 {
280 auto lower = critical->second.find("CriticalLow");
281 auto upper = critical->second.find("CriticalHigh");
282 if (lower != critical->second.end())
283 {
284 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300285 if (std::isfinite(value))
286 {
Johnathan Mantey92217f02024-06-20 12:43:01 -0700287 min = std::fmin(value, min);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300288 }
Willy Tude54f482021-01-26 15:59:09 -0800289 }
290 if (upper != critical->second.end())
291 {
292 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300293 if (std::isfinite(value))
294 {
Johnathan Mantey92217f02024-06-20 12:43:01 -0700295 max = std::fmax(value, max);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300296 }
Willy Tude54f482021-01-26 15:59:09 -0800297 }
298 }
299 if (warning != sensorMap.end())
300 {
Willy Tude54f482021-01-26 15:59:09 -0800301 auto lower = warning->second.find("WarningLow");
302 auto upper = warning->second.find("WarningHigh");
303 if (lower != warning->second.end())
304 {
305 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300306 if (std::isfinite(value))
307 {
Johnathan Mantey92217f02024-06-20 12:43:01 -0700308 min = std::fmin(value, min);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300309 }
Willy Tude54f482021-01-26 15:59:09 -0800310 }
311 if (upper != warning->second.end())
312 {
313 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300314 if (std::isfinite(value))
315 {
Johnathan Mantey92217f02024-06-20 12:43:01 -0700316 max = std::fmax(value, max);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300317 }
Willy Tude54f482021-01-26 15:59:09 -0800318 }
319 }
320}
321
322static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700323 std::string sensorPath, DbusInterfaceMap& sensorMap,
324 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800325{
Scron Chang2703b022021-07-06 15:47:45 +0800326#ifdef FEATURE_HYBRID_SENSORS
327 if (auto sensor = findStaticSensor(sensorPath);
328 sensor != ipmi::sensor::sensors.end() &&
329 getSensorEventTypeFromPath(sensorPath) !=
330 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
331 {
332 // If the incoming sensor is a discrete sensor, it might fail in
333 // getManagedObjects(), return true, and use its own getFunc to get
334 // value.
335 return true;
336 }
337#endif
338
Willy Tude54f482021-01-26 15:59:09 -0800339 static boost::container::flat_map<
340 std::string, std::chrono::time_point<std::chrono::steady_clock>>
341 updateTimeMap;
342
343 auto updateFind = updateTimeMap.find(sensorConnection);
344 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
345 if (updateFind != updateTimeMap.end())
346 {
347 lastUpdate = updateFind->second;
348 }
349
350 auto now = std::chrono::steady_clock::now();
351
352 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700353 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800354 {
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800355 bool found = false;
Willy Tude54f482021-01-26 15:59:09 -0800356
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800357 // Object managers for different kinds of OpenBMC DBus interfaces.
358 // Documented in the phosphor-dbus-interfaces repository.
359 const char* paths[] = {
360 "/xyz/openbmc_project/sensors",
361 "/xyz/openbmc_project/vr",
362 };
363 constexpr size_t num_paths = sizeof(paths) / sizeof(paths[0]);
364 ObjectValueTree allManagedObjects;
365
366 for (size_t i = 0; i < num_paths; i++)
367 {
368 ObjectValueTree managedObjects;
369 boost::system::error_code ec = getManagedObjects(
370 ctx, sensorConnection.c_str(), paths[i], managedObjects);
371 if (ec)
372 {
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800373 continue;
374 }
375 allManagedObjects.merge(managedObjects);
376 found = true;
377 }
378
379 if (!found)
380 {
George Liude6694e2024-07-17 15:22:25 +0800381 lg2::error("GetMangagedObjects for getSensorMap failed, "
382 "service: {SERVICE}",
383 "SERVICE", sensorConnection);
Tom Tung6615d472023-05-31 18:48:12 +0800384
Willy Tude54f482021-01-26 15:59:09 -0800385 return false;
386 }
387
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800388 SensorCache[sensorConnection] = allManagedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700389 // Update time after finish building the map which allow the
390 // data to be cached for updatePeriod plus the build time.
391 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800392 }
393 auto connection = SensorCache.find(sensorConnection);
394 if (connection == SensorCache.end())
395 {
396 return false;
397 }
398 auto path = connection->second.find(sensorPath);
399 if (path == connection->second.end())
400 {
401 return false;
402 }
403 sensorMap = path->second;
404
405 return true;
406}
407
Hao Jiangd2afd052020-12-10 15:09:32 -0800408namespace sensor
409{
Hao Jiangd48c9212021-02-03 15:45:06 -0800410// Read VR profiles from sensor(daemon) interface
411static std::optional<std::vector<std::string>>
412 getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object)
Hao Jiangd2afd052020-12-10 15:09:32 -0800413{
414 // get VR mode profiles from Supported Interface
Hao Jiangd48c9212021-02-03 15:45:06 -0800415 auto supportedProperty = object.find("Supported");
416 if (supportedProperty == object.end() ||
417 object.find("Selected") == object.end())
Hao Jiangd2afd052020-12-10 15:09:32 -0800418 {
George Liude6694e2024-07-17 15:22:25 +0800419 lg2::error("Missing the required Supported and Selected properties");
Hao Jiangd2afd052020-12-10 15:09:32 -0800420 return std::nullopt;
421 }
422
423 const auto profilesPtr =
424 std::get_if<std::vector<std::string>>(&supportedProperty->second);
425
426 if (profilesPtr == nullptr)
427 {
George Liude6694e2024-07-17 15:22:25 +0800428 lg2::error("property is not array of string");
Hao Jiangd2afd052020-12-10 15:09:32 -0800429 return std::nullopt;
430 }
Hao Jiangd48c9212021-02-03 15:45:06 -0800431 return *profilesPtr;
432}
433
434// Calculate VR Mode from input IPMI discrete event bytes
435static std::optional<std::string>
436 calculateVRMode(uint15_t assertOffset,
437 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
438{
439 // get VR mode profiles from Supported Interface
440 auto profiles = getSupportedVrProfiles(VRObject);
441 if (!profiles)
442 {
443 return std::nullopt;
444 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800445
446 // interpret IPMI cmd bits into profiles' index
447 long unsigned int index = 0;
448 // only one bit should be set and the highest bit should not be used.
449 if (assertOffset == 0 || assertOffset == (1u << 15) ||
450 (assertOffset & (assertOffset - 1)))
451 {
George Liude6694e2024-07-17 15:22:25 +0800452 lg2::error("IPMI cmd format incorrect, bytes: {BYTES}", "BYTES",
453 lg2::hex, static_cast<uint16_t>(assertOffset));
Hao Jiangd2afd052020-12-10 15:09:32 -0800454 return std::nullopt;
455 }
456
457 while (assertOffset != 1)
458 {
459 assertOffset >>= 1;
460 index++;
461 }
462
Hao Jiangd48c9212021-02-03 15:45:06 -0800463 if (index >= profiles->size())
Hao Jiangd2afd052020-12-10 15:09:32 -0800464 {
George Liude6694e2024-07-17 15:22:25 +0800465 lg2::error("profile index out of boundary");
Hao Jiangd2afd052020-12-10 15:09:32 -0800466 return std::nullopt;
467 }
468
Hao Jiangd48c9212021-02-03 15:45:06 -0800469 return profiles->at(index);
Hao Jiangd2afd052020-12-10 15:09:32 -0800470}
471
472// Calculate sensor value from IPMI reading byte
473static std::optional<double>
474 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
475 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
476{
477 if (valueObject.find("Value") == valueObject.end())
478 {
George Liude6694e2024-07-17 15:22:25 +0800479 lg2::error("Missing the required Value property");
Hao Jiangd2afd052020-12-10 15:09:32 -0800480 return std::nullopt;
481 }
482
483 double max = 0;
484 double min = 0;
485 getSensorMaxMin(sensorMap, max, min);
486
487 int16_t mValue = 0;
488 int16_t bValue = 0;
489 int8_t rExp = 0;
490 int8_t bExp = 0;
491 bool bSigned = false;
492
493 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
494 {
495 return std::nullopt;
496 }
497
498 double value = bSigned ? ((int8_t)reading) : reading;
499
500 value *= ((double)mValue);
501 value += ((double)bValue) * std::pow(10.0, bExp);
502 value *= std::pow(10.0, rExp);
503
504 return value;
505}
506
Willy Tu38e7a2b2021-03-29 15:09:56 -0700507// Extract file name from sensor path as the sensors SDR ID. Simplify the name
508// if it is too long.
509std::string parseSdrIdFromPath(const std::string& path)
510{
511 std::string name;
512 size_t nameStart = path.rfind("/");
513 if (nameStart != std::string::npos)
514 {
515 name = path.substr(nameStart + 1, std::string::npos - nameStart);
516 }
517
Willy Tu38e7a2b2021-03-29 15:09:56 -0700518 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
519 {
Alexander Hansenc2c26f92023-07-17 09:38:43 +0200520#ifdef SHORTNAME_REMOVE_SUFFIX
JeffLind950f412021-10-20 18:49:34 +0800521 for (const auto& suffix : suffixes)
Willy Tu38e7a2b2021-03-29 15:09:56 -0700522 {
JeffLind950f412021-10-20 18:49:34 +0800523 if (boost::ends_with(name, suffix))
524 {
525 boost::replace_all(name, suffix, "");
526 break;
527 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700528 }
Alexander Hansenc2c26f92023-07-17 09:38:43 +0200529#endif
530#ifdef SHORTNAME_REPLACE_WORDS
531 constexpr std::array<std::pair<const char*, const char*>, 2>
532 replaceWords = {std::make_pair("Output", "Out"),
533 std::make_pair("Input", "In")};
534 for (const auto& [find, replace] : replaceWords)
Duke Du97014f52021-12-16 17:21:01 +0800535 {
Alexander Hansenc2c26f92023-07-17 09:38:43 +0200536 boost::replace_all(name, find, replace);
Duke Du97014f52021-12-16 17:21:01 +0800537 }
Alexander Hansenc2c26f92023-07-17 09:38:43 +0200538#endif
539
540 // as a backup and if nothing else is configured
541 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
Willy Tu38e7a2b2021-03-29 15:09:56 -0700542 }
543 return name;
544}
545
Hao Jiangd48c9212021-02-03 15:45:06 -0800546bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection,
547 const std::string& path,
548 const ipmi::DbusInterfaceMap::mapped_type& object,
549 std::bitset<16>& assertions)
550{
551 auto profiles = sensor::getSupportedVrProfiles(object);
552 if (!profiles)
553 {
554 return false;
555 }
Willy Tu8366f0b2022-04-29 05:00:17 -0700556 std::string mode;
Hao Jiangd48c9212021-02-03 15:45:06 -0800557
558 auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface,
Willy Tu8366f0b2022-04-29 05:00:17 -0700559 "Selected", mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800560 if (ec)
561 {
George Liude6694e2024-07-17 15:22:25 +0800562 lg2::error("Failed to get Selected, path: {PATH}, "
563 "interface: {INTERFACE}, error: {ERROR}",
564 "PATH", path, "INTERFACE", sensor::sensorInterface, "ERROR",
565 ec.message());
Hao Jiangd48c9212021-02-03 15:45:06 -0800566 return false;
567 }
568
Willy Tu8366f0b2022-04-29 05:00:17 -0700569 auto itr = std::find(profiles->begin(), profiles->end(), mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800570 if (itr == profiles->end())
571 {
George Liude6694e2024-07-17 15:22:25 +0800572 lg2::error("VR mode doesn't match any of its profiles, path: {PATH}",
573 "PATH", path);
Hao Jiangd48c9212021-02-03 15:45:06 -0800574 return false;
575 }
576 std::size_t index =
577 static_cast<std::size_t>(std::distance(profiles->begin(), itr));
578
Willy Tubef102a2022-06-09 15:36:09 -0700579 // map index to response event assertion bit.
580 if (index < 16)
Hao Jiangd48c9212021-02-03 15:45:06 -0800581 {
Willy Tubef102a2022-06-09 15:36:09 -0700582 assertions.set(index);
Hao Jiangd48c9212021-02-03 15:45:06 -0800583 }
584 else
585 {
George Liude6694e2024-07-17 15:22:25 +0800586 lg2::error("VR profile index reaches max assertion bit, "
587 "path: {PATH}, index: {INDEX}",
588 "PATH", path, "INDEX", index);
Hao Jiangd48c9212021-02-03 15:45:06 -0800589 return false;
590 }
591 if constexpr (debug)
592 {
593 std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path)
Willy Tu8366f0b2022-04-29 05:00:17 -0700594 << " mode is: [" << index << "] " << mode << std::endl;
Hao Jiangd48c9212021-02-03 15:45:06 -0800595 }
596 return true;
597}
Johnathan Mantey777cfaf2024-06-13 10:45:47 -0700598
599/*
600 * Handle every Sensor Data Record besides Type 01
601 *
602 * The D-Bus sensors work well for generating Type 01 SDRs.
603 * After the Type 01 sensors are processed the remaining sensor types require
604 * special handling. Each BMC vendor is going to have their own requirements for
605 * insertion of non-Type 01 records.
606 * Manage non-Type 01 records:
607 *
608 * Create a new file: dbus-sdr/sensorcommands_oem.cpp
609 * Populate it with the two weakly linked functions below, without adding the
610 * 'weak' attribute definition prior to the function definition.
611 * getOtherSensorsCount(...)
612 * getOtherSensorsDataRecord(...)
613 * Example contents are provided in the weak definitions below
614 * Enable 'sensors-oem' in your phosphor-ipmi-host bbappend file
615 * 'EXTRA_OEMESON:append = " -Dsensors-oem=enabled"'
616 * The contents of the sensorcommands_oem.cpp file will then override the code
617 * provided below.
618 */
619
620size_t getOtherSensorsCount(ipmi::Context::ptr ctx) __attribute__((weak));
621size_t getOtherSensorsCount(ipmi::Context::ptr ctx)
622{
623 size_t fruCount = 0;
624
625 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
626 if (ret != ipmi::ccSuccess)
627 {
George Liude6694e2024-07-17 15:22:25 +0800628 lg2::error("getOtherSensorsCount: getFruSdrCount error");
Johnathan Mantey777cfaf2024-06-13 10:45:47 -0700629 return std::numeric_limits<size_t>::max();
630 }
631
632 const auto& entityRecords =
633 ipmi::sensor::EntityInfoMapContainer::getContainer()
634 ->getIpmiEntityRecords();
635 size_t entityCount = entityRecords.size();
636
637 return fruCount + ipmi::storage::type12Count + entityCount;
638}
639
640int getOtherSensorsDataRecord(ipmi::Context::ptr ctx, uint16_t recordID,
641 std::vector<uint8_t>& recordData)
642 __attribute__((weak));
643int getOtherSensorsDataRecord(ipmi::Context::ptr ctx, uint16_t recordID,
644 std::vector<uint8_t>& recordData)
645{
646 size_t otherCount{ipmi::sensor::getOtherSensorsCount(ctx)};
647 if (otherCount == std::numeric_limits<size_t>::max())
648 {
649 return GENERAL_ERROR;
650 }
651 const auto& entityRecords =
652 ipmi::sensor::EntityInfoMapContainer::getContainer()
653 ->getIpmiEntityRecords();
654
655 size_t sdrIndex(recordID - ipmi::getNumberOfSensors());
656 size_t entityCount{entityRecords.size()};
657 size_t fruCount{otherCount - ipmi::storage::type12Count - entityCount};
658
659 if (sdrIndex > otherCount)
660 {
661 return std::numeric_limits<int>::min();
662 }
663 else if (sdrIndex >= fruCount + ipmi::storage::type12Count)
664 {
665 // handle type 8 entity map records
666 ipmi::sensor::EntityInfoMap::const_iterator entity =
667 entityRecords.find(static_cast<uint8_t>(
668 sdrIndex - fruCount - ipmi::storage::type12Count));
669
670 if (entity == entityRecords.end())
671 {
672 return GENERAL_ERROR;
673 }
674 recordData = ipmi::storage::getType8SDRs(entity, recordID);
675 }
676 else if (sdrIndex >= fruCount)
677 {
678 // handle type 12 hardcoded records
679 size_t type12Index = sdrIndex - fruCount;
680 if (type12Index >= ipmi::storage::type12Count)
681 {
George Liude6694e2024-07-17 15:22:25 +0800682 lg2::error("getSensorDataRecord: type12Index error");
Johnathan Mantey777cfaf2024-06-13 10:45:47 -0700683 return GENERAL_ERROR;
684 }
685 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
686 }
687 else
688 {
689 // handle fru records
690 get_sdr::SensorDataFruRecord data;
691 if (ipmi::Cc ret = ipmi::storage::getFruSdrs(ctx, sdrIndex, data);
692 ret != IPMI_CC_OK)
693 {
694 return GENERAL_ERROR;
695 }
696 data.header.record_id_msb = recordID >> 8;
697 data.header.record_id_lsb = recordID & 0xFF;
698 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&data),
699 reinterpret_cast<uint8_t*>(&data) + sizeof(data));
700 }
701
702 return 0;
703}
704
Hao Jiangd2afd052020-12-10 15:09:32 -0800705} // namespace sensor
706
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000707ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
708 ipmi::message::Payload& p)
Willy Tude54f482021-01-26 15:59:09 -0800709{
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000710 constexpr const uint8_t validEnvmRev = 0x04;
711 constexpr const uint8_t lastSensorType = 0x2C;
712 constexpr const uint8_t oemReserved = 0xC0;
713
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700714 uint8_t sysgeneratorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000715 uint8_t evmRev = 0;
716 uint8_t sensorType = 0;
717 uint8_t sensorNum = 0;
718 uint8_t eventType = 0;
719 uint8_t eventData1 = 0;
720 std::optional<uint8_t> eventData2 = 0;
721 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700722 [[maybe_unused]] uint16_t generatorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000723 ipmi::ChannelInfo chInfo;
724
725 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
726 {
George Liude6694e2024-07-17 15:22:25 +0800727 lg2::error("Failed to get Channel Info, channel: {CHANNEL}", "CHANNEL",
728 ctx->channel);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000729 return ipmi::responseUnspecifiedError();
730 }
731
732 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
733 ipmi::EChannelMediumType::systemInterface)
734 {
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700735 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000736 eventData1, eventData2, eventData3);
Johnathan Manteya440cd42024-06-20 13:21:48 -0700737 constexpr const uint8_t isSoftwareID = 0x01;
738 if (!(sysgeneratorID & isSoftwareID))
739 {
740 return ipmi::responseInvalidFieldRequest();
741 }
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700742 // Refer to IPMI Spec Table 32: SEL Event Records
743 generatorID = (ctx->channel << 12) // Channel
744 | (0x0 << 10) // Reserved
745 | (0x0 << 8) // 0x0 for sys-soft ID
Johnathan Manteya440cd42024-06-20 13:21:48 -0700746 | sysgeneratorID;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000747 }
748 else
749 {
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000750 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
751 eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700752 // Refer to IPMI Spec Table 32: SEL Event Records
753 generatorID = (ctx->channel << 12) // Channel
754 | (0x0 << 10) // Reserved
755 | ((ctx->lun & 0x3) << 8) // Lun
756 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000757 }
758
759 if (!p.fullyUnpacked())
760 {
761 return ipmi::responseReqDataLenInvalid();
762 }
763
764 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
765 if (evmRev != validEnvmRev)
766 {
767 return ipmi::responseInvalidFieldRequest();
768 }
769 if ((sensorType > lastSensorType) && (sensorType < oemReserved))
770 {
771 return ipmi::responseInvalidFieldRequest();
772 }
773
Willy Tude54f482021-01-26 15:59:09 -0800774 return ipmi::responseSuccess();
775}
776
Willy Tudbafbce2021-03-29 00:37:05 -0700777ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
Willy Tu11d68892022-01-20 10:37:34 -0800778 uint8_t sensorNumber, uint8_t,
Willy Tudbafbce2021-03-29 00:37:05 -0700779 uint8_t reading, uint15_t assertOffset,
Willy Tu11d68892022-01-20 10:37:34 -0800780 bool, uint15_t, bool, uint8_t, uint8_t,
781 uint8_t)
Willy Tudbafbce2021-03-29 00:37:05 -0700782{
783 std::string connection;
784 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -0700785 std::vector<std::string> interfaces;
786
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500787 ipmi::Cc status = getSensorConnection(ctx, sensorNumber, connection, path,
788 &interfaces);
Willy Tudbafbce2021-03-29 00:37:05 -0700789 if (status)
790 {
791 return ipmi::response(status);
792 }
793
Hao Jiangd2afd052020-12-10 15:09:32 -0800794 // we can tell the sensor type by its interface type
Hao Jiange39d4d82021-04-16 17:02:40 -0700795 if (std::find(interfaces.begin(), interfaces.end(),
796 sensor::sensorInterface) != interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700797 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700798 DbusInterfaceMap sensorMap;
799 if (!getSensorMap(ctx, connection, path, sensorMap))
800 {
801 return ipmi::responseResponseError();
802 }
803 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800804 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700805 {
806 return ipmi::responseResponseError();
807 }
808
Jie Yangf0a89942021-07-29 15:30:25 -0700809 // Only allow external SetSensor if write permission granted
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800810 if (!details::sdrWriteTable.getWritePermission((ctx->lun << 8) |
811 sensorNumber))
Jie Yangf0a89942021-07-29 15:30:25 -0700812 {
813 return ipmi::responseResponseError();
814 }
815
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500816 auto value = sensor::calculateValue(reading, sensorMap,
817 sensorObject->second);
Hao Jiangd2afd052020-12-10 15:09:32 -0800818 if (!value)
819 {
820 return ipmi::responseResponseError();
821 }
822
823 if constexpr (debug)
824 {
George Liude6694e2024-07-17 15:22:25 +0800825 lg2::info("IPMI SET_SENSOR, sensor number: {SENSOR_NUM}, "
826 "byte: {BYTE}, value: {VALUE}",
827 "SENSOR_NUM", sensorNumber, "BYTE", (unsigned int)reading,
828 "VALUE", *value);
Hao Jiangd2afd052020-12-10 15:09:32 -0800829 }
830
831 boost::system::error_code ec =
832 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
833 "Value", ipmi::Value(*value));
834
835 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500836 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800837 // callback functions for now (e.g. ipmiSetSensorReading).
838 if (ec)
839 {
George Liude6694e2024-07-17 15:22:25 +0800840 lg2::error("Failed to set Value, path: {PATH}, "
841 "interface: {INTERFACE}, ERROR: {ERROR}",
842 "PATH", path, "INTERFACE", sensor::sensorInterface,
843 "ERROR", ec.message());
Hao Jiangd2afd052020-12-10 15:09:32 -0800844 return ipmi::responseResponseError();
845 }
846 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700847 }
848
Hao Jiange39d4d82021-04-16 17:02:40 -0700849 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
850 interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700851 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700852 DbusInterfaceMap sensorMap;
853 if (!getSensorMap(ctx, connection, path, sensorMap))
854 {
855 return ipmi::responseResponseError();
856 }
857 auto sensorObject = sensorMap.find(sensor::vrInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800858 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700859 {
860 return ipmi::responseResponseError();
861 }
862
Hao Jiangd2afd052020-12-10 15:09:32 -0800863 // VR sensors are treated as a special case and we will not check the
864 // write permission for VR sensors, since they always deemed writable
865 // and permission table are not applied to VR sensors.
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500866 auto vrMode = sensor::calculateVRMode(assertOffset,
867 sensorObject->second);
Hao Jiangd2afd052020-12-10 15:09:32 -0800868 if (!vrMode)
869 {
870 return ipmi::responseResponseError();
871 }
872 boost::system::error_code ec = setDbusProperty(
873 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
874 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500875 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800876 // callback functions for now (e.g. ipmiSetSensorReading).
877 if (ec)
878 {
George Liude6694e2024-07-17 15:22:25 +0800879 lg2::error("Failed to set Selected, path: {PATH}, "
880 "interface: {INTERFACE}, ERROR: {ERROR}",
881 "PATH", path, "INTERFACE", sensor::sensorInterface,
882 "ERROR", ec.message());
Hao Jiangd2afd052020-12-10 15:09:32 -0800883 }
884 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700885 }
886
George Liude6694e2024-07-17 15:22:25 +0800887 lg2::error("unknown sensor type, path: {PATH}", "PATH", path);
Hao Jiangd2afd052020-12-10 15:09:32 -0800888 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700889}
890
Willy Tude54f482021-01-26 15:59:09 -0800891ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
892 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
893{
894 std::string connection;
895 std::string path;
896
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000897 if (sensnum == reservedSensorNumber)
898 {
899 return ipmi::responseInvalidFieldRequest();
900 }
901
Willy Tude54f482021-01-26 15:59:09 -0800902 auto status = getSensorConnection(ctx, sensnum, connection, path);
903 if (status)
904 {
905 return ipmi::response(status);
906 }
907
Scron Chang2703b022021-07-06 15:47:45 +0800908#ifdef FEATURE_HYBRID_SENSORS
909 if (auto sensor = findStaticSensor(path);
910 sensor != ipmi::sensor::sensors.end() &&
911 getSensorEventTypeFromPath(path) !=
912 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
913 {
914 if (ipmi::sensor::Mutability::Read !=
915 (sensor->second.mutability & ipmi::sensor::Mutability::Read))
916 {
917 return ipmi::responseIllegalCommand();
918 }
919
920 uint8_t operation;
921 try
922 {
923 ipmi::sensor::GetSensorResponse getResponse =
924 sensor->second.getFunc(sensor->second);
925
926 if (getResponse.readingOrStateUnavailable)
927 {
928 operation |= static_cast<uint8_t>(
929 IPMISensorReadingByte2::readingStateUnavailable);
930 }
931 if (getResponse.scanningEnabled)
932 {
933 operation |= static_cast<uint8_t>(
934 IPMISensorReadingByte2::sensorScanningEnable);
935 }
936 if (getResponse.allEventMessagesEnabled)
937 {
938 operation |= static_cast<uint8_t>(
939 IPMISensorReadingByte2::eventMessagesEnable);
940 }
941 return ipmi::responseSuccess(
942 getResponse.reading, operation,
943 getResponse.thresholdLevelsStates,
944 getResponse.discreteReadingSensorStates);
945 }
946 catch (const std::exception& e)
947 {
948 operation |= static_cast<uint8_t>(
949 IPMISensorReadingByte2::readingStateUnavailable);
950 return ipmi::responseSuccess(0, operation, 0, std::nullopt);
951 }
952 }
953#endif
954
Willy Tude54f482021-01-26 15:59:09 -0800955 DbusInterfaceMap sensorMap;
956 if (!getSensorMap(ctx, connection, path, sensorMap))
957 {
958 return ipmi::responseResponseError();
959 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800960 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800961
962 if (sensorObject == sensorMap.end() ||
963 sensorObject->second.find("Value") == sensorObject->second.end())
964 {
965 return ipmi::responseResponseError();
966 }
967 auto& valueVariant = sensorObject->second["Value"];
968 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
969
970 double max = 0;
971 double min = 0;
972 getSensorMaxMin(sensorMap, max, min);
973
974 int16_t mValue = 0;
975 int16_t bValue = 0;
976 int8_t rExp = 0;
977 int8_t bExp = 0;
978 bool bSigned = false;
979
980 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
981 {
982 return ipmi::responseResponseError();
983 }
984
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500985 uint8_t value = scaleIPMIValueFromDouble(reading, mValue, rExp, bValue,
986 bExp, bSigned);
Willy Tude54f482021-01-26 15:59:09 -0800987 uint8_t operation =
988 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
989 operation |=
990 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
991 bool notReading = std::isnan(reading);
992
993 if (!notReading)
994 {
995 auto availableObject =
996 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
997 if (availableObject != sensorMap.end())
998 {
999 auto findAvailable = availableObject->second.find("Available");
1000 if (findAvailable != availableObject->second.end())
1001 {
1002 bool* available = std::get_if<bool>(&(findAvailable->second));
1003 if (available && !(*available))
1004 {
1005 notReading = true;
1006 }
1007 }
1008 }
1009 }
1010
1011 if (notReading)
1012 {
1013 operation |= static_cast<uint8_t>(
1014 IPMISensorReadingByte2::readingStateUnavailable);
1015 }
1016
Josh Lehana55c9532020-10-28 21:59:06 -07001017 if constexpr (details::enableInstrumentation)
1018 {
1019 int byteValue;
1020 if (bSigned)
1021 {
1022 byteValue = static_cast<int>(static_cast<int8_t>(value));
1023 }
1024 else
1025 {
1026 byteValue = static_cast<int>(static_cast<uint8_t>(value));
1027 }
1028
1029 // Keep stats on the reading just obtained, even if it is "NaN"
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001030 if (details::sdrStatsTable.updateReading((ctx->lun << 8) | sensnum,
1031 reading, byteValue))
Josh Lehana55c9532020-10-28 21:59:06 -07001032 {
1033 // This is the first reading, show the coefficients
1034 double step = (max - min) / 255.0;
1035 std::cerr << "IPMI sensor "
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001036 << details::sdrStatsTable.getName((ctx->lun << 8) |
1037 sensnum)
Josh Lehana55c9532020-10-28 21:59:06 -07001038 << ": Range min=" << min << " max=" << max
1039 << ", step=" << step
1040 << ", Coefficients mValue=" << static_cast<int>(mValue)
1041 << " rExp=" << static_cast<int>(rExp)
1042 << " bValue=" << static_cast<int>(bValue)
1043 << " bExp=" << static_cast<int>(bExp)
1044 << " bSigned=" << static_cast<int>(bSigned) << "\n";
1045 }
1046 }
1047
Willy Tude54f482021-01-26 15:59:09 -08001048 uint8_t thresholds = 0;
1049
1050 auto warningObject =
1051 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1052 if (warningObject != sensorMap.end())
1053 {
1054 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
1055 auto alarmLow = warningObject->second.find("WarningAlarmLow");
1056 if (alarmHigh != warningObject->second.end())
1057 {
1058 if (std::get<bool>(alarmHigh->second))
1059 {
1060 thresholds |= static_cast<uint8_t>(
1061 IPMISensorReadingByte3::upperNonCritical);
1062 }
1063 }
1064 if (alarmLow != warningObject->second.end())
1065 {
1066 if (std::get<bool>(alarmLow->second))
1067 {
1068 thresholds |= static_cast<uint8_t>(
1069 IPMISensorReadingByte3::lowerNonCritical);
1070 }
1071 }
1072 }
1073
1074 auto criticalObject =
1075 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1076 if (criticalObject != sensorMap.end())
1077 {
1078 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
1079 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
1080 if (alarmHigh != criticalObject->second.end())
1081 {
1082 if (std::get<bool>(alarmHigh->second))
1083 {
1084 thresholds |=
1085 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1086 }
1087 }
1088 if (alarmLow != criticalObject->second.end())
1089 {
1090 if (std::get<bool>(alarmLow->second))
1091 {
1092 thresholds |=
1093 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1094 }
1095 }
1096 }
1097
1098 // no discrete as of today so optional byte is never returned
1099 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
1100}
1101
1102/** @brief implements the Set Sensor threshold command
1103 * @param sensorNumber - sensor number
1104 * @param lowerNonCriticalThreshMask
1105 * @param lowerCriticalThreshMask
1106 * @param lowerNonRecovThreshMask
1107 * @param upperNonCriticalThreshMask
1108 * @param upperCriticalThreshMask
1109 * @param upperNonRecovThreshMask
1110 * @param reserved
1111 * @param lowerNonCritical - lower non-critical threshold
1112 * @param lowerCritical - Lower critical threshold
1113 * @param lowerNonRecoverable - Lower non recovarable threshold
1114 * @param upperNonCritical - Upper non-critical threshold
1115 * @param upperCritical - Upper critical
1116 * @param upperNonRecoverable - Upper Non-recoverable
1117 *
1118 * @returns IPMI completion code
1119 */
1120ipmi::RspType<> ipmiSenSetSensorThresholds(
1121 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
1122 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
1123 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
1124 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
Willy Tu11d68892022-01-20 10:37:34 -08001125 uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
Willy Tude54f482021-01-26 15:59:09 -08001126 uint8_t upperNonCritical, uint8_t upperCritical,
Willy Tu11d68892022-01-20 10:37:34 -08001127 [[maybe_unused]] uint8_t upperNonRecoverable)
Willy Tude54f482021-01-26 15:59:09 -08001128{
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001129 if (sensorNum == reservedSensorNumber || reserved)
Willy Tude54f482021-01-26 15:59:09 -08001130 {
1131 return ipmi::responseInvalidFieldRequest();
1132 }
1133
1134 // lower nc and upper nc not suppported on any sensor
1135 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
1136 {
1137 return ipmi::responseInvalidFieldRequest();
1138 }
1139
1140 // if none of the threshold mask are set, nothing to do
1141 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
1142 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
1143 upperCriticalThreshMask | upperNonRecovThreshMask))
1144 {
1145 return ipmi::responseSuccess();
1146 }
1147
1148 std::string connection;
1149 std::string path;
1150
1151 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
1152 if (status)
1153 {
1154 return ipmi::response(status);
1155 }
1156 DbusInterfaceMap sensorMap;
1157 if (!getSensorMap(ctx, connection, path, sensorMap))
1158 {
1159 return ipmi::responseResponseError();
1160 }
1161
1162 double max = 0;
1163 double min = 0;
1164 getSensorMaxMin(sensorMap, max, min);
1165
1166 int16_t mValue = 0;
1167 int16_t bValue = 0;
1168 int8_t rExp = 0;
1169 int8_t bExp = 0;
1170 bool bSigned = false;
1171
1172 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1173 {
1174 return ipmi::responseResponseError();
1175 }
1176
1177 // store a vector of property name, value to set, and interface
1178 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
1179
1180 // define the indexes of the tuple
1181 constexpr uint8_t propertyName = 0;
1182 constexpr uint8_t thresholdValue = 1;
1183 constexpr uint8_t interface = 2;
1184 // verifiy all needed fields are present
1185 if (lowerCriticalThreshMask || upperCriticalThreshMask)
1186 {
1187 auto findThreshold =
1188 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1189 if (findThreshold == sensorMap.end())
1190 {
1191 return ipmi::responseInvalidFieldRequest();
1192 }
1193 if (lowerCriticalThreshMask)
1194 {
1195 auto findLower = findThreshold->second.find("CriticalLow");
1196 if (findLower == findThreshold->second.end())
1197 {
1198 return ipmi::responseInvalidFieldRequest();
1199 }
1200 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
1201 findThreshold->first);
1202 }
1203 if (upperCriticalThreshMask)
1204 {
1205 auto findUpper = findThreshold->second.find("CriticalHigh");
1206 if (findUpper == findThreshold->second.end())
1207 {
1208 return ipmi::responseInvalidFieldRequest();
1209 }
1210 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
1211 findThreshold->first);
1212 }
1213 }
1214 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
1215 {
1216 auto findThreshold =
1217 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1218 if (findThreshold == sensorMap.end())
1219 {
1220 return ipmi::responseInvalidFieldRequest();
1221 }
1222 if (lowerNonCriticalThreshMask)
1223 {
1224 auto findLower = findThreshold->second.find("WarningLow");
1225 if (findLower == findThreshold->second.end())
1226 {
1227 return ipmi::responseInvalidFieldRequest();
1228 }
1229 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
1230 findThreshold->first);
1231 }
1232 if (upperNonCriticalThreshMask)
1233 {
1234 auto findUpper = findThreshold->second.find("WarningHigh");
1235 if (findUpper == findThreshold->second.end())
1236 {
1237 return ipmi::responseInvalidFieldRequest();
1238 }
1239 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
1240 findThreshold->first);
1241 }
1242 }
1243 for (const auto& property : thresholdsToSet)
1244 {
1245 // from section 36.3 in the IPMI Spec, assume all linear
1246 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
1247 (bValue * std::pow(10.0, bExp))) *
1248 std::pow(10.0, rExp);
1249 setDbusProperty(
1250 *getSdBus(), connection, path, std::get<interface>(property),
1251 std::get<propertyName>(property), ipmi::Value(valueToSet));
1252 }
1253 return ipmi::responseSuccess();
1254}
1255
1256IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
1257{
1258 IPMIThresholds resp;
1259 auto warningInterface =
1260 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1261 auto criticalInterface =
1262 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1263
1264 if ((warningInterface != sensorMap.end()) ||
1265 (criticalInterface != sensorMap.end()))
1266 {
Hao Jiangd2afd052020-12-10 15:09:32 -08001267 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -08001268
1269 if (sensorPair == sensorMap.end())
1270 {
1271 // should not have been able to find a sensor not implementing
1272 // the sensor object
1273 throw std::runtime_error("Invalid sensor map");
1274 }
1275
1276 double max = 0;
1277 double min = 0;
1278 getSensorMaxMin(sensorMap, max, min);
1279
1280 int16_t mValue = 0;
1281 int16_t bValue = 0;
1282 int8_t rExp = 0;
1283 int8_t bExp = 0;
1284 bool bSigned = false;
1285
1286 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1287 {
1288 throw std::runtime_error("Invalid sensor atrributes");
1289 }
1290 if (warningInterface != sensorMap.end())
1291 {
1292 auto& warningMap = warningInterface->second;
1293
1294 auto warningHigh = warningMap.find("WarningHigh");
1295 auto warningLow = warningMap.find("WarningLow");
1296
1297 if (warningHigh != warningMap.end())
1298 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001299 double value = std::visit(VariantToDoubleVisitor(),
1300 warningHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001301 if (std::isfinite(value))
1302 {
1303 resp.warningHigh = scaleIPMIValueFromDouble(
1304 value, mValue, rExp, bValue, bExp, bSigned);
1305 }
Willy Tude54f482021-01-26 15:59:09 -08001306 }
1307 if (warningLow != warningMap.end())
1308 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001309 double value = std::visit(VariantToDoubleVisitor(),
1310 warningLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001311 if (std::isfinite(value))
1312 {
1313 resp.warningLow = scaleIPMIValueFromDouble(
1314 value, mValue, rExp, bValue, bExp, bSigned);
1315 }
Willy Tude54f482021-01-26 15:59:09 -08001316 }
1317 }
1318 if (criticalInterface != sensorMap.end())
1319 {
1320 auto& criticalMap = criticalInterface->second;
1321
1322 auto criticalHigh = criticalMap.find("CriticalHigh");
1323 auto criticalLow = criticalMap.find("CriticalLow");
1324
1325 if (criticalHigh != criticalMap.end())
1326 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001327 double value = std::visit(VariantToDoubleVisitor(),
1328 criticalHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001329 if (std::isfinite(value))
1330 {
1331 resp.criticalHigh = scaleIPMIValueFromDouble(
1332 value, mValue, rExp, bValue, bExp, bSigned);
1333 }
Willy Tude54f482021-01-26 15:59:09 -08001334 }
1335 if (criticalLow != criticalMap.end())
1336 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001337 double value = std::visit(VariantToDoubleVisitor(),
1338 criticalLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001339 if (std::isfinite(value))
1340 {
1341 resp.criticalLow = scaleIPMIValueFromDouble(
1342 value, mValue, rExp, bValue, bExp, bSigned);
1343 }
Willy Tude54f482021-01-26 15:59:09 -08001344 }
1345 }
1346 }
1347 return resp;
1348}
1349
1350ipmi::RspType<uint8_t, // readable
1351 uint8_t, // lowerNCrit
1352 uint8_t, // lowerCrit
1353 uint8_t, // lowerNrecoverable
1354 uint8_t, // upperNC
1355 uint8_t, // upperCrit
1356 uint8_t> // upperNRecoverable
1357 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
1358{
1359 std::string connection;
1360 std::string path;
1361
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001362 if (sensorNumber == reservedSensorNumber)
1363 {
1364 return ipmi::responseInvalidFieldRequest();
1365 }
1366
Willy Tude54f482021-01-26 15:59:09 -08001367 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
1368 if (status)
1369 {
1370 return ipmi::response(status);
1371 }
1372
1373 DbusInterfaceMap sensorMap;
1374 if (!getSensorMap(ctx, connection, path, sensorMap))
1375 {
1376 return ipmi::responseResponseError();
1377 }
1378
1379 IPMIThresholds thresholdData;
1380 try
1381 {
1382 thresholdData = getIPMIThresholds(sensorMap);
1383 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001384 catch (const std::exception&)
Willy Tude54f482021-01-26 15:59:09 -08001385 {
1386 return ipmi::responseResponseError();
1387 }
1388
1389 uint8_t readable = 0;
1390 uint8_t lowerNC = 0;
1391 uint8_t lowerCritical = 0;
1392 uint8_t lowerNonRecoverable = 0;
1393 uint8_t upperNC = 0;
1394 uint8_t upperCritical = 0;
1395 uint8_t upperNonRecoverable = 0;
1396
1397 if (thresholdData.warningHigh)
1398 {
1399 readable |=
1400 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
1401 upperNC = *thresholdData.warningHigh;
1402 }
1403 if (thresholdData.warningLow)
1404 {
1405 readable |=
1406 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
1407 lowerNC = *thresholdData.warningLow;
1408 }
1409
1410 if (thresholdData.criticalHigh)
1411 {
1412 readable |=
1413 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
1414 upperCritical = *thresholdData.criticalHigh;
1415 }
1416 if (thresholdData.criticalLow)
1417 {
1418 readable |=
1419 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
1420 lowerCritical = *thresholdData.criticalLow;
1421 }
1422
1423 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
1424 lowerNonRecoverable, upperNC, upperCritical,
1425 upperNonRecoverable);
1426}
1427
1428/** @brief implements the get Sensor event enable command
1429 * @param sensorNumber - sensor number
1430 *
1431 * @returns IPMI completion code plus response data
1432 * - enabled - Sensor Event messages
1433 * - assertionEnabledLsb - Assertion event messages
1434 * - assertionEnabledMsb - Assertion event messages
1435 * - deassertionEnabledLsb - Deassertion event messages
1436 * - deassertionEnabledMsb - Deassertion event messages
1437 */
1438
1439ipmi::RspType<uint8_t, // enabled
1440 uint8_t, // assertionEnabledLsb
1441 uint8_t, // assertionEnabledMsb
1442 uint8_t, // deassertionEnabledLsb
1443 uint8_t> // deassertionEnabledMsb
1444 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
1445{
1446 std::string connection;
1447 std::string path;
1448
1449 uint8_t enabled = 0;
1450 uint8_t assertionEnabledLsb = 0;
1451 uint8_t assertionEnabledMsb = 0;
1452 uint8_t deassertionEnabledLsb = 0;
1453 uint8_t deassertionEnabledMsb = 0;
1454
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001455 if (sensorNum == reservedSensorNumber)
1456 {
1457 return ipmi::responseInvalidFieldRequest();
1458 }
1459
Willy Tude54f482021-01-26 15:59:09 -08001460 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1461 if (status)
1462 {
1463 return ipmi::response(status);
1464 }
1465
Scron Chang2703b022021-07-06 15:47:45 +08001466#ifdef FEATURE_HYBRID_SENSORS
1467 if (auto sensor = findStaticSensor(path);
1468 sensor != ipmi::sensor::sensors.end() &&
1469 getSensorEventTypeFromPath(path) !=
1470 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1471 {
1472 enabled = static_cast<uint8_t>(
1473 IPMISensorEventEnableByte2::sensorScanningEnable);
1474 uint16_t assertionEnabled = 0;
1475 for (auto& offsetValMap : sensor->second.propertyInterfaces.begin()
1476 ->second.begin()
1477 ->second.second)
1478 {
1479 assertionEnabled |= (1 << offsetValMap.first);
1480 }
1481 assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF));
1482 assertionEnabledMsb =
1483 static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF));
1484
1485 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1486 assertionEnabledMsb, deassertionEnabledLsb,
1487 deassertionEnabledMsb);
1488 }
1489#endif
1490
Willy Tude54f482021-01-26 15:59:09 -08001491 DbusInterfaceMap sensorMap;
1492 if (!getSensorMap(ctx, connection, path, sensorMap))
1493 {
1494 return ipmi::responseResponseError();
1495 }
1496
1497 auto warningInterface =
1498 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1499 auto criticalInterface =
1500 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1501 if ((warningInterface != sensorMap.end()) ||
1502 (criticalInterface != sensorMap.end()))
1503 {
1504 enabled = static_cast<uint8_t>(
1505 IPMISensorEventEnableByte2::sensorScanningEnable);
1506 if (warningInterface != sensorMap.end())
1507 {
1508 auto& warningMap = warningInterface->second;
1509
1510 auto warningHigh = warningMap.find("WarningHigh");
1511 auto warningLow = warningMap.find("WarningLow");
1512 if (warningHigh != warningMap.end())
1513 {
Johnathan Mantey92217f02024-06-20 12:43:01 -07001514 double value = std::visit(VariantToDoubleVisitor(),
1515 warningHigh->second);
1516 if (std::isfinite(value))
1517 {
1518 assertionEnabledLsb |= static_cast<uint8_t>(
1519 IPMISensorEventEnableThresholds::
1520 upperNonCriticalGoingHigh);
1521 deassertionEnabledLsb |= static_cast<uint8_t>(
1522 IPMISensorEventEnableThresholds::
1523 upperNonCriticalGoingLow);
1524 }
Willy Tude54f482021-01-26 15:59:09 -08001525 }
1526 if (warningLow != warningMap.end())
1527 {
Johnathan Mantey92217f02024-06-20 12:43:01 -07001528 double value = std::visit(VariantToDoubleVisitor(),
1529 warningLow->second);
1530 if (std::isfinite(value))
1531 {
1532 assertionEnabledLsb |= static_cast<uint8_t>(
1533 IPMISensorEventEnableThresholds::
1534 lowerNonCriticalGoingLow);
1535 deassertionEnabledLsb |= static_cast<uint8_t>(
1536 IPMISensorEventEnableThresholds::
1537 lowerNonCriticalGoingHigh);
1538 }
Willy Tude54f482021-01-26 15:59:09 -08001539 }
1540 }
1541 if (criticalInterface != sensorMap.end())
1542 {
1543 auto& criticalMap = criticalInterface->second;
1544
1545 auto criticalHigh = criticalMap.find("CriticalHigh");
1546 auto criticalLow = criticalMap.find("CriticalLow");
1547
1548 if (criticalHigh != criticalMap.end())
1549 {
Johnathan Mantey92217f02024-06-20 12:43:01 -07001550 double value = std::visit(VariantToDoubleVisitor(),
1551 criticalHigh->second);
1552 if (std::isfinite(value))
1553 {
1554 assertionEnabledMsb |= static_cast<uint8_t>(
1555 IPMISensorEventEnableThresholds::
1556 upperCriticalGoingHigh);
1557 deassertionEnabledMsb |= static_cast<uint8_t>(
1558 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1559 }
Willy Tude54f482021-01-26 15:59:09 -08001560 }
1561 if (criticalLow != criticalMap.end())
1562 {
Johnathan Mantey92217f02024-06-20 12:43:01 -07001563 double value = std::visit(VariantToDoubleVisitor(),
1564 criticalLow->second);
1565 if (std::isfinite(value))
1566 {
1567 assertionEnabledLsb |= static_cast<uint8_t>(
1568 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1569 deassertionEnabledLsb |= static_cast<uint8_t>(
1570 IPMISensorEventEnableThresholds::
1571 lowerCriticalGoingHigh);
1572 }
Willy Tude54f482021-01-26 15:59:09 -08001573 }
1574 }
1575 }
1576
1577 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1578 assertionEnabledMsb, deassertionEnabledLsb,
1579 deassertionEnabledMsb);
1580}
1581
1582/** @brief implements the get Sensor event status command
1583 * @param sensorNumber - sensor number, FFh = reserved
1584 *
1585 * @returns IPMI completion code plus response data
1586 * - sensorEventStatus - Sensor Event messages state
1587 * - assertions - Assertion event messages
1588 * - deassertions - Deassertion event messages
1589 */
1590ipmi::RspType<uint8_t, // sensorEventStatus
1591 std::bitset<16>, // assertions
1592 std::bitset<16> // deassertion
1593 >
1594 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1595{
1596 if (sensorNum == reservedSensorNumber)
1597 {
1598 return ipmi::responseInvalidFieldRequest();
1599 }
1600
1601 std::string connection;
1602 std::string path;
1603 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1604 if (status)
1605 {
George Liude6694e2024-07-17 15:22:25 +08001606 lg2::error("ipmiSenGetSensorEventStatus: Sensor connection Error, "
1607 "sensor number: {SENSOR_NUM}",
1608 "SENSOR_NUM", sensorNum);
Willy Tude54f482021-01-26 15:59:09 -08001609 return ipmi::response(status);
1610 }
1611
Scron Chang2703b022021-07-06 15:47:45 +08001612#ifdef FEATURE_HYBRID_SENSORS
1613 if (auto sensor = findStaticSensor(path);
1614 sensor != ipmi::sensor::sensors.end() &&
1615 getSensorEventTypeFromPath(path) !=
1616 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1617 {
1618 auto response = ipmi::sensor::get::mapDbusToAssertion(
1619 sensor->second, path, sensor->second.sensorInterface);
1620 std::bitset<16> assertions;
1621 // deassertions are not used.
1622 std::bitset<16> deassertions = 0;
1623 uint8_t sensorEventStatus;
1624 if (response.readingOrStateUnavailable)
1625 {
1626 sensorEventStatus |= static_cast<uint8_t>(
1627 IPMISensorReadingByte2::readingStateUnavailable);
1628 }
1629 if (response.scanningEnabled)
1630 {
1631 sensorEventStatus |= static_cast<uint8_t>(
1632 IPMISensorReadingByte2::sensorScanningEnable);
1633 }
1634 if (response.allEventMessagesEnabled)
1635 {
1636 sensorEventStatus |= static_cast<uint8_t>(
1637 IPMISensorReadingByte2::eventMessagesEnable);
1638 }
1639 assertions |= response.discreteReadingSensorStates << 8;
1640 assertions |= response.thresholdLevelsStates;
1641 return ipmi::responseSuccess(sensorEventStatus, assertions,
1642 deassertions);
1643 }
1644#endif
1645
Willy Tude54f482021-01-26 15:59:09 -08001646 DbusInterfaceMap sensorMap;
1647 if (!getSensorMap(ctx, connection, path, sensorMap))
1648 {
George Liude6694e2024-07-17 15:22:25 +08001649 lg2::error("ipmiSenGetSensorEventStatus: Sensor Mapping Error, "
1650 "sensor path: {SENSOR_PATH}",
1651 "SENSOR_PATH", path);
Willy Tude54f482021-01-26 15:59:09 -08001652 return ipmi::responseResponseError();
1653 }
Hao Jiangd48c9212021-02-03 15:45:06 -08001654
1655 uint8_t sensorEventStatus =
1656 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1657 std::bitset<16> assertions = 0;
1658 std::bitset<16> deassertions = 0;
1659
1660 // handle VR typed sensor
1661 auto vrInterface = sensorMap.find(sensor::vrInterface);
1662 if (vrInterface != sensorMap.end())
1663 {
1664 if (!sensor::getVrEventStatus(ctx, connection, path,
1665 vrInterface->second, assertions))
1666 {
1667 return ipmi::responseResponseError();
1668 }
1669
1670 // both Event Message and Sensor Scanning are disable for VR.
1671 sensorEventStatus = 0;
1672 return ipmi::responseSuccess(sensorEventStatus, assertions,
1673 deassertions);
1674 }
1675
Willy Tude54f482021-01-26 15:59:09 -08001676 auto warningInterface =
1677 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1678 auto criticalInterface =
1679 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1680
Willy Tude54f482021-01-26 15:59:09 -08001681 std::optional<bool> criticalDeassertHigh =
1682 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1683 std::optional<bool> criticalDeassertLow =
1684 thresholdDeassertMap[path]["CriticalAlarmLow"];
1685 std::optional<bool> warningDeassertHigh =
1686 thresholdDeassertMap[path]["WarningAlarmHigh"];
1687 std::optional<bool> warningDeassertLow =
1688 thresholdDeassertMap[path]["WarningAlarmLow"];
1689
Willy Tude54f482021-01-26 15:59:09 -08001690 if (criticalDeassertHigh && !*criticalDeassertHigh)
1691 {
1692 deassertions.set(static_cast<size_t>(
1693 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1694 }
1695 if (criticalDeassertLow && !*criticalDeassertLow)
1696 {
1697 deassertions.set(static_cast<size_t>(
1698 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1699 }
1700 if (warningDeassertHigh && !*warningDeassertHigh)
1701 {
1702 deassertions.set(static_cast<size_t>(
1703 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1704 }
1705 if (warningDeassertLow && !*warningDeassertLow)
1706 {
1707 deassertions.set(static_cast<size_t>(
1708 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1709 }
1710 if ((warningInterface != sensorMap.end()) ||
1711 (criticalInterface != sensorMap.end()))
1712 {
1713 sensorEventStatus = static_cast<size_t>(
1714 IPMISensorEventEnableByte2::eventMessagesEnable);
1715 if (warningInterface != sensorMap.end())
1716 {
1717 auto& warningMap = warningInterface->second;
1718
1719 auto warningHigh = warningMap.find("WarningAlarmHigh");
1720 auto warningLow = warningMap.find("WarningAlarmLow");
1721 auto warningHighAlarm = false;
1722 auto warningLowAlarm = false;
1723
1724 if (warningHigh != warningMap.end())
1725 {
1726 warningHighAlarm = std::get<bool>(warningHigh->second);
1727 }
1728 if (warningLow != warningMap.end())
1729 {
1730 warningLowAlarm = std::get<bool>(warningLow->second);
1731 }
1732 if (warningHighAlarm)
1733 {
1734 assertions.set(
1735 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1736 upperNonCriticalGoingHigh));
1737 }
1738 if (warningLowAlarm)
1739 {
1740 assertions.set(
1741 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1742 lowerNonCriticalGoingLow));
1743 }
1744 }
1745 if (criticalInterface != sensorMap.end())
1746 {
1747 auto& criticalMap = criticalInterface->second;
1748
1749 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1750 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1751 auto criticalHighAlarm = false;
1752 auto criticalLowAlarm = false;
1753
1754 if (criticalHigh != criticalMap.end())
1755 {
1756 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1757 }
1758 if (criticalLow != criticalMap.end())
1759 {
1760 criticalLowAlarm = std::get<bool>(criticalLow->second);
1761 }
1762 if (criticalHighAlarm)
1763 {
1764 assertions.set(
1765 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1766 upperCriticalGoingHigh));
1767 }
1768 if (criticalLowAlarm)
1769 {
1770 assertions.set(static_cast<size_t>(
1771 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1772 }
1773 }
1774 }
1775
1776 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1777}
1778
Willy Tu38e7a2b2021-03-29 15:09:56 -07001779// Construct a type 1 SDR for threshold sensor.
Hao Jiange39d4d82021-04-16 17:02:40 -07001780void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1781 get_sdr::SensorDataFullRecord& record)
Willy Tude54f482021-01-26 15:59:09 -08001782{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001783 get_sdr::header::set_record_id(
1784 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1785
Willy Tu38e7a2b2021-03-29 15:09:56 -07001786 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1787 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1788
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001789 record.header.sdr_version = ipmiSdrVersion;
1790 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1791 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1792 sizeof(get_sdr::SensorDataRecordHeader);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001793 record.key.owner_id = bmcI2CAddr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001794 record.key.owner_lun = lun;
1795 record.key.sensor_number = sensornumber;
Hao Jiange39d4d82021-04-16 17:02:40 -07001796}
Willy Tu4eca2512022-06-20 21:14:51 -07001797bool constructSensorSdr(
1798 ipmi::Context::ptr ctx,
1799 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1800 uint16_t sensorNum, uint16_t recordID, const std::string& service,
1801 const std::string& path, get_sdr::SensorDataFullRecord& record)
Hao Jiange39d4d82021-04-16 17:02:40 -07001802{
Hao Jiange39d4d82021-04-16 17:02:40 -07001803 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1804
1805 DbusInterfaceMap sensorMap;
1806 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1807 {
George Liude6694e2024-07-17 15:22:25 +08001808 lg2::error("Failed to update sensor map for threshold sensor, "
1809 "service: {SERVICE}, path: {PATH}",
1810 "SERVICE", service, "PATH", path);
Hao Jiange39d4d82021-04-16 17:02:40 -07001811 return false;
1812 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001813
1814 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1815 record.body.sensor_type = getSensorTypeFromPath(path);
1816 std::string type = getSensorTypeStringFromPath(path);
1817 auto typeCstr = type.c_str();
1818 auto findUnits = sensorUnits.find(typeCstr);
1819 if (findUnits != sensorUnits.end())
1820 {
1821 record.body.sensor_units_2_base =
1822 static_cast<uint8_t>(findUnits->second);
1823 } // else default 0x0 unspecified
1824
1825 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1826
Hao Jiangd2afd052020-12-10 15:09:32 -08001827 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001828 if (sensorObject == sensorMap.end())
1829 {
George Liude6694e2024-07-17 15:22:25 +08001830 lg2::error("constructSensorSdr: sensorObject error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001831 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001832 }
1833
1834 uint8_t entityId = 0;
1835 uint8_t entityInstance = 0x01;
1836
1837 // follow the association chain to get the parent board's entityid and
1838 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001839 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, entityId,
1840 entityInstance);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001841
1842 record.body.entity_id = entityId;
1843 record.body.entity_instance = entityInstance;
1844
Shakeeb Pasha93889722021-10-14 10:20:13 +05301845 double max = 0;
1846 double min = 0;
1847 getSensorMaxMin(sensorMap, max, min);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001848
1849 int16_t mValue = 0;
1850 int8_t rExp = 0;
1851 int16_t bValue = 0;
1852 int8_t bExp = 0;
1853 bool bSigned = false;
1854
1855 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1856 {
George Liude6694e2024-07-17 15:22:25 +08001857 lg2::error("constructSensorSdr: getSensorAttributes error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001858 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001859 }
1860
1861 // The record.body is a struct SensorDataFullRecordBody
1862 // from sensorhandler.hpp in phosphor-ipmi-host.
1863 // The meaning of these bits appears to come from
1864 // table 43.1 of the IPMI spec.
1865 // The above 5 sensor attributes are stuffed in as follows:
1866 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1867 // Byte 22-24 are for other purposes
1868 // Byte 25 = MMMMMMMM = LSB of M
1869 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1870 // Byte 27 = BBBBBBBB = LSB of B
1871 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1872 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1873 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1874
1875 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1876 record.body.m_lsb = mValue & 0xFF;
1877
1878 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1879 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1880
1881 // move the smallest bit of the MSB into place (bit 9)
1882 // the MSbs are bits 7:8 in m_msb_and_tolerance
1883 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1884
1885 record.body.b_lsb = bValue & 0xFF;
1886
1887 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1888 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1889
1890 // move the smallest bit of the MSB into place (bit 9)
1891 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1892 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1893
1894 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1895 uint8_t rExpBits = rExp & 0x07;
1896
1897 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1898 uint8_t bExpBits = bExp & 0x07;
1899
1900 // move rExp and bExp into place
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001901 record.body.r_b_exponents = (rExpSign << 7) | (rExpBits << 4) |
1902 (bExpSign << 3) | bExpBits;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001903
1904 // Set the analog reading byte interpretation accordingly
1905 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1906
1907 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1908 // These seem redundant, but derivable from the above 5 attributes
1909 // Original comment said "todo fill out rest of units"
1910
1911 // populate sensor name from path
Willy Tu38e7a2b2021-03-29 15:09:56 -07001912 auto name = sensor::parseSdrIdFromPath(path);
Paul Fertser51136982022-08-18 12:36:41 +00001913 get_sdr::body::set_id_strlen(name.size(), &record.body);
1914 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Patrick Williams2f0a6d02023-08-17 12:54:08 -05001915 std::memcpy(record.body.id_string, name.c_str(),
1916 std::min(name.length() + 1, sizeof(record.body.id_string)));
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001917
Josh Lehana55c9532020-10-28 21:59:06 -07001918 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001919 details::sdrStatsTable.updateName(sensorNum, name);
Josh Lehana55c9532020-10-28 21:59:06 -07001920
Jie Yangf0a89942021-07-29 15:30:25 -07001921 bool sensorSettable = false;
1922 auto mutability =
1923 sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability");
1924 if (mutability != sensorMap.end())
1925 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05001926 sensorSettable = mappedVariant<bool>(mutability->second, "Mutable",
1927 false);
Jie Yangf0a89942021-07-29 15:30:25 -07001928 }
1929 get_sdr::body::init_settable_state(sensorSettable, &record.body);
1930
1931 // Grant write permission to sensors deemed externally settable
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001932 details::sdrWriteTable.setWritePermission(sensorNum, sensorSettable);
Willy Tu530e2772021-07-02 14:42:06 -07001933
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001934 IPMIThresholds thresholdData;
1935 try
1936 {
1937 thresholdData = getIPMIThresholds(sensorMap);
1938 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001939 catch (const std::exception&)
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001940 {
George Liude6694e2024-07-17 15:22:25 +08001941 lg2::error("constructSensorSdr: getIPMIThresholds error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001942 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001943 }
1944
1945 if (thresholdData.criticalHigh)
1946 {
1947 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1948 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1949 IPMISensorEventEnableThresholds::criticalThreshold);
1950 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1951 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1952 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1953 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1954 record.body.discrete_reading_setting_mask[0] |=
1955 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1956 }
1957 if (thresholdData.warningHigh)
1958 {
1959 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1960 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1961 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1962 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1963 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1964 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1965 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1966 record.body.discrete_reading_setting_mask[0] |=
1967 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1968 }
1969 if (thresholdData.criticalLow)
1970 {
1971 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1972 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1973 IPMISensorEventEnableThresholds::criticalThreshold);
1974 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1975 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1976 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1977 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1978 record.body.discrete_reading_setting_mask[0] |=
1979 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1980 }
1981 if (thresholdData.warningLow)
1982 {
1983 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1984 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1985 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1986 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1987 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1988 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1989 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1990 record.body.discrete_reading_setting_mask[0] |=
1991 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1992 }
1993
1994 // everything that is readable is setable
1995 record.body.discrete_reading_setting_mask[1] =
1996 record.body.discrete_reading_setting_mask[0];
Willy Tu38e7a2b2021-03-29 15:09:56 -07001997 return true;
1998}
1999
Scron Chang2703b022021-07-06 15:47:45 +08002000#ifdef FEATURE_HYBRID_SENSORS
2001// Construct a type 1 SDR for discrete Sensor typed sensor.
Willy Tu11d68892022-01-20 10:37:34 -08002002void constructStaticSensorSdr(ipmi::Context::ptr, uint16_t sensorNum,
Scron Chang2703b022021-07-06 15:47:45 +08002003 uint16_t recordID,
2004 ipmi::sensor::IdInfoMap::const_iterator sensor,
2005 get_sdr::SensorDataFullRecord& record)
2006{
2007 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2008
2009 record.body.entity_id = sensor->second.entityType;
2010 record.body.sensor_type = sensor->second.sensorType;
2011 record.body.event_reading_type = sensor->second.sensorReadingType;
2012 record.body.entity_instance = sensor->second.instance;
2013 if (ipmi::sensor::Mutability::Write ==
2014 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
2015 {
2016 get_sdr::body::init_settable_state(true, &(record.body));
2017 }
2018
2019 auto id_string = sensor->second.sensorName;
2020
2021 if (id_string.empty())
2022 {
2023 id_string = sensor->second.sensorNameFunc(sensor->second);
2024 }
2025
2026 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
2027 {
2028 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH,
2029 &(record.body));
2030 }
2031 else
2032 {
2033 get_sdr::body::set_id_strlen(id_string.length(), &(record.body));
2034 }
Paul Fertser51136982022-08-18 12:36:41 +00002035 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Scron Chang2703b022021-07-06 15:47:45 +08002036 std::strncpy(record.body.id_string, id_string.c_str(),
2037 get_sdr::body::get_id_strlen(&(record.body)));
2038}
2039#endif
2040
Hao Jiange39d4d82021-04-16 17:02:40 -07002041// Construct type 3 SDR header and key (for VR and other discrete sensors)
2042void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
2043 get_sdr::SensorDataEventRecord& record)
Willy Tu61992ad2021-03-29 15:33:20 -07002044{
2045 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
2046 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
2047
2048 get_sdr::header::set_record_id(
2049 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
2050
2051 record.header.sdr_version = ipmiSdrVersion;
2052 record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD;
2053 record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) -
2054 sizeof(get_sdr::SensorDataRecordHeader);
2055 record.key.owner_id = bmcI2CAddr;
2056 record.key.owner_lun = lun;
2057 record.key.sensor_number = sensornumber;
2058
2059 record.body.entity_id = 0x00;
2060 record.body.entity_instance = 0x01;
Hao Jiange39d4d82021-04-16 17:02:40 -07002061}
Willy Tu61992ad2021-03-29 15:33:20 -07002062
Hao Jiange39d4d82021-04-16 17:02:40 -07002063// Construct a type 3 SDR for VR typed sensor(daemon).
Willy Tu4eca2512022-06-20 21:14:51 -07002064bool constructVrSdr(ipmi::Context::ptr ctx,
2065 const std::unordered_set<std::string>& ipmiDecoratorPaths,
2066 uint16_t sensorNum, uint16_t recordID,
2067 const std::string& service, const std::string& path,
Hao Jiange39d4d82021-04-16 17:02:40 -07002068 get_sdr::SensorDataEventRecord& record)
2069{
Hao Jiange39d4d82021-04-16 17:02:40 -07002070 constructEventSdrHeaderKey(sensorNum, recordID, record);
2071
2072 DbusInterfaceMap sensorMap;
2073 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
2074 {
George Liude6694e2024-07-17 15:22:25 +08002075 lg2::error("Failed to update sensor map for VR sensor, "
2076 "service: {SERVICE}, path: {PATH}",
2077 "SERVICE", service, "PATH", path);
Hao Jiange39d4d82021-04-16 17:02:40 -07002078 return false;
2079 }
Willy Tu61992ad2021-03-29 15:33:20 -07002080 // follow the association chain to get the parent board's entityid and
2081 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07002082 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap,
2083 record.body.entity_id,
Willy Tu61992ad2021-03-29 15:33:20 -07002084 record.body.entity_instance);
2085
2086 // Sensor type is hardcoded as a module/board type instead of parsing from
2087 // sensor path. This is because VR control is allocated in an independent
2088 // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by
2089 // types.
2090 static constexpr const uint8_t module_board_type = 0x15;
2091 record.body.sensor_type = module_board_type;
2092 record.body.event_reading_type = 0x00;
2093
2094 record.body.sensor_record_sharing_1 = 0x00;
2095 record.body.sensor_record_sharing_2 = 0x00;
2096
2097 // populate sensor name from path
2098 auto name = sensor::parseSdrIdFromPath(path);
2099 int nameSize = std::min(name.size(), sizeof(record.body.id_string));
Paul Fertser51136982022-08-18 12:36:41 +00002100 get_sdr::body::set_id_strlen(nameSize, &record.body);
2101 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Willy Tu61992ad2021-03-29 15:33:20 -07002102 std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string));
2103 std::memcpy(record.body.id_string, name.c_str(), nameSize);
2104
2105 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08002106 details::sdrStatsTable.updateName(sensorNum, name);
Hao Jiange39d4d82021-04-16 17:02:40 -07002107
2108 return true;
Willy Tu61992ad2021-03-29 15:33:20 -07002109}
2110
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002111uint16_t getNumberOfSensors()
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002112{
2113 return std::min(getSensorTree().size(), maxIPMISensors);
2114}
2115
Willy Tu4eca2512022-06-20 21:14:51 -07002116static int getSensorDataRecord(
2117 ipmi::Context::ptr ctx,
2118 const std::unordered_set<std::string>& ipmiDecoratorPaths,
2119 std::vector<uint8_t>& recordData, uint16_t recordID,
2120 uint8_t readBytes = std::numeric_limits<uint8_t>::max())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002121{
selvaganapathi7b2e5502023-02-14 07:10:47 +05302122 recordData.clear();
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002123 size_t lastRecord = ipmi::getNumberOfSensors() +
2124 ipmi::sensor::getOtherSensorsCount(ctx) - 1;
2125 uint16_t nextRecord(recordID + 1);
2126
Willy Tu38e7a2b2021-03-29 15:09:56 -07002127 if (recordID == lastRecordIndex)
2128 {
2129 recordID = lastRecord;
2130 }
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002131 if (recordID == lastRecord)
2132 {
2133 nextRecord = lastRecordIndex;
2134 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002135 if (recordID > lastRecord)
2136 {
George Liude6694e2024-07-17 15:22:25 +08002137 lg2::error("getSensorDataRecord: recordID > lastRecord error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07002138 return GENERAL_ERROR;
2139 }
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002140 if (recordID >= ipmi::getNumberOfSensors())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002141 {
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002142 if (auto err = ipmi::sensor::getOtherSensorsDataRecord(ctx, recordID,
2143 recordData);
2144 err < 0)
Harvey Wu05d17c02021-09-15 08:46:59 +08002145 {
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002146 return lastRecordIndex;
Harvey Wu05d17c02021-09-15 08:46:59 +08002147 }
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002148 return nextRecord;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002149 }
2150
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002151 // Perform a incremental scan of the SDR Record ID's and translate the
2152 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
2153 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
2154 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
2155 // which has special meaning.
Willy Tu38e7a2b2021-03-29 15:09:56 -07002156 std::string connection;
2157 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -07002158 std::vector<std::string> interfaces;
Johnathan Manteyce982772021-07-28 15:08:30 -07002159 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002160 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyce982772021-07-28 15:08:30 -07002161 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002162 // LUN 0 has one reserved sensor number. Compensate here by adding one
2163 // to the record ID
2164 sensNumFromRecID = recordID + 1;
Harvey Wu75893062023-03-22 17:17:31 +08002165 ctx->lun = lun1;
Johnathan Manteyce982772021-07-28 15:08:30 -07002166 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002167 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyce982772021-07-28 15:08:30 -07002168 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002169 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
2170 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
2171 // rules governing its use.
2172 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Harvey Wu75893062023-03-22 17:17:31 +08002173 ctx->lun = lun3;
Johnathan Manteyce982772021-07-28 15:08:30 -07002174 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002175
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05002176 auto status = getSensorConnection(ctx,
2177 static_cast<uint8_t>(sensNumFromRecID),
2178 connection, path, &interfaces);
Willy Tu38e7a2b2021-03-29 15:09:56 -07002179 if (status)
2180 {
George Liude6694e2024-07-17 15:22:25 +08002181 lg2::error("getSensorDataRecord: getSensorConnection error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07002182 return GENERAL_ERROR;
2183 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002184 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002185 // Return an error on LUN 2 assingments, and any sensor number beyond the
2186 // range of LUN 3
2187 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
2188 (sensorNum > lun3MaxSensorNum))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002189 {
George Liude6694e2024-07-17 15:22:25 +08002190 lg2::error("getSensorDataRecord: invalidSensorNumber");
Willy Tu38e7a2b2021-03-29 15:09:56 -07002191 return GENERAL_ERROR;
2192 }
Johnathan Manteyce982772021-07-28 15:08:30 -07002193 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
2194 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
2195
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002196 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
2197 (lun != ctx->lun))
Johnathan Manteyce982772021-07-28 15:08:30 -07002198 {
George Liude6694e2024-07-17 15:22:25 +08002199 lg2::error("getSensorDataRecord: sensor record mismatch");
Johnathan Manteyce982772021-07-28 15:08:30 -07002200 return GENERAL_ERROR;
2201 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002202
Willy Tu38e7a2b2021-03-29 15:09:56 -07002203 // Construct full record (SDR type 1) for the threshold sensors
Hao Jiange39d4d82021-04-16 17:02:40 -07002204 if (std::find(interfaces.begin(), interfaces.end(),
2205 sensor::sensorInterface) != interfaces.end())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002206 {
Willy Tu11d68892022-01-20 10:37:34 -08002207 get_sdr::SensorDataFullRecord record = {};
Willy Tu38e7a2b2021-03-29 15:09:56 -07002208
Hao Jiange39d4d82021-04-16 17:02:40 -07002209 // If the request doesn't read SDR body, construct only header and key
2210 // part to avoid additional DBus transaction.
2211 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2212 {
2213 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2214 }
Willy Tu4eca2512022-06-20 21:14:51 -07002215 else if (!constructSensorSdr(ctx, ipmiDecoratorPaths, sensorNum,
2216 recordID, connection, path, record))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002217 {
2218 return GENERAL_ERROR;
2219 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002220
selvaganapathi7b2e5502023-02-14 07:10:47 +05302221 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2222 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002223
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002224 return nextRecord;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002225 }
Willy Tu61992ad2021-03-29 15:33:20 -07002226
Scron Chang2703b022021-07-06 15:47:45 +08002227#ifdef FEATURE_HYBRID_SENSORS
2228 if (auto sensor = findStaticSensor(path);
2229 sensor != ipmi::sensor::sensors.end() &&
2230 getSensorEventTypeFromPath(path) !=
2231 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
2232 {
Willy Tu11d68892022-01-20 10:37:34 -08002233 get_sdr::SensorDataFullRecord record = {};
Scron Chang2703b022021-07-06 15:47:45 +08002234
2235 // If the request doesn't read SDR body, construct only header and key
2236 // part to avoid additional DBus transaction.
2237 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2238 {
2239 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2240 }
2241 else
2242 {
2243 constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record);
2244 }
2245
selvaganapathi7b2e5502023-02-14 07:10:47 +05302246 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2247 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Scron Chang2703b022021-07-06 15:47:45 +08002248
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002249 return nextRecord;
Scron Chang2703b022021-07-06 15:47:45 +08002250 }
2251#endif
2252
Willy Tu61992ad2021-03-29 15:33:20 -07002253 // Contruct SDR type 3 record for VR sensor (daemon)
Hao Jiange39d4d82021-04-16 17:02:40 -07002254 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
2255 interfaces.end())
Willy Tu61992ad2021-03-29 15:33:20 -07002256 {
Willy Tu11d68892022-01-20 10:37:34 -08002257 get_sdr::SensorDataEventRecord record = {};
Willy Tu61992ad2021-03-29 15:33:20 -07002258
Hao Jiange39d4d82021-04-16 17:02:40 -07002259 // If the request doesn't read SDR body, construct only header and key
2260 // part to avoid additional DBus transaction.
2261 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2262 {
2263 constructEventSdrHeaderKey(sensorNum, recordID, record);
2264 }
Willy Tu4eca2512022-06-20 21:14:51 -07002265 else if (!constructVrSdr(ctx, ipmiDecoratorPaths, sensorNum, recordID,
2266 connection, path, record))
Hao Jiange39d4d82021-04-16 17:02:40 -07002267 {
2268 return GENERAL_ERROR;
2269 }
selvaganapathi7b2e5502023-02-14 07:10:47 +05302270 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2271 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002272 }
2273
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002274 return nextRecord;
Willy Tude54f482021-01-26 15:59:09 -08002275}
2276
2277/** @brief implements the get SDR Info command
2278 * @param count - Operation
2279 *
2280 * @returns IPMI completion code plus response data
2281 * - sdrCount - sensor/SDR count
2282 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
2283 */
2284static ipmi::RspType<uint8_t, // respcount
2285 uint8_t, // dynamic population flags
2286 uint32_t // last time a sensor was added
2287 >
2288 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
2289 std::optional<uint8_t> count)
2290{
2291 auto& sensorTree = getSensorTree();
2292 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002293 uint16_t recordID = 0;
2294 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08002295 // Sensors are dynamically allocated, and there is at least one LUN
2296 uint8_t lunsAndDynamicPopulation = 0x80;
2297 constexpr uint8_t getSdrCount = 0x01;
2298 constexpr uint8_t getSensorCount = 0x00;
2299
2300 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
2301 {
2302 return ipmi::responseResponseError();
2303 }
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002304 uint16_t numSensors = ipmi::getNumberOfSensors();
Willy Tude54f482021-01-26 15:59:09 -08002305 if (count.value_or(0) == getSdrCount)
2306 {
Willy Tu4eca2512022-06-20 21:14:51 -07002307 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2308
Harvey Wu75893062023-03-22 17:17:31 +08002309 if (ctx->lun == lun1)
Harvey Wua3476272023-03-22 10:09:38 +08002310 {
2311 recordID += maxSensorsPerLUN;
2312 }
Harvey Wu75893062023-03-22 17:17:31 +08002313 else if (ctx->lun == lun3)
Harvey Wua3476272023-03-22 10:09:38 +08002314 {
2315 recordID += maxSensorsPerLUN * 2;
2316 }
2317
Harvey Wu75893062023-03-22 17:17:31 +08002318 // Count the number of Type 1h, Type 2h, Type 11h, Type 12h SDR entries
2319 // assigned to the LUN
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002320 while (getSensorDataRecord(ctx,
2321 ipmiDecoratorPaths.value_or(
2322 std::unordered_set<std::string>()),
2323 record, recordID++) >= 0)
Willy Tude54f482021-01-26 15:59:09 -08002324 {
2325 get_sdr::SensorDataRecordHeader* hdr =
2326 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002327 record.data());
selvaganapathi7b2e5502023-02-14 07:10:47 +05302328 if (!hdr)
2329 {
2330 continue;
2331 }
2332
2333 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
Willy Tude54f482021-01-26 15:59:09 -08002334 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002335 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08002336 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002337 record.data());
2338 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08002339 {
2340 sdrCount++;
2341 }
2342 }
selvaganapathi7b2e5502023-02-14 07:10:47 +05302343 else if (hdr->record_type == get_sdr::SENSOR_DATA_COMPACT_RECORD)
2344 {
2345 get_sdr::SensorDataCompactRecord* recordData =
2346 reinterpret_cast<get_sdr::SensorDataCompactRecord*>(
2347 record.data());
2348 if (ctx->lun == recordData->key.owner_lun)
2349 {
2350 sdrCount++;
2351 }
2352 }
Harvey Wua3476272023-03-22 10:09:38 +08002353 else if (hdr->record_type == get_sdr::SENSOR_DATA_FRU_RECORD ||
2354 hdr->record_type == get_sdr::SENSOR_DATA_MGMT_CTRL_LOCATOR)
selvaganapathi7b2e5502023-02-14 07:10:47 +05302355 {
2356 sdrCount++;
2357 }
Harvey Wua3476272023-03-22 10:09:38 +08002358
2359 // Because response count data is 1 byte, so sdrCount need to avoid
2360 // overflow.
2361 if (sdrCount == maxSensorsPerLUN)
2362 {
2363 break;
2364 }
Willy Tude54f482021-01-26 15:59:09 -08002365 }
2366 }
2367 else if (count.value_or(0) == getSensorCount)
2368 {
2369 // Return the number of sensors attached to the LUN
Harvey Wu75893062023-03-22 17:17:31 +08002370 if ((ctx->lun == lun0) && (numSensors > 0))
Willy Tude54f482021-01-26 15:59:09 -08002371 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05002372 sdrCount = (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN
2373 : numSensors;
Willy Tude54f482021-01-26 15:59:09 -08002374 }
Harvey Wu75893062023-03-22 17:17:31 +08002375 else if ((ctx->lun == lun1) && (numSensors > maxSensorsPerLUN))
Willy Tude54f482021-01-26 15:59:09 -08002376 {
2377 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
2378 ? maxSensorsPerLUN
2379 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
2380 }
Harvey Wu75893062023-03-22 17:17:31 +08002381 else if (ctx->lun == lun3)
Willy Tude54f482021-01-26 15:59:09 -08002382 {
2383 if (numSensors <= maxIPMISensors)
2384 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05002385 sdrCount = (numSensors - (2 * maxSensorsPerLUN)) &
2386 maxSensorsPerLUN;
Willy Tude54f482021-01-26 15:59:09 -08002387 }
2388 else
2389 {
2390 // error
2391 throw std::out_of_range(
2392 "Maximum number of IPMI sensors exceeded.");
2393 }
2394 }
2395 }
2396 else
2397 {
2398 return ipmi::responseInvalidFieldRequest();
2399 }
2400
2401 // Get Sensor count. This returns the number of sensors
2402 if (numSensors > 0)
2403 {
2404 lunsAndDynamicPopulation |= 1;
2405 }
2406 if (numSensors > maxSensorsPerLUN)
2407 {
2408 lunsAndDynamicPopulation |= 2;
2409 }
2410 if (numSensors >= (maxSensorsPerLUN * 2))
2411 {
2412 lunsAndDynamicPopulation |= 8;
2413 }
2414 if (numSensors > maxIPMISensors)
2415 {
2416 // error
2417 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
2418 }
2419
2420 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
2421 sdrLastAdd);
2422}
2423
2424/* end sensor commands */
2425
2426/* storage commands */
2427
2428ipmi::RspType<uint8_t, // sdr version
2429 uint16_t, // record count
2430 uint16_t, // free space
2431 uint32_t, // most recent addition
2432 uint32_t, // most recent erase
2433 uint8_t // operationSupport
2434 >
2435 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
2436{
Willy Tude54f482021-01-26 15:59:09 -08002437 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Johnathan Mantey31c1ecd2024-06-20 11:10:41 -07002438 uint16_t recordCount = ipmi::getNumberOfSensors() +
2439 ipmi::sensor::getOtherSensorsCount(ctx);
Willy Tude54f482021-01-26 15:59:09 -08002440
2441 uint8_t operationSupport = static_cast<uint8_t>(
2442 SdrRepositoryInfoOps::overflow); // write not supported
2443
2444 operationSupport |=
2445 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
2446 operationSupport |= static_cast<uint8_t>(
2447 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
2448 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
2449 unspecifiedFreeSpace, sdrLastAdd,
2450 sdrLastRemove, operationSupport);
2451}
2452
2453/** @brief implements the get SDR allocation info command
2454 *
2455 * @returns IPMI completion code plus response data
2456 * - allocUnits - Number of possible allocation units
2457 * - allocUnitSize - Allocation unit size in bytes.
2458 * - allocUnitFree - Number of free allocation units
2459 * - allocUnitLargestFree - Largest free block in allocation units
2460 * - maxRecordSize - Maximum record size in allocation units.
2461 */
2462ipmi::RspType<uint16_t, // allocUnits
2463 uint16_t, // allocUnitSize
2464 uint16_t, // allocUnitFree
2465 uint16_t, // allocUnitLargestFree
2466 uint8_t // maxRecordSize
2467 >
2468 ipmiStorageGetSDRAllocationInfo()
2469{
2470 // 0000h unspecified number of alloc units
2471 constexpr uint16_t allocUnits = 0;
2472
2473 constexpr uint16_t allocUnitFree = 0;
2474 constexpr uint16_t allocUnitLargestFree = 0;
2475 // only allow one block at a time
2476 constexpr uint8_t maxRecordSize = 1;
2477
2478 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
2479 allocUnitLargestFree, maxRecordSize);
2480}
2481
2482/** @brief implements the reserve SDR command
2483 * @returns IPMI completion code plus response data
2484 * - sdrReservationID
2485 */
2486ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
2487{
2488 sdrReservationID++;
2489 if (sdrReservationID == 0)
2490 {
2491 sdrReservationID++;
2492 }
2493
2494 return ipmi::responseSuccess(sdrReservationID);
2495}
2496
2497ipmi::RspType<uint16_t, // next record ID
2498 std::vector<uint8_t> // payload
2499 >
2500 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
2501 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
2502{
2503 // reservation required for partial reads with non zero offset into
2504 // record
2505 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
2506 {
George Liude6694e2024-07-17 15:22:25 +08002507 lg2::error("ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08002508 return ipmi::responseInvalidReservationId();
2509 }
Harvey Wu05d17c02021-09-15 08:46:59 +08002510
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002511 auto& sensorTree = getSensorTree();
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002512 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002513 {
George Liude6694e2024-07-17 15:22:25 +08002514 lg2::error("ipmiStorageGetSDR: getSensorSubtree error");
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002515 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08002516 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002517
Willy Tu4eca2512022-06-20 21:14:51 -07002518 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2519
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002520 std::vector<uint8_t> record;
Johnathan Mantey777cfaf2024-06-13 10:45:47 -07002521 int nextRecordId = getSensorDataRecord(
2522 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2523 record, recordID, offset + bytesToRead);
2524
2525 if (nextRecordId < 0)
Willy Tude54f482021-01-26 15:59:09 -08002526 {
George Liude6694e2024-07-17 15:22:25 +08002527 lg2::error("ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08002528 return ipmi::responseInvalidFieldRequest();
2529 }
Willy Tude54f482021-01-26 15:59:09 -08002530 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002531 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08002532 if (!hdr)
2533 {
George Liude6694e2024-07-17 15:22:25 +08002534 lg2::error("ipmiStorageGetSDR: record header is null");
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002535 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002536 }
2537
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05002538 size_t sdrLength = sizeof(get_sdr::SensorDataRecordHeader) +
2539 hdr->record_length;
Vernon Mauery6dbea082023-07-21 11:43:00 -07002540 if (offset >= sdrLength)
2541 {
George Liude6694e2024-07-17 15:22:25 +08002542 lg2::error("ipmiStorageGetSDR: offset is outside the record");
Vernon Mauery6dbea082023-07-21 11:43:00 -07002543 return ipmi::responseParmOutOfRange();
2544 }
Willy Tude54f482021-01-26 15:59:09 -08002545 if (sdrLength < (offset + bytesToRead))
2546 {
2547 bytesToRead = sdrLength - offset;
2548 }
2549
2550 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
2551 if (!respStart)
2552 {
George Liude6694e2024-07-17 15:22:25 +08002553 lg2::error("ipmiStorageGetSDR: record is null");
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002554 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002555 }
2556
2557 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002558
Willy Tude54f482021-01-26 15:59:09 -08002559 return ipmi::responseSuccess(nextRecordId, recordData);
2560}
adarshgrami042e9db2022-09-15 10:34:34 +05302561namespace dcmi
2562{
2563
Thang Tranb1416ef2023-08-02 13:57:09 +07002564std::tuple<uint8_t, // Total of instance sensors
2565 std::vector<sensorInfo> // The list of sensors
2566 >
2567 getSensorsByEntityId(ipmi::Context::ptr ctx, uint8_t entityId,
2568 uint8_t entityInstance, uint8_t instanceStart)
2569{
2570 std::vector<sensorInfo> sensorList;
2571 uint8_t totalInstSensor = 0;
2572 auto match = ipmi::dcmi::validEntityId.find(entityId);
2573
2574 if (match == ipmi::dcmi::validEntityId.end())
2575 {
2576 return std::make_tuple(totalInstSensor, sensorList);
2577 }
2578
2579 auto& sensorTree = getSensorTree();
2580 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
2581 {
2582 return std::make_tuple(totalInstSensor, sensorList);
2583 }
2584
2585 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2586
Willy Tu62e3ca82024-01-31 17:28:34 +00002587 size_t invalidSensorNumberErrCount = 0;
Thang Tranb1416ef2023-08-02 13:57:09 +07002588 for (const auto& sensor : sensorTree)
2589 {
2590 const std::string& sensorObjPath = sensor.first;
2591 const auto& sensorTypeValue = getSensorTypeFromPath(sensorObjPath);
2592
2593 /*
2594 * In the DCMI specification, it only supports the sensor type is 0x01
2595 * (temperature type) for both Get Sensor Info and Get Temperature
2596 * Readings commands.
2597 */
2598 if (sensorTypeValue != ipmi::dcmi::temperatureSensorType)
2599 {
2600 continue;
2601 }
2602
2603 const auto& connection = sensor.second.begin()->first;
2604 DbusInterfaceMap sensorMap;
2605
2606 if (!getSensorMap(ctx, connection, sensorObjPath, sensorMap,
2607 sensorMapSdrUpdatePeriod))
2608 {
George Liude6694e2024-07-17 15:22:25 +08002609 lg2::error("Failed to update sensor map for threshold sensor, "
2610 "service: {SERVICE}, path: {PATH}",
2611 "SERVICE", connection, "PATH", sensorObjPath);
Thang Tranb1416ef2023-08-02 13:57:09 +07002612 continue;
2613 }
2614
2615 uint8_t entityIdValue = 0;
2616 uint8_t entityInstanceValue = 0;
2617
2618 /*
2619 * Get the Entity ID, Entity Instance information which are configured
2620 * in the Entity-Manger.
2621 */
2622 updateIpmiFromAssociation(
2623 sensorObjPath,
2624 ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2625 sensorMap, entityIdValue, entityInstanceValue);
2626
2627 if (entityIdValue == match->first || entityIdValue == match->second)
2628 {
2629 totalInstSensor++;
2630
2631 /*
2632 * When Entity Instance parameter is not 0, we only get the first
2633 * sensor whose Entity Instance number is equal input Entity
2634 * Instance parameter.
2635 */
2636 if (entityInstance)
2637 {
2638 if (!sensorList.empty())
2639 {
2640 continue;
2641 }
2642
2643 if (entityInstanceValue == entityInstance)
2644 {
2645 auto recordId = getSensorNumberFromPath(sensorObjPath);
Willy Tu62e3ca82024-01-31 17:28:34 +00002646 if (recordId == invalidSensorNumber)
Thang Tranb1416ef2023-08-02 13:57:09 +07002647 {
Willy Tu62e3ca82024-01-31 17:28:34 +00002648 ++invalidSensorNumberErrCount;
2649 continue;
Thang Tranb1416ef2023-08-02 13:57:09 +07002650 }
Thang Tranb1416ef2023-08-02 13:57:09 +07002651 sensorList.emplace_back(sensorObjPath, sensorTypeValue,
2652 recordId, entityIdValue,
2653 entityInstanceValue);
2654 }
2655 }
Willy Tu62e3ca82024-01-31 17:28:34 +00002656 else if (entityInstanceValue >= instanceStart)
2657 {
2658 auto recordId = getSensorNumberFromPath(sensorObjPath);
2659 if (recordId == invalidSensorNumber)
2660 {
2661 ++invalidSensorNumberErrCount;
2662 continue;
2663 }
2664 sensorList.emplace_back(sensorObjPath, sensorTypeValue,
2665 recordId, entityIdValue,
2666 entityInstanceValue);
2667 }
Thang Tranb1416ef2023-08-02 13:57:09 +07002668 }
2669 }
Willy Tu62e3ca82024-01-31 17:28:34 +00002670 if (invalidSensorNumberErrCount != 0)
2671 {
George Liude6694e2024-07-17 15:22:25 +08002672 lg2::error("getSensorNumberFromPath returned invalidSensorNumber "
2673 "{ERR_COUNT} times",
2674 "ERR_COUNT", invalidSensorNumberErrCount);
Willy Tu62e3ca82024-01-31 17:28:34 +00002675 }
Thang Tranb1416ef2023-08-02 13:57:09 +07002676
2677 auto cmpFunc = [](sensorInfo first, sensorInfo second) {
2678 return first.entityInstance <= second.entityInstance;
2679 };
2680
2681 sort(sensorList.begin(), sensorList.end(), cmpFunc);
2682
2683 return std::make_tuple(totalInstSensor, sensorList);
2684}
2685
Thang Tran3dad8262023-08-17 15:20:56 +07002686std::tuple<bool, // Reading result
2687 uint7_t, // Temp value
2688 bool> // Sign bit
2689 readTemp(ipmi::Context::ptr ctx, const std::string& objectPath)
2690{
2691 std::string service{};
2692 boost::system::error_code ec =
2693 ipmi::getService(ctx, sensor::sensorInterface, objectPath, service);
2694 if (ec.value())
2695 {
2696 return std::make_tuple(false, 0, false);
2697 }
2698
2699 ipmi::PropertyMap properties{};
2700 ec = ipmi::getAllDbusProperties(ctx, service, objectPath,
2701 sensor::sensorInterface, properties);
2702 if (ec.value())
2703 {
2704 return std::make_tuple(false, 0, false);
2705 }
2706
2707 auto scaleIt = properties.find("Scale");
2708 double scaleVal = 0.0;
2709 if (scaleIt != properties.end())
2710 {
2711 scaleVal = std::visit(ipmi::VariantToDoubleVisitor(), scaleIt->second);
2712 }
2713
2714 auto tempValIt = properties.find("Value");
2715 double tempVal = 0.0;
2716 if (tempValIt == properties.end())
2717 {
2718 return std::make_tuple(false, 0, false);
2719 }
2720
2721 const double maxTemp = 127;
2722 double absTempVal = 0.0;
2723 bool signBit = false;
2724
2725 tempVal = std::visit(ipmi::VariantToDoubleVisitor(), tempValIt->second);
2726 tempVal = std::pow(10, scaleVal) * tempVal;
2727 absTempVal = std::abs(tempVal);
2728 absTempVal = std::min(absTempVal, maxTemp);
2729 signBit = (tempVal < 0) ? true : false;
2730
2731 return std::make_tuple(true, static_cast<uint7_t>(absTempVal), signBit);
2732}
2733
adarshgrami042e9db2022-09-15 10:34:34 +05302734ipmi::RspType<uint8_t, // No of instances for requested id
2735 uint8_t, // No of record ids in the response
2736 std::vector<uint16_t> // SDR Record ID corresponding to the Entity
2737 // IDs
2738 >
2739 getSensorInfo(ipmi::Context::ptr ctx, uint8_t sensorType, uint8_t entityId,
Thang Tranb1416ef2023-08-02 13:57:09 +07002740 uint8_t entityInstance, uint8_t instanceStart)
adarshgrami042e9db2022-09-15 10:34:34 +05302741{
2742 auto match = ipmi::dcmi::validEntityId.find(entityId);
2743 if (match == ipmi::dcmi::validEntityId.end())
2744 {
George Liude6694e2024-07-17 15:22:25 +08002745 lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
adarshgrami042e9db2022-09-15 10:34:34 +05302746
2747 return ipmi::responseInvalidFieldRequest();
2748 }
2749
2750 if (sensorType != ipmi::dcmi::temperatureSensorType)
2751 {
George Liude6694e2024-07-17 15:22:25 +08002752 lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
2753 sensorType);
adarshgrami042e9db2022-09-15 10:34:34 +05302754
2755 return ipmi::responseInvalidFieldRequest();
2756 }
adarshgrami042e9db2022-09-15 10:34:34 +05302757
2758 std::vector<uint16_t> sensorRec{};
Thang Tranb1416ef2023-08-02 13:57:09 +07002759 const auto& [totalSensorInst, sensorList] =
2760 getSensorsByEntityId(ctx, entityId, entityInstance, instanceStart);
adarshgrami042e9db2022-09-15 10:34:34 +05302761
Thang Tranb1416ef2023-08-02 13:57:09 +07002762 if (sensorList.empty())
adarshgrami042e9db2022-09-15 10:34:34 +05302763 {
Thang Tranb1416ef2023-08-02 13:57:09 +07002764 return ipmi::responseSuccess(totalSensorInst, 0, sensorRec);
2765 }
adarshgrami042e9db2022-09-15 10:34:34 +05302766
Thang Tranb1416ef2023-08-02 13:57:09 +07002767 /*
2768 * As DCMI specification, the maximum number of Record Ids of response data
2769 * is 1 if Entity Instance paramter is not 0. Else the maximum number of
2770 * Record Ids of response data is 8. Therefore, not all of sensors are shown
2771 * in response data.
2772 */
2773 uint8_t numOfRec = (entityInstance != 0) ? 1 : ipmi::dcmi::maxRecords;
2774
2775 for (const auto& sensor : sensorList)
2776 {
2777 sensorRec.emplace_back(sensor.recordId);
2778 if (sensorRec.size() >= numOfRec)
adarshgrami042e9db2022-09-15 10:34:34 +05302779 {
Thang Tranb1416ef2023-08-02 13:57:09 +07002780 break;
adarshgrami042e9db2022-09-15 10:34:34 +05302781 }
2782 }
Thang Tranb1416ef2023-08-02 13:57:09 +07002783
2784 return ipmi::responseSuccess(
2785 totalSensorInst, static_cast<uint8_t>(sensorRec.size()), sensorRec);
adarshgrami042e9db2022-09-15 10:34:34 +05302786}
Thang Tran3dad8262023-08-17 15:20:56 +07002787
2788ipmi::RspType<uint8_t, // No of instances for requested id
2789 uint8_t, // No of record ids in the response
2790 std::vector< // Temperature Data
2791 std::tuple<uint7_t, // Temperature value
2792 bool, // Sign bit
2793 uint8_t // Entity Instance of sensor
2794 >>>
2795 getTempReadings(ipmi::Context::ptr ctx, uint8_t sensorType,
2796 uint8_t entityId, uint8_t entityInstance,
2797 uint8_t instanceStart)
2798{
2799 auto match = ipmi::dcmi::validEntityId.find(entityId);
2800 if (match == ipmi::dcmi::validEntityId.end())
2801 {
George Liude6694e2024-07-17 15:22:25 +08002802 lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
Thang Tran3dad8262023-08-17 15:20:56 +07002803
2804 return ipmi::responseInvalidFieldRequest();
2805 }
2806
2807 if (sensorType != ipmi::dcmi::temperatureSensorType)
2808 {
George Liude6694e2024-07-17 15:22:25 +08002809 lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
2810 sensorType);
Thang Tran3dad8262023-08-17 15:20:56 +07002811
2812 return ipmi::responseInvalidFieldRequest();
2813 }
2814
2815 std::vector<std::tuple<uint7_t, bool, uint8_t>> tempReadingVal{};
2816 const auto& [totalSensorInst, sensorList] =
2817 getSensorsByEntityId(ctx, entityId, entityInstance, instanceStart);
2818
2819 if (sensorList.empty())
2820 {
2821 return ipmi::responseSuccess(totalSensorInst, 0, tempReadingVal);
2822 }
2823
2824 /*
2825 * As DCMI specification, the maximum number of Record Ids of response data
2826 * is 1 if Entity Instance paramter is not 0. Else the maximum number of
2827 * Record Ids of response data is 8. Therefore, not all of sensors are shown
2828 * in response data.
2829 */
2830 uint8_t numOfRec = (entityInstance != 0) ? 1 : ipmi::dcmi::maxRecords;
2831
2832 for (const auto& sensor : sensorList)
2833 {
2834 const auto& [readResult, tempVal,
2835 signBit] = readTemp(ctx, sensor.objectPath);
2836
2837 if (readResult)
2838 {
2839 tempReadingVal.emplace_back(
2840 std::make_tuple(tempVal, signBit, sensor.entityInstance));
2841
2842 if (tempReadingVal.size() >= numOfRec)
2843 {
2844 break;
2845 }
2846 }
2847 }
2848
2849 return ipmi::responseSuccess(totalSensorInst,
2850 static_cast<uint8_t>(tempReadingVal.size()),
2851 tempReadingVal);
2852}
2853
adarshgrami042e9db2022-09-15 10:34:34 +05302854} // namespace dcmi
2855
Willy Tude54f482021-01-26 15:59:09 -08002856/* end storage commands */
2857
2858void registerSensorFunctions()
2859{
2860 // <Platform Event>
2861 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2862 ipmi::sensor_event::cmdPlatformEvent,
2863 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
2864
Willy Tudbafbce2021-03-29 00:37:05 -07002865 // <Set Sensor Reading and Event Status>
2866 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2867 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
2868 ipmi::Privilege::Operator, ipmiSetSensorReading);
Willy Tudbafbce2021-03-29 00:37:05 -07002869
Willy Tude54f482021-01-26 15:59:09 -08002870 // <Get Sensor Reading>
2871 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2872 ipmi::sensor_event::cmdGetSensorReading,
2873 ipmi::Privilege::User, ipmiSenGetSensorReading);
2874
2875 // <Get Sensor Threshold>
2876 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2877 ipmi::sensor_event::cmdGetSensorThreshold,
2878 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
2879
2880 // <Set Sensor Threshold>
2881 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2882 ipmi::sensor_event::cmdSetSensorThreshold,
2883 ipmi::Privilege::Operator,
2884 ipmiSenSetSensorThresholds);
2885
2886 // <Get Sensor Event Enable>
2887 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2888 ipmi::sensor_event::cmdGetSensorEventEnable,
2889 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
2890
2891 // <Get Sensor Event Status>
2892 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2893 ipmi::sensor_event::cmdGetSensorEventStatus,
2894 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
2895
2896 // register all storage commands for both Sensor and Storage command
2897 // versions
2898
2899 // <Get SDR Repository Info>
2900 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2901 ipmi::storage::cmdGetSdrRepositoryInfo,
2902 ipmi::Privilege::User,
2903 ipmiStorageGetSDRRepositoryInfo);
2904
2905 // <Get Device SDR Info>
2906 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2907 ipmi::sensor_event::cmdGetDeviceSdrInfo,
2908 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
2909
2910 // <Get SDR Allocation Info>
2911 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2912 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
2913 ipmi::Privilege::User,
2914 ipmiStorageGetSDRAllocationInfo);
2915
2916 // <Reserve SDR Repo>
2917 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2918 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
2919 ipmi::Privilege::User, ipmiStorageReserveSDR);
2920
2921 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2922 ipmi::storage::cmdReserveSdrRepository,
2923 ipmi::Privilege::User, ipmiStorageReserveSDR);
2924
2925 // <Get Sdr>
2926 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2927 ipmi::sensor_event::cmdGetDeviceSdr,
2928 ipmi::Privilege::User, ipmiStorageGetSDR);
2929
2930 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2931 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
2932 ipmiStorageGetSDR);
adarshgrami042e9db2022-09-15 10:34:34 +05302933 // <Get DCMI Sensor Info>
2934 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
2935 ipmi::dcmi::cmdGetDcmiSensorInfo,
Chau Lyd74df5f2023-05-25 10:33:00 +00002936 ipmi::Privilege::Operator,
adarshgrami042e9db2022-09-15 10:34:34 +05302937 ipmi::dcmi::getSensorInfo);
Thang Tran3dad8262023-08-17 15:20:56 +07002938 // <Get Temperature Readings>
2939 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
2940 ipmi::dcmi::cmdGetTemperatureReadings,
2941 ipmi::Privilege::User,
2942 ipmi::dcmi::getTempReadings);
Willy Tude54f482021-01-26 15:59:09 -08002943}
2944} // namespace ipmi