blob: ca6040f638098f2896e90d787854d747da34d279 [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
Harvey Wu75893062023-03-22 17:17:31 +080097// number of IPMI sensors are LUN 0 + LUN 1 + LUN 3, less the reserved
Johnathan Mantey6619ae42021-08-06 11:21:10 -070098// location.
99static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
100
Harvey Wu75893062023-03-22 17:17:31 +0800101static constexpr uint8_t lun0 = 0x0;
102static constexpr uint8_t lun1 = 0x1;
103static constexpr uint8_t lun3 = 0x3;
104
Johnathan Mantey6619ae42021-08-06 11:21:10 -0700105static constexpr size_t lun0MaxSensorNum = 0xfe;
106static constexpr size_t lun1MaxSensorNum = 0x1fe;
107static constexpr size_t lun3MaxSensorNum = 0x3fe;
Willy Tude54f482021-01-26 15:59:09 -0800108static constexpr int GENERAL_ERROR = -1;
109
Willy Tude54f482021-01-26 15:59:09 -0800110static boost::container::flat_map<std::string, ObjectValueTree> SensorCache;
111
112// Specify the comparison required to sort and find char* map objects
113struct CmpStr
114{
115 bool operator()(const char* a, const char* b) const
116 {
117 return std::strcmp(a, b) < 0;
118 }
119};
120const static boost::container::flat_map<const char*, SensorUnits, CmpStr>
121 sensorUnits{{{"temperature", SensorUnits::degreesC},
122 {"voltage", SensorUnits::volts},
123 {"current", SensorUnits::amps},
124 {"fan_tach", SensorUnits::rpm},
125 {"power", SensorUnits::watts}}};
126
127void registerSensorFunctions() __attribute__((constructor));
128
Patrick Williams5d82f472022-07-22 19:26:53 -0500129static sdbusplus::bus::match_t sensorAdded(
Willy Tude54f482021-01-26 15:59:09 -0800130 *getSdBus(),
131 "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
132 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500133 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800134 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700135 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800136 sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
137 std::chrono::system_clock::now().time_since_epoch())
138 .count();
139 });
140
Patrick Williams5d82f472022-07-22 19:26:53 -0500141static sdbusplus::bus::match_t sensorRemoved(
Willy Tude54f482021-01-26 15:59:09 -0800142 *getSdBus(),
143 "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
144 "sensors/'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500145 [](sdbusplus::message_t&) {
Willy Tude54f482021-01-26 15:59:09 -0800146 getSensorTree().clear();
Willy Tu4eca2512022-06-20 21:14:51 -0700147 getIpmiDecoratorPaths(/*ctx=*/std::nullopt).reset();
Willy Tude54f482021-01-26 15:59:09 -0800148 sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
149 std::chrono::system_clock::now().time_since_epoch())
150 .count();
151 });
152
153// this keeps track of deassertions for sensor event status command. A
154// deasertion can only happen if an assertion was seen first.
155static boost::container::flat_map<
156 std::string, boost::container::flat_map<std::string, std::optional<bool>>>
157 thresholdDeassertMap;
158
Patrick Williams5d82f472022-07-22 19:26:53 -0500159static sdbusplus::bus::match_t thresholdChanged(
Willy Tude54f482021-01-26 15:59:09 -0800160 *getSdBus(),
161 "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
162 "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
Patrick Williams5d82f472022-07-22 19:26:53 -0500163 [](sdbusplus::message_t& m) {
Willy Tude54f482021-01-26 15:59:09 -0800164 boost::container::flat_map<std::string, std::variant<bool, double>>
165 values;
166 m.read(std::string(), values);
167
168 auto findAssert =
169 std::find_if(values.begin(), values.end(), [](const auto& pair) {
170 return pair.first.find("Alarm") != std::string::npos;
171 });
172 if (findAssert != values.end())
173 {
174 auto ptr = std::get_if<bool>(&(findAssert->second));
175 if (ptr == nullptr)
176 {
177 phosphor::logging::log<phosphor::logging::level::ERR>(
178 "thresholdChanged: Assert non bool");
179 return;
180 }
181 if (*ptr)
182 {
183 phosphor::logging::log<phosphor::logging::level::INFO>(
184 "thresholdChanged: Assert",
185 phosphor::logging::entry("SENSOR=%s", m.get_path()));
186 thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
187 }
188 else
189 {
190 auto& value =
191 thresholdDeassertMap[m.get_path()][findAssert->first];
192 if (value)
193 {
194 phosphor::logging::log<phosphor::logging::level::INFO>(
195 "thresholdChanged: deassert",
196 phosphor::logging::entry("SENSOR=%s", m.get_path()));
197 value = *ptr;
198 }
199 }
200 }
201 });
202
Hao Jiangd2afd052020-12-10 15:09:32 -0800203namespace sensor
204{
205static constexpr const char* vrInterface =
206 "xyz.openbmc_project.Control.VoltageRegulatorMode";
207static constexpr const char* sensorInterface =
208 "xyz.openbmc_project.Sensor.Value";
209} // namespace sensor
210
Willy Tude54f482021-01-26 15:59:09 -0800211static void getSensorMaxMin(const DbusInterfaceMap& sensorMap, double& max,
212 double& min)
213{
214 max = 127;
215 min = -128;
216
Hao Jiangd2afd052020-12-10 15:09:32 -0800217 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800218 auto critical =
219 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
220 auto warning =
221 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
222
223 if (sensorObject != sensorMap.end())
224 {
225 auto maxMap = sensorObject->second.find("MaxValue");
226 auto minMap = sensorObject->second.find("MinValue");
227
228 if (maxMap != sensorObject->second.end())
229 {
230 max = std::visit(VariantToDoubleVisitor(), maxMap->second);
231 }
232 if (minMap != sensorObject->second.end())
233 {
234 min = std::visit(VariantToDoubleVisitor(), minMap->second);
235 }
236 }
237 if (critical != sensorMap.end())
238 {
239 auto lower = critical->second.find("CriticalLow");
240 auto upper = critical->second.find("CriticalHigh");
241 if (lower != critical->second.end())
242 {
243 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300244 if (std::isfinite(value))
245 {
246 min = std::min(value, min);
247 }
Willy Tude54f482021-01-26 15:59:09 -0800248 }
249 if (upper != critical->second.end())
250 {
251 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300252 if (std::isfinite(value))
253 {
254 max = std::max(value, max);
255 }
Willy Tude54f482021-01-26 15:59:09 -0800256 }
257 }
258 if (warning != sensorMap.end())
259 {
260
261 auto lower = warning->second.find("WarningLow");
262 auto upper = warning->second.find("WarningHigh");
263 if (lower != warning->second.end())
264 {
265 double value = std::visit(VariantToDoubleVisitor(), lower->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300266 if (std::isfinite(value))
267 {
268 min = std::min(value, min);
269 }
Willy Tude54f482021-01-26 15:59:09 -0800270 }
271 if (upper != warning->second.end())
272 {
273 double value = std::visit(VariantToDoubleVisitor(), upper->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +0300274 if (std::isfinite(value))
275 {
276 max = std::max(value, max);
277 }
Willy Tude54f482021-01-26 15:59:09 -0800278 }
279 }
280}
281
282static bool getSensorMap(ipmi::Context::ptr ctx, std::string sensorConnection,
Alex Qiu9ab2f942020-07-15 17:56:21 -0700283 std::string sensorPath, DbusInterfaceMap& sensorMap,
284 int updatePeriod = sensorMapUpdatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800285{
Scron Chang2703b022021-07-06 15:47:45 +0800286#ifdef FEATURE_HYBRID_SENSORS
287 if (auto sensor = findStaticSensor(sensorPath);
288 sensor != ipmi::sensor::sensors.end() &&
289 getSensorEventTypeFromPath(sensorPath) !=
290 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
291 {
292 // If the incoming sensor is a discrete sensor, it might fail in
293 // getManagedObjects(), return true, and use its own getFunc to get
294 // value.
295 return true;
296 }
297#endif
298
Willy Tude54f482021-01-26 15:59:09 -0800299 static boost::container::flat_map<
300 std::string, std::chrono::time_point<std::chrono::steady_clock>>
301 updateTimeMap;
302
303 auto updateFind = updateTimeMap.find(sensorConnection);
304 auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
305 if (updateFind != updateTimeMap.end())
306 {
307 lastUpdate = updateFind->second;
308 }
309
310 auto now = std::chrono::steady_clock::now();
311
312 if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
Alex Qiu9ab2f942020-07-15 17:56:21 -0700313 .count() > updatePeriod)
Willy Tude54f482021-01-26 15:59:09 -0800314 {
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800315 bool found = false;
Willy Tude54f482021-01-26 15:59:09 -0800316
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800317 // Object managers for different kinds of OpenBMC DBus interfaces.
318 // Documented in the phosphor-dbus-interfaces repository.
319 const char* paths[] = {
320 "/xyz/openbmc_project/sensors",
321 "/xyz/openbmc_project/vr",
322 };
323 constexpr size_t num_paths = sizeof(paths) / sizeof(paths[0]);
324 ObjectValueTree allManagedObjects;
325
326 for (size_t i = 0; i < num_paths; i++)
327 {
328 ObjectValueTree managedObjects;
329 boost::system::error_code ec = getManagedObjects(
330 ctx, sensorConnection.c_str(), paths[i], managedObjects);
331 if (ec)
332 {
333 phosphor::logging::log<phosphor::logging::level::ERR>(
334 "GetMangagedObjects for getSensorMap failed",
335 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
336
337 continue;
338 }
339 allManagedObjects.merge(managedObjects);
340 found = true;
341 }
342
343 if (!found)
344 {
Willy Tude54f482021-01-26 15:59:09 -0800345 return false;
346 }
347
Sui Chenc2cb1bc2023-01-10 02:52:06 -0800348 SensorCache[sensorConnection] = allManagedObjects;
Alex Qiu9ab2f942020-07-15 17:56:21 -0700349 // Update time after finish building the map which allow the
350 // data to be cached for updatePeriod plus the build time.
351 updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
Willy Tude54f482021-01-26 15:59:09 -0800352 }
353 auto connection = SensorCache.find(sensorConnection);
354 if (connection == SensorCache.end())
355 {
356 return false;
357 }
358 auto path = connection->second.find(sensorPath);
359 if (path == connection->second.end())
360 {
361 return false;
362 }
363 sensorMap = path->second;
364
365 return true;
366}
367
Hao Jiangd2afd052020-12-10 15:09:32 -0800368namespace sensor
369{
Hao Jiangd48c9212021-02-03 15:45:06 -0800370// Read VR profiles from sensor(daemon) interface
371static std::optional<std::vector<std::string>>
372 getSupportedVrProfiles(const ipmi::DbusInterfaceMap::mapped_type& object)
Hao Jiangd2afd052020-12-10 15:09:32 -0800373{
374 // get VR mode profiles from Supported Interface
Hao Jiangd48c9212021-02-03 15:45:06 -0800375 auto supportedProperty = object.find("Supported");
376 if (supportedProperty == object.end() ||
377 object.find("Selected") == object.end())
Hao Jiangd2afd052020-12-10 15:09:32 -0800378 {
379 phosphor::logging::log<phosphor::logging::level::ERR>(
380 "Missing the required Supported and Selected properties");
381 return std::nullopt;
382 }
383
384 const auto profilesPtr =
385 std::get_if<std::vector<std::string>>(&supportedProperty->second);
386
387 if (profilesPtr == nullptr)
388 {
389 phosphor::logging::log<phosphor::logging::level::ERR>(
390 "property is not array of string");
391 return std::nullopt;
392 }
Hao Jiangd48c9212021-02-03 15:45:06 -0800393 return *profilesPtr;
394}
395
396// Calculate VR Mode from input IPMI discrete event bytes
397static std::optional<std::string>
398 calculateVRMode(uint15_t assertOffset,
399 const ipmi::DbusInterfaceMap::mapped_type& VRObject)
400{
401 // get VR mode profiles from Supported Interface
402 auto profiles = getSupportedVrProfiles(VRObject);
403 if (!profiles)
404 {
405 return std::nullopt;
406 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800407
408 // interpret IPMI cmd bits into profiles' index
409 long unsigned int index = 0;
410 // only one bit should be set and the highest bit should not be used.
411 if (assertOffset == 0 || assertOffset == (1u << 15) ||
412 (assertOffset & (assertOffset - 1)))
413 {
414 phosphor::logging::log<phosphor::logging::level::ERR>(
415 "IPMI cmd format incorrect",
416
417 phosphor::logging::entry("BYTES=%#02x",
418 static_cast<uint16_t>(assertOffset)));
419 return std::nullopt;
420 }
421
422 while (assertOffset != 1)
423 {
424 assertOffset >>= 1;
425 index++;
426 }
427
Hao Jiangd48c9212021-02-03 15:45:06 -0800428 if (index >= profiles->size())
Hao Jiangd2afd052020-12-10 15:09:32 -0800429 {
430 phosphor::logging::log<phosphor::logging::level::ERR>(
431 "profile index out of boundary");
432 return std::nullopt;
433 }
434
Hao Jiangd48c9212021-02-03 15:45:06 -0800435 return profiles->at(index);
Hao Jiangd2afd052020-12-10 15:09:32 -0800436}
437
438// Calculate sensor value from IPMI reading byte
439static std::optional<double>
440 calculateValue(uint8_t reading, const ipmi::DbusInterfaceMap& sensorMap,
441 const ipmi::DbusInterfaceMap::mapped_type& valueObject)
442{
443 if (valueObject.find("Value") == valueObject.end())
444 {
445 phosphor::logging::log<phosphor::logging::level::ERR>(
446 "Missing the required Value property");
447 return std::nullopt;
448 }
449
450 double max = 0;
451 double min = 0;
452 getSensorMaxMin(sensorMap, max, min);
453
454 int16_t mValue = 0;
455 int16_t bValue = 0;
456 int8_t rExp = 0;
457 int8_t bExp = 0;
458 bool bSigned = false;
459
460 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
461 {
462 return std::nullopt;
463 }
464
465 double value = bSigned ? ((int8_t)reading) : reading;
466
467 value *= ((double)mValue);
468 value += ((double)bValue) * std::pow(10.0, bExp);
469 value *= std::pow(10.0, rExp);
470
471 return value;
472}
473
Willy Tu38e7a2b2021-03-29 15:09:56 -0700474// Extract file name from sensor path as the sensors SDR ID. Simplify the name
475// if it is too long.
476std::string parseSdrIdFromPath(const std::string& path)
477{
478 std::string name;
479 size_t nameStart = path.rfind("/");
480 if (nameStart != std::string::npos)
481 {
482 name = path.substr(nameStart + 1, std::string::npos - nameStart);
483 }
484
Willy Tu38e7a2b2021-03-29 15:09:56 -0700485 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
486 {
487 // try to not truncate by replacing common words
JeffLind950f412021-10-20 18:49:34 +0800488 for (const auto& suffix : suffixes)
Willy Tu38e7a2b2021-03-29 15:09:56 -0700489 {
JeffLind950f412021-10-20 18:49:34 +0800490 if (boost::ends_with(name, suffix))
491 {
492 boost::replace_all(name, suffix, "");
493 break;
494 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700495 }
Duke Du97014f52021-12-16 17:21:01 +0800496 if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
497 {
498 name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
499 }
Willy Tu38e7a2b2021-03-29 15:09:56 -0700500 }
501 return name;
502}
503
Hao Jiangd48c9212021-02-03 15:45:06 -0800504bool getVrEventStatus(ipmi::Context::ptr ctx, const std::string& connection,
505 const std::string& path,
506 const ipmi::DbusInterfaceMap::mapped_type& object,
507 std::bitset<16>& assertions)
508{
509 auto profiles = sensor::getSupportedVrProfiles(object);
510 if (!profiles)
511 {
512 return false;
513 }
Willy Tu8366f0b2022-04-29 05:00:17 -0700514 std::string mode;
Hao Jiangd48c9212021-02-03 15:45:06 -0800515
516 auto ec = getDbusProperty(ctx, connection, path, sensor::vrInterface,
Willy Tu8366f0b2022-04-29 05:00:17 -0700517 "Selected", mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800518 if (ec)
519 {
520 log<level::ERR>("Failed to get property",
521 entry("PROPERTY=%s", "Selected"),
522 entry("PATH=%s", path.c_str()),
523 entry("INTERFACE=%s", sensor::sensorInterface),
524 entry("WHAT=%s", ec.message().c_str()));
525 return false;
526 }
527
Willy Tu8366f0b2022-04-29 05:00:17 -0700528 auto itr = std::find(profiles->begin(), profiles->end(), mode);
Hao Jiangd48c9212021-02-03 15:45:06 -0800529 if (itr == profiles->end())
530 {
531 using namespace phosphor::logging;
532 log<level::ERR>("VR mode doesn't match any of its profiles",
533 entry("PATH=%s", path.c_str()));
534 return false;
535 }
536 std::size_t index =
537 static_cast<std::size_t>(std::distance(profiles->begin(), itr));
538
Willy Tubef102a2022-06-09 15:36:09 -0700539 // map index to response event assertion bit.
540 if (index < 16)
Hao Jiangd48c9212021-02-03 15:45:06 -0800541 {
Willy Tubef102a2022-06-09 15:36:09 -0700542 assertions.set(index);
Hao Jiangd48c9212021-02-03 15:45:06 -0800543 }
544 else
545 {
546 log<level::ERR>("VR profile index reaches max assertion bit",
547 entry("PATH=%s", path.c_str()),
548 entry("INDEX=%uz", index));
549 return false;
550 }
551 if constexpr (debug)
552 {
553 std::cerr << "VR sensor " << sensor::parseSdrIdFromPath(path)
Willy Tu8366f0b2022-04-29 05:00:17 -0700554 << " mode is: [" << index << "] " << mode << std::endl;
Hao Jiangd48c9212021-02-03 15:45:06 -0800555 }
556 return true;
557}
Hao Jiangd2afd052020-12-10 15:09:32 -0800558} // namespace sensor
559
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000560ipmi::RspType<> ipmiSenPlatformEvent(ipmi::Context::ptr ctx,
561 ipmi::message::Payload& p)
Willy Tude54f482021-01-26 15:59:09 -0800562{
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000563 constexpr const uint8_t validEnvmRev = 0x04;
564 constexpr const uint8_t lastSensorType = 0x2C;
565 constexpr const uint8_t oemReserved = 0xC0;
566
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700567 uint8_t sysgeneratorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000568 uint8_t evmRev = 0;
569 uint8_t sensorType = 0;
570 uint8_t sensorNum = 0;
571 uint8_t eventType = 0;
572 uint8_t eventData1 = 0;
573 std::optional<uint8_t> eventData2 = 0;
574 std::optional<uint8_t> eventData3 = 0;
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700575 [[maybe_unused]] uint16_t generatorID = 0;
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000576 ipmi::ChannelInfo chInfo;
577
578 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess)
579 {
580 phosphor::logging::log<phosphor::logging::level::ERR>(
581 "Failed to get Channel Info",
582 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
583 return ipmi::responseUnspecifiedError();
584 }
585
586 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) ==
587 ipmi::EChannelMediumType::systemInterface)
588 {
589
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700590 p.unpack(sysgeneratorID, evmRev, sensorType, sensorNum, eventType,
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000591 eventData1, eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700592 // Refer to IPMI Spec Table 32: SEL Event Records
593 generatorID = (ctx->channel << 12) // Channel
594 | (0x0 << 10) // Reserved
595 | (0x0 << 8) // 0x0 for sys-soft ID
596 | ((sysgeneratorID << 1) | 0x1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000597 }
598 else
599 {
600
601 p.unpack(evmRev, sensorType, sensorNum, eventType, eventData1,
602 eventData2, eventData3);
Sujoy Ray3ab2c2b2021-11-01 13:17:27 -0700603 // Refer to IPMI Spec Table 32: SEL Event Records
604 generatorID = (ctx->channel << 12) // Channel
605 | (0x0 << 10) // Reserved
606 | ((ctx->lun & 0x3) << 8) // Lun
607 | (ctx->rqSA << 1);
Chalapathi Venkataramashetty6f43f4a2021-06-20 19:50:33 +0000608 }
609
610 if (!p.fullyUnpacked())
611 {
612 return ipmi::responseReqDataLenInvalid();
613 }
614
615 // Check for valid evmRev and Sensor Type(per Table 42 of spec)
616 if (evmRev != validEnvmRev)
617 {
618 return ipmi::responseInvalidFieldRequest();
619 }
620 if ((sensorType > lastSensorType) && (sensorType < oemReserved))
621 {
622 return ipmi::responseInvalidFieldRequest();
623 }
624
Willy Tude54f482021-01-26 15:59:09 -0800625 return ipmi::responseSuccess();
626}
627
Willy Tudbafbce2021-03-29 00:37:05 -0700628ipmi::RspType<> ipmiSetSensorReading(ipmi::Context::ptr ctx,
Willy Tu11d68892022-01-20 10:37:34 -0800629 uint8_t sensorNumber, uint8_t,
Willy Tudbafbce2021-03-29 00:37:05 -0700630 uint8_t reading, uint15_t assertOffset,
Willy Tu11d68892022-01-20 10:37:34 -0800631 bool, uint15_t, bool, uint8_t, uint8_t,
632 uint8_t)
Willy Tudbafbce2021-03-29 00:37:05 -0700633{
634 std::string connection;
635 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -0700636 std::vector<std::string> interfaces;
637
638 ipmi::Cc status =
639 getSensorConnection(ctx, sensorNumber, connection, path, &interfaces);
Willy Tudbafbce2021-03-29 00:37:05 -0700640 if (status)
641 {
642 return ipmi::response(status);
643 }
644
Hao Jiangd2afd052020-12-10 15:09:32 -0800645 // we can tell the sensor type by its interface type
Hao Jiange39d4d82021-04-16 17:02:40 -0700646 if (std::find(interfaces.begin(), interfaces.end(),
647 sensor::sensorInterface) != interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700648 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700649 DbusInterfaceMap sensorMap;
650 if (!getSensorMap(ctx, connection, path, sensorMap))
651 {
652 return ipmi::responseResponseError();
653 }
654 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800655 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700656 {
657 return ipmi::responseResponseError();
658 }
659
Jie Yangf0a89942021-07-29 15:30:25 -0700660 // Only allow external SetSensor if write permission granted
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800661 if (!details::sdrWriteTable.getWritePermission((ctx->lun << 8) |
662 sensorNumber))
Jie Yangf0a89942021-07-29 15:30:25 -0700663 {
664 return ipmi::responseResponseError();
665 }
666
Hao Jiangd2afd052020-12-10 15:09:32 -0800667 auto value =
668 sensor::calculateValue(reading, sensorMap, sensorObject->second);
669 if (!value)
670 {
671 return ipmi::responseResponseError();
672 }
673
674 if constexpr (debug)
675 {
676 phosphor::logging::log<phosphor::logging::level::INFO>(
677 "IPMI SET_SENSOR",
678 phosphor::logging::entry("SENSOR_NUM=%d", sensorNumber),
679 phosphor::logging::entry("BYTE=%u", (unsigned int)reading),
680 phosphor::logging::entry("VALUE=%f", *value));
681 }
682
683 boost::system::error_code ec =
684 setDbusProperty(ctx, connection, path, sensor::sensorInterface,
685 "Value", ipmi::Value(*value));
686
687 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500688 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800689 // callback functions for now (e.g. ipmiSetSensorReading).
690 if (ec)
691 {
692 using namespace phosphor::logging;
693 log<level::ERR>("Failed to set property",
694 entry("PROPERTY=%s", "Value"),
695 entry("PATH=%s", path.c_str()),
696 entry("INTERFACE=%s", sensor::sensorInterface),
697 entry("WHAT=%s", ec.message().c_str()));
698 return ipmi::responseResponseError();
699 }
700 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700701 }
702
Hao Jiange39d4d82021-04-16 17:02:40 -0700703 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
704 interfaces.end())
Willy Tudbafbce2021-03-29 00:37:05 -0700705 {
Hao Jiange39d4d82021-04-16 17:02:40 -0700706 DbusInterfaceMap sensorMap;
707 if (!getSensorMap(ctx, connection, path, sensorMap))
708 {
709 return ipmi::responseResponseError();
710 }
711 auto sensorObject = sensorMap.find(sensor::vrInterface);
Harvey Wuf61c0862021-09-15 08:48:40 +0800712 if (sensorObject == sensorMap.end())
Hao Jiange39d4d82021-04-16 17:02:40 -0700713 {
714 return ipmi::responseResponseError();
715 }
716
Hao Jiangd2afd052020-12-10 15:09:32 -0800717 // VR sensors are treated as a special case and we will not check the
718 // write permission for VR sensors, since they always deemed writable
719 // and permission table are not applied to VR sensors.
720 auto vrMode =
721 sensor::calculateVRMode(assertOffset, sensorObject->second);
722 if (!vrMode)
723 {
724 return ipmi::responseResponseError();
725 }
726 boost::system::error_code ec = setDbusProperty(
727 ctx, connection, path, sensor::vrInterface, "Selected", *vrMode);
728 // setDbusProperty intended to resolve dbus exception/rc within the
Patrick Williamsef1259b2021-09-02 09:12:33 -0500729 // function but failed to achieve that. Catch exception in the ipmi
Hao Jiangd2afd052020-12-10 15:09:32 -0800730 // callback functions for now (e.g. ipmiSetSensorReading).
731 if (ec)
732 {
733 using namespace phosphor::logging;
734 log<level::ERR>("Failed to set property",
735 entry("PROPERTY=%s", "Selected"),
736 entry("PATH=%s", path.c_str()),
737 entry("INTERFACE=%s", sensor::sensorInterface),
738 entry("WHAT=%s", ec.message().c_str()));
739 return ipmi::responseResponseError();
740 }
741 return ipmi::responseSuccess();
Willy Tudbafbce2021-03-29 00:37:05 -0700742 }
743
Hao Jiangd2afd052020-12-10 15:09:32 -0800744 phosphor::logging::log<phosphor::logging::level::ERR>(
745 "unknown sensor type",
746 phosphor::logging::entry("PATH=%s", path.c_str()));
747 return ipmi::responseResponseError();
Willy Tudbafbce2021-03-29 00:37:05 -0700748}
749
Willy Tude54f482021-01-26 15:59:09 -0800750ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
751 ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
752{
753 std::string connection;
754 std::string path;
755
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000756 if (sensnum == reservedSensorNumber)
757 {
758 return ipmi::responseInvalidFieldRequest();
759 }
760
Willy Tude54f482021-01-26 15:59:09 -0800761 auto status = getSensorConnection(ctx, sensnum, connection, path);
762 if (status)
763 {
764 return ipmi::response(status);
765 }
766
Scron Chang2703b022021-07-06 15:47:45 +0800767#ifdef FEATURE_HYBRID_SENSORS
768 if (auto sensor = findStaticSensor(path);
769 sensor != ipmi::sensor::sensors.end() &&
770 getSensorEventTypeFromPath(path) !=
771 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
772 {
773 if (ipmi::sensor::Mutability::Read !=
774 (sensor->second.mutability & ipmi::sensor::Mutability::Read))
775 {
776 return ipmi::responseIllegalCommand();
777 }
778
779 uint8_t operation;
780 try
781 {
782 ipmi::sensor::GetSensorResponse getResponse =
783 sensor->second.getFunc(sensor->second);
784
785 if (getResponse.readingOrStateUnavailable)
786 {
787 operation |= static_cast<uint8_t>(
788 IPMISensorReadingByte2::readingStateUnavailable);
789 }
790 if (getResponse.scanningEnabled)
791 {
792 operation |= static_cast<uint8_t>(
793 IPMISensorReadingByte2::sensorScanningEnable);
794 }
795 if (getResponse.allEventMessagesEnabled)
796 {
797 operation |= static_cast<uint8_t>(
798 IPMISensorReadingByte2::eventMessagesEnable);
799 }
800 return ipmi::responseSuccess(
801 getResponse.reading, operation,
802 getResponse.thresholdLevelsStates,
803 getResponse.discreteReadingSensorStates);
804 }
805 catch (const std::exception& e)
806 {
807 operation |= static_cast<uint8_t>(
808 IPMISensorReadingByte2::readingStateUnavailable);
809 return ipmi::responseSuccess(0, operation, 0, std::nullopt);
810 }
811 }
812#endif
813
Willy Tude54f482021-01-26 15:59:09 -0800814 DbusInterfaceMap sensorMap;
815 if (!getSensorMap(ctx, connection, path, sensorMap))
816 {
817 return ipmi::responseResponseError();
818 }
Hao Jiangd2afd052020-12-10 15:09:32 -0800819 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -0800820
821 if (sensorObject == sensorMap.end() ||
822 sensorObject->second.find("Value") == sensorObject->second.end())
823 {
824 return ipmi::responseResponseError();
825 }
826 auto& valueVariant = sensorObject->second["Value"];
827 double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
828
829 double max = 0;
830 double min = 0;
831 getSensorMaxMin(sensorMap, max, min);
832
833 int16_t mValue = 0;
834 int16_t bValue = 0;
835 int8_t rExp = 0;
836 int8_t bExp = 0;
837 bool bSigned = false;
838
839 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
840 {
841 return ipmi::responseResponseError();
842 }
843
844 uint8_t value =
845 scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
846 uint8_t operation =
847 static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
848 operation |=
849 static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
850 bool notReading = std::isnan(reading);
851
852 if (!notReading)
853 {
854 auto availableObject =
855 sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
856 if (availableObject != sensorMap.end())
857 {
858 auto findAvailable = availableObject->second.find("Available");
859 if (findAvailable != availableObject->second.end())
860 {
861 bool* available = std::get_if<bool>(&(findAvailable->second));
862 if (available && !(*available))
863 {
864 notReading = true;
865 }
866 }
867 }
868 }
869
870 if (notReading)
871 {
872 operation |= static_cast<uint8_t>(
873 IPMISensorReadingByte2::readingStateUnavailable);
874 }
875
Josh Lehana55c9532020-10-28 21:59:06 -0700876 if constexpr (details::enableInstrumentation)
877 {
878 int byteValue;
879 if (bSigned)
880 {
881 byteValue = static_cast<int>(static_cast<int8_t>(value));
882 }
883 else
884 {
885 byteValue = static_cast<int>(static_cast<uint8_t>(value));
886 }
887
888 // Keep stats on the reading just obtained, even if it is "NaN"
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800889 if (details::sdrStatsTable.updateReading((ctx->lun << 8) | sensnum,
890 reading, byteValue))
Josh Lehana55c9532020-10-28 21:59:06 -0700891 {
892 // This is the first reading, show the coefficients
893 double step = (max - min) / 255.0;
894 std::cerr << "IPMI sensor "
Harvey.Wu0e7a8af2022-06-10 16:46:46 +0800895 << details::sdrStatsTable.getName((ctx->lun << 8) |
896 sensnum)
Josh Lehana55c9532020-10-28 21:59:06 -0700897 << ": Range min=" << min << " max=" << max
898 << ", step=" << step
899 << ", Coefficients mValue=" << static_cast<int>(mValue)
900 << " rExp=" << static_cast<int>(rExp)
901 << " bValue=" << static_cast<int>(bValue)
902 << " bExp=" << static_cast<int>(bExp)
903 << " bSigned=" << static_cast<int>(bSigned) << "\n";
904 }
905 }
906
Willy Tude54f482021-01-26 15:59:09 -0800907 uint8_t thresholds = 0;
908
909 auto warningObject =
910 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
911 if (warningObject != sensorMap.end())
912 {
913 auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
914 auto alarmLow = warningObject->second.find("WarningAlarmLow");
915 if (alarmHigh != warningObject->second.end())
916 {
917 if (std::get<bool>(alarmHigh->second))
918 {
919 thresholds |= static_cast<uint8_t>(
920 IPMISensorReadingByte3::upperNonCritical);
921 }
922 }
923 if (alarmLow != warningObject->second.end())
924 {
925 if (std::get<bool>(alarmLow->second))
926 {
927 thresholds |= static_cast<uint8_t>(
928 IPMISensorReadingByte3::lowerNonCritical);
929 }
930 }
931 }
932
933 auto criticalObject =
934 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
935 if (criticalObject != sensorMap.end())
936 {
937 auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
938 auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
939 if (alarmHigh != criticalObject->second.end())
940 {
941 if (std::get<bool>(alarmHigh->second))
942 {
943 thresholds |=
944 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
945 }
946 }
947 if (alarmLow != criticalObject->second.end())
948 {
949 if (std::get<bool>(alarmLow->second))
950 {
951 thresholds |=
952 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
953 }
954 }
955 }
956
957 // no discrete as of today so optional byte is never returned
958 return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
959}
960
961/** @brief implements the Set Sensor threshold command
962 * @param sensorNumber - sensor number
963 * @param lowerNonCriticalThreshMask
964 * @param lowerCriticalThreshMask
965 * @param lowerNonRecovThreshMask
966 * @param upperNonCriticalThreshMask
967 * @param upperCriticalThreshMask
968 * @param upperNonRecovThreshMask
969 * @param reserved
970 * @param lowerNonCritical - lower non-critical threshold
971 * @param lowerCritical - Lower critical threshold
972 * @param lowerNonRecoverable - Lower non recovarable threshold
973 * @param upperNonCritical - Upper non-critical threshold
974 * @param upperCritical - Upper critical
975 * @param upperNonRecoverable - Upper Non-recoverable
976 *
977 * @returns IPMI completion code
978 */
979ipmi::RspType<> ipmiSenSetSensorThresholds(
980 ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
981 bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
982 bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
983 bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800984 uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
Willy Tude54f482021-01-26 15:59:09 -0800985 uint8_t upperNonCritical, uint8_t upperCritical,
Willy Tu11d68892022-01-20 10:37:34 -0800986 [[maybe_unused]] uint8_t upperNonRecoverable)
Willy Tude54f482021-01-26 15:59:09 -0800987{
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +0000988 if (sensorNum == reservedSensorNumber || reserved)
Willy Tude54f482021-01-26 15:59:09 -0800989 {
990 return ipmi::responseInvalidFieldRequest();
991 }
992
993 // lower nc and upper nc not suppported on any sensor
994 if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
995 {
996 return ipmi::responseInvalidFieldRequest();
997 }
998
999 // if none of the threshold mask are set, nothing to do
1000 if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
1001 lowerNonRecovThreshMask | upperNonCriticalThreshMask |
1002 upperCriticalThreshMask | upperNonRecovThreshMask))
1003 {
1004 return ipmi::responseSuccess();
1005 }
1006
1007 std::string connection;
1008 std::string path;
1009
1010 ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
1011 if (status)
1012 {
1013 return ipmi::response(status);
1014 }
1015 DbusInterfaceMap sensorMap;
1016 if (!getSensorMap(ctx, connection, path, sensorMap))
1017 {
1018 return ipmi::responseResponseError();
1019 }
1020
1021 double max = 0;
1022 double min = 0;
1023 getSensorMaxMin(sensorMap, max, min);
1024
1025 int16_t mValue = 0;
1026 int16_t bValue = 0;
1027 int8_t rExp = 0;
1028 int8_t bExp = 0;
1029 bool bSigned = false;
1030
1031 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1032 {
1033 return ipmi::responseResponseError();
1034 }
1035
1036 // store a vector of property name, value to set, and interface
1037 std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
1038
1039 // define the indexes of the tuple
1040 constexpr uint8_t propertyName = 0;
1041 constexpr uint8_t thresholdValue = 1;
1042 constexpr uint8_t interface = 2;
1043 // verifiy all needed fields are present
1044 if (lowerCriticalThreshMask || upperCriticalThreshMask)
1045 {
1046 auto findThreshold =
1047 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1048 if (findThreshold == sensorMap.end())
1049 {
1050 return ipmi::responseInvalidFieldRequest();
1051 }
1052 if (lowerCriticalThreshMask)
1053 {
1054 auto findLower = findThreshold->second.find("CriticalLow");
1055 if (findLower == findThreshold->second.end())
1056 {
1057 return ipmi::responseInvalidFieldRequest();
1058 }
1059 thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
1060 findThreshold->first);
1061 }
1062 if (upperCriticalThreshMask)
1063 {
1064 auto findUpper = findThreshold->second.find("CriticalHigh");
1065 if (findUpper == findThreshold->second.end())
1066 {
1067 return ipmi::responseInvalidFieldRequest();
1068 }
1069 thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
1070 findThreshold->first);
1071 }
1072 }
1073 if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
1074 {
1075 auto findThreshold =
1076 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1077 if (findThreshold == sensorMap.end())
1078 {
1079 return ipmi::responseInvalidFieldRequest();
1080 }
1081 if (lowerNonCriticalThreshMask)
1082 {
1083 auto findLower = findThreshold->second.find("WarningLow");
1084 if (findLower == findThreshold->second.end())
1085 {
1086 return ipmi::responseInvalidFieldRequest();
1087 }
1088 thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
1089 findThreshold->first);
1090 }
1091 if (upperNonCriticalThreshMask)
1092 {
1093 auto findUpper = findThreshold->second.find("WarningHigh");
1094 if (findUpper == findThreshold->second.end())
1095 {
1096 return ipmi::responseInvalidFieldRequest();
1097 }
1098 thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
1099 findThreshold->first);
1100 }
1101 }
1102 for (const auto& property : thresholdsToSet)
1103 {
1104 // from section 36.3 in the IPMI Spec, assume all linear
1105 double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
1106 (bValue * std::pow(10.0, bExp))) *
1107 std::pow(10.0, rExp);
1108 setDbusProperty(
1109 *getSdBus(), connection, path, std::get<interface>(property),
1110 std::get<propertyName>(property), ipmi::Value(valueToSet));
1111 }
1112 return ipmi::responseSuccess();
1113}
1114
1115IPMIThresholds getIPMIThresholds(const DbusInterfaceMap& sensorMap)
1116{
1117 IPMIThresholds resp;
1118 auto warningInterface =
1119 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1120 auto criticalInterface =
1121 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1122
1123 if ((warningInterface != sensorMap.end()) ||
1124 (criticalInterface != sensorMap.end()))
1125 {
Hao Jiangd2afd052020-12-10 15:09:32 -08001126 auto sensorPair = sensorMap.find(sensor::sensorInterface);
Willy Tude54f482021-01-26 15:59:09 -08001127
1128 if (sensorPair == sensorMap.end())
1129 {
1130 // should not have been able to find a sensor not implementing
1131 // the sensor object
1132 throw std::runtime_error("Invalid sensor map");
1133 }
1134
1135 double max = 0;
1136 double min = 0;
1137 getSensorMaxMin(sensorMap, max, min);
1138
1139 int16_t mValue = 0;
1140 int16_t bValue = 0;
1141 int8_t rExp = 0;
1142 int8_t bExp = 0;
1143 bool bSigned = false;
1144
1145 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1146 {
1147 throw std::runtime_error("Invalid sensor atrributes");
1148 }
1149 if (warningInterface != sensorMap.end())
1150 {
1151 auto& warningMap = warningInterface->second;
1152
1153 auto warningHigh = warningMap.find("WarningHigh");
1154 auto warningLow = warningMap.find("WarningLow");
1155
1156 if (warningHigh != warningMap.end())
1157 {
1158
1159 double value =
1160 std::visit(VariantToDoubleVisitor(), warningHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001161 if (std::isfinite(value))
1162 {
1163 resp.warningHigh = scaleIPMIValueFromDouble(
1164 value, mValue, rExp, bValue, bExp, bSigned);
1165 }
Willy Tude54f482021-01-26 15:59:09 -08001166 }
1167 if (warningLow != warningMap.end())
1168 {
1169 double value =
1170 std::visit(VariantToDoubleVisitor(), warningLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001171 if (std::isfinite(value))
1172 {
1173 resp.warningLow = scaleIPMIValueFromDouble(
1174 value, mValue, rExp, bValue, bExp, bSigned);
1175 }
Willy Tude54f482021-01-26 15:59:09 -08001176 }
1177 }
1178 if (criticalInterface != sensorMap.end())
1179 {
1180 auto& criticalMap = criticalInterface->second;
1181
1182 auto criticalHigh = criticalMap.find("CriticalHigh");
1183 auto criticalLow = criticalMap.find("CriticalLow");
1184
1185 if (criticalHigh != criticalMap.end())
1186 {
1187 double value =
1188 std::visit(VariantToDoubleVisitor(), criticalHigh->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001189 if (std::isfinite(value))
1190 {
1191 resp.criticalHigh = scaleIPMIValueFromDouble(
1192 value, mValue, rExp, bValue, bExp, bSigned);
1193 }
Willy Tude54f482021-01-26 15:59:09 -08001194 }
1195 if (criticalLow != criticalMap.end())
1196 {
1197 double value =
1198 std::visit(VariantToDoubleVisitor(), criticalLow->second);
Konstantin Aladyshev8265af22021-12-16 18:18:10 +03001199 if (std::isfinite(value))
1200 {
1201 resp.criticalLow = scaleIPMIValueFromDouble(
1202 value, mValue, rExp, bValue, bExp, bSigned);
1203 }
Willy Tude54f482021-01-26 15:59:09 -08001204 }
1205 }
1206 }
1207 return resp;
1208}
1209
1210ipmi::RspType<uint8_t, // readable
1211 uint8_t, // lowerNCrit
1212 uint8_t, // lowerCrit
1213 uint8_t, // lowerNrecoverable
1214 uint8_t, // upperNC
1215 uint8_t, // upperCrit
1216 uint8_t> // upperNRecoverable
1217 ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
1218{
1219 std::string connection;
1220 std::string path;
1221
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001222 if (sensorNumber == reservedSensorNumber)
1223 {
1224 return ipmi::responseInvalidFieldRequest();
1225 }
1226
Willy Tude54f482021-01-26 15:59:09 -08001227 auto status = getSensorConnection(ctx, sensorNumber, connection, path);
1228 if (status)
1229 {
1230 return ipmi::response(status);
1231 }
1232
1233 DbusInterfaceMap sensorMap;
1234 if (!getSensorMap(ctx, connection, path, sensorMap))
1235 {
1236 return ipmi::responseResponseError();
1237 }
1238
1239 IPMIThresholds thresholdData;
1240 try
1241 {
1242 thresholdData = getIPMIThresholds(sensorMap);
1243 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001244 catch (const std::exception&)
Willy Tude54f482021-01-26 15:59:09 -08001245 {
1246 return ipmi::responseResponseError();
1247 }
1248
1249 uint8_t readable = 0;
1250 uint8_t lowerNC = 0;
1251 uint8_t lowerCritical = 0;
1252 uint8_t lowerNonRecoverable = 0;
1253 uint8_t upperNC = 0;
1254 uint8_t upperCritical = 0;
1255 uint8_t upperNonRecoverable = 0;
1256
1257 if (thresholdData.warningHigh)
1258 {
1259 readable |=
1260 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
1261 upperNC = *thresholdData.warningHigh;
1262 }
1263 if (thresholdData.warningLow)
1264 {
1265 readable |=
1266 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
1267 lowerNC = *thresholdData.warningLow;
1268 }
1269
1270 if (thresholdData.criticalHigh)
1271 {
1272 readable |=
1273 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
1274 upperCritical = *thresholdData.criticalHigh;
1275 }
1276 if (thresholdData.criticalLow)
1277 {
1278 readable |=
1279 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
1280 lowerCritical = *thresholdData.criticalLow;
1281 }
1282
1283 return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
1284 lowerNonRecoverable, upperNC, upperCritical,
1285 upperNonRecoverable);
1286}
1287
1288/** @brief implements the get Sensor event enable command
1289 * @param sensorNumber - sensor number
1290 *
1291 * @returns IPMI completion code plus response data
1292 * - enabled - Sensor Event messages
1293 * - assertionEnabledLsb - Assertion event messages
1294 * - assertionEnabledMsb - Assertion event messages
1295 * - deassertionEnabledLsb - Deassertion event messages
1296 * - deassertionEnabledMsb - Deassertion event messages
1297 */
1298
1299ipmi::RspType<uint8_t, // enabled
1300 uint8_t, // assertionEnabledLsb
1301 uint8_t, // assertionEnabledMsb
1302 uint8_t, // deassertionEnabledLsb
1303 uint8_t> // deassertionEnabledMsb
1304 ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
1305{
1306 std::string connection;
1307 std::string path;
1308
1309 uint8_t enabled = 0;
1310 uint8_t assertionEnabledLsb = 0;
1311 uint8_t assertionEnabledMsb = 0;
1312 uint8_t deassertionEnabledLsb = 0;
1313 uint8_t deassertionEnabledMsb = 0;
1314
Chalapathi Venkataramashetty8c2f3c42021-06-13 19:51:17 +00001315 if (sensorNum == reservedSensorNumber)
1316 {
1317 return ipmi::responseInvalidFieldRequest();
1318 }
1319
Willy Tude54f482021-01-26 15:59:09 -08001320 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1321 if (status)
1322 {
1323 return ipmi::response(status);
1324 }
1325
Scron Chang2703b022021-07-06 15:47:45 +08001326#ifdef FEATURE_HYBRID_SENSORS
1327 if (auto sensor = findStaticSensor(path);
1328 sensor != ipmi::sensor::sensors.end() &&
1329 getSensorEventTypeFromPath(path) !=
1330 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1331 {
1332 enabled = static_cast<uint8_t>(
1333 IPMISensorEventEnableByte2::sensorScanningEnable);
1334 uint16_t assertionEnabled = 0;
1335 for (auto& offsetValMap : sensor->second.propertyInterfaces.begin()
1336 ->second.begin()
1337 ->second.second)
1338 {
1339 assertionEnabled |= (1 << offsetValMap.first);
1340 }
1341 assertionEnabledLsb = static_cast<uint8_t>((assertionEnabled & 0xFF));
1342 assertionEnabledMsb =
1343 static_cast<uint8_t>(((assertionEnabled >> 8) & 0xFF));
1344
1345 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1346 assertionEnabledMsb, deassertionEnabledLsb,
1347 deassertionEnabledMsb);
1348 }
1349#endif
1350
Willy Tude54f482021-01-26 15:59:09 -08001351 DbusInterfaceMap sensorMap;
1352 if (!getSensorMap(ctx, connection, path, sensorMap))
1353 {
1354 return ipmi::responseResponseError();
1355 }
1356
1357 auto warningInterface =
1358 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1359 auto criticalInterface =
1360 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1361 if ((warningInterface != sensorMap.end()) ||
1362 (criticalInterface != sensorMap.end()))
1363 {
1364 enabled = static_cast<uint8_t>(
1365 IPMISensorEventEnableByte2::sensorScanningEnable);
1366 if (warningInterface != sensorMap.end())
1367 {
1368 auto& warningMap = warningInterface->second;
1369
1370 auto warningHigh = warningMap.find("WarningHigh");
1371 auto warningLow = warningMap.find("WarningLow");
1372 if (warningHigh != warningMap.end())
1373 {
1374 assertionEnabledLsb |= static_cast<uint8_t>(
1375 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1376 deassertionEnabledLsb |= static_cast<uint8_t>(
1377 IPMISensorEventEnableThresholds::upperNonCriticalGoingLow);
1378 }
1379 if (warningLow != warningMap.end())
1380 {
1381 assertionEnabledLsb |= static_cast<uint8_t>(
1382 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1383 deassertionEnabledLsb |= static_cast<uint8_t>(
1384 IPMISensorEventEnableThresholds::lowerNonCriticalGoingHigh);
1385 }
1386 }
1387 if (criticalInterface != sensorMap.end())
1388 {
1389 auto& criticalMap = criticalInterface->second;
1390
1391 auto criticalHigh = criticalMap.find("CriticalHigh");
1392 auto criticalLow = criticalMap.find("CriticalLow");
1393
1394 if (criticalHigh != criticalMap.end())
1395 {
1396 assertionEnabledMsb |= static_cast<uint8_t>(
1397 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1398 deassertionEnabledMsb |= static_cast<uint8_t>(
1399 IPMISensorEventEnableThresholds::upperCriticalGoingLow);
1400 }
1401 if (criticalLow != criticalMap.end())
1402 {
1403 assertionEnabledLsb |= static_cast<uint8_t>(
1404 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1405 deassertionEnabledLsb |= static_cast<uint8_t>(
1406 IPMISensorEventEnableThresholds::lowerCriticalGoingHigh);
1407 }
1408 }
1409 }
1410
1411 return ipmi::responseSuccess(enabled, assertionEnabledLsb,
1412 assertionEnabledMsb, deassertionEnabledLsb,
1413 deassertionEnabledMsb);
1414}
1415
1416/** @brief implements the get Sensor event status command
1417 * @param sensorNumber - sensor number, FFh = reserved
1418 *
1419 * @returns IPMI completion code plus response data
1420 * - sensorEventStatus - Sensor Event messages state
1421 * - assertions - Assertion event messages
1422 * - deassertions - Deassertion event messages
1423 */
1424ipmi::RspType<uint8_t, // sensorEventStatus
1425 std::bitset<16>, // assertions
1426 std::bitset<16> // deassertion
1427 >
1428 ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
1429{
1430 if (sensorNum == reservedSensorNumber)
1431 {
1432 return ipmi::responseInvalidFieldRequest();
1433 }
1434
1435 std::string connection;
1436 std::string path;
1437 auto status = getSensorConnection(ctx, sensorNum, connection, path);
1438 if (status)
1439 {
1440 phosphor::logging::log<phosphor::logging::level::ERR>(
1441 "ipmiSenGetSensorEventStatus: Sensor connection Error",
1442 phosphor::logging::entry("SENSOR=%d", sensorNum));
1443 return ipmi::response(status);
1444 }
1445
Scron Chang2703b022021-07-06 15:47:45 +08001446#ifdef FEATURE_HYBRID_SENSORS
1447 if (auto sensor = findStaticSensor(path);
1448 sensor != ipmi::sensor::sensors.end() &&
1449 getSensorEventTypeFromPath(path) !=
1450 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
1451 {
1452 auto response = ipmi::sensor::get::mapDbusToAssertion(
1453 sensor->second, path, sensor->second.sensorInterface);
1454 std::bitset<16> assertions;
1455 // deassertions are not used.
1456 std::bitset<16> deassertions = 0;
1457 uint8_t sensorEventStatus;
1458 if (response.readingOrStateUnavailable)
1459 {
1460 sensorEventStatus |= static_cast<uint8_t>(
1461 IPMISensorReadingByte2::readingStateUnavailable);
1462 }
1463 if (response.scanningEnabled)
1464 {
1465 sensorEventStatus |= static_cast<uint8_t>(
1466 IPMISensorReadingByte2::sensorScanningEnable);
1467 }
1468 if (response.allEventMessagesEnabled)
1469 {
1470 sensorEventStatus |= static_cast<uint8_t>(
1471 IPMISensorReadingByte2::eventMessagesEnable);
1472 }
1473 assertions |= response.discreteReadingSensorStates << 8;
1474 assertions |= response.thresholdLevelsStates;
1475 return ipmi::responseSuccess(sensorEventStatus, assertions,
1476 deassertions);
1477 }
1478#endif
1479
Willy Tude54f482021-01-26 15:59:09 -08001480 DbusInterfaceMap sensorMap;
1481 if (!getSensorMap(ctx, connection, path, sensorMap))
1482 {
1483 phosphor::logging::log<phosphor::logging::level::ERR>(
1484 "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
1485 phosphor::logging::entry("SENSOR=%s", path.c_str()));
1486 return ipmi::responseResponseError();
1487 }
Hao Jiangd48c9212021-02-03 15:45:06 -08001488
1489 uint8_t sensorEventStatus =
1490 static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
1491 std::bitset<16> assertions = 0;
1492 std::bitset<16> deassertions = 0;
1493
1494 // handle VR typed sensor
1495 auto vrInterface = sensorMap.find(sensor::vrInterface);
1496 if (vrInterface != sensorMap.end())
1497 {
1498 if (!sensor::getVrEventStatus(ctx, connection, path,
1499 vrInterface->second, assertions))
1500 {
1501 return ipmi::responseResponseError();
1502 }
1503
1504 // both Event Message and Sensor Scanning are disable for VR.
1505 sensorEventStatus = 0;
1506 return ipmi::responseSuccess(sensorEventStatus, assertions,
1507 deassertions);
1508 }
1509
Willy Tude54f482021-01-26 15:59:09 -08001510 auto warningInterface =
1511 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
1512 auto criticalInterface =
1513 sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
1514
Willy Tude54f482021-01-26 15:59:09 -08001515 std::optional<bool> criticalDeassertHigh =
1516 thresholdDeassertMap[path]["CriticalAlarmHigh"];
1517 std::optional<bool> criticalDeassertLow =
1518 thresholdDeassertMap[path]["CriticalAlarmLow"];
1519 std::optional<bool> warningDeassertHigh =
1520 thresholdDeassertMap[path]["WarningAlarmHigh"];
1521 std::optional<bool> warningDeassertLow =
1522 thresholdDeassertMap[path]["WarningAlarmLow"];
1523
Willy Tude54f482021-01-26 15:59:09 -08001524 if (criticalDeassertHigh && !*criticalDeassertHigh)
1525 {
1526 deassertions.set(static_cast<size_t>(
1527 IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
1528 }
1529 if (criticalDeassertLow && !*criticalDeassertLow)
1530 {
1531 deassertions.set(static_cast<size_t>(
1532 IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
1533 }
1534 if (warningDeassertHigh && !*warningDeassertHigh)
1535 {
1536 deassertions.set(static_cast<size_t>(
1537 IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
1538 }
1539 if (warningDeassertLow && !*warningDeassertLow)
1540 {
1541 deassertions.set(static_cast<size_t>(
1542 IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
1543 }
1544 if ((warningInterface != sensorMap.end()) ||
1545 (criticalInterface != sensorMap.end()))
1546 {
1547 sensorEventStatus = static_cast<size_t>(
1548 IPMISensorEventEnableByte2::eventMessagesEnable);
1549 if (warningInterface != sensorMap.end())
1550 {
1551 auto& warningMap = warningInterface->second;
1552
1553 auto warningHigh = warningMap.find("WarningAlarmHigh");
1554 auto warningLow = warningMap.find("WarningAlarmLow");
1555 auto warningHighAlarm = false;
1556 auto warningLowAlarm = false;
1557
1558 if (warningHigh != warningMap.end())
1559 {
1560 warningHighAlarm = std::get<bool>(warningHigh->second);
1561 }
1562 if (warningLow != warningMap.end())
1563 {
1564 warningLowAlarm = std::get<bool>(warningLow->second);
1565 }
1566 if (warningHighAlarm)
1567 {
1568 assertions.set(
1569 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1570 upperNonCriticalGoingHigh));
1571 }
1572 if (warningLowAlarm)
1573 {
1574 assertions.set(
1575 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1576 lowerNonCriticalGoingLow));
1577 }
1578 }
1579 if (criticalInterface != sensorMap.end())
1580 {
1581 auto& criticalMap = criticalInterface->second;
1582
1583 auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
1584 auto criticalLow = criticalMap.find("CriticalAlarmLow");
1585 auto criticalHighAlarm = false;
1586 auto criticalLowAlarm = false;
1587
1588 if (criticalHigh != criticalMap.end())
1589 {
1590 criticalHighAlarm = std::get<bool>(criticalHigh->second);
1591 }
1592 if (criticalLow != criticalMap.end())
1593 {
1594 criticalLowAlarm = std::get<bool>(criticalLow->second);
1595 }
1596 if (criticalHighAlarm)
1597 {
1598 assertions.set(
1599 static_cast<size_t>(IPMIGetSensorEventEnableThresholds::
1600 upperCriticalGoingHigh));
1601 }
1602 if (criticalLowAlarm)
1603 {
1604 assertions.set(static_cast<size_t>(
1605 IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
1606 }
1607 }
1608 }
1609
1610 return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
1611}
1612
Willy Tu38e7a2b2021-03-29 15:09:56 -07001613// Construct a type 1 SDR for threshold sensor.
Hao Jiange39d4d82021-04-16 17:02:40 -07001614void constructSensorSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1615 get_sdr::SensorDataFullRecord& record)
Willy Tude54f482021-01-26 15:59:09 -08001616{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001617 get_sdr::header::set_record_id(
1618 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1619
Willy Tu38e7a2b2021-03-29 15:09:56 -07001620 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1621 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1622
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001623 record.header.sdr_version = ipmiSdrVersion;
1624 record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
1625 record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
1626 sizeof(get_sdr::SensorDataRecordHeader);
Willy Tu38e7a2b2021-03-29 15:09:56 -07001627 record.key.owner_id = bmcI2CAddr;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001628 record.key.owner_lun = lun;
1629 record.key.sensor_number = sensornumber;
Hao Jiange39d4d82021-04-16 17:02:40 -07001630}
Willy Tu4eca2512022-06-20 21:14:51 -07001631bool constructSensorSdr(
1632 ipmi::Context::ptr ctx,
1633 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1634 uint16_t sensorNum, uint16_t recordID, const std::string& service,
1635 const std::string& path, get_sdr::SensorDataFullRecord& record)
Hao Jiange39d4d82021-04-16 17:02:40 -07001636{
Hao Jiange39d4d82021-04-16 17:02:40 -07001637 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1638
1639 DbusInterfaceMap sensorMap;
1640 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1641 {
1642 phosphor::logging::log<phosphor::logging::level::ERR>(
1643 "Failed to update sensor map for threshold sensor",
1644 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1645 phosphor::logging::entry("PATH=%s", path.c_str()));
1646 return false;
1647 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001648
1649 record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
1650 record.body.sensor_type = getSensorTypeFromPath(path);
1651 std::string type = getSensorTypeStringFromPath(path);
1652 auto typeCstr = type.c_str();
1653 auto findUnits = sensorUnits.find(typeCstr);
1654 if (findUnits != sensorUnits.end())
1655 {
1656 record.body.sensor_units_2_base =
1657 static_cast<uint8_t>(findUnits->second);
1658 } // else default 0x0 unspecified
1659
1660 record.body.event_reading_type = getSensorEventTypeFromPath(path);
1661
Hao Jiangd2afd052020-12-10 15:09:32 -08001662 auto sensorObject = sensorMap.find(sensor::sensorInterface);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001663 if (sensorObject == sensorMap.end())
1664 {
1665 phosphor::logging::log<phosphor::logging::level::ERR>(
1666 "getSensorDataRecord: sensorObject error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001667 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001668 }
1669
1670 uint8_t entityId = 0;
1671 uint8_t entityInstance = 0x01;
1672
1673 // follow the association chain to get the parent board's entityid and
1674 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001675 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap, entityId,
1676 entityInstance);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001677
1678 record.body.entity_id = entityId;
1679 record.body.entity_instance = entityInstance;
1680
Shakeeb Pasha93889722021-10-14 10:20:13 +05301681 double max = 0;
1682 double min = 0;
1683 getSensorMaxMin(sensorMap, max, min);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001684
1685 int16_t mValue = 0;
1686 int8_t rExp = 0;
1687 int16_t bValue = 0;
1688 int8_t bExp = 0;
1689 bool bSigned = false;
1690
1691 if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
1692 {
1693 phosphor::logging::log<phosphor::logging::level::ERR>(
1694 "getSensorDataRecord: getSensorAttributes error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001695 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001696 }
1697
1698 // The record.body is a struct SensorDataFullRecordBody
1699 // from sensorhandler.hpp in phosphor-ipmi-host.
1700 // The meaning of these bits appears to come from
1701 // table 43.1 of the IPMI spec.
1702 // The above 5 sensor attributes are stuffed in as follows:
1703 // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
1704 // Byte 22-24 are for other purposes
1705 // Byte 25 = MMMMMMMM = LSB of M
1706 // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
1707 // Byte 27 = BBBBBBBB = LSB of B
1708 // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
1709 // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
1710 // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
1711
1712 // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
1713 record.body.m_lsb = mValue & 0xFF;
1714
1715 uint8_t mBitSign = (mValue < 0) ? 1 : 0;
1716 uint8_t mBitNine = (mValue & 0x0100) >> 8;
1717
1718 // move the smallest bit of the MSB into place (bit 9)
1719 // the MSbs are bits 7:8 in m_msb_and_tolerance
1720 record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
1721
1722 record.body.b_lsb = bValue & 0xFF;
1723
1724 uint8_t bBitSign = (bValue < 0) ? 1 : 0;
1725 uint8_t bBitNine = (bValue & 0x0100) >> 8;
1726
1727 // move the smallest bit of the MSB into place (bit 9)
1728 // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
1729 record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
1730
1731 uint8_t rExpSign = (rExp < 0) ? 1 : 0;
1732 uint8_t rExpBits = rExp & 0x07;
1733
1734 uint8_t bExpSign = (bExp < 0) ? 1 : 0;
1735 uint8_t bExpBits = bExp & 0x07;
1736
1737 // move rExp and bExp into place
1738 record.body.r_b_exponents =
1739 (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
1740
1741 // Set the analog reading byte interpretation accordingly
1742 record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
1743
1744 // TODO(): Perhaps care about Tolerance, Accuracy, and so on
1745 // These seem redundant, but derivable from the above 5 attributes
1746 // Original comment said "todo fill out rest of units"
1747
1748 // populate sensor name from path
Willy Tu38e7a2b2021-03-29 15:09:56 -07001749 auto name = sensor::parseSdrIdFromPath(path);
Paul Fertser51136982022-08-18 12:36:41 +00001750 get_sdr::body::set_id_strlen(name.size(), &record.body);
1751 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001752 std::strncpy(record.body.id_string, name.c_str(),
1753 sizeof(record.body.id_string));
1754
Josh Lehana55c9532020-10-28 21:59:06 -07001755 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001756 details::sdrStatsTable.updateName(sensorNum, name);
Josh Lehana55c9532020-10-28 21:59:06 -07001757
Jie Yangf0a89942021-07-29 15:30:25 -07001758 bool sensorSettable = false;
1759 auto mutability =
1760 sensorMap.find("xyz.openbmc_project.Sensor.ValueMutability");
1761 if (mutability != sensorMap.end())
1762 {
1763 sensorSettable =
1764 mappedVariant<bool>(mutability->second, "Mutable", false);
1765 }
1766 get_sdr::body::init_settable_state(sensorSettable, &record.body);
1767
1768 // Grant write permission to sensors deemed externally settable
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001769 details::sdrWriteTable.setWritePermission(sensorNum, sensorSettable);
Willy Tu530e2772021-07-02 14:42:06 -07001770
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001771 IPMIThresholds thresholdData;
1772 try
1773 {
1774 thresholdData = getIPMIThresholds(sensorMap);
1775 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001776 catch (const std::exception&)
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001777 {
1778 phosphor::logging::log<phosphor::logging::level::ERR>(
1779 "getSensorDataRecord: getIPMIThresholds error");
Willy Tu38e7a2b2021-03-29 15:09:56 -07001780 return false;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08001781 }
1782
1783 if (thresholdData.criticalHigh)
1784 {
1785 record.body.upper_critical_threshold = *thresholdData.criticalHigh;
1786 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1787 IPMISensorEventEnableThresholds::criticalThreshold);
1788 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1789 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1790 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1791 IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
1792 record.body.discrete_reading_setting_mask[0] |=
1793 static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
1794 }
1795 if (thresholdData.warningHigh)
1796 {
1797 record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
1798 record.body.supported_deassertions[1] |= static_cast<uint8_t>(
1799 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1800 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1801 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1802 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1803 IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
1804 record.body.discrete_reading_setting_mask[0] |=
1805 static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
1806 }
1807 if (thresholdData.criticalLow)
1808 {
1809 record.body.lower_critical_threshold = *thresholdData.criticalLow;
1810 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1811 IPMISensorEventEnableThresholds::criticalThreshold);
1812 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1813 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1814 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1815 IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
1816 record.body.discrete_reading_setting_mask[0] |=
1817 static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
1818 }
1819 if (thresholdData.warningLow)
1820 {
1821 record.body.lower_noncritical_threshold = *thresholdData.warningLow;
1822 record.body.supported_assertions[1] |= static_cast<uint8_t>(
1823 IPMISensorEventEnableThresholds::nonCriticalThreshold);
1824 record.body.supported_deassertions[0] |= static_cast<uint8_t>(
1825 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1826 record.body.supported_assertions[0] |= static_cast<uint8_t>(
1827 IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
1828 record.body.discrete_reading_setting_mask[0] |=
1829 static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
1830 }
1831
1832 // everything that is readable is setable
1833 record.body.discrete_reading_setting_mask[1] =
1834 record.body.discrete_reading_setting_mask[0];
Willy Tu38e7a2b2021-03-29 15:09:56 -07001835 return true;
1836}
1837
Scron Chang2703b022021-07-06 15:47:45 +08001838#ifdef FEATURE_HYBRID_SENSORS
1839// Construct a type 1 SDR for discrete Sensor typed sensor.
Willy Tu11d68892022-01-20 10:37:34 -08001840void constructStaticSensorSdr(ipmi::Context::ptr, uint16_t sensorNum,
Scron Chang2703b022021-07-06 15:47:45 +08001841 uint16_t recordID,
1842 ipmi::sensor::IdInfoMap::const_iterator sensor,
1843 get_sdr::SensorDataFullRecord& record)
1844{
1845 constructSensorSdrHeaderKey(sensorNum, recordID, record);
1846
1847 record.body.entity_id = sensor->second.entityType;
1848 record.body.sensor_type = sensor->second.sensorType;
1849 record.body.event_reading_type = sensor->second.sensorReadingType;
1850 record.body.entity_instance = sensor->second.instance;
1851 if (ipmi::sensor::Mutability::Write ==
1852 (sensor->second.mutability & ipmi::sensor::Mutability::Write))
1853 {
1854 get_sdr::body::init_settable_state(true, &(record.body));
1855 }
1856
1857 auto id_string = sensor->second.sensorName;
1858
1859 if (id_string.empty())
1860 {
1861 id_string = sensor->second.sensorNameFunc(sensor->second);
1862 }
1863
1864 if (id_string.length() > FULL_RECORD_ID_STR_MAX_LENGTH)
1865 {
1866 get_sdr::body::set_id_strlen(FULL_RECORD_ID_STR_MAX_LENGTH,
1867 &(record.body));
1868 }
1869 else
1870 {
1871 get_sdr::body::set_id_strlen(id_string.length(), &(record.body));
1872 }
Paul Fertser51136982022-08-18 12:36:41 +00001873 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Scron Chang2703b022021-07-06 15:47:45 +08001874 std::strncpy(record.body.id_string, id_string.c_str(),
1875 get_sdr::body::get_id_strlen(&(record.body)));
1876}
1877#endif
1878
Hao Jiange39d4d82021-04-16 17:02:40 -07001879// Construct type 3 SDR header and key (for VR and other discrete sensors)
1880void constructEventSdrHeaderKey(uint16_t sensorNum, uint16_t recordID,
1881 get_sdr::SensorDataEventRecord& record)
Willy Tu61992ad2021-03-29 15:33:20 -07001882{
1883 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
1884 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
1885
1886 get_sdr::header::set_record_id(
1887 recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
1888
1889 record.header.sdr_version = ipmiSdrVersion;
1890 record.header.record_type = get_sdr::SENSOR_DATA_EVENT_RECORD;
1891 record.header.record_length = sizeof(get_sdr::SensorDataEventRecord) -
1892 sizeof(get_sdr::SensorDataRecordHeader);
1893 record.key.owner_id = bmcI2CAddr;
1894 record.key.owner_lun = lun;
1895 record.key.sensor_number = sensornumber;
1896
1897 record.body.entity_id = 0x00;
1898 record.body.entity_instance = 0x01;
Hao Jiange39d4d82021-04-16 17:02:40 -07001899}
Willy Tu61992ad2021-03-29 15:33:20 -07001900
Hao Jiange39d4d82021-04-16 17:02:40 -07001901// Construct a type 3 SDR for VR typed sensor(daemon).
Willy Tu4eca2512022-06-20 21:14:51 -07001902bool constructVrSdr(ipmi::Context::ptr ctx,
1903 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1904 uint16_t sensorNum, uint16_t recordID,
1905 const std::string& service, const std::string& path,
Hao Jiange39d4d82021-04-16 17:02:40 -07001906 get_sdr::SensorDataEventRecord& record)
1907{
Hao Jiange39d4d82021-04-16 17:02:40 -07001908 constructEventSdrHeaderKey(sensorNum, recordID, record);
1909
1910 DbusInterfaceMap sensorMap;
1911 if (!getSensorMap(ctx, service, path, sensorMap, sensorMapSdrUpdatePeriod))
1912 {
1913 phosphor::logging::log<phosphor::logging::level::ERR>(
1914 "Failed to update sensor map for VR sensor",
1915 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1916 phosphor::logging::entry("PATH=%s", path.c_str()));
1917 return false;
1918 }
Willy Tu61992ad2021-03-29 15:33:20 -07001919 // follow the association chain to get the parent board's entityid and
1920 // entityInstance
Willy Tu4eca2512022-06-20 21:14:51 -07001921 updateIpmiFromAssociation(path, ipmiDecoratorPaths, sensorMap,
1922 record.body.entity_id,
Willy Tu61992ad2021-03-29 15:33:20 -07001923 record.body.entity_instance);
1924
1925 // Sensor type is hardcoded as a module/board type instead of parsing from
1926 // sensor path. This is because VR control is allocated in an independent
1927 // path(/xyz/openbmc_project/vr/profile/...) which is not categorized by
1928 // types.
1929 static constexpr const uint8_t module_board_type = 0x15;
1930 record.body.sensor_type = module_board_type;
1931 record.body.event_reading_type = 0x00;
1932
1933 record.body.sensor_record_sharing_1 = 0x00;
1934 record.body.sensor_record_sharing_2 = 0x00;
1935
1936 // populate sensor name from path
1937 auto name = sensor::parseSdrIdFromPath(path);
1938 int nameSize = std::min(name.size(), sizeof(record.body.id_string));
Paul Fertser51136982022-08-18 12:36:41 +00001939 get_sdr::body::set_id_strlen(nameSize, &record.body);
1940 get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
Willy Tu61992ad2021-03-29 15:33:20 -07001941 std::memset(record.body.id_string, 0x00, sizeof(record.body.id_string));
1942 std::memcpy(record.body.id_string, name.c_str(), nameSize);
1943
1944 // Remember the sensor name, as determined for this sensor number
Harvey.Wu0e7a8af2022-06-10 16:46:46 +08001945 details::sdrStatsTable.updateName(sensorNum, name);
Hao Jiange39d4d82021-04-16 17:02:40 -07001946
1947 return true;
Willy Tu61992ad2021-03-29 15:33:20 -07001948}
1949
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001950static inline uint16_t getNumberOfSensors()
1951{
1952 return std::min(getSensorTree().size(), maxIPMISensors);
1953}
1954
Willy Tu4eca2512022-06-20 21:14:51 -07001955static int getSensorDataRecord(
1956 ipmi::Context::ptr ctx,
1957 const std::unordered_set<std::string>& ipmiDecoratorPaths,
1958 std::vector<uint8_t>& recordData, uint16_t recordID,
1959 uint8_t readBytes = std::numeric_limits<uint8_t>::max())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001960{
1961 size_t fruCount = 0;
1962 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
1963 if (ret != ipmi::ccSuccess)
1964 {
1965 phosphor::logging::log<phosphor::logging::level::ERR>(
1966 "getSensorDataRecord: getFruSdrCount error");
1967 return GENERAL_ERROR;
1968 }
1969
Harvey Wu05d17c02021-09-15 08:46:59 +08001970 const auto& entityRecords =
1971 ipmi::sensor::EntityInfoMapContainer::getContainer()
1972 ->getIpmiEntityRecords();
1973 size_t entityCount = entityRecords.size();
1974
selvaganapathi7b2e5502023-02-14 07:10:47 +05301975 recordData.clear();
Harvey Wu05d17c02021-09-15 08:46:59 +08001976 size_t lastRecord = getNumberOfSensors() + fruCount +
1977 ipmi::storage::type12Count + entityCount - 1;
Willy Tu38e7a2b2021-03-29 15:09:56 -07001978 if (recordID == lastRecordIndex)
1979 {
1980 recordID = lastRecord;
1981 }
1982 if (recordID > lastRecord)
1983 {
1984 phosphor::logging::log<phosphor::logging::level::ERR>(
1985 "getSensorDataRecord: recordID > lastRecord error");
1986 return GENERAL_ERROR;
1987 }
1988
Johnathan Mantey6619ae42021-08-06 11:21:10 -07001989 if (recordID >= getNumberOfSensors())
Willy Tu38e7a2b2021-03-29 15:09:56 -07001990 {
Harvey Wu05d17c02021-09-15 08:46:59 +08001991 size_t sdrIndex = recordID - getNumberOfSensors();
Willy Tu38e7a2b2021-03-29 15:09:56 -07001992
Harvey Wu05d17c02021-09-15 08:46:59 +08001993 if (sdrIndex >= fruCount + ipmi::storage::type12Count)
1994 {
1995 // handle type 8 entity map records
1996 ipmi::sensor::EntityInfoMap::const_iterator entity =
1997 entityRecords.find(static_cast<uint8_t>(
1998 sdrIndex - fruCount - ipmi::storage::type12Count));
1999 if (entity == entityRecords.end())
2000 {
2001 return IPMI_CC_SENSOR_INVALID;
2002 }
2003 recordData = ipmi::storage::getType8SDRs(entity, recordID);
2004 }
2005 else if (sdrIndex >= fruCount)
Willy Tu38e7a2b2021-03-29 15:09:56 -07002006 {
2007 // handle type 12 hardcoded records
Harvey Wu05d17c02021-09-15 08:46:59 +08002008 size_t type12Index = sdrIndex - fruCount;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002009 if (type12Index >= ipmi::storage::type12Count)
2010 {
2011 phosphor::logging::log<phosphor::logging::level::ERR>(
2012 "getSensorDataRecord: type12Index error");
2013 return GENERAL_ERROR;
2014 }
2015 recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
2016 }
2017 else
2018 {
2019 // handle fru records
2020 get_sdr::SensorDataFruRecord data;
Harvey Wu05d17c02021-09-15 08:46:59 +08002021 ret = ipmi::storage::getFruSdrs(ctx, sdrIndex, data);
Willy Tu38e7a2b2021-03-29 15:09:56 -07002022 if (ret != IPMI_CC_OK)
2023 {
2024 return GENERAL_ERROR;
2025 }
2026 data.header.record_id_msb = recordID >> 8;
2027 data.header.record_id_lsb = recordID & 0xFF;
selvaganapathi7b2e5502023-02-14 07:10:47 +05302028 recordData.insert(recordData.end(),
2029 reinterpret_cast<uint8_t*>(&data),
2030 reinterpret_cast<uint8_t*>(&data) + sizeof(data));
Willy Tu38e7a2b2021-03-29 15:09:56 -07002031 }
2032
2033 return 0;
2034 }
2035
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002036 // Perform a incremental scan of the SDR Record ID's and translate the
2037 // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
2038 // Numbers. The IPMI sensor numbers are not linear, and have a reserved
2039 // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
2040 // which has special meaning.
Willy Tu38e7a2b2021-03-29 15:09:56 -07002041 std::string connection;
2042 std::string path;
Hao Jiange39d4d82021-04-16 17:02:40 -07002043 std::vector<std::string> interfaces;
Johnathan Manteyce982772021-07-28 15:08:30 -07002044 uint16_t sensNumFromRecID{recordID};
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002045 if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
Johnathan Manteyce982772021-07-28 15:08:30 -07002046 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002047 // LUN 0 has one reserved sensor number. Compensate here by adding one
2048 // to the record ID
2049 sensNumFromRecID = recordID + 1;
Harvey Wu75893062023-03-22 17:17:31 +08002050 ctx->lun = lun1;
Johnathan Manteyce982772021-07-28 15:08:30 -07002051 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002052 else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
Johnathan Manteyce982772021-07-28 15:08:30 -07002053 {
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002054 // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
2055 // to the record ID. Skip all 256 sensors in LUN 2, as it has special
2056 // rules governing its use.
2057 sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
Harvey Wu75893062023-03-22 17:17:31 +08002058 ctx->lun = lun3;
Johnathan Manteyce982772021-07-28 15:08:30 -07002059 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002060
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002061 auto status =
2062 getSensorConnection(ctx, static_cast<uint8_t>(sensNumFromRecID),
2063 connection, path, &interfaces);
Willy Tu38e7a2b2021-03-29 15:09:56 -07002064 if (status)
2065 {
2066 phosphor::logging::log<phosphor::logging::level::ERR>(
2067 "getSensorDataRecord: getSensorConnection error");
2068 return GENERAL_ERROR;
2069 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002070 uint16_t sensorNum = getSensorNumberFromPath(path);
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002071 // Return an error on LUN 2 assingments, and any sensor number beyond the
2072 // range of LUN 3
2073 if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
2074 (sensorNum > lun3MaxSensorNum))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002075 {
2076 phosphor::logging::log<phosphor::logging::level::ERR>(
2077 "getSensorDataRecord: invalidSensorNumber");
2078 return GENERAL_ERROR;
2079 }
Johnathan Manteyce982772021-07-28 15:08:30 -07002080 uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
2081 uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
2082
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002083 if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
2084 (lun != ctx->lun))
Johnathan Manteyce982772021-07-28 15:08:30 -07002085 {
2086 phosphor::logging::log<phosphor::logging::level::ERR>(
2087 "getSensorDataRecord: sensor record mismatch");
2088 return GENERAL_ERROR;
2089 }
Willy Tu38e7a2b2021-03-29 15:09:56 -07002090
Willy Tu38e7a2b2021-03-29 15:09:56 -07002091 // Construct full record (SDR type 1) for the threshold sensors
Hao Jiange39d4d82021-04-16 17:02:40 -07002092 if (std::find(interfaces.begin(), interfaces.end(),
2093 sensor::sensorInterface) != interfaces.end())
Willy Tu38e7a2b2021-03-29 15:09:56 -07002094 {
Willy Tu11d68892022-01-20 10:37:34 -08002095 get_sdr::SensorDataFullRecord record = {};
Willy Tu38e7a2b2021-03-29 15:09:56 -07002096
Hao Jiange39d4d82021-04-16 17:02:40 -07002097 // 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 }
Willy Tu4eca2512022-06-20 21:14:51 -07002103 else if (!constructSensorSdr(ctx, ipmiDecoratorPaths, sensorNum,
2104 recordID, connection, path, record))
Willy Tu38e7a2b2021-03-29 15:09:56 -07002105 {
2106 return GENERAL_ERROR;
2107 }
Hao Jiange39d4d82021-04-16 17:02:40 -07002108
selvaganapathi7b2e5502023-02-14 07:10:47 +05302109 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2110 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002111
2112 return 0;
Willy Tu38e7a2b2021-03-29 15:09:56 -07002113 }
Willy Tu61992ad2021-03-29 15:33:20 -07002114
Scron Chang2703b022021-07-06 15:47:45 +08002115#ifdef FEATURE_HYBRID_SENSORS
2116 if (auto sensor = findStaticSensor(path);
2117 sensor != ipmi::sensor::sensors.end() &&
2118 getSensorEventTypeFromPath(path) !=
2119 static_cast<uint8_t>(SensorEventTypeCodes::threshold))
2120 {
Willy Tu11d68892022-01-20 10:37:34 -08002121 get_sdr::SensorDataFullRecord record = {};
Scron Chang2703b022021-07-06 15:47:45 +08002122
2123 // If the request doesn't read SDR body, construct only header and key
2124 // part to avoid additional DBus transaction.
2125 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2126 {
2127 constructSensorSdrHeaderKey(sensorNum, recordID, record);
2128 }
2129 else
2130 {
2131 constructStaticSensorSdr(ctx, sensorNum, recordID, sensor, record);
2132 }
2133
selvaganapathi7b2e5502023-02-14 07:10:47 +05302134 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2135 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Scron Chang2703b022021-07-06 15:47:45 +08002136
2137 return 0;
2138 }
2139#endif
2140
Willy Tu61992ad2021-03-29 15:33:20 -07002141 // Contruct SDR type 3 record for VR sensor (daemon)
Hao Jiange39d4d82021-04-16 17:02:40 -07002142 if (std::find(interfaces.begin(), interfaces.end(), sensor::vrInterface) !=
2143 interfaces.end())
Willy Tu61992ad2021-03-29 15:33:20 -07002144 {
Willy Tu11d68892022-01-20 10:37:34 -08002145 get_sdr::SensorDataEventRecord record = {};
Willy Tu61992ad2021-03-29 15:33:20 -07002146
Hao Jiange39d4d82021-04-16 17:02:40 -07002147 // If the request doesn't read SDR body, construct only header and key
2148 // part to avoid additional DBus transaction.
2149 if (readBytes <= sizeof(record.header) + sizeof(record.key))
2150 {
2151 constructEventSdrHeaderKey(sensorNum, recordID, record);
2152 }
Willy Tu4eca2512022-06-20 21:14:51 -07002153 else if (!constructVrSdr(ctx, ipmiDecoratorPaths, sensorNum, recordID,
2154 connection, path, record))
Hao Jiange39d4d82021-04-16 17:02:40 -07002155 {
2156 return GENERAL_ERROR;
2157 }
selvaganapathi7b2e5502023-02-14 07:10:47 +05302158 recordData.insert(recordData.end(), reinterpret_cast<uint8_t*>(&record),
2159 reinterpret_cast<uint8_t*>(&record) + sizeof(record));
Willy Tu61992ad2021-03-29 15:33:20 -07002160 }
2161
Willy Tude54f482021-01-26 15:59:09 -08002162 return 0;
2163}
2164
2165/** @brief implements the get SDR Info command
2166 * @param count - Operation
2167 *
2168 * @returns IPMI completion code plus response data
2169 * - sdrCount - sensor/SDR count
2170 * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
2171 */
2172static ipmi::RspType<uint8_t, // respcount
2173 uint8_t, // dynamic population flags
2174 uint32_t // last time a sensor was added
2175 >
2176 ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
2177 std::optional<uint8_t> count)
2178{
2179 auto& sensorTree = getSensorTree();
2180 uint8_t sdrCount = 0;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002181 uint16_t recordID = 0;
2182 std::vector<uint8_t> record;
Willy Tude54f482021-01-26 15:59:09 -08002183 // Sensors are dynamically allocated, and there is at least one LUN
2184 uint8_t lunsAndDynamicPopulation = 0x80;
2185 constexpr uint8_t getSdrCount = 0x01;
2186 constexpr uint8_t getSensorCount = 0x00;
2187
2188 if (!getSensorSubtree(sensorTree) || sensorTree.empty())
2189 {
2190 return ipmi::responseResponseError();
2191 }
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002192 uint16_t numSensors = getNumberOfSensors();
Willy Tude54f482021-01-26 15:59:09 -08002193 if (count.value_or(0) == getSdrCount)
2194 {
Willy Tu4eca2512022-06-20 21:14:51 -07002195 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2196
Harvey Wu75893062023-03-22 17:17:31 +08002197 if (ctx->lun == lun1)
Harvey Wua3476272023-03-22 10:09:38 +08002198 {
2199 recordID += maxSensorsPerLUN;
2200 }
Harvey Wu75893062023-03-22 17:17:31 +08002201 else if (ctx->lun == lun3)
Harvey Wua3476272023-03-22 10:09:38 +08002202 {
2203 recordID += maxSensorsPerLUN * 2;
2204 }
2205
Harvey Wu75893062023-03-22 17:17:31 +08002206 // Count the number of Type 1h, Type 2h, Type 11h, Type 12h SDR entries
2207 // assigned to the LUN
Willy Tu4eca2512022-06-20 21:14:51 -07002208 while (!getSensorDataRecord(
2209 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2210 record, recordID++))
Willy Tude54f482021-01-26 15:59:09 -08002211 {
2212 get_sdr::SensorDataRecordHeader* hdr =
2213 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002214 record.data());
selvaganapathi7b2e5502023-02-14 07:10:47 +05302215 if (!hdr)
2216 {
2217 continue;
2218 }
2219
2220 if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
Willy Tude54f482021-01-26 15:59:09 -08002221 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002222 get_sdr::SensorDataFullRecord* recordData =
Willy Tude54f482021-01-26 15:59:09 -08002223 reinterpret_cast<get_sdr::SensorDataFullRecord*>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002224 record.data());
2225 if (ctx->lun == recordData->key.owner_lun)
Willy Tude54f482021-01-26 15:59:09 -08002226 {
2227 sdrCount++;
2228 }
2229 }
selvaganapathi7b2e5502023-02-14 07:10:47 +05302230 else if (hdr->record_type == get_sdr::SENSOR_DATA_COMPACT_RECORD)
2231 {
2232 get_sdr::SensorDataCompactRecord* recordData =
2233 reinterpret_cast<get_sdr::SensorDataCompactRecord*>(
2234 record.data());
2235 if (ctx->lun == recordData->key.owner_lun)
2236 {
2237 sdrCount++;
2238 }
2239 }
Harvey Wua3476272023-03-22 10:09:38 +08002240 else if (hdr->record_type == get_sdr::SENSOR_DATA_FRU_RECORD ||
2241 hdr->record_type == get_sdr::SENSOR_DATA_MGMT_CTRL_LOCATOR)
selvaganapathi7b2e5502023-02-14 07:10:47 +05302242 {
2243 sdrCount++;
2244 }
Harvey Wua3476272023-03-22 10:09:38 +08002245
2246 // Because response count data is 1 byte, so sdrCount need to avoid
2247 // overflow.
2248 if (sdrCount == maxSensorsPerLUN)
2249 {
2250 break;
2251 }
Willy Tude54f482021-01-26 15:59:09 -08002252 }
2253 }
2254 else if (count.value_or(0) == getSensorCount)
2255 {
2256 // Return the number of sensors attached to the LUN
Harvey Wu75893062023-03-22 17:17:31 +08002257 if ((ctx->lun == lun0) && (numSensors > 0))
Willy Tude54f482021-01-26 15:59:09 -08002258 {
2259 sdrCount =
2260 (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
2261 }
Harvey Wu75893062023-03-22 17:17:31 +08002262 else if ((ctx->lun == lun1) && (numSensors > maxSensorsPerLUN))
Willy Tude54f482021-01-26 15:59:09 -08002263 {
2264 sdrCount = (numSensors > (2 * maxSensorsPerLUN))
2265 ? maxSensorsPerLUN
2266 : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
2267 }
Harvey Wu75893062023-03-22 17:17:31 +08002268 else if (ctx->lun == lun3)
Willy Tude54f482021-01-26 15:59:09 -08002269 {
2270 if (numSensors <= maxIPMISensors)
2271 {
2272 sdrCount =
2273 (numSensors - (2 * maxSensorsPerLUN)) & maxSensorsPerLUN;
2274 }
2275 else
2276 {
2277 // error
2278 throw std::out_of_range(
2279 "Maximum number of IPMI sensors exceeded.");
2280 }
2281 }
2282 }
2283 else
2284 {
2285 return ipmi::responseInvalidFieldRequest();
2286 }
2287
2288 // Get Sensor count. This returns the number of sensors
2289 if (numSensors > 0)
2290 {
2291 lunsAndDynamicPopulation |= 1;
2292 }
2293 if (numSensors > maxSensorsPerLUN)
2294 {
2295 lunsAndDynamicPopulation |= 2;
2296 }
2297 if (numSensors >= (maxSensorsPerLUN * 2))
2298 {
2299 lunsAndDynamicPopulation |= 8;
2300 }
2301 if (numSensors > maxIPMISensors)
2302 {
2303 // error
2304 throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
2305 }
2306
2307 return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
2308 sdrLastAdd);
2309}
2310
2311/* end sensor commands */
2312
2313/* storage commands */
2314
2315ipmi::RspType<uint8_t, // sdr version
2316 uint16_t, // record count
2317 uint16_t, // free space
2318 uint32_t, // most recent addition
2319 uint32_t, // most recent erase
2320 uint8_t // operationSupport
2321 >
2322 ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
2323{
2324 auto& sensorTree = getSensorTree();
2325 constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002326 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002327 {
2328 return ipmi::responseResponseError();
2329 }
2330
2331 size_t fruCount = 0;
2332 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2333 if (ret != ipmi::ccSuccess)
2334 {
2335 return ipmi::response(ret);
2336 }
2337
2338 uint16_t recordCount =
Johnathan Mantey6619ae42021-08-06 11:21:10 -07002339 getNumberOfSensors() + fruCount + ipmi::storage::type12Count;
Willy Tude54f482021-01-26 15:59:09 -08002340
2341 uint8_t operationSupport = static_cast<uint8_t>(
2342 SdrRepositoryInfoOps::overflow); // write not supported
2343
2344 operationSupport |=
2345 static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
2346 operationSupport |= static_cast<uint8_t>(
2347 SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
2348 return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
2349 unspecifiedFreeSpace, sdrLastAdd,
2350 sdrLastRemove, operationSupport);
2351}
2352
2353/** @brief implements the get SDR allocation info command
2354 *
2355 * @returns IPMI completion code plus response data
2356 * - allocUnits - Number of possible allocation units
2357 * - allocUnitSize - Allocation unit size in bytes.
2358 * - allocUnitFree - Number of free allocation units
2359 * - allocUnitLargestFree - Largest free block in allocation units
2360 * - maxRecordSize - Maximum record size in allocation units.
2361 */
2362ipmi::RspType<uint16_t, // allocUnits
2363 uint16_t, // allocUnitSize
2364 uint16_t, // allocUnitFree
2365 uint16_t, // allocUnitLargestFree
2366 uint8_t // maxRecordSize
2367 >
2368 ipmiStorageGetSDRAllocationInfo()
2369{
2370 // 0000h unspecified number of alloc units
2371 constexpr uint16_t allocUnits = 0;
2372
2373 constexpr uint16_t allocUnitFree = 0;
2374 constexpr uint16_t allocUnitLargestFree = 0;
2375 // only allow one block at a time
2376 constexpr uint8_t maxRecordSize = 1;
2377
2378 return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
2379 allocUnitLargestFree, maxRecordSize);
2380}
2381
2382/** @brief implements the reserve SDR command
2383 * @returns IPMI completion code plus response data
2384 * - sdrReservationID
2385 */
2386ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
2387{
2388 sdrReservationID++;
2389 if (sdrReservationID == 0)
2390 {
2391 sdrReservationID++;
2392 }
2393
2394 return ipmi::responseSuccess(sdrReservationID);
2395}
2396
2397ipmi::RspType<uint16_t, // next record ID
2398 std::vector<uint8_t> // payload
2399 >
2400 ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
2401 uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
2402{
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002403 size_t fruCount = 0;
Willy Tude54f482021-01-26 15:59:09 -08002404 // reservation required for partial reads with non zero offset into
2405 // record
2406 if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
2407 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002408 phosphor::logging::log<phosphor::logging::level::ERR>(
2409 "ipmiStorageGetSDR: responseInvalidReservationId");
Willy Tude54f482021-01-26 15:59:09 -08002410 return ipmi::responseInvalidReservationId();
2411 }
Willy Tude54f482021-01-26 15:59:09 -08002412 ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
2413 if (ret != ipmi::ccSuccess)
2414 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002415 phosphor::logging::log<phosphor::logging::level::ERR>(
2416 "ipmiStorageGetSDR: getFruSdrCount error");
Willy Tude54f482021-01-26 15:59:09 -08002417 return ipmi::response(ret);
2418 }
2419
Harvey Wu05d17c02021-09-15 08:46:59 +08002420 const auto& entityRecords =
2421 ipmi::sensor::EntityInfoMapContainer::getContainer()
2422 ->getIpmiEntityRecords();
2423 int entityCount = entityRecords.size();
2424
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002425 auto& sensorTree = getSensorTree();
Harvey Wu05d17c02021-09-15 08:46:59 +08002426 size_t lastRecord = getNumberOfSensors() + fruCount +
2427 ipmi::storage::type12Count + entityCount - 1;
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002428 uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
2429
2430 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
Willy Tude54f482021-01-26 15:59:09 -08002431 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002432 phosphor::logging::log<phosphor::logging::level::ERR>(
2433 "ipmiStorageGetSDR: getSensorSubtree error");
2434 return ipmi::responseResponseError();
Willy Tude54f482021-01-26 15:59:09 -08002435 }
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002436
Willy Tu4eca2512022-06-20 21:14:51 -07002437 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
2438
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002439 std::vector<uint8_t> record;
Willy Tu4eca2512022-06-20 21:14:51 -07002440 if (getSensorDataRecord(
2441 ctx, ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2442 record, recordID, offset + bytesToRead))
Willy Tude54f482021-01-26 15:59:09 -08002443 {
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002444 phosphor::logging::log<phosphor::logging::level::ERR>(
2445 "ipmiStorageGetSDR: fail to get SDR");
Willy Tude54f482021-01-26 15:59:09 -08002446 return ipmi::responseInvalidFieldRequest();
2447 }
Willy Tude54f482021-01-26 15:59:09 -08002448 get_sdr::SensorDataRecordHeader* hdr =
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002449 reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
Willy Tude54f482021-01-26 15:59:09 -08002450 if (!hdr)
2451 {
2452 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002453 "ipmiStorageGetSDR: record header is null");
2454 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002455 }
2456
2457 size_t sdrLength =
2458 sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
2459 if (sdrLength < (offset + bytesToRead))
2460 {
2461 bytesToRead = sdrLength - offset;
2462 }
2463
2464 uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
2465 if (!respStart)
2466 {
2467 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002468 "ipmiStorageGetSDR: record is null");
2469 return ipmi::responseSuccess(nextRecordId, record);
Willy Tude54f482021-01-26 15:59:09 -08002470 }
2471
2472 std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
Kuiying Wanga8b5b262021-02-06 23:38:22 +08002473
Willy Tude54f482021-01-26 15:59:09 -08002474 return ipmi::responseSuccess(nextRecordId, recordData);
2475}
adarshgrami042e9db2022-09-15 10:34:34 +05302476namespace dcmi
2477{
2478
2479ipmi::RspType<uint8_t, // No of instances for requested id
2480 uint8_t, // No of record ids in the response
2481 std::vector<uint16_t> // SDR Record ID corresponding to the Entity
2482 // IDs
2483 >
2484 getSensorInfo(ipmi::Context::ptr ctx, uint8_t sensorType, uint8_t entityId,
Willy Tu0679e4b2022-11-11 14:34:33 -08002485 uint8_t entityInstance,
2486 [[maybe_unused]] uint8_t instanceStart)
adarshgrami042e9db2022-09-15 10:34:34 +05302487{
2488 auto match = ipmi::dcmi::validEntityId.find(entityId);
2489 if (match == ipmi::dcmi::validEntityId.end())
2490 {
2491 log<level::ERR>("Unknown Entity ID", entry("ENTITY_ID=%d", entityId));
2492
2493 return ipmi::responseInvalidFieldRequest();
2494 }
2495
2496 if (sensorType != ipmi::dcmi::temperatureSensorType)
2497 {
2498 log<level::ERR>("Invalid sensor type",
2499 entry("SENSOR_TYPE=%d", sensorType));
2500
2501 return ipmi::responseInvalidFieldRequest();
2502 }
2503 auto& sensorTree = getSensorTree();
2504 if (!getSensorSubtree(sensorTree) && sensorTree.empty())
2505 {
2506 return ipmi::responseUnspecifiedError();
2507 }
2508
2509 std::vector<uint16_t> sensorRec{};
2510 uint8_t numInstances = 0;
2511
Willy Tu0679e4b2022-11-11 14:34:33 -08002512 auto& ipmiDecoratorPaths = getIpmiDecoratorPaths(ctx);
adarshgrami042e9db2022-09-15 10:34:34 +05302513 for (const auto& sensor : sensorTree)
2514 {
2515 auto sensorTypeValue = getSensorTypeFromPath(sensor.first);
2516 if (sensorTypeValue != ipmi::dcmi::temperatureSensorType)
2517 {
2518 continue;
2519 }
2520 const auto& connection = sensor.second.begin()->first;
2521
2522 DbusInterfaceMap sensorMap;
2523 if (!getSensorMap(ctx, connection, sensor.first, sensorMap,
2524 sensorMapSdrUpdatePeriod))
2525 {
2526 phosphor::logging::log<phosphor::logging::level::ERR>(
2527 "Failed to update sensor map for threshold sensor",
2528 phosphor::logging::entry("SERVICE=%s", connection.c_str()),
2529 phosphor::logging::entry("PATH=%s", sensor.first.c_str()));
2530 continue;
2531 }
2532 uint8_t entityIdValue = 0;
2533 uint8_t entityInstanceValue = 0;
Willy Tu0679e4b2022-11-11 14:34:33 -08002534 updateIpmiFromAssociation(
2535 sensor.first,
2536 ipmiDecoratorPaths.value_or(std::unordered_set<std::string>()),
2537 sensorMap, entityIdValue, entityInstanceValue);
adarshgrami042e9db2022-09-15 10:34:34 +05302538 if (!entityInstance)
2539 {
2540 if (entityIdValue == match->first || entityIdValue == match->second)
2541 {
2542 auto recordId = getSensorNumberFromPath(sensor.first);
2543 if (recordId != invalidSensorNumber)
2544 {
2545 numInstances++;
2546 if (numInstances <= ipmi::dcmi::maxRecords)
2547 {
2548 sensorRec.push_back(recordId);
2549 }
2550 }
2551 }
2552 }
2553 else
2554 {
2555 if (entityIdValue == match->first || entityIdValue == match->second)
2556 {
2557 if (entityInstance == entityInstanceValue)
2558 {
2559 auto recordId = getSensorNumberFromPath(sensor.first);
2560 if ((recordId != invalidSensorNumber) && sensorRec.empty())
2561 {
2562 sensorRec.push_back(recordId);
2563 }
2564 }
2565 numInstances++;
2566 }
2567 }
2568 }
2569 if (sensorRec.empty())
2570 {
2571 return ipmi::responseSensorInvalid();
2572 }
2573 uint8_t numRecords = sensorRec.size();
2574 return ipmi::responseSuccess(numInstances, numRecords, sensorRec);
2575}
2576} // namespace dcmi
2577
Willy Tude54f482021-01-26 15:59:09 -08002578/* end storage commands */
2579
2580void registerSensorFunctions()
2581{
2582 // <Platform Event>
2583 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2584 ipmi::sensor_event::cmdPlatformEvent,
2585 ipmi::Privilege::Operator, ipmiSenPlatformEvent);
2586
Willy Tudbafbce2021-03-29 00:37:05 -07002587 // <Set Sensor Reading and Event Status>
2588 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2589 ipmi::sensor_event::cmdSetSensorReadingAndEvtSts,
2590 ipmi::Privilege::Operator, ipmiSetSensorReading);
Willy Tudbafbce2021-03-29 00:37:05 -07002591
Willy Tude54f482021-01-26 15:59:09 -08002592 // <Get Sensor Reading>
2593 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2594 ipmi::sensor_event::cmdGetSensorReading,
2595 ipmi::Privilege::User, ipmiSenGetSensorReading);
2596
2597 // <Get Sensor Threshold>
2598 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2599 ipmi::sensor_event::cmdGetSensorThreshold,
2600 ipmi::Privilege::User, ipmiSenGetSensorThresholds);
2601
2602 // <Set Sensor Threshold>
2603 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2604 ipmi::sensor_event::cmdSetSensorThreshold,
2605 ipmi::Privilege::Operator,
2606 ipmiSenSetSensorThresholds);
2607
2608 // <Get Sensor Event Enable>
2609 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2610 ipmi::sensor_event::cmdGetSensorEventEnable,
2611 ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
2612
2613 // <Get Sensor Event Status>
2614 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2615 ipmi::sensor_event::cmdGetSensorEventStatus,
2616 ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
2617
2618 // register all storage commands for both Sensor and Storage command
2619 // versions
2620
2621 // <Get SDR Repository Info>
2622 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2623 ipmi::storage::cmdGetSdrRepositoryInfo,
2624 ipmi::Privilege::User,
2625 ipmiStorageGetSDRRepositoryInfo);
2626
2627 // <Get Device SDR Info>
2628 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2629 ipmi::sensor_event::cmdGetDeviceSdrInfo,
2630 ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
2631
2632 // <Get SDR Allocation Info>
2633 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2634 ipmi::storage::cmdGetSdrRepositoryAllocInfo,
2635 ipmi::Privilege::User,
2636 ipmiStorageGetSDRAllocationInfo);
2637
2638 // <Reserve SDR Repo>
2639 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2640 ipmi::sensor_event::cmdReserveDeviceSdrRepository,
2641 ipmi::Privilege::User, ipmiStorageReserveSDR);
2642
2643 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2644 ipmi::storage::cmdReserveSdrRepository,
2645 ipmi::Privilege::User, ipmiStorageReserveSDR);
2646
2647 // <Get Sdr>
2648 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
2649 ipmi::sensor_event::cmdGetDeviceSdr,
2650 ipmi::Privilege::User, ipmiStorageGetSDR);
2651
2652 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
2653 ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
2654 ipmiStorageGetSDR);
adarshgrami042e9db2022-09-15 10:34:34 +05302655 // <Get DCMI Sensor Info>
2656 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
2657 ipmi::dcmi::cmdGetDcmiSensorInfo,
2658 ipmi::Privilege::User,
2659 ipmi::dcmi::getSensorInfo);
Willy Tude54f482021-01-26 15:59:09 -08002660}
2661} // namespace ipmi