blob: ecb8fc2c2f20c301354cbf8cd14a20d349ace820 [file] [log] [blame]
Willy Tude54f482021-01-26 15:59:09 -08001/*
2// Copyright (c) 2017 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
17#include "dbus-sdr/sensorcommands.hpp"
18
19#include "dbus-sdr/sdrutils.hpp"
20#include "dbus-sdr/sensorutils.hpp"
21#include "dbus-sdr/storagecommands.hpp"
Harvey Wu05d17c02021-09-15 08:46:59 +080022#include "entity_map_json.hpp"
Willy Tude54f482021-01-26 15:59:09 -080023
24#include <algorithm>
25#include <array>
26#include <boost/algorithm/string.hpp>
27#include <boost/container/flat_map.hpp>
28#include <chrono>
29#include <cmath>
30#include <cstring>
31#include <iostream>
32#include <ipmid/api.hpp>
33#include <ipmid/types.hpp>
34#include <ipmid/utils.hpp>
35#include <map>
36#include <memory>
37#include <optional>
38#include <phosphor-logging/log.hpp>
39#include <sdbusplus/bus.hpp>
40#include <stdexcept>
41#include <string>
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +000042#include <user_channel/channel_layer.hpp>
Willy Tude54f482021-01-26 15:59:09 -080043#include <utility>
44#include <variant>
45
Scron Chang2703b022021-07-06 15:47:45 +080046#ifdef FEATURE_HYBRID_SENSORS
47
48#include "sensordatahandler.hpp"
49namespace ipmi
50{
51namespace sensor
52{
53extern const IdInfoMap sensors;
54} // namespace sensor
55} // namespace ipmi
56#endif
adarshgrami042e9db2022-09-15 10:34:34 +053057namespace ipmi
58{
59namespace dcmi
60{
61// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
62static const std::map<uint8_t, uint8_t> validEntityId{
63 {0x40, 0x37}, {0x37, 0x40}, {0x41, 0x03},
64 {0x03, 0x41}, {0x42, 0x07}, {0x07, 0x42}};
65constexpr uint8_t temperatureSensorType = 0x01;
66constexpr uint8_t maxRecords = 8;
67} // namespace dcmi
68} // namespace ipmi
JeffLind950f412021-10-20 18:49:34 +080069constexpr std::array<const char*, 7> suffixes = {
70 "_Output_Voltage", "_Input_Voltage", "_Output_Current", "_Input_Current",
71 "_Output_Power", "_Input_Power", "_Temperature"};
Willy Tude54f482021-01-26 15:59:09 -080072namespace ipmi
73{
Hao Jiangd48c9212021-02-03 15:45:06 -080074
75using phosphor::logging::entry;
76using phosphor::logging::level;
77using phosphor::logging::log;
78
Willy Tude54f482021-01-26 15:59:09 -080079static constexpr int sensorMapUpdatePeriod = 10;
Alex Qiu9ab2f942020-07-15 17:56:21 -070080static constexpr int sensorMapSdrUpdatePeriod = 60;
Willy Tude54f482021-01-26 15:59:09 -080081
Willy Tu38e7a2b2021-03-29 15:09:56 -070082// BMC I2C address is generally at 0x20
83static constexpr uint8_t bmcI2CAddr = 0x20;
84
Willy Tude54f482021-01-26 15:59:09 -080085constexpr size_t maxSDRTotalSize =
86 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
87constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
88
89static uint16_t sdrReservationID;
90static uint32_t sdrLastAdd = noTimestamp;
91static uint32_t sdrLastRemove = noTimestamp;
92static constexpr size_t lastRecordIndex = 0xFFFF;
Johnathan Mantey6619ae42021-08-06 11:21:10 -070093
94// The IPMI spec defines four Logical Units (LUN), each capable of supporting
95// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
96// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
97// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
98// location.
99static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
100
101static constexpr size_t lun0MaxSensorNum = 0xfe;
102static constexpr size_t lun1MaxSensorNum = 0x1fe;
103static constexpr size_t lun3MaxSensorNum = 0x3fe;
Willy Tude54f482021-01-26 15:59:09 -0800104static constexpr int GENERAL_ERROR = -1;
105
Willy Tude54f482021-01-26 15:59:09 -0800106static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
107
108// Specify the comparison required to sort and find char* map objects
109struct CmpStr
110{
111 bool operator()(const char* a, const char* b) const
112 {
113 return std::strcmp(a, b) < 0;
114 }
115};
116const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
117 sensorUnits{{{"temperature", SensorUnits::degreesC},
118 {"voltage", SensorUnits::volts},
119 {"current", SensorUnits::amps},
120 {"fan_tach", SensorUnits::rpm},
121 {"power", SensorUnits::watts}}};
122
123void registerSensorFunctions() __attribute__((constructor));
124
Patrick Williams5d82f472022-07-22 19:26:53 -0500125static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800126 *getSdBus(),
127 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
128 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500129 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800130 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700131 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800132 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
133 std::chrono::system_clock::now().time_since_epoch())
134 .count();
135 });
136
Patrick Williams5d82f472022-07-22 19:26:53 -0500137static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800138 *getSdBus(),
139 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
140 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500141 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800142 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700143 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800144 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
145 std::chrono::system_clock::now().time_since_epoch())
146 .count();
147 });
148
149// this keeps track of deassertions for sensor event status command. A
150// deasertion can only happen if an assertion was seen first.
151static boost::container::flat_map<
152 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
153 thresholdDeassertMap;
154
Patrick Williams5d82f472022-07-22 19:26:53 -0500155static sdbusplus::bus::match_t thresholdChanged(
Willy Tude54f482021-01-26 15:59:09 -0800156 *getSdBus(),
157 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
158 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500159 [](sdbusplus::message_t& m) {
Willy Tude54f482021-01-26 15:59:09 -0800160 boost::container::flat_map<std::string, std::variant<bool, double>>
161 values;
162 m.read(std::string(), values);
163
164 auto findAssert =
165 std::find_if(values.begin(), values.end(), [](const auto& pair) {
166 return pair.first.find("Alarm") != std::string::npos;
167 });
168 if (findAssert != values.end())
169 {
170 auto ptr = std::get_if<bool>(&(findAssert->second));
171 if (ptr == nullptr)
172 {
173 phosphor::logging::log<phosphor::logging::level::ERR>(
174 "thresholdChanged: Assert non bool");
175 return;
176 }
177 if (*ptr)
178 {
179 phosphor::logging::log<phosphor::logging::level::INFO>(
180 "thresholdChanged: Assert",
181 phosphor::logging::entry("SENSOR=%s", m.get_path()));
182 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
183 }
184 else
185 {
186 auto& value =
187 thresholdDeassertMap[m.get_path()][findAssert->first];
188 if (value)
189 {
190 phosphor::logging::log<phosphor::logging::level::INFO>(
191 "thresholdChanged: deassert",
192 phosphor::logging::entry("SENSOR=%s", m.get_path()));
193 value = *ptr;
194 }
195 }
196 }
197 });
198
Hao Jiangd2afd052020-12-10 15:09:32 -0800199namespace sensor
200{
201static constexpr const char* vrInterface =
202 "xyz.openbmc_project.Control.VoltageRegulatorMode";
203static constexpr const char* sensorInterface =
204 "xyz.openbmc_project.Sensor.Value";
205} // namespace sensor
206
Willy Tude54f482021-01-26 15:59:09 -0800207static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
208 double& min)
209{
210 max = 127;
211 min = -128;
212
Hao Jiangd2afd052020-12-10 15:09:32 -0800213 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800214 auto critical =
215 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
216 auto warning =
217 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
218
219 if (sensorObject != sensorMap.end())
220 {
221 auto maxMap = sensorObject->second.find("MaxValue");
222 auto minMap = sensorObject->second.find("MinValue");
223
224 if (maxMap != sensorObject->second.end())
225 {
226 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
227 }
228 if (minMap != sensorObject->second.end())
229 {
230 min = std::visit(VariantToDoubleVisitor(), minMap->second);
231 }
232 }
233 if (critical != sensorMap.end())
234 {
235 auto lower = critical->second.find("CriticalLow");
236 auto upper = critical->second.find("CriticalHigh");
237 if (lower != critical->second.end())
238 {
239 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300240 if (std::isfinite(value))
241 {
242 min = std::min(value, min);
243 }
Willy Tude54f482021-01-26 15:59:09 -0800244 }
245 if (upper != critical->second.end())
246 {
247 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300248 if (std::isfinite(value))
249 {
250 max = std::max(value, max);
251 }
Willy Tude54f482021-01-26 15:59:09 -0800252 }
253 }
254 if (warning != sensorMap.end())
255 {
256
257 auto lower = warning->second.find("WarningLow");
258 auto upper = warning->second.find("WarningHigh");
259 if (lower != warning->second.end())
260 {
261 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300262 if (std::isfinite(value))
263 {
264 min = std::min(value, min);
265 }
Willy Tude54f482021-01-26 15:59:09 -0800266 }
267 if (upper != warning->second.end())
268 {
269 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300270 if (std::isfinite(value))
271 {
272 max = std::max(value, max);
273 }
Willy Tude54f482021-01-26 15:59:09 -0800274 }
275 }
276}
277
278static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700279 std::string sensorPath, DbusInterfaceMap& sensorMap,
280 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800281{
Scron Chang2703b022021-07-06 15:47:45 +0800282#ifdef FEATURE_HYBRID_SENSORS
283 if (auto sensor = findStaticSensor(sensorPath);
284 sensor != ipmi::sensor::sensors.end() &&
285 getSensorEventTypeFromPath(sensorPath) !=
286 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
287 {
288 // If the incoming sensor is a discrete sensor, it might fail in
289 // getManagedObjects(), return true, and use its own getFunc to get
290 // value.
291 return true;
292 }
293#endif
294
Willy Tude54f482021-01-26 15:59:09 -0800295 static boost::container::flat_map<
296 std::string, std::chrono::time_point<std::chrono::steady_clock>>
297 updateTimeMap;
298
299 auto updateFind = updateTimeMap.find(sensorConnection);
300 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
301 if (updateFind != updateTimeMap.end())
302 {
303 lastUpdate = updateFind->second;
304 }
305
306 auto now = std::chrono::steady_clock::now();
307
308 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700309 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800310 {
Willy Tude54f482021-01-26 15:59:09 -0800311 ObjectValueTree managedObjects;
Ed Tanous9a9ac0b2022-10-04 17:18:57 -0700312 boost::system::error_code ec =
313 getManagedObjects(ctx, sensorConnection.c_str(),
314 "/xyz/openbmc_project/sensors", managedObjects);
Willy Tude54f482021-01-26 15:59:09 -0800315 if (ec)
316 {
317 phosphor::logging::log<phosphor::logging::level::ERR>(
318 "GetMangagedObjects for getSensorMap failed",
319 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
320
321 return false;
322 }
323
324 SensorCache[sensorConnection] = managedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700325 // Update time after finish building the map which allow the
326 // data to be cached for updatePeriod plus the build time.
327 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800328 }
329 auto connection = SensorCache.find(sensorConnection);
330 if (connection == SensorCache.end())
331 {
332 return false;
333 }
334 auto path = connection->second.find(sensorPath);
335 if (path == connection->second.end())
336 {
337 return false;
338 }
339 sensorMap = path->second;
340
341 return true;
342}
343
Hao Jiangd2afd052020-12-10 15:09:32 -0800344namespace sensor
345{
Hao Jiangd48c9212021-02-03 15:45:06 -0800346// Read VR profiles from sensor(daemon) interface
347static std::optional<std::vector<std::string>>
348 getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object)
Hao Jiangd2afd052020-12-10 15:09:32 -0800349{
350 // get VR mode profiles from Supported Interface
Hao Jiangd48c9212021-02-03 15:45:06 -0800351 auto supportedProperty = object.find("Supported");
352 if (supportedProperty == object.end() ||
353 object.find("Selected") == object.end())
Hao Jiangd2afd052020-12-10 15:09:32 -0800354 {
355 phosphor::logging::log<phosphor::logging::level::ERR>(
356 "Missing the required Supported and Selected properties");
357 return std::nullopt;
358 }
359
360 const auto profilesPtr =
361 std::get_if<std::vector<std::string>>(&supportedProperty->second);
362
363 if (profilesPtr == nullptr)
364 {
365 phosphor::logging::log<phosphor::logging::level::ERR>(
366 "property is not array of string");
367 return std::nullopt;
368 }
Hao Jiangd48c9212021-02-03 15:45:06 -0800369 return *profilesPtr;
370}
371
372// Calculate VR Mode from input IPMI discrete event bytes
373static std::optional<std::string>
374 calculateVRMode(uint15_t assertOffset,
375 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
376{
377 // get VR mode profiles from Supported Interface
378 auto profiles = getSupportedVrProfiles(VRObject);
379 if (!profiles)
380 {
381 return std::nullopt;
382 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800383
384 // interpret IPMI cmd bits into profiles' index
385 long unsigned int index = 0;
386 // only one bit should be set and the highest bit should not be used.
387 if (assertOffset == 0 || assertOffset == (1u << 15) ||
388 (assertOffset & (assertOffset - 1)))
389 {
390 phosphor::logging::log<phosphor::logging::level::ERR>(
391 "IPMI cmd format incorrect",
392
393 phosphor::logging::entry("BYTES=%#02x",
394 static_cast<uint16_t>(assertOffset)));
395 return std::nullopt;
396 }
397
398 while (assertOffset != 1)
399 {
400 assertOffset >>= 1;
401 index++;
402 }
403
Hao Jiangd48c9212021-02-03 15:45:06 -0800404 if (index >= profiles->size())
Hao Jiangd2afd052020-12-10 15:09:32 -0800405 {
406 phosphor::logging::log<phosphor::logging::level::ERR>(
407 "profile index out of boundary");
408 return std::nullopt;
409 }
410
Hao Jiangd48c9212021-02-03 15:45:06 -0800411 return profiles->at(index);
Hao Jiangd2afd052020-12-10 15:09:32 -0800412}
413
414// Calculate sensor value from IPMI reading byte
415static std::optional<double>
416 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
417 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
418{
419 if (valueObject.find("Value") == valueObject.end())
420 {
421 phosphor::logging::log<phosphor::logging::level::ERR>(
422 "Missing the required Value property");
423 return std::nullopt;
424 }
425
426 double max = 0;
427 double min = 0;
428 getSensorMaxMin(sensorMap, max, min);
429
430 int16_t mValue = 0;
431 int16_t bValue = 0;
432 int8_t rExp = 0;
433 int8_t bExp = 0;
434 bool bSigned = false;
435
436 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
437 {
438 return std::nullopt;
439 }
440
441 double value = bSigned ? ((int8_t)reading) : reading;
442
443 value *= ((double)mValue);
444 value += ((double)bValue) * std::pow(10.0, bExp);
445 value *= std::pow(10.0, rExp);
446
447 return value;
448}
449
Willy Tu38e7a2b2021-03-29 15:09:56 -0700450// Extract file name from sensor path as the sensors SDR ID. Simplify the name
451// if it is too long.
452std::string parseSdrIdFromPath(const std::string& path)
453{
454 std::string name;
455 size_t nameStart = path.rfind("/");
456 if (nameStart != std::string::npos)
457 {
458 name = path.substr(nameStart + 1, std::string::npos - nameStart);
459 }
460
Willy Tu38e7a2b2021-03-29 15:09:56 -0700461 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
462 {
463 // try to not truncate by replacing common words
JeffLind950f412021-10-20 18:49:34 +0800464 for (const auto& suffix : suffixes)
Willy Tu38e7a2b2021-03-29 15:09:56 -0700465 {
JeffLind950f412021-10-20 18:49:34 +0800466 if (boost::ends_with(name, suffix))
467 {
468 boost::replace_all(name, suffix, "");
469 break;
470 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700471 }
Duke Du97014f52021-12-16 17:21:01 +0800472 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
473 {
474 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
475 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700476 }
477 return name;
478}
479
Hao Jiangd48c9212021-02-03 15:45:06 -0800480bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection,
481 const std::string& path,
482 const ipmi::DbusInterfaceMap::mapped_type& object,
483 std::bitset<16>& assertions)
484{
485 auto profiles = sensor::getSupportedVrProfiles(object);
486 if (!profiles)
487 {
488 return false;
489 }
Willy Tu8366f0b2022-04-29 05:00:17 -0700490 std::string mode;
Hao Jiangd48c9212021-02-03 15:45:06 -0800491
492 auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface,
Willy Tu8366f0b2022-04-29 05:00:17 -0700493 "Selected", mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800494 if (ec)
495 {
496 log<level::ERR>("Failed to get property",
497 entry("PROPERTY=%s", "Selected"),
498 entry("PATH=%s", path.c_str()),
499 entry("INTERFACE=%s", sensor::sensorInterface),
500 entry("WHAT=%s", ec.message().c_str()));
501 return false;
502 }
503
Willy Tu8366f0b2022-04-29 05:00:17 -0700504 auto itr = std::find(profiles->begin(), profiles->end(), mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800505 if (itr == profiles->end())
506 {
507 using namespace phosphor::logging;
508 log<level::ERR>("VR mode doesn't match any of its profiles",
509 entry("PATH=%s", path.c_str()));
510 return false;
511 }
512 std::size_t index =
513 static_cast<std::size_t>(std::distance(profiles->begin(), itr));
514
Willy Tubef102a2022-06-09 15:36:09 -0700515 // map index to response event assertion bit.
516 if (index < 16)
Hao Jiangd48c9212021-02-03 15:45:06 -0800517 {
Willy Tubef102a2022-06-09 15:36:09 -0700518 assertions.set(index);
Hao Jiangd48c9212021-02-03 15:45:06 -0800519 }
520 else
521 {
522 log<level::ERR>("VR profile index reaches max assertion bit",
523 entry("PATH=%s", path.c_str()),
524 entry("INDEX=%uz", index));
525 return false;
526 }
527 if constexpr (debug)
528 {
529 std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path)
Willy Tu8366f0b2022-04-29 05:00:17 -0700530 << " mode is: [" << index << "] " << mode << std::endl;
Hao Jiangd48c9212021-02-03 15:45:06 -0800531 }
532 return true;
533}
Hao Jiangd2afd052020-12-10 15:09:32 -0800534} // namespace sensor
535
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000536ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
537 ipmi::message::Payload& p)
Willy Tude54f482021-01-26 15:59:09 -0800538{
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000539 constexpr const uint8_t validEnvmRev = 0x04;
540 constexpr const uint8_t lastSensorType = 0x2C;
541 constexpr const uint8_t oemReserved = 0xC0;
542
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700543 uint8_t sysgeneratorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000544 uint8_t evmRev = 0;
545 uint8_t sensorType = 0;
546 uint8_t sensorNum = 0;
547 uint8_t eventType = 0;
548 uint8_t eventData1 = 0;
549 std::optional<uint8_t> eventData2 = 0;
550 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700551 [[maybe_unused]] uint16_t generatorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000552 ipmi::ChannelInfo chInfo;
553
554 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
555 {
556 phosphor::logging::log<phosphor::logging::level::ERR>(
557 "Failed to get Channel Info",
558 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
559 return ipmi::responseUnspecifiedError();
560 }
561
562 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
563 ipmi::EChannelMediumType::systemInterface)
564 {
565
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700566 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000567 eventData1, eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700568 // Refer to IPMI Spec Table 32: SEL Event Records
569 generatorID = (ctx->channel << 12) // Channel
570 | (0x0 << 10) // Reserved
571 | (0x0 << 8) // 0x0 for sys-soft ID
572 | ((sysgeneratorID << 1) | 0x1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000573 }
574 else
575 {
576
577 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
578 eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700579 // Refer to IPMI Spec Table 32: SEL Event Records
580 generatorID = (ctx->channel << 12) // Channel
581 | (0x0 << 10) // Reserved
582 | ((ctx->lun & 0x3) << 8) // Lun
583 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000584 }
585
586 if (!p.fullyUnpacked())
587 {
588 return ipmi::responseReqDataLenInvalid();
589 }
590
591 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
592 if (evmRev != validEnvmRev)
593 {
594 return ipmi::responseInvalidFieldRequest();
595 }
596 if ((sensorType > lastSensorType) && (sensorType < oemReserved))
597 {
598 return ipmi::responseInvalidFieldRequest();
599 }
600
Willy Tude54f482021-01-26 15:59:09 -0800601 return ipmi::responseSuccess();
602}
603
Willy Tudbafbce2021-03-29 00:37:05 -0700604ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
Willy Tu11d68892022-01-20 10:37:34 -0800605 uint8_t sensorNumber, uint8_t,
Willy Tudbafbce2021-03-29 00:37:05 -0700606 uint8_t reading, uint15_t assertOffset,
Willy Tu11d68892022-01-20 10:37:34 -0800607 bool, uint15_t, bool, uint8_t, uint8_t,
608 uint8_t)
Willy Tudbafbce2021-03-29 00:37:05 -0700609{
610 std::string connection;
611 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -0700612 std::vector<std::string> interfaces;
613
614 ipmi::Cc status =
615 getSensorConnection(ctx, sensorNumber, connection, path, &interfaces);
Willy Tudbafbce2021-03-29 00:37:05 -0700616 if (status)
617 {
618 return ipmi::response(status);
619 }
620
Hao Jiangd2afd052020-12-10 15:09:32 -0800621 // we can tell the sensor type by its interface type
Hao Jiange39d4d82021-04-16 17:02:40 -0700622 if (std::find(interfaces.begin(), interfaces.end(),
623 sensor::sensorInterface) != interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700624 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700625 DbusInterfaceMap sensorMap;
626 if (!getSensorMap(ctx, connection, path, sensorMap))
627 {
628 return ipmi::responseResponseError();
629 }
630 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800631 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700632 {
633 return ipmi::responseResponseError();
634 }
635
Jie Yangf0a89942021-07-29 15:30:25 -0700636 // Only allow external SetSensor if write permission granted
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800637 if (!details::sdrWriteTable.getWritePermission((ctx->lun << 8) |
638 sensorNumber))
Jie Yangf0a89942021-07-29 15:30:25 -0700639 {
640 return ipmi::responseResponseError();
641 }
642
Hao Jiangd2afd052020-12-10 15:09:32 -0800643 auto value =
644 sensor::calculateValue(reading, sensorMap, sensorObject->second);
645 if (!value)
646 {
647 return ipmi::responseResponseError();
648 }
649
650 if constexpr (debug)
651 {
652 phosphor::logging::log<phosphor::logging::level::INFO>(
653 "IPMI SET_SENSOR",
654 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber),
655 phosphor::logging::entry("BYTE=%u", (unsigned int)reading),
656 phosphor::logging::entry("VALUE=%f", *value));
657 }
658
659 boost::system::error_code ec =
660 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
661 "Value", ipmi::Value(*value));
662
663 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500664 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800665 // callback functions for now (e.g. ipmiSetSensorReading).
666 if (ec)
667 {
668 using namespace phosphor::logging;
669 log<level::ERR>("Failed to set property",
670 entry("PROPERTY=%s", "Value"),
671 entry("PATH=%s", path.c_str()),
672 entry("INTERFACE=%s", sensor::sensorInterface),
673 entry("WHAT=%s", ec.message().c_str()));
674 return ipmi::responseResponseError();
675 }
676 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700677 }
678
Hao Jiange39d4d82021-04-16 17:02:40 -0700679 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
680 interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700681 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700682 DbusInterfaceMap sensorMap;
683 if (!getSensorMap(ctx, connection, path, sensorMap))
684 {
685 return ipmi::responseResponseError();
686 }
687 auto sensorObject = sensorMap.find(sensor::vrInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800688 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700689 {
690 return ipmi::responseResponseError();
691 }
692
Hao Jiangd2afd052020-12-10 15:09:32 -0800693 // VR sensors are treated as a special case and we will not check the
694 // write permission for VR sensors, since they always deemed writable
695 // and permission table are not applied to VR sensors.
696 auto vrMode =
697 sensor::calculateVRMode(assertOffset, sensorObject->second);
698 if (!vrMode)
699 {
700 return ipmi::responseResponseError();
701 }
702 boost::system::error_code ec = setDbusProperty(
703 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
704 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500705 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800706 // callback functions for now (e.g. ipmiSetSensorReading).
707 if (ec)
708 {
709 using namespace phosphor::logging;
710 log<level::ERR>("Failed to set property",
711 entry("PROPERTY=%s", "Selected"),
712 entry("PATH=%s", path.c_str()),
713 entry("INTERFACE=%s", sensor::sensorInterface),
714 entry("WHAT=%s", ec.message().c_str()));
715 return ipmi::responseResponseError();
716 }
717 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700718 }
719
Hao Jiangd2afd052020-12-10 15:09:32 -0800720 phosphor::logging::log<phosphor::logging::level::ERR>(
721 "unknown sensor type",
722 phosphor::logging::entry("PATH=%s", path.c_str()));
723 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700724}
725
Willy Tude54f482021-01-26 15:59:09 -0800726ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
727 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
728{
729 std::string connection;
730 std::string path;
731
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000732 if (sensnum == reservedSensorNumber)
733 {
734 return ipmi::responseInvalidFieldRequest();
735 }
736
Willy Tude54f482021-01-26 15:59:09 -0800737 auto status = getSensorConnection(ctx, sensnum, connection, path);
738 if (status)
739 {
740 return ipmi::response(status);
741 }
742
Scron Chang2703b022021-07-06 15:47:45 +0800743#ifdef FEATURE_HYBRID_SENSORS
744 if (auto sensor = findStaticSensor(path);
745 sensor != ipmi::sensor::sensors.end() &&
746 getSensorEventTypeFromPath(path) !=
747 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
748 {
749 if (ipmi::sensor::Mutability::Read !=
750 (sensor->second.mutability & ipmi::sensor::Mutability::Read))
751 {
752 return ipmi::responseIllegalCommand();
753 }
754
755 uint8_t operation;
756 try
757 {
758 ipmi::sensor::GetSensorResponse getResponse =
759 sensor->second.getFunc(sensor->second);
760
761 if (getResponse.readingOrStateUnavailable)
762 {
763 operation |= static_cast<uint8_t>(
764 IPMISensorReadingByte2::readingStateUnavailable);
765 }
766 if (getResponse.scanningEnabled)
767 {
768 operation |= static_cast<uint8_t>(
769 IPMISensorReadingByte2::sensorScanningEnable);
770 }
771 if (getResponse.allEventMessagesEnabled)
772 {
773 operation |= static_cast<uint8_t>(
774 IPMISensorReadingByte2::eventMessagesEnable);
775 }
776 return ipmi::responseSuccess(
777 getResponse.reading, operation,
778 getResponse.thresholdLevelsStates,
779 getResponse.discreteReadingSensorStates);
780 }
781 catch (const std::exception& e)
782 {
783 operation |= static_cast<uint8_t>(
784 IPMISensorReadingByte2::readingStateUnavailable);
785 return ipmi::responseSuccess(0, operation, 0, std::nullopt);
786 }
787 }
788#endif
789
Willy Tude54f482021-01-26 15:59:09 -0800790 DbusInterfaceMap sensorMap;
791 if (!getSensorMap(ctx, connection, path, sensorMap))
792 {
793 return ipmi::responseResponseError();
794 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800795 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800796
797 if (sensorObject == sensorMap.end() ||
798 sensorObject->second.find("Value") == sensorObject->second.end())
799 {
800 return ipmi::responseResponseError();
801 }
802 auto& valueVariant = sensorObject->second["Value"];
803 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
804
805 double max = 0;
806 double min = 0;
807 getSensorMaxMin(sensorMap, max, min);
808
809 int16_t mValue = 0;
810 int16_t bValue = 0;
811 int8_t rExp = 0;
812 int8_t bExp = 0;
813 bool bSigned = false;
814
815 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
816 {
817 return ipmi::responseResponseError();
818 }
819
820 uint8_t value =
821 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
822 uint8_t operation =
823 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
824 operation |=
825 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
826 bool notReading = std::isnan(reading);
827
828 if (!notReading)
829 {
830 auto availableObject =
831 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
832 if (availableObject != sensorMap.end())
833 {
834 auto findAvailable = availableObject->second.find("Available");
835 if (findAvailable != availableObject->second.end())
836 {
837 bool* available = std::get_if<bool>(&(findAvailable->second));
838 if (available && !(*available))
839 {
840 notReading = true;
841 }
842 }
843 }
844 }
845
846 if (notReading)
847 {
848 operation |= static_cast<uint8_t>(
849 IPMISensorReadingByte2::readingStateUnavailable);
850 }
851
Josh Lehana55c9532020-10-28 21:59:06 -0700852 if constexpr (details::enableInstrumentation)
853 {
854 int byteValue;
855 if (bSigned)
856 {
857 byteValue = static_cast<int>(static_cast<int8_t>(value));
858 }
859 else
860 {
861 byteValue = static_cast<int>(static_cast<uint8_t>(value));
862 }
863
864 // Keep stats on the reading just obtained, even if it is "NaN"
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800865 if (details::sdrStatsTable.updateReading((ctx->lun << 8) | sensnum,
866 reading, byteValue))
Josh Lehana55c9532020-10-28 21:59:06 -0700867 {
868 // This is the first reading, show the coefficients
869 double step = (max - min) / 255.0;
870 std::cerr << "IPMI sensor "
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800871 << details::sdrStatsTable.getName((ctx->lun << 8) |
872 sensnum)
Josh Lehana55c9532020-10-28 21:59:06 -0700873 << ": Range min=" << min << " max=" << max
874 << ", step=" << step
875 << ", Coefficients mValue=" << static_cast<int>(mValue)
876 << " rExp=" << static_cast<int>(rExp)
877 << " bValue=" << static_cast<int>(bValue)
878 << " bExp=" << static_cast<int>(bExp)
879 << " bSigned=" << static_cast<int>(bSigned) << "\n";
880 }
881 }
882
Willy Tude54f482021-01-26 15:59:09 -0800883 uint8_t thresholds = 0;
884
885 auto warningObject =
886 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
887 if (warningObject != sensorMap.end())
888 {
889 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
890 auto alarmLow = warningObject->second.find("WarningAlarmLow");
891 if (alarmHigh != warningObject->second.end())
892 {
893 if (std::get<bool>(alarmHigh->second))
894 {
895 thresholds |= static_cast<uint8_t>(
896 IPMISensorReadingByte3::upperNonCritical);
897 }
898 }
899 if (alarmLow != warningObject->second.end())
900 {
901 if (std::get<bool>(alarmLow->second))
902 {
903 thresholds |= static_cast<uint8_t>(
904 IPMISensorReadingByte3::lowerNonCritical);
905 }
906 }
907 }
908
909 auto criticalObject =
910 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
911 if (criticalObject != sensorMap.end())
912 {
913 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
914 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
915 if (alarmHigh != criticalObject->second.end())
916 {
917 if (std::get<bool>(alarmHigh->second))
918 {
919 thresholds |=
920 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
921 }
922 }
923 if (alarmLow != criticalObject->second.end())
924 {
925 if (std::get<bool>(alarmLow->second))
926 {
927 thresholds |=
928 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
929 }
930 }
931 }
932
933 // no discrete as of today so optional byte is never returned
934 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
935}
936
937/** @brief implements the Set Sensor threshold command
938 * @param sensorNumber - sensor number
939 * @param lowerNonCriticalThreshMask
940 * @param lowerCriticalThreshMask
941 * @param lowerNonRecovThreshMask
942 * @param upperNonCriticalThreshMask
943 * @param upperCriticalThreshMask
944 * @param upperNonRecovThreshMask
945 * @param reserved
946 * @param lowerNonCritical - lower non-critical threshold
947 * @param lowerCritical - Lower critical threshold
948 * @param lowerNonRecoverable - Lower non recovarable threshold
949 * @param upperNonCritical - Upper non-critical threshold
950 * @param upperCritical - Upper critical
951 * @param upperNonRecoverable - Upper Non-recoverable
952 *
953 * @returns IPMI completion code
954 */
955ipmi::RspType<> ipmiSenSetSensorThresholds(
956 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
957 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
958 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
959 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800960 uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
Willy Tude54f482021-01-26 15:59:09 -0800961 uint8_t upperNonCritical, uint8_t upperCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800962 [[maybe_unused]] uint8_t upperNonRecoverable)
Willy Tude54f482021-01-26 15:59:09 -0800963{
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000964 if (sensorNum == reservedSensorNumber || reserved)
Willy Tude54f482021-01-26 15:59:09 -0800965 {
966 return ipmi::responseInvalidFieldRequest();
967 }
968
969 // lower nc and upper nc not suppported on any sensor
970 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
971 {
972 return ipmi::responseInvalidFieldRequest();
973 }
974
975 // if none of the threshold mask are set, nothing to do
976 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
977 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
978 upperCriticalThreshMask | upperNonRecovThreshMask))
979 {
980 return ipmi::responseSuccess();
981 }
982
983 std::string connection;
984 std::string path;
985
986 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
987 if (status)
988 {
989 return ipmi::response(status);
990 }
991 DbusInterfaceMap sensorMap;
992 if (!getSensorMap(ctx, connection, path, sensorMap))
993 {
994 return ipmi::responseResponseError();
995 }
996
997 double max = 0;
998 double min = 0;
999 getSensorMaxMin(sensorMap, max, min);
1000
1001 int16_t mValue = 0;
1002 int16_t bValue = 0;
1003 int8_t rExp = 0;
1004 int8_t bExp = 0;
1005 bool bSigned = false;
1006
1007 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1008 {
1009 return ipmi::responseResponseError();
1010 }
1011
1012 // store a vector of property name, value to set, and interface
1013 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
1014
1015 // define the indexes of the tuple
1016 constexpr uint8_t propertyName = 0;
1017 constexpr uint8_t thresholdValue = 1;
1018 constexpr uint8_t interface = 2;
1019 // verifiy all needed fields are present
1020 if (lowerCriticalThreshMask || upperCriticalThreshMask)
1021 {
1022 auto findThreshold =
1023 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1024 if (findThreshold == sensorMap.end())
1025 {
1026 return ipmi::responseInvalidFieldRequest();
1027 }
1028 if (lowerCriticalThreshMask)
1029 {
1030 auto findLower = findThreshold->second.find("CriticalLow");
1031 if (findLower == findThreshold->second.end())
1032 {
1033 return ipmi::responseInvalidFieldRequest();
1034 }
1035 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
1036 findThreshold->first);
1037 }
1038 if (upperCriticalThreshMask)
1039 {
1040 auto findUpper = findThreshold->second.find("CriticalHigh");
1041 if (findUpper == findThreshold->second.end())
1042 {
1043 return ipmi::responseInvalidFieldRequest();
1044 }
1045 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
1046 findThreshold->first);
1047 }
1048 }
1049 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
1050 {
1051 auto findThreshold =
1052 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1053 if (findThreshold == sensorMap.end())
1054 {
1055 return ipmi::responseInvalidFieldRequest();
1056 }
1057 if (lowerNonCriticalThreshMask)
1058 {
1059 auto findLower = findThreshold->second.find("WarningLow");
1060 if (findLower == findThreshold->second.end())
1061 {
1062 return ipmi::responseInvalidFieldRequest();
1063 }
1064 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
1065 findThreshold->first);
1066 }
1067 if (upperNonCriticalThreshMask)
1068 {
1069 auto findUpper = findThreshold->second.find("WarningHigh");
1070 if (findUpper == findThreshold->second.end())
1071 {
1072 return ipmi::responseInvalidFieldRequest();
1073 }
1074 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
1075 findThreshold->first);
1076 }
1077 }
1078 for (const auto& property : thresholdsToSet)
1079 {
1080 // from section 36.3 in the IPMI Spec, assume all linear
1081 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
1082 (bValue * std::pow(10.0, bExp))) *
1083 std::pow(10.0, rExp);
1084 setDbusProperty(
1085 *getSdBus(), connection, path, std::get<interface>(property),
1086 std::get<propertyName>(property), ipmi::Value(valueToSet));
1087 }
1088 return ipmi::responseSuccess();
1089}
1090
1091IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
1092{
1093 IPMIThresholds resp;
1094 auto warningInterface =
1095 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1096 auto criticalInterface =
1097 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1098
1099 if ((warningInterface != sensorMap.end()) ||
1100 (criticalInterface != sensorMap.end()))
1101 {
Hao Jiangd2afd052020-12-10 15:09:32 -08001102 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -08001103
1104 if (sensorPair == sensorMap.end())
1105 {
1106 // should not have been able to find a sensor not implementing
1107 // the sensor object
1108 throw std::runtime_error("Invalid sensor map");
1109 }
1110
1111 double max = 0;
1112 double min = 0;
1113 getSensorMaxMin(sensorMap, max, min);
1114
1115 int16_t mValue = 0;
1116 int16_t bValue = 0;
1117 int8_t rExp = 0;
1118 int8_t bExp = 0;
1119 bool bSigned = false;
1120
1121 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1122 {
1123 throw std::runtime_error("Invalid sensor atrributes");
1124 }
1125 if (warningInterface != sensorMap.end())
1126 {
1127 auto& warningMap = warningInterface->second;
1128
1129 auto warningHigh = warningMap.find("WarningHigh");
1130 auto warningLow = warningMap.find("WarningLow");
1131
1132 if (warningHigh != warningMap.end())
1133 {
1134
1135 double value =
1136 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001137 if (std::isfinite(value))
1138 {
1139 resp.warningHigh = scaleIPMIValueFromDouble(
1140 value, mValue, rExp, bValue, bExp, bSigned);
1141 }
Willy Tude54f482021-01-26 15:59:09 -08001142 }
1143 if (warningLow != warningMap.end())
1144 {
1145 double value =
1146 std::visit(VariantToDoubleVisitor(), warningLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001147 if (std::isfinite(value))
1148 {
1149 resp.warningLow = scaleIPMIValueFromDouble(
1150 value, mValue, rExp, bValue, bExp, bSigned);
1151 }
Willy Tude54f482021-01-26 15:59:09 -08001152 }
1153 }
1154 if (criticalInterface != sensorMap.end())
1155 {
1156 auto& criticalMap = criticalInterface->second;
1157
1158 auto criticalHigh = criticalMap.find("CriticalHigh");
1159 auto criticalLow = criticalMap.find("CriticalLow");
1160
1161 if (criticalHigh != criticalMap.end())
1162 {
1163 double value =
1164 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001165 if (std::isfinite(value))
1166 {
1167 resp.criticalHigh = scaleIPMIValueFromDouble(
1168 value, mValue, rExp, bValue, bExp, bSigned);
1169 }
Willy Tude54f482021-01-26 15:59:09 -08001170 }
1171 if (criticalLow != criticalMap.end())
1172 {
1173 double value =
1174 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001175 if (std::isfinite(value))
1176 {
1177 resp.criticalLow = scaleIPMIValueFromDouble(
1178 value, mValue, rExp, bValue, bExp, bSigned);
1179 }
Willy Tude54f482021-01-26 15:59:09 -08001180 }
1181 }
1182 }
1183 return resp;
1184}
1185
1186ipmi::RspType<uint8_t, // readable
1187 uint8_t, // lowerNCrit
1188 uint8_t, // lowerCrit
1189 uint8_t, // lowerNrecoverable
1190 uint8_t, // upperNC
1191 uint8_t, // upperCrit
1192 uint8_t> // upperNRecoverable
1193 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
1194{
1195 std::string connection;
1196 std::string path;
1197
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001198 if (sensorNumber == reservedSensorNumber)
1199 {
1200 return ipmi::responseInvalidFieldRequest();
1201 }
1202
Willy Tude54f482021-01-26 15:59:09 -08001203 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
1204 if (status)
1205 {
1206 return ipmi::response(status);
1207 }
1208
1209 DbusInterfaceMap sensorMap;
1210 if (!getSensorMap(ctx, connection, path, sensorMap))
1211 {
1212 return ipmi::responseResponseError();
1213 }
1214
1215 IPMIThresholds thresholdData;
1216 try
1217 {
1218 thresholdData = getIPMIThresholds(sensorMap);
1219 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001220 catch (const std::exception&)
Willy Tude54f482021-01-26 15:59:09 -08001221 {
1222 return ipmi::responseResponseError();
1223 }
1224
1225 uint8_t readable = 0;
1226 uint8_t lowerNC = 0;
1227 uint8_t lowerCritical = 0;
1228 uint8_t lowerNonRecoverable = 0;
1229 uint8_t upperNC = 0;
1230 uint8_t upperCritical = 0;
1231 uint8_t upperNonRecoverable = 0;
1232
1233 if (thresholdData.warningHigh)
1234 {
1235 readable |=
1236 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
1237 upperNC = *thresholdData.warningHigh;
1238 }
1239 if (thresholdData.warningLow)
1240 {
1241 readable |=
1242 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
1243 lowerNC = *thresholdData.warningLow;
1244 }
1245
1246 if (thresholdData.criticalHigh)
1247 {
1248 readable |=
1249 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
1250 upperCritical = *thresholdData.criticalHigh;
1251 }
1252 if (thresholdData.criticalLow)
1253 {
1254 readable |=
1255 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
1256 lowerCritical = *thresholdData.criticalLow;
1257 }
1258
1259 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
1260 lowerNonRecoverable, upperNC, upperCritical,
1261 upperNonRecoverable);
1262}
1263
1264/** @brief implements the get Sensor event enable command
1265 * @param sensorNumber - sensor number
1266 *
1267 * @returns IPMI completion code plus response data
1268 * - enabled - Sensor Event messages
1269 * - assertionEnabledLsb - Assertion event messages
1270 * - assertionEnabledMsb - Assertion event messages
1271 * - deassertionEnabledLsb - Deassertion event messages
1272 * - deassertionEnabledMsb - Deassertion event messages
1273 */
1274
1275ipmi::RspType<uint8_t, // enabled
1276 uint8_t, // assertionEnabledLsb
1277 uint8_t, // assertionEnabledMsb
1278 uint8_t, // deassertionEnabledLsb
1279 uint8_t> // deassertionEnabledMsb
1280 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
1281{
1282 std::string connection;
1283 std::string path;
1284
1285 uint8_t enabled = 0;
1286 uint8_t assertionEnabledLsb = 0;
1287 uint8_t assertionEnabledMsb = 0;
1288 uint8_t deassertionEnabledLsb = 0;
1289 uint8_t deassertionEnabledMsb = 0;
1290
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001291 if (sensorNum == reservedSensorNumber)
1292 {
1293 return ipmi::responseInvalidFieldRequest();
1294 }
1295
Willy Tude54f482021-01-26 15:59:09 -08001296 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1297 if (status)
1298 {
1299 return ipmi::response(status);
1300 }
1301
Scron Chang2703b022021-07-06 15:47:45 +08001302#ifdef FEATURE_HYBRID_SENSORS
1303 if (auto sensor = findStaticSensor(path);
1304 sensor != ipmi::sensor::sensors.end() &&
1305 getSensorEventTypeFromPath(path) !=
1306 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1307 {
1308 enabled = static_cast<uint8_t>(
1309 IPMISensorEventEnableByte2::sensorScanningEnable);
1310 uint16_t assertionEnabled = 0;
1311 for (auto& offsetValMap : sensor->second.propertyInterfaces.begin()
1312 ->second.begin()
1313 ->second.second)
1314 {
1315 assertionEnabled |= (1 << offsetValMap.first);
1316 }
1317 assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF));
1318 assertionEnabledMsb =
1319 static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF));
1320
1321 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1322 assertionEnabledMsb, deassertionEnabledLsb,
1323 deassertionEnabledMsb);
1324 }
1325#endif
1326
Willy Tude54f482021-01-26 15:59:09 -08001327 DbusInterfaceMap sensorMap;
1328 if (!getSensorMap(ctx, connection, path, sensorMap))
1329 {
1330 return ipmi::responseResponseError();
1331 }
1332
1333 auto warningInterface =
1334 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1335 auto criticalInterface =
1336 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1337 if ((warningInterface != sensorMap.end()) ||
1338 (criticalInterface != sensorMap.end()))
1339 {
1340 enabled = static_cast<uint8_t>(
1341 IPMISensorEventEnableByte2::sensorScanningEnable);
1342 if (warningInterface != sensorMap.end())
1343 {
1344 auto& warningMap = warningInterface->second;
1345
1346 auto warningHigh = warningMap.find("WarningHigh");
1347 auto warningLow = warningMap.find("WarningLow");
1348 if (warningHigh != warningMap.end())
1349 {
1350 assertionEnabledLsb |= static_cast<uint8_t>(
1351 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1352 deassertionEnabledLsb |= static_cast<uint8_t>(
1353 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
1354 }
1355 if (warningLow != warningMap.end())
1356 {
1357 assertionEnabledLsb |= static_cast<uint8_t>(
1358 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1359 deassertionEnabledLsb |= static_cast<uint8_t>(
1360 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
1361 }
1362 }
1363 if (criticalInterface != sensorMap.end())
1364 {
1365 auto& criticalMap = criticalInterface->second;
1366
1367 auto criticalHigh = criticalMap.find("CriticalHigh");
1368 auto criticalLow = criticalMap.find("CriticalLow");
1369
1370 if (criticalHigh != criticalMap.end())
1371 {
1372 assertionEnabledMsb |= static_cast<uint8_t>(
1373 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1374 deassertionEnabledMsb |= static_cast<uint8_t>(
1375 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1376 }
1377 if (criticalLow != criticalMap.end())
1378 {
1379 assertionEnabledLsb |= static_cast<uint8_t>(
1380 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1381 deassertionEnabledLsb |= static_cast<uint8_t>(
1382 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1383 }
1384 }
1385 }
1386
1387 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1388 assertionEnabledMsb, deassertionEnabledLsb,
1389 deassertionEnabledMsb);
1390}
1391
1392/** @brief implements the get Sensor event status command
1393 * @param sensorNumber - sensor number, FFh = reserved
1394 *
1395 * @returns IPMI completion code plus response data
1396 * - sensorEventStatus - Sensor Event messages state
1397 * - assertions - Assertion event messages
1398 * - deassertions - Deassertion event messages
1399 */
1400ipmi::RspType<uint8_t, // sensorEventStatus
1401 std::bitset<16>, // assertions
1402 std::bitset<16> // deassertion
1403 >
1404 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1405{
1406 if (sensorNum == reservedSensorNumber)
1407 {
1408 return ipmi::responseInvalidFieldRequest();
1409 }
1410
1411 std::string connection;
1412 std::string path;
1413 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1414 if (status)
1415 {
1416 phosphor::logging::log<phosphor::logging::level::ERR>(
1417 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1418 phosphor::logging::entry("SENSOR=%d", sensorNum));
1419 return ipmi::response(status);
1420 }
1421
Scron Chang2703b022021-07-06 15:47:45 +08001422#ifdef FEATURE_HYBRID_SENSORS
1423 if (auto sensor = findStaticSensor(path);
1424 sensor != ipmi::sensor::sensors.end() &&
1425 getSensorEventTypeFromPath(path) !=
1426 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1427 {
1428 auto response = ipmi::sensor::get::mapDbusToAssertion(
1429 sensor->second, path, sensor->second.sensorInterface);
1430 std::bitset<16> assertions;
1431 // deassertions are not used.
1432 std::bitset<16> deassertions = 0;
1433 uint8_t sensorEventStatus;
1434 if (response.readingOrStateUnavailable)
1435 {
1436 sensorEventStatus |= static_cast<uint8_t>(
1437 IPMISensorReadingByte2::readingStateUnavailable);
1438 }
1439 if (response.scanningEnabled)
1440 {
1441 sensorEventStatus |= static_cast<uint8_t>(
1442 IPMISensorReadingByte2::sensorScanningEnable);
1443 }
1444 if (response.allEventMessagesEnabled)
1445 {
1446 sensorEventStatus |= static_cast<uint8_t>(
1447 IPMISensorReadingByte2::eventMessagesEnable);
1448 }
1449 assertions |= response.discreteReadingSensorStates << 8;
1450 assertions |= response.thresholdLevelsStates;
1451 return ipmi::responseSuccess(sensorEventStatus, assertions,
1452 deassertions);
1453 }
1454#endif
1455
Willy Tude54f482021-01-26 15:59:09 -08001456 DbusInterfaceMap sensorMap;
1457 if (!getSensorMap(ctx, connection, path, sensorMap))
1458 {
1459 phosphor::logging::log<phosphor::logging::level::ERR>(
1460 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1461 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1462 return ipmi::responseResponseError();
1463 }
Hao Jiangd48c9212021-02-03 15:45:06 -08001464
1465 uint8_t sensorEventStatus =
1466 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1467 std::bitset<16> assertions = 0;
1468 std::bitset<16> deassertions = 0;
1469
1470 // handle VR typed sensor
1471 auto vrInterface = sensorMap.find(sensor::vrInterface);
1472 if (vrInterface != sensorMap.end())
1473 {
1474 if (!sensor::getVrEventStatus(ctx, connection, path,
1475 vrInterface->second, assertions))
1476 {
1477 return ipmi::responseResponseError();
1478 }
1479
1480 // both Event Message and Sensor Scanning are disable for VR.
1481 sensorEventStatus = 0;
1482 return ipmi::responseSuccess(sensorEventStatus, assertions,
1483 deassertions);
1484 }
1485
Willy Tude54f482021-01-26 15:59:09 -08001486 auto warningInterface =
1487 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1488 auto criticalInterface =
1489 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1490
Willy Tude54f482021-01-26 15:59:09 -08001491 std::optional<bool> criticalDeassertHigh =
1492 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1493 std::optional<bool> criticalDeassertLow =
1494 thresholdDeassertMap[path]["CriticalAlarmLow"];
1495 std::optional<bool> warningDeassertHigh =
1496 thresholdDeassertMap[path]["WarningAlarmHigh"];
1497 std::optional<bool> warningDeassertLow =
1498 thresholdDeassertMap[path]["WarningAlarmLow"];
1499
Willy Tude54f482021-01-26 15:59:09 -08001500 if (criticalDeassertHigh && !*criticalDeassertHigh)
1501 {
1502 deassertions.set(static_cast<size_t>(
1503 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1504 }
1505 if (criticalDeassertLow && !*criticalDeassertLow)
1506 {
1507 deassertions.set(static_cast<size_t>(
1508 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1509 }
1510 if (warningDeassertHigh && !*warningDeassertHigh)
1511 {
1512 deassertions.set(static_cast<size_t>(
1513 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1514 }
1515 if (warningDeassertLow && !*warningDeassertLow)
1516 {
1517 deassertions.set(static_cast<size_t>(
1518 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1519 }
1520 if ((warningInterface != sensorMap.end()) ||
1521 (criticalInterface != sensorMap.end()))
1522 {
1523 sensorEventStatus = static_cast<size_t>(
1524 IPMISensorEventEnableByte2::eventMessagesEnable);
1525 if (warningInterface != sensorMap.end())
1526 {
1527 auto& warningMap = warningInterface->second;
1528
1529 auto warningHigh = warningMap.find("WarningAlarmHigh");
1530 auto warningLow = warningMap.find("WarningAlarmLow");
1531 auto warningHighAlarm = false;
1532 auto warningLowAlarm = false;
1533
1534 if (warningHigh != warningMap.end())
1535 {
1536 warningHighAlarm = std::get<bool>(warningHigh->second);
1537 }
1538 if (warningLow != warningMap.end())
1539 {
1540 warningLowAlarm = std::get<bool>(warningLow->second);
1541 }
1542 if (warningHighAlarm)
1543 {
1544 assertions.set(
1545 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1546 upperNonCriticalGoingHigh));
1547 }
1548 if (warningLowAlarm)
1549 {
1550 assertions.set(
1551 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1552 lowerNonCriticalGoingLow));
1553 }
1554 }
1555 if (criticalInterface != sensorMap.end())
1556 {
1557 auto& criticalMap = criticalInterface->second;
1558
1559 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1560 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1561 auto criticalHighAlarm = false;
1562 auto criticalLowAlarm = false;
1563
1564 if (criticalHigh != criticalMap.end())
1565 {
1566 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1567 }
1568 if (criticalLow != criticalMap.end())
1569 {
1570 criticalLowAlarm = std::get<bool>(criticalLow->second);
1571 }
1572 if (criticalHighAlarm)
1573 {
1574 assertions.set(
1575 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1576 upperCriticalGoingHigh));
1577 }
1578 if (criticalLowAlarm)
1579 {
1580 assertions.set(static_cast<size_t>(
1581 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1582 }
1583 }
1584 }
1585
1586 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1587}
1588
Willy Tu38e7a2b2021-03-29 15:09:56 -07001589// Construct a type 1 SDR for threshold sensor.
Hao Jiange39d4d82021-04-16 17:02:40 -07001590void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1591 get_sdr::SensorDataFullRecord& record)
Willy Tude54f482021-01-26 15:59:09 -08001592{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001593 get_sdr::header::set_record_id(
1594 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1595
Willy Tu38e7a2b2021-03-29 15:09:56 -07001596 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1597 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1598
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001599 record.header.sdr_version = ipmiSdrVersion;
1600 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1601 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1602 sizeof(get_sdr::SensorDataRecordHeader);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001603 record.key.owner_id = bmcI2CAddr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001604 record.key.owner_lun = lun;
1605 record.key.sensor_number = sensornumber;
Hao Jiange39d4d82021-04-16 17:02:40 -07001606}
Willy Tu4eca2512022-06-20 21:14:51 -07001607bool constructSensorSdr(
1608 ipmi::Context::ptr ctx,
1609 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1610 uint16_t sensorNum, uint16_t recordID, const std::string& service,
1611 const std::string& path, get_sdr::SensorDataFullRecord& record)
Hao Jiange39d4d82021-04-16 17:02:40 -07001612{
Hao Jiange39d4d82021-04-16 17:02:40 -07001613 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1614
1615 DbusInterfaceMap sensorMap;
1616 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1617 {
1618 phosphor::logging::log<phosphor::logging::level::ERR>(
1619 "Failed to update sensor map for threshold sensor",
1620 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1621 phosphor::logging::entry("PATH=%s", path.c_str()));
1622 return false;
1623 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001624
1625 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1626 record.body.sensor_type = getSensorTypeFromPath(path);
1627 std::string type = getSensorTypeStringFromPath(path);
1628 auto typeCstr = type.c_str();
1629 auto findUnits = sensorUnits.find(typeCstr);
1630 if (findUnits != sensorUnits.end())
1631 {
1632 record.body.sensor_units_2_base =
1633 static_cast<uint8_t>(findUnits->second);
1634 } // else default 0x0 unspecified
1635
1636 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1637
Hao Jiangd2afd052020-12-10 15:09:32 -08001638 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001639 if (sensorObject == sensorMap.end())
1640 {
1641 phosphor::logging::log<phosphor::logging::level::ERR>(
1642 "getSensorDataRecord: sensorObject error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001643 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001644 }
1645
1646 uint8_t entityId = 0;
1647 uint8_t entityInstance = 0x01;
1648
1649 // follow the association chain to get the parent board's entityid and
1650 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001651 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, entityId,
1652 entityInstance);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001653
1654 record.body.entity_id = entityId;
1655 record.body.entity_instance = entityInstance;
1656
Shakeeb Pasha93889722021-10-14 10:20:13 +05301657 double max = 0;
1658 double min = 0;
1659 getSensorMaxMin(sensorMap, max, min);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001660
1661 int16_t mValue = 0;
1662 int8_t rExp = 0;
1663 int16_t bValue = 0;
1664 int8_t bExp = 0;
1665 bool bSigned = false;
1666
1667 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1668 {
1669 phosphor::logging::log<phosphor::logging::level::ERR>(
1670 "getSensorDataRecord: getSensorAttributes error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001671 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001672 }
1673
1674 // The record.body is a struct SensorDataFullRecordBody
1675 // from sensorhandler.hpp in phosphor-ipmi-host.
1676 // The meaning of these bits appears to come from
1677 // table 43.1 of the IPMI spec.
1678 // The above 5 sensor attributes are stuffed in as follows:
1679 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1680 // Byte 22-24 are for other purposes
1681 // Byte 25 = MMMMMMMM = LSB of M
1682 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1683 // Byte 27 = BBBBBBBB = LSB of B
1684 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1685 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1686 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1687
1688 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1689 record.body.m_lsb = mValue & 0xFF;
1690
1691 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1692 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1693
1694 // move the smallest bit of the MSB into place (bit 9)
1695 // the MSbs are bits 7:8 in m_msb_and_tolerance
1696 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1697
1698 record.body.b_lsb = bValue & 0xFF;
1699
1700 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1701 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1702
1703 // move the smallest bit of the MSB into place (bit 9)
1704 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1705 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1706
1707 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1708 uint8_t rExpBits = rExp & 0x07;
1709
1710 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1711 uint8_t bExpBits = bExp & 0x07;
1712
1713 // move rExp and bExp into place
1714 record.body.r_b_exponents =
1715 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1716
1717 // Set the analog reading byte interpretation accordingly
1718 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1719
1720 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1721 // These seem redundant, but derivable from the above 5 attributes
1722 // Original comment said "todo fill out rest of units"
1723
1724 // populate sensor name from path
Willy Tu38e7a2b2021-03-29 15:09:56 -07001725 auto name = sensor::parseSdrIdFromPath(path);
Paul Fertser51136982022-08-18 12:36:41 +00001726 get_sdr::body::set_id_strlen(name.size(), &record.body);
1727 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001728 std::strncpy(record.body.id_string, name.c_str(),
1729 sizeof(record.body.id_string));
1730
Josh Lehana55c9532020-10-28 21:59:06 -07001731 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001732 details::sdrStatsTable.updateName(sensorNum, name);
Josh Lehana55c9532020-10-28 21:59:06 -07001733
Jie Yangf0a89942021-07-29 15:30:25 -07001734 bool sensorSettable = false;
1735 auto mutability =
1736 sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability");
1737 if (mutability != sensorMap.end())
1738 {
1739 sensorSettable =
1740 mappedVariant<bool>(mutability->second, "Mutable", false);
1741 }
1742 get_sdr::body::init_settable_state(sensorSettable, &record.body);
1743
1744 // Grant write permission to sensors deemed externally settable
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001745 details::sdrWriteTable.setWritePermission(sensorNum, sensorSettable);
Willy Tu530e2772021-07-02 14:42:06 -07001746
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001747 IPMIThresholds thresholdData;
1748 try
1749 {
1750 thresholdData = getIPMIThresholds(sensorMap);
1751 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001752 catch (const std::exception&)
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001753 {
1754 phosphor::logging::log<phosphor::logging::level::ERR>(
1755 "getSensorDataRecord: getIPMIThresholds error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001756 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001757 }
1758
1759 if (thresholdData.criticalHigh)
1760 {
1761 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1762 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1763 IPMISensorEventEnableThresholds::criticalThreshold);
1764 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1765 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1766 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1767 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1768 record.body.discrete_reading_setting_mask[0] |=
1769 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1770 }
1771 if (thresholdData.warningHigh)
1772 {
1773 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1774 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1775 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1776 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1777 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1778 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1779 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1780 record.body.discrete_reading_setting_mask[0] |=
1781 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1782 }
1783 if (thresholdData.criticalLow)
1784 {
1785 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1786 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1787 IPMISensorEventEnableThresholds::criticalThreshold);
1788 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1789 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1790 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1791 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1792 record.body.discrete_reading_setting_mask[0] |=
1793 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1794 }
1795 if (thresholdData.warningLow)
1796 {
1797 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1798 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1799 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1800 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1801 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1802 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1803 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1804 record.body.discrete_reading_setting_mask[0] |=
1805 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1806 }
1807
1808 // everything that is readable is setable
1809 record.body.discrete_reading_setting_mask[1] =
1810 record.body.discrete_reading_setting_mask[0];
Willy Tu38e7a2b2021-03-29 15:09:56 -07001811 return true;
1812}
1813
Scron Chang2703b022021-07-06 15:47:45 +08001814#ifdef FEATURE_HYBRID_SENSORS
1815// Construct a type 1 SDR for discrete Sensor typed sensor.
Willy Tu11d68892022-01-20 10:37:34 -08001816void constructStaticSensorSdr(ipmi::Context::ptr, uint16_t sensorNum,
Scron Chang2703b022021-07-06 15:47:45 +08001817 uint16_t recordID,
1818 ipmi::sensor::IdInfoMap::const_iterator sensor,
1819 get_sdr::SensorDataFullRecord& record)
1820{
1821 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1822
1823 record.body.entity_id = sensor->second.entityType;
1824 record.body.sensor_type = sensor->second.sensorType;
1825 record.body.event_reading_type = sensor->second.sensorReadingType;
1826 record.body.entity_instance = sensor->second.instance;
1827 if (ipmi::sensor::Mutability::Write ==
1828 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
1829 {
1830 get_sdr::body::init_settable_state(true, &(record.body));
1831 }
1832
1833 auto id_string = sensor->second.sensorName;
1834
1835 if (id_string.empty())
1836 {
1837 id_string = sensor->second.sensorNameFunc(sensor->second);
1838 }
1839
1840 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
1841 {
1842 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH,
1843 &(record.body));
1844 }
1845 else
1846 {
1847 get_sdr::body::set_id_strlen(id_string.length(), &(record.body));
1848 }
Paul Fertser51136982022-08-18 12:36:41 +00001849 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Scron Chang2703b022021-07-06 15:47:45 +08001850 std::strncpy(record.body.id_string, id_string.c_str(),
1851 get_sdr::body::get_id_strlen(&(record.body)));
1852}
1853#endif
1854
Hao Jiange39d4d82021-04-16 17:02:40 -07001855// Construct type 3 SDR header and key (for VR and other discrete sensors)
1856void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1857 get_sdr::SensorDataEventRecord& record)
Willy Tu61992ad2021-03-29 15:33:20 -07001858{
1859 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1860 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1861
1862 get_sdr::header::set_record_id(
1863 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1864
1865 record.header.sdr_version = ipmiSdrVersion;
1866 record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD;
1867 record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) -
1868 sizeof(get_sdr::SensorDataRecordHeader);
1869 record.key.owner_id = bmcI2CAddr;
1870 record.key.owner_lun = lun;
1871 record.key.sensor_number = sensornumber;
1872
1873 record.body.entity_id = 0x00;
1874 record.body.entity_instance = 0x01;
Hao Jiange39d4d82021-04-16 17:02:40 -07001875}
Willy Tu61992ad2021-03-29 15:33:20 -07001876
Hao Jiange39d4d82021-04-16 17:02:40 -07001877// Construct a type 3 SDR for VR typed sensor(daemon).
Willy Tu4eca2512022-06-20 21:14:51 -07001878bool constructVrSdr(ipmi::Context::ptr ctx,
1879 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1880 uint16_t sensorNum, uint16_t recordID,
1881 const std::string& service, const std::string& path,
Hao Jiange39d4d82021-04-16 17:02:40 -07001882 get_sdr::SensorDataEventRecord& record)
1883{
Hao Jiange39d4d82021-04-16 17:02:40 -07001884 constructEventSdrHeaderKey(sensorNum, recordID, record);
1885
1886 DbusInterfaceMap sensorMap;
1887 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1888 {
1889 phosphor::logging::log<phosphor::logging::level::ERR>(
1890 "Failed to update sensor map for VR sensor",
1891 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1892 phosphor::logging::entry("PATH=%s", path.c_str()));
1893 return false;
1894 }
Willy Tu61992ad2021-03-29 15:33:20 -07001895 // follow the association chain to get the parent board's entityid and
1896 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001897 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap,
1898 record.body.entity_id,
Willy Tu61992ad2021-03-29 15:33:20 -07001899 record.body.entity_instance);
1900
1901 // Sensor type is hardcoded as a module/board type instead of parsing from
1902 // sensor path. This is because VR control is allocated in an independent
1903 // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by
1904 // types.
1905 static constexpr const uint8_t module_board_type = 0x15;
1906 record.body.sensor_type = module_board_type;
1907 record.body.event_reading_type = 0x00;
1908
1909 record.body.sensor_record_sharing_1 = 0x00;
1910 record.body.sensor_record_sharing_2 = 0x00;
1911
1912 // populate sensor name from path
1913 auto name = sensor::parseSdrIdFromPath(path);
1914 int nameSize = std::min(name.size(), sizeof(record.body.id_string));
Paul Fertser51136982022-08-18 12:36:41 +00001915 get_sdr::body::set_id_strlen(nameSize, &record.body);
1916 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Willy Tu61992ad2021-03-29 15:33:20 -07001917 std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string));
1918 std::memcpy(record.body.id_string, name.c_str(), nameSize);
1919
1920 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001921 details::sdrStatsTable.updateName(sensorNum, name);
Hao Jiange39d4d82021-04-16 17:02:40 -07001922
1923 return true;
Willy Tu61992ad2021-03-29 15:33:20 -07001924}
1925
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001926static inline uint16_t getNumberOfSensors()
1927{
1928 return std::min(getSensorTree().size(), maxIPMISensors);
1929}
1930
Willy Tu4eca2512022-06-20 21:14:51 -07001931static int getSensorDataRecord(
1932 ipmi::Context::ptr ctx,
1933 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1934 std::vector<uint8_t>& recordData, uint16_t recordID,
1935 uint8_t readBytes = std::numeric_limits<uint8_t>::max())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001936{
1937 size_t fruCount = 0;
1938 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1939 if (ret != ipmi::ccSuccess)
1940 {
1941 phosphor::logging::log<phosphor::logging::level::ERR>(
1942 "getSensorDataRecord: getFruSdrCount error");
1943 return GENERAL_ERROR;
1944 }
1945
Harvey Wu05d17c02021-09-15 08:46:59 +08001946 const auto& entityRecords =
1947 ipmi::sensor::EntityInfoMapContainer::getContainer()
1948 ->getIpmiEntityRecords();
1949 size_t entityCount = entityRecords.size();
1950
1951 size_t lastRecord = getNumberOfSensors() + fruCount +
1952 ipmi::storage::type12Count + entityCount - 1;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001953 if (recordID == lastRecordIndex)
1954 {
1955 recordID = lastRecord;
1956 }
1957 if (recordID > lastRecord)
1958 {
1959 phosphor::logging::log<phosphor::logging::level::ERR>(
1960 "getSensorDataRecord: recordID > lastRecord error");
1961 return GENERAL_ERROR;
1962 }
1963
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001964 if (recordID >= getNumberOfSensors())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001965 {
Harvey Wu05d17c02021-09-15 08:46:59 +08001966 size_t sdrIndex = recordID - getNumberOfSensors();
Willy Tu38e7a2b2021-03-29 15:09:56 -07001967
Harvey Wu05d17c02021-09-15 08:46:59 +08001968 if (sdrIndex >= fruCount + ipmi::storage::type12Count)
1969 {
1970 // handle type 8 entity map records
1971 ipmi::sensor::EntityInfoMap::const_iterator entity =
1972 entityRecords.find(static_cast<uint8_t>(
1973 sdrIndex - fruCount - ipmi::storage::type12Count));
1974 if (entity == entityRecords.end())
1975 {
1976 return IPMI_CC_SENSOR_INVALID;
1977 }
1978 recordData = ipmi::storage::getType8SDRs(entity, recordID);
1979 }
1980 else if (sdrIndex >= fruCount)
Willy Tu38e7a2b2021-03-29 15:09:56 -07001981 {
1982 // handle type 12 hardcoded records
Harvey Wu05d17c02021-09-15 08:46:59 +08001983 size_t type12Index = sdrIndex - fruCount;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001984 if (type12Index >= ipmi::storage::type12Count)
1985 {
1986 phosphor::logging::log<phosphor::logging::level::ERR>(
1987 "getSensorDataRecord: type12Index error");
1988 return GENERAL_ERROR;
1989 }
1990 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
1991 }
1992 else
1993 {
1994 // handle fru records
1995 get_sdr::SensorDataFruRecord data;
Harvey Wu05d17c02021-09-15 08:46:59 +08001996 ret = ipmi::storage::getFruSdrs(ctx, sdrIndex, data);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001997 if (ret != IPMI_CC_OK)
1998 {
1999 return GENERAL_ERROR;
2000 }
2001 data.header.record_id_msb = recordID >> 8;
2002 data.header.record_id_lsb = recordID & 0xFF;
2003 recordData.insert(recordData.end(), (uint8_t*)&data,
2004 ((uint8_t*)&data) + sizeof(data));
2005 }
2006
2007 return 0;
2008 }
2009
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002010 // Perform a incremental scan of the SDR Record ID's and translate the
2011 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
2012 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
2013 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
2014 // which has special meaning.
Willy Tu38e7a2b2021-03-29 15:09:56 -07002015 std::string connection;
2016 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -07002017 std::vector<std::string> interfaces;
Johnathan Manteyce982772021-07-28 15:08:30 -07002018 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002019 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyce982772021-07-28 15:08:30 -07002020 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002021 // LUN 0 has one reserved sensor number. Compensate here by adding one
2022 // to the record ID
2023 sensNumFromRecID = recordID + 1;
Johnathan Manteyce982772021-07-28 15:08:30 -07002024 ctx->lun = 1;
2025 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002026 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyce982772021-07-28 15:08:30 -07002027 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002028 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
2029 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
2030 // rules governing its use.
2031 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Johnathan Manteyce982772021-07-28 15:08:30 -07002032 ctx->lun = 3;
2033 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002034
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002035 auto status =
2036 getSensorConnection(ctx, static_cast<uint8_t>(sensNumFromRecID),
2037 connection, path, &interfaces);
Willy Tu38e7a2b2021-03-29 15:09:56 -07002038 if (status)
2039 {
2040 phosphor::logging::log<phosphor::logging::level::ERR>(
2041 "getSensorDataRecord: getSensorConnection error");
2042 return GENERAL_ERROR;
2043 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002044 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002045 // Return an error on LUN 2 assingments, and any sensor number beyond the
2046 // range of LUN 3
2047 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
2048 (sensorNum > lun3MaxSensorNum))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002049 {
2050 phosphor::logging::log<phosphor::logging::level::ERR>(
2051 "getSensorDataRecord: invalidSensorNumber");
2052 return GENERAL_ERROR;
2053 }
Johnathan Manteyce982772021-07-28 15:08:30 -07002054 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
2055 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
2056
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002057 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
2058 (lun != ctx->lun))
Johnathan Manteyce982772021-07-28 15:08:30 -07002059 {
2060 phosphor::logging::log<phosphor::logging::level::ERR>(
2061 "getSensorDataRecord: sensor record mismatch");
2062 return GENERAL_ERROR;
2063 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002064
Willy Tu38e7a2b2021-03-29 15:09:56 -07002065 // Construct full record (SDR type 1) for the threshold sensors
Hao Jiange39d4d82021-04-16 17:02:40 -07002066 if (std::find(interfaces.begin(), interfaces.end(),
2067 sensor::sensorInterface) != interfaces.end())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002068 {
Willy Tu11d68892022-01-20 10:37:34 -08002069 get_sdr::SensorDataFullRecord record = {};
Willy Tu38e7a2b2021-03-29 15:09:56 -07002070
Hao Jiange39d4d82021-04-16 17:02:40 -07002071 // If the request doesn't read SDR body, construct only header and key
2072 // part to avoid additional DBus transaction.
2073 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2074 {
2075 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2076 }
Willy Tu4eca2512022-06-20 21:14:51 -07002077 else if (!constructSensorSdr(ctx, ipmiDecoratorPaths, sensorNum,
2078 recordID, connection, path, record))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002079 {
2080 return GENERAL_ERROR;
2081 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002082
Willy Tu38e7a2b2021-03-29 15:09:56 -07002083 recordData.insert(recordData.end(), (uint8_t*)&record,
2084 ((uint8_t*)&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002085
2086 return 0;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002087 }
Willy Tu61992ad2021-03-29 15:33:20 -07002088
Scron Chang2703b022021-07-06 15:47:45 +08002089#ifdef FEATURE_HYBRID_SENSORS
2090 if (auto sensor = findStaticSensor(path);
2091 sensor != ipmi::sensor::sensors.end() &&
2092 getSensorEventTypeFromPath(path) !=
2093 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
2094 {
Willy Tu11d68892022-01-20 10:37:34 -08002095 get_sdr::SensorDataFullRecord record = {};
Scron Chang2703b022021-07-06 15:47:45 +08002096
2097 // If the request doesn't read SDR body, construct only header and key
2098 // part to avoid additional DBus transaction.
2099 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2100 {
2101 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2102 }
2103 else
2104 {
2105 constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record);
2106 }
2107
2108 recordData.insert(recordData.end(), (uint8_t*)&record,
2109 ((uint8_t*)&record) + sizeof(record));
2110
2111 return 0;
2112 }
2113#endif
2114
Willy Tu61992ad2021-03-29 15:33:20 -07002115 // Contruct SDR type 3 record for VR sensor (daemon)
Hao Jiange39d4d82021-04-16 17:02:40 -07002116 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
2117 interfaces.end())
Willy Tu61992ad2021-03-29 15:33:20 -07002118 {
Willy Tu11d68892022-01-20 10:37:34 -08002119 get_sdr::SensorDataEventRecord record = {};
Willy Tu61992ad2021-03-29 15:33:20 -07002120
Hao Jiange39d4d82021-04-16 17:02:40 -07002121 // If the request doesn't read SDR body, construct only header and key
2122 // part to avoid additional DBus transaction.
2123 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2124 {
2125 constructEventSdrHeaderKey(sensorNum, recordID, record);
2126 }
Willy Tu4eca2512022-06-20 21:14:51 -07002127 else if (!constructVrSdr(ctx, ipmiDecoratorPaths, sensorNum, recordID,
2128 connection, path, record))
Hao Jiange39d4d82021-04-16 17:02:40 -07002129 {
2130 return GENERAL_ERROR;
2131 }
Willy Tu61992ad2021-03-29 15:33:20 -07002132 recordData.insert(recordData.end(), (uint8_t*)&record,
2133 ((uint8_t*)&record) + sizeof(record));
2134 }
2135
Willy Tude54f482021-01-26 15:59:09 -08002136 return 0;
2137}
2138
2139/** @brief implements the get SDR Info command
2140 * @param count - Operation
2141 *
2142 * @returns IPMI completion code plus response data
2143 * - sdrCount - sensor/SDR count
2144 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
2145 */
2146static ipmi::RspType<uint8_t, // respcount
2147 uint8_t, // dynamic population flags
2148 uint32_t // last time a sensor was added
2149 >
2150 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
2151 std::optional<uint8_t> count)
2152{
2153 auto& sensorTree = getSensorTree();
2154 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002155 uint16_t recordID = 0;
2156 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08002157 // Sensors are dynamically allocated, and there is at least one LUN
2158 uint8_t lunsAndDynamicPopulation = 0x80;
2159 constexpr uint8_t getSdrCount = 0x01;
2160 constexpr uint8_t getSensorCount = 0x00;
2161
2162 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
2163 {
2164 return ipmi::responseResponseError();
2165 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002166 uint16_t numSensors = getNumberOfSensors();
Willy Tude54f482021-01-26 15:59:09 -08002167 if (count.value_or(0) == getSdrCount)
2168 {
Willy Tu4eca2512022-06-20 21:14:51 -07002169 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2170
Willy Tude54f482021-01-26 15:59:09 -08002171 // Count the number of Type 1 SDR entries assigned to the LUN
Willy Tu4eca2512022-06-20 21:14:51 -07002172 while (!getSensorDataRecord(
2173 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2174 record, recordID++))
Willy Tude54f482021-01-26 15:59:09 -08002175 {
2176 get_sdr::SensorDataRecordHeader* hdr =
2177 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002178 record.data());
Willy Tude54f482021-01-26 15:59:09 -08002179 if (hdr && hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
2180 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002181 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08002182 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002183 record.data());
2184 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08002185 {
2186 sdrCount++;
2187 }
2188 }
2189 }
2190 }
2191 else if (count.value_or(0) == getSensorCount)
2192 {
2193 // Return the number of sensors attached to the LUN
2194 if ((ctx->lun == 0) && (numSensors > 0))
2195 {
2196 sdrCount =
2197 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
2198 }
2199 else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
2200 {
2201 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
2202 ? maxSensorsPerLUN
2203 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
2204 }
2205 else if (ctx->lun == 3)
2206 {
2207 if (numSensors <= maxIPMISensors)
2208 {
2209 sdrCount =
2210 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
2211 }
2212 else
2213 {
2214 // error
2215 throw std::out_of_range(
2216 "Maximum number of IPMI sensors exceeded.");
2217 }
2218 }
2219 }
2220 else
2221 {
2222 return ipmi::responseInvalidFieldRequest();
2223 }
2224
2225 // Get Sensor count. This returns the number of sensors
2226 if (numSensors > 0)
2227 {
2228 lunsAndDynamicPopulation |= 1;
2229 }
2230 if (numSensors > maxSensorsPerLUN)
2231 {
2232 lunsAndDynamicPopulation |= 2;
2233 }
2234 if (numSensors >= (maxSensorsPerLUN * 2))
2235 {
2236 lunsAndDynamicPopulation |= 8;
2237 }
2238 if (numSensors > maxIPMISensors)
2239 {
2240 // error
2241 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
2242 }
2243
2244 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
2245 sdrLastAdd);
2246}
2247
2248/* end sensor commands */
2249
2250/* storage commands */
2251
2252ipmi::RspType<uint8_t, // sdr version
2253 uint16_t, // record count
2254 uint16_t, // free space
2255 uint32_t, // most recent addition
2256 uint32_t, // most recent erase
2257 uint8_t // operationSupport
2258 >
2259 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
2260{
2261 auto& sensorTree = getSensorTree();
2262 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002263 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002264 {
2265 return ipmi::responseResponseError();
2266 }
2267
2268 size_t fruCount = 0;
2269 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2270 if (ret != ipmi::ccSuccess)
2271 {
2272 return ipmi::response(ret);
2273 }
2274
2275 uint16_t recordCount =
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002276 getNumberOfSensors() + fruCount + ipmi::storage::type12Count;
Willy Tude54f482021-01-26 15:59:09 -08002277
2278 uint8_t operationSupport = static_cast<uint8_t>(
2279 SdrRepositoryInfoOps::overflow); // write not supported
2280
2281 operationSupport |=
2282 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
2283 operationSupport |= static_cast<uint8_t>(
2284 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
2285 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
2286 unspecifiedFreeSpace, sdrLastAdd,
2287 sdrLastRemove, operationSupport);
2288}
2289
2290/** @brief implements the get SDR allocation info command
2291 *
2292 * @returns IPMI completion code plus response data
2293 * - allocUnits - Number of possible allocation units
2294 * - allocUnitSize - Allocation unit size in bytes.
2295 * - allocUnitFree - Number of free allocation units
2296 * - allocUnitLargestFree - Largest free block in allocation units
2297 * - maxRecordSize - Maximum record size in allocation units.
2298 */
2299ipmi::RspType<uint16_t, // allocUnits
2300 uint16_t, // allocUnitSize
2301 uint16_t, // allocUnitFree
2302 uint16_t, // allocUnitLargestFree
2303 uint8_t // maxRecordSize
2304 >
2305 ipmiStorageGetSDRAllocationInfo()
2306{
2307 // 0000h unspecified number of alloc units
2308 constexpr uint16_t allocUnits = 0;
2309
2310 constexpr uint16_t allocUnitFree = 0;
2311 constexpr uint16_t allocUnitLargestFree = 0;
2312 // only allow one block at a time
2313 constexpr uint8_t maxRecordSize = 1;
2314
2315 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
2316 allocUnitLargestFree, maxRecordSize);
2317}
2318
2319/** @brief implements the reserve SDR command
2320 * @returns IPMI completion code plus response data
2321 * - sdrReservationID
2322 */
2323ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
2324{
2325 sdrReservationID++;
2326 if (sdrReservationID == 0)
2327 {
2328 sdrReservationID++;
2329 }
2330
2331 return ipmi::responseSuccess(sdrReservationID);
2332}
2333
2334ipmi::RspType<uint16_t, // next record ID
2335 std::vector<uint8_t> // payload
2336 >
2337 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
2338 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
2339{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002340 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08002341 // reservation required for partial reads with non zero offset into
2342 // record
2343 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
2344 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002345 phosphor::logging::log<phosphor::logging::level::ERR>(
2346 "ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08002347 return ipmi::responseInvalidReservationId();
2348 }
Willy Tude54f482021-01-26 15:59:09 -08002349 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2350 if (ret != ipmi::ccSuccess)
2351 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002352 phosphor::logging::log<phosphor::logging::level::ERR>(
2353 "ipmiStorageGetSDR: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08002354 return ipmi::response(ret);
2355 }
2356
Harvey Wu05d17c02021-09-15 08:46:59 +08002357 const auto& entityRecords =
2358 ipmi::sensor::EntityInfoMapContainer::getContainer()
2359 ->getIpmiEntityRecords();
2360 int entityCount = entityRecords.size();
2361
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002362 auto& sensorTree = getSensorTree();
Harvey Wu05d17c02021-09-15 08:46:59 +08002363 size_t lastRecord = getNumberOfSensors() + fruCount +
2364 ipmi::storage::type12Count + entityCount - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002365 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
2366
2367 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002368 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002369 phosphor::logging::log<phosphor::logging::level::ERR>(
2370 "ipmiStorageGetSDR: getSensorSubtree error");
2371 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08002372 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002373
Willy Tu4eca2512022-06-20 21:14:51 -07002374 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2375
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002376 std::vector<uint8_t> record;
Willy Tu4eca2512022-06-20 21:14:51 -07002377 if (getSensorDataRecord(
2378 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2379 record, recordID, offset + bytesToRead))
Willy Tude54f482021-01-26 15:59:09 -08002380 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002381 phosphor::logging::log<phosphor::logging::level::ERR>(
2382 "ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08002383 return ipmi::responseInvalidFieldRequest();
2384 }
Willy Tude54f482021-01-26 15:59:09 -08002385 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002386 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08002387 if (!hdr)
2388 {
2389 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002390 "ipmiStorageGetSDR: record header is null");
2391 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002392 }
2393
2394 size_t sdrLength =
2395 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
2396 if (sdrLength < (offset + bytesToRead))
2397 {
2398 bytesToRead = sdrLength - offset;
2399 }
2400
2401 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
2402 if (!respStart)
2403 {
2404 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002405 "ipmiStorageGetSDR: record is null");
2406 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002407 }
2408
2409 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002410
Willy Tude54f482021-01-26 15:59:09 -08002411 return ipmi::responseSuccess(nextRecordId, recordData);
2412}
adarshgrami042e9db2022-09-15 10:34:34 +05302413namespace dcmi
2414{
2415
2416ipmi::RspType<uint8_t, // No of instances for requested id
2417 uint8_t, // No of record ids in the response
2418 std::vector<uint16_t> // SDR Record ID corresponding to the Entity
2419 // IDs
2420 >
2421 getSensorInfo(ipmi::Context::ptr ctx, uint8_t sensorType, uint8_t entityId,
Willy Tu0679e4b2022-11-11 14:34:33 -08002422 uint8_t entityInstance,
2423 [[maybe_unused]] uint8_t instanceStart)
adarshgrami042e9db2022-09-15 10:34:34 +05302424{
2425 auto match = ipmi::dcmi::validEntityId.find(entityId);
2426 if (match == ipmi::dcmi::validEntityId.end())
2427 {
2428 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId));
2429
2430 return ipmi::responseInvalidFieldRequest();
2431 }
2432
2433 if (sensorType != ipmi::dcmi::temperatureSensorType)
2434 {
2435 log<level::ERR>("Invalid sensor type",
2436 entry("SENSOR_TYPE=%d", sensorType));
2437
2438 return ipmi::responseInvalidFieldRequest();
2439 }
2440 auto& sensorTree = getSensorTree();
2441 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
2442 {
2443 return ipmi::responseUnspecifiedError();
2444 }
2445
2446 std::vector<uint16_t> sensorRec{};
2447 uint8_t numInstances = 0;
2448
Willy Tu0679e4b2022-11-11 14:34:33 -08002449 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
adarshgrami042e9db2022-09-15 10:34:34 +05302450 for (const auto& sensor : sensorTree)
2451 {
2452 auto sensorTypeValue = getSensorTypeFromPath(sensor.first);
2453 if (sensorTypeValue != ipmi::dcmi::temperatureSensorType)
2454 {
2455 continue;
2456 }
2457 const auto& connection = sensor.second.begin()->first;
2458
2459 DbusInterfaceMap sensorMap;
2460 if (!getSensorMap(ctx, connection, sensor.first, sensorMap,
2461 sensorMapSdrUpdatePeriod))
2462 {
2463 phosphor::logging::log<phosphor::logging::level::ERR>(
2464 "Failed to update sensor map for threshold sensor",
2465 phosphor::logging::entry("SERVICE=%s", connection.c_str()),
2466 phosphor::logging::entry("PATH=%s", sensor.first.c_str()));
2467 continue;
2468 }
2469 uint8_t entityIdValue = 0;
2470 uint8_t entityInstanceValue = 0;
Willy Tu0679e4b2022-11-11 14:34:33 -08002471 updateIpmiFromAssociation(
2472 sensor.first,
2473 ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2474 sensorMap, entityIdValue, entityInstanceValue);
adarshgrami042e9db2022-09-15 10:34:34 +05302475 if (!entityInstance)
2476 {
2477 if (entityIdValue == match->first || entityIdValue == match->second)
2478 {
2479 auto recordId = getSensorNumberFromPath(sensor.first);
2480 if (recordId != invalidSensorNumber)
2481 {
2482 numInstances++;
2483 if (numInstances <= ipmi::dcmi::maxRecords)
2484 {
2485 sensorRec.push_back(recordId);
2486 }
2487 }
2488 }
2489 }
2490 else
2491 {
2492 if (entityIdValue == match->first || entityIdValue == match->second)
2493 {
2494 if (entityInstance == entityInstanceValue)
2495 {
2496 auto recordId = getSensorNumberFromPath(sensor.first);
2497 if ((recordId != invalidSensorNumber) && sensorRec.empty())
2498 {
2499 sensorRec.push_back(recordId);
2500 }
2501 }
2502 numInstances++;
2503 }
2504 }
2505 }
2506 if (sensorRec.empty())
2507 {
2508 return ipmi::responseSensorInvalid();
2509 }
2510 uint8_t numRecords = sensorRec.size();
2511 return ipmi::responseSuccess(numInstances, numRecords, sensorRec);
2512}
2513} // namespace dcmi
2514
Willy Tude54f482021-01-26 15:59:09 -08002515/* end storage commands */
2516
2517void registerSensorFunctions()
2518{
2519 // <Platform Event>
2520 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2521 ipmi::sensor_event::cmdPlatformEvent,
2522 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
2523
Willy Tudbafbce2021-03-29 00:37:05 -07002524 // <Set Sensor Reading and Event Status>
2525 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2526 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
2527 ipmi::Privilege::Operator, ipmiSetSensorReading);
Willy Tudbafbce2021-03-29 00:37:05 -07002528
Willy Tude54f482021-01-26 15:59:09 -08002529 // <Get Sensor Reading>
2530 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2531 ipmi::sensor_event::cmdGetSensorReading,
2532 ipmi::Privilege::User, ipmiSenGetSensorReading);
2533
2534 // <Get Sensor Threshold>
2535 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2536 ipmi::sensor_event::cmdGetSensorThreshold,
2537 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
2538
2539 // <Set Sensor Threshold>
2540 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2541 ipmi::sensor_event::cmdSetSensorThreshold,
2542 ipmi::Privilege::Operator,
2543 ipmiSenSetSensorThresholds);
2544
2545 // <Get Sensor Event Enable>
2546 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2547 ipmi::sensor_event::cmdGetSensorEventEnable,
2548 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
2549
2550 // <Get Sensor Event Status>
2551 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2552 ipmi::sensor_event::cmdGetSensorEventStatus,
2553 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
2554
2555 // register all storage commands for both Sensor and Storage command
2556 // versions
2557
2558 // <Get SDR Repository Info>
2559 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2560 ipmi::storage::cmdGetSdrRepositoryInfo,
2561 ipmi::Privilege::User,
2562 ipmiStorageGetSDRRepositoryInfo);
2563
2564 // <Get Device SDR Info>
2565 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2566 ipmi::sensor_event::cmdGetDeviceSdrInfo,
2567 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
2568
2569 // <Get SDR Allocation Info>
2570 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2571 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
2572 ipmi::Privilege::User,
2573 ipmiStorageGetSDRAllocationInfo);
2574
2575 // <Reserve SDR Repo>
2576 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2577 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
2578 ipmi::Privilege::User, ipmiStorageReserveSDR);
2579
2580 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2581 ipmi::storage::cmdReserveSdrRepository,
2582 ipmi::Privilege::User, ipmiStorageReserveSDR);
2583
2584 // <Get Sdr>
2585 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2586 ipmi::sensor_event::cmdGetDeviceSdr,
2587 ipmi::Privilege::User, ipmiStorageGetSDR);
2588
2589 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2590 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
2591 ipmiStorageGetSDR);
adarshgrami042e9db2022-09-15 10:34:34 +05302592 // <Get DCMI Sensor Info>
2593 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
2594 ipmi::dcmi::cmdGetDcmiSensorInfo,
2595 ipmi::Privilege::User,
2596 ipmi::dcmi::getSensorInfo);
Willy Tude54f482021-01-26 15:59:09 -08002597}
2598} // namespace ipmi