Migrate sensor handling to phosphor-ipmi-host D-Bus
Updates have been applied to phosphor-ipmi-host D-Bus sensors code to
allow removal of virtually all functions in the sensorcommands.cpp
file.
Side by side comparison of the functions that handle SDRs and other
sensor features shows that the code is almost an exact duplicate.
Implementing a sensorcommands_oem linkable module to
phosphor-ipmi-host allows the remaining OEM functionality to be
inserted into the phosphor-ipmi-host shared object.
Tested:
Side by side comparison of the SDR dump
Spot checks of sensor lists
Confirmed SEL data is still sent to /var/log/redfish
Change-Id: I1a15208e38fa77df71a06740d66e6ab359508b80
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/src/sensorcommands.cpp b/src/sensorcommands.cpp
index 997875c..6b74dea 100644
--- a/src/sensorcommands.cpp
+++ b/src/sensorcommands.cpp
@@ -14,14 +14,7 @@
// limitations under the License.
*/
-#include "sensorcommands.hpp"
-
-#include "commandutils.hpp"
#include "ipmi_to_redfish_hooks.hpp"
-#include "sdrutils.hpp"
-#include "sensorutils.hpp"
-#include "storagecommands.hpp"
-#include "types.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/container/flat_map.hpp>
@@ -32,247 +25,17 @@
#include <algorithm>
#include <array>
-#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstring>
-#include <iostream>
-#include <map>
#include <memory>
#include <optional>
-#include <stdexcept>
#include <string>
-#include <utility>
-#include <variant>
namespace ipmi
{
-using ManagedObjectType =
- std::map<sdbusplus::message::object_path,
- std::map<std::string, std::map<std::string, DbusVariant>>>;
-
-static constexpr int sensorMapUpdatePeriod = 10;
-static constexpr int sensorMapSdrUpdatePeriod = 60;
-
-constexpr size_t maxSDRTotalSize =
- 76; // Largest SDR Record Size (type 01) + SDR Overheader Size
-constexpr static const uint32_t noTimestamp = 0xFFFFFFFF;
-
-static uint16_t sdrReservationID;
-static uint32_t sdrLastAdd = noTimestamp;
-static uint32_t sdrLastRemove = noTimestamp;
-static constexpr size_t lastRecordIndex = 0xFFFF;
-
-// The IPMI spec defines four Logical Units (LUN), each capable of supporting
-// 255 sensors. The 256 values assigned to LUN 2 are special and are not used
-// for general purpose sensors. Each LUN reserves location 0xFF. The maximum
-// number of IPMI sensors are LUN 0 + LUN 1 + LUN 2, less the reserved
-// location.
-static constexpr size_t maxIPMISensors = ((3 * 256) - (3 * 1));
-
-static constexpr size_t lun0MaxSensorNum = 0xfe;
-static constexpr size_t lun1MaxSensorNum = 0x1fe;
-static constexpr size_t lun3MaxSensorNum = 0x3fe;
-static constexpr int GENERAL_ERROR = -1;
-
-SensorSubTree sensorTree;
-
-static boost::container::flat_map<std::string, ManagedObjectType> SensorCache;
-
-constexpr static std::array<std::pair<const char*, SensorUnits>, 5> sensorUnits{
- {{"temperature", SensorUnits::degreesC},
- {"voltage", SensorUnits::volts},
- {"current", SensorUnits::amps},
- {"fan_tach", SensorUnits::rpm},
- {"power", SensorUnits::watts}}};
-
void registerSensorFunctions() __attribute__((constructor));
-static sdbusplus::bus::match_t sensorAdded(
- *getSdBus(),
- "type='signal',member='InterfacesAdded',arg0path='/xyz/openbmc_project/"
- "sensors/'",
- [](sdbusplus::message_t&) {
- sensorTree.clear();
- sdrLastAdd = std::chrono::duration_cast<std::chrono::seconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
- });
-
-static sdbusplus::bus::match_t sensorRemoved(
- *getSdBus(),
- "type='signal',member='InterfacesRemoved',arg0path='/xyz/openbmc_project/"
- "sensors/'",
- [](sdbusplus::message_t&) {
- sensorTree.clear();
- sdrLastRemove = std::chrono::duration_cast<std::chrono::seconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
- });
-
-// this keeps track of deassertions for sensor event status command. A
-// deasertion can only happen if an assertion was seen first.
-static boost::container::flat_map<
- std::string, boost::container::flat_map<std::string, std::optional<bool>>>
- thresholdDeassertMap;
-
-static sdbusplus::bus::match_t thresholdChanged(
- *getSdBus(),
- "type='signal',member='PropertiesChanged',interface='org.freedesktop.DBus."
- "Properties',arg0namespace='xyz.openbmc_project.Sensor.Threshold'",
- [](sdbusplus::message_t& m) {
- boost::container::flat_map<std::string, ipmi::DbusVariant> values;
- m.read(std::string(), values);
-
- auto findAssert =
- std::find_if(values.begin(), values.end(), [](const auto& pair) {
- return pair.first.find("Alarm") != std::string::npos;
- });
- if (findAssert != values.end())
- {
- auto ptr = std::get_if<bool>(&(findAssert->second));
- if (ptr == nullptr)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "thresholdChanged: Assert non bool");
- return;
- }
- if (*ptr)
- {
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "thresholdChanged: Assert",
- phosphor::logging::entry("SENSOR=%s", m.get_path()));
- thresholdDeassertMap[m.get_path()][findAssert->first] = *ptr;
- }
- else
- {
- auto& value =
- thresholdDeassertMap[m.get_path()][findAssert->first];
- if (value)
- {
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "thresholdChanged: deassert",
- phosphor::logging::entry("SENSOR=%s", m.get_path()));
- value = *ptr;
- }
- }
- }
- });
-
-static void getSensorMaxMin(const SensorMap& sensorMap, double& max,
- double& min)
-{
- max = 127;
- min = -128;
-
- auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
- auto critical =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
- auto warning =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
-
- if (sensorObject != sensorMap.end())
- {
- auto maxMap = sensorObject->second.find("MaxValue");
- auto minMap = sensorObject->second.find("MinValue");
-
- if (maxMap != sensorObject->second.end())
- {
- max = std::visit(VariantToDoubleVisitor(), maxMap->second);
- }
- if (minMap != sensorObject->second.end())
- {
- min = std::visit(VariantToDoubleVisitor(), minMap->second);
- }
- }
- if (critical != sensorMap.end())
- {
- auto lower = critical->second.find("CriticalLow");
- auto upper = critical->second.find("CriticalHigh");
- if (lower != critical->second.end())
- {
- double value = std::visit(VariantToDoubleVisitor(), lower->second);
- min = std::fmin(value, min);
- }
- if (upper != critical->second.end())
- {
- double value = std::visit(VariantToDoubleVisitor(), upper->second);
- max = std::fmax(value, max);
- }
- }
- if (warning != sensorMap.end())
- {
- auto lower = warning->second.find("WarningLow");
- auto upper = warning->second.find("WarningHigh");
- if (lower != warning->second.end())
- {
- double value = std::visit(VariantToDoubleVisitor(), lower->second);
- min = std::fmin(value, min);
- }
- if (upper != warning->second.end())
- {
- double value = std::visit(VariantToDoubleVisitor(), upper->second);
- max = std::fmax(value, max);
- }
- }
-}
-
-static bool getSensorMap(boost::asio::yield_context yield,
- std::string sensorConnection, std::string sensorPath,
- SensorMap& sensorMap,
- int updatePeriod = sensorMapUpdatePeriod)
-{
- static boost::container::flat_map<
- std::string, std::chrono::time_point<std::chrono::steady_clock>>
- updateTimeMap;
-
- auto updateFind = updateTimeMap.find(sensorConnection);
- auto lastUpdate = std::chrono::time_point<std::chrono::steady_clock>();
- if (updateFind != updateTimeMap.end())
- {
- lastUpdate = updateFind->second;
- }
-
- auto now = std::chrono::steady_clock::now();
-
- if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate)
- .count() > updatePeriod)
- {
- std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
- boost::system::error_code ec;
- auto managedObjects = dbus->yield_method_call<ManagedObjectType>(
- yield, ec, sensorConnection.c_str(), "/xyz/openbmc_project/sensors",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "GetMangagedObjects for getSensorMap failed",
- phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
-
- return false;
- }
-
- SensorCache[sensorConnection] = managedObjects;
- // Update time after finish building the map which allow the
- // data to be cached for updatePeriod plus the build time.
- updateTimeMap[sensorConnection] = std::chrono::steady_clock::now();
- }
- auto connection = SensorCache.find(sensorConnection);
- if (connection == SensorCache.end())
- {
- return false;
- }
- auto path = connection->second.find(sensorPath);
- if (path == connection->second.end())
- {
- return false;
- }
- sensorMap = path->second;
-
- return true;
-}
-
-/* sensor commands */
namespace meHealth
{
constexpr const char* busname = "xyz.openbmc_project.NodeManagerProxy";
@@ -422,1471 +185,11 @@
return ipmi::responseSuccess();
}
-ipmi::RspType<uint8_t, uint8_t, uint8_t, std::optional<uint8_t>>
- ipmiSenGetSensorReading(ipmi::Context::ptr ctx, uint8_t sensnum)
-{
- std::string connection;
- std::string path;
-
- if (sensnum == reservedSensorNumber)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- auto status = getSensorConnection(ctx, sensnum, connection, path);
- if (status)
- {
- return ipmi::response(status);
- }
-
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap))
- {
- return ipmi::responseResponseError();
- }
- auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
-
- if (sensorObject == sensorMap.end() ||
- sensorObject->second.find("Value") == sensorObject->second.end())
- {
- return ipmi::responseResponseError();
- }
- auto& valueVariant = sensorObject->second["Value"];
- double reading = std::visit(VariantToDoubleVisitor(), valueVariant);
-
- double max = 0;
- double min = 0;
- getSensorMaxMin(sensorMap, max, min);
-
- int16_t mValue = 0;
- int16_t bValue = 0;
- int8_t rExp = 0;
- int8_t bExp = 0;
- bool bSigned = false;
-
- if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
- {
- return ipmi::responseResponseError();
- }
-
- uint8_t value =
- scaleIPMIValueFromDouble(reading, mValue, rExp, bValue, bExp, bSigned);
- uint8_t operation =
- static_cast<uint8_t>(IPMISensorReadingByte2::sensorScanningEnable);
- operation |=
- static_cast<uint8_t>(IPMISensorReadingByte2::eventMessagesEnable);
- bool notReading = std::isnan(reading);
-
- if (!notReading)
- {
- auto availableObject =
- sensorMap.find("xyz.openbmc_project.State.Decorator.Availability");
- if (availableObject != sensorMap.end())
- {
- auto findAvailable = availableObject->second.find("Available");
- if (findAvailable != availableObject->second.end())
- {
- bool* available = std::get_if<bool>(&(findAvailable->second));
- if (available && !(*available))
- {
- notReading = true;
- }
- }
- }
- }
-
- if (notReading)
- {
- operation |= static_cast<uint8_t>(
- IPMISensorReadingByte2::readingStateUnavailable);
- }
-
- int byteValue;
- if (bSigned)
- {
- byteValue = static_cast<int>(static_cast<int8_t>(value));
- }
- else
- {
- byteValue = static_cast<int>(static_cast<uint8_t>(value));
- }
-
- // Keep stats on the reading just obtained, even if it is "NaN"
- if (details::sdrStatsTable.updateReading(sensnum, reading, byteValue))
- {
- // This is the first reading, show the coefficients
- double step = (max - min) / 255.0;
- std::cerr << "IPMI sensor " << details::sdrStatsTable.getName(sensnum)
- << ": Range min=" << min << " max=" << max
- << ", step=" << step
- << ", Coefficients mValue=" << static_cast<int>(mValue)
- << " rExp=" << static_cast<int>(rExp)
- << " bValue=" << static_cast<int>(bValue)
- << " bExp=" << static_cast<int>(bExp)
- << " bSigned=" << static_cast<int>(bSigned) << "\n";
- };
-
- uint8_t thresholds = 0;
-
- auto warningObject =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
- if (warningObject != sensorMap.end())
- {
- auto alarmHigh = warningObject->second.find("WarningAlarmHigh");
- auto alarmLow = warningObject->second.find("WarningAlarmLow");
- if (alarmHigh != warningObject->second.end())
- {
- if (std::get<bool>(alarmHigh->second))
- {
- thresholds |= static_cast<uint8_t>(
- IPMISensorReadingByte3::upperNonCritical);
- }
- }
- if (alarmLow != warningObject->second.end())
- {
- if (std::get<bool>(alarmLow->second))
- {
- thresholds |= static_cast<uint8_t>(
- IPMISensorReadingByte3::lowerNonCritical);
- }
- }
- }
-
- auto criticalObject =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
- if (criticalObject != sensorMap.end())
- {
- auto alarmHigh = criticalObject->second.find("CriticalAlarmHigh");
- auto alarmLow = criticalObject->second.find("CriticalAlarmLow");
- if (alarmHigh != criticalObject->second.end())
- {
- if (std::get<bool>(alarmHigh->second))
- {
- thresholds |=
- static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
- }
- }
- if (alarmLow != criticalObject->second.end())
- {
- if (std::get<bool>(alarmLow->second))
- {
- thresholds |=
- static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
- }
- }
- }
-
- // no discrete as of today so optional byte is never returned
- return ipmi::responseSuccess(value, operation, thresholds, std::nullopt);
-}
-
-/** @brief implements the Set Sensor threshold command
- * @param sensorNumber - sensor number
- * @param lowerNonCriticalThreshMask
- * @param lowerCriticalThreshMask
- * @param lowerNonRecovThreshMask
- * @param upperNonCriticalThreshMask
- * @param upperCriticalThreshMask
- * @param upperNonRecovThreshMask
- * @param reserved
- * @param lowerNonCritical - lower non-critical threshold
- * @param lowerCritical - Lower critical threshold
- * @param lowerNonRecoverable - Lower non recovarable threshold
- * @param upperNonCritical - Upper non-critical threshold
- * @param upperCritical - Upper critical
- * @param upperNonRecoverable - Upper Non-recoverable
- *
- * @returns IPMI completion code
- */
-ipmi::RspType<> ipmiSenSetSensorThresholds(
- ipmi::Context::ptr ctx, uint8_t sensorNum, bool lowerNonCriticalThreshMask,
- bool lowerCriticalThreshMask, bool lowerNonRecovThreshMask,
- bool upperNonCriticalThreshMask, bool upperCriticalThreshMask,
- bool upperNonRecovThreshMask, uint2_t reserved, uint8_t lowerNonCritical,
- uint8_t lowerCritical, [[maybe_unused]] uint8_t lowerNonRecoverable,
- uint8_t upperNonCritical, uint8_t upperCritical,
- [[maybe_unused]] uint8_t upperNonRecoverable)
-{
- if (sensorNum == reservedSensorNumber)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- if (reserved)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- // lower nc and upper nc not suppported on any sensor
- if (lowerNonRecovThreshMask || upperNonRecovThreshMask)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- // if none of the threshold mask are set, nothing to do
- if (!(lowerNonCriticalThreshMask | lowerCriticalThreshMask |
- lowerNonRecovThreshMask | upperNonCriticalThreshMask |
- upperCriticalThreshMask | upperNonRecovThreshMask))
- {
- return ipmi::responseSuccess();
- }
-
- std::string connection;
- std::string path;
-
- ipmi::Cc status = getSensorConnection(ctx, sensorNum, connection, path);
- if (status)
- {
- return ipmi::response(status);
- }
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap))
- {
- return ipmi::responseResponseError();
- }
-
- double max = 0;
- double min = 0;
- getSensorMaxMin(sensorMap, max, min);
-
- int16_t mValue = 0;
- int16_t bValue = 0;
- int8_t rExp = 0;
- int8_t bExp = 0;
- bool bSigned = false;
-
- if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
- {
- return ipmi::responseResponseError();
- }
-
- // store a vector of property name, value to set, and interface
- std::vector<std::tuple<std::string, uint8_t, std::string>> thresholdsToSet;
-
- // define the indexes of the tuple
- constexpr uint8_t propertyName = 0;
- constexpr uint8_t thresholdValue = 1;
- constexpr uint8_t interface = 2;
- // verifiy all needed fields are present
- if (lowerCriticalThreshMask || upperCriticalThreshMask)
- {
- auto findThreshold =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
- if (findThreshold == sensorMap.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- if (lowerCriticalThreshMask)
- {
- auto findLower = findThreshold->second.find("CriticalLow");
- if (findLower == findThreshold->second.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- thresholdsToSet.emplace_back("CriticalLow", lowerCritical,
- findThreshold->first);
- }
- if (upperCriticalThreshMask)
- {
- auto findUpper = findThreshold->second.find("CriticalHigh");
- if (findUpper == findThreshold->second.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- thresholdsToSet.emplace_back("CriticalHigh", upperCritical,
- findThreshold->first);
- }
- }
- if (lowerNonCriticalThreshMask || upperNonCriticalThreshMask)
- {
- auto findThreshold =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
- if (findThreshold == sensorMap.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- if (lowerNonCriticalThreshMask)
- {
- auto findLower = findThreshold->second.find("WarningLow");
- if (findLower == findThreshold->second.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- thresholdsToSet.emplace_back("WarningLow", lowerNonCritical,
- findThreshold->first);
- }
- if (upperNonCriticalThreshMask)
- {
- auto findUpper = findThreshold->second.find("WarningHigh");
- if (findUpper == findThreshold->second.end())
- {
- return ipmi::responseInvalidFieldRequest();
- }
- thresholdsToSet.emplace_back("WarningHigh", upperNonCritical,
- findThreshold->first);
- }
- }
- for (const auto& property : thresholdsToSet)
- {
- // from section 36.3 in the IPMI Spec, assume all linear
- double valueToSet = ((mValue * std::get<thresholdValue>(property)) +
- (bValue * std::pow(10.0, bExp))) *
- std::pow(10.0, rExp);
- setDbusProperty(
- *getSdBus(), connection, path, std::get<interface>(property),
- std::get<propertyName>(property), ipmi::Value(valueToSet));
- }
- return ipmi::responseSuccess();
-}
-
-IPMIThresholds getIPMIThresholds(const SensorMap& sensorMap)
-{
- IPMIThresholds resp;
- auto warningInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
- auto criticalInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
-
- if ((warningInterface != sensorMap.end()) ||
- (criticalInterface != sensorMap.end()))
- {
- auto sensorPair = sensorMap.find("xyz.openbmc_project.Sensor.Value");
-
- if (sensorPair == sensorMap.end())
- {
- // should not have been able to find a sensor not implementing
- // the sensor object
- throw std::runtime_error("Invalid sensor map");
- }
-
- double max = 0;
- double min = 0;
- getSensorMaxMin(sensorMap, max, min);
-
- int16_t mValue = 0;
- int16_t bValue = 0;
- int8_t rExp = 0;
- int8_t bExp = 0;
- bool bSigned = false;
-
- if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
- {
- throw std::runtime_error("Invalid sensor atrributes");
- }
- if (warningInterface != sensorMap.end())
- {
- auto& warningMap = warningInterface->second;
-
- auto warningHigh = warningMap.find("WarningHigh");
- auto warningLow = warningMap.find("WarningLow");
-
- if (warningHigh != warningMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), warningHigh->second);
- if (std::isfinite(value))
- {
- resp.warningHigh = scaleIPMIValueFromDouble(
- value, mValue, rExp, bValue, bExp, bSigned);
- }
- }
- if (warningLow != warningMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), warningLow->second);
- if (std::isfinite(value))
- {
- resp.warningLow = scaleIPMIValueFromDouble(
- value, mValue, rExp, bValue, bExp, bSigned);
- }
- }
- }
- if (criticalInterface != sensorMap.end())
- {
- auto& criticalMap = criticalInterface->second;
-
- auto criticalHigh = criticalMap.find("CriticalHigh");
- auto criticalLow = criticalMap.find("CriticalLow");
-
- if (criticalHigh != criticalMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), criticalHigh->second);
- if (std::isfinite(value))
- {
- resp.criticalHigh = scaleIPMIValueFromDouble(
- value, mValue, rExp, bValue, bExp, bSigned);
- }
- }
- if (criticalLow != criticalMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), criticalLow->second);
- if (std::isfinite(value))
- {
- resp.criticalLow = scaleIPMIValueFromDouble(
- value, mValue, rExp, bValue, bExp, bSigned);
- }
- }
- }
- }
- return resp;
-}
-
-ipmi::RspType<uint8_t, // readable
- uint8_t, // lowerNCrit
- uint8_t, // lowerCrit
- uint8_t, // lowerNrecoverable
- uint8_t, // upperNC
- uint8_t, // upperCrit
- uint8_t> // upperNRecoverable
- ipmiSenGetSensorThresholds(ipmi::Context::ptr ctx, uint8_t sensorNumber)
-{
- std::string connection;
- std::string path;
-
- if (sensorNumber == reservedSensorNumber)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- auto status = getSensorConnection(ctx, sensorNumber, connection, path);
- if (status)
- {
- return ipmi::response(status);
- }
-
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap))
- {
- return ipmi::responseResponseError();
- }
-
- IPMIThresholds thresholdData;
- try
- {
- thresholdData = getIPMIThresholds(sensorMap);
- }
- catch (const std::exception&)
- {
- return ipmi::responseResponseError();
- }
-
- uint8_t readable = 0;
- uint8_t lowerNC = 0;
- uint8_t lowerCritical = 0;
- uint8_t lowerNonRecoverable = 0;
- uint8_t upperNC = 0;
- uint8_t upperCritical = 0;
- uint8_t upperNonRecoverable = 0;
-
- if (thresholdData.warningHigh)
- {
- readable |=
- 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperNonCritical);
- upperNC = *thresholdData.warningHigh;
- }
- if (thresholdData.warningLow)
- {
- readable |=
- 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerNonCritical);
- lowerNC = *thresholdData.warningLow;
- }
-
- if (thresholdData.criticalHigh)
- {
- readable |=
- 1 << static_cast<uint8_t>(IPMIThresholdRespBits::upperCritical);
- upperCritical = *thresholdData.criticalHigh;
- }
- if (thresholdData.criticalLow)
- {
- readable |=
- 1 << static_cast<uint8_t>(IPMIThresholdRespBits::lowerCritical);
- lowerCritical = *thresholdData.criticalLow;
- }
-
- return ipmi::responseSuccess(readable, lowerNC, lowerCritical,
- lowerNonRecoverable, upperNC, upperCritical,
- upperNonRecoverable);
-}
-
-/** @brief implements the get Sensor event enable command
- * @param sensorNumber - sensor number
- *
- * @returns IPMI completion code plus response data
- * - enabled - Sensor Event messages
- * - assertionEnabledLsb - Assertion event messages
- * - assertionEnabledMsb - Assertion event messages
- * - deassertionEnabledLsb - Deassertion event messages
- * - deassertionEnabledMsb - Deassertion event messages
- */
-
-ipmi::RspType<uint8_t, // enabled
- uint8_t, // assertionEnabledLsb
- uint8_t, // assertionEnabledMsb
- uint8_t, // deassertionEnabledLsb
- uint8_t> // deassertionEnabledMsb
- ipmiSenGetSensorEventEnable(ipmi::Context::ptr ctx, uint8_t sensorNum)
-{
- std::string connection;
- std::string path;
-
- uint8_t enabled = 0;
- uint8_t assertionEnabledLsb = 0;
- uint8_t assertionEnabledMsb = 0;
- uint8_t deassertionEnabledLsb = 0;
- uint8_t deassertionEnabledMsb = 0;
-
- if (sensorNum == reservedSensorNumber)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- auto status = getSensorConnection(ctx, sensorNum, connection, path);
- if (status)
- {
- return ipmi::response(status);
- }
-
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap))
- {
- return ipmi::responseResponseError();
- }
-
- auto warningInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
- auto criticalInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
- if ((warningInterface != sensorMap.end()) ||
- (criticalInterface != sensorMap.end()))
- {
- enabled = static_cast<uint8_t>(
- IPMISensorEventEnableByte2::sensorScanningEnable);
- if (warningInterface != sensorMap.end())
- {
- auto& warningMap = warningInterface->second;
-
- auto warningHigh = warningMap.find("WarningHigh");
- auto warningLow = warningMap.find("WarningLow");
- if (warningHigh != warningMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), warningHigh->second);
- if (std::isfinite(value))
- {
- assertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- upperNonCriticalGoingHigh);
- deassertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- upperNonCriticalGoingLow);
- }
- }
- if (warningLow != warningMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), warningLow->second);
- if (std::isfinite(value))
- {
- assertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- lowerNonCriticalGoingLow);
- deassertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- lowerNonCriticalGoingHigh);
- }
- }
- }
- if (criticalInterface != sensorMap.end())
- {
- auto& criticalMap = criticalInterface->second;
-
- auto criticalHigh = criticalMap.find("CriticalHigh");
- auto criticalLow = criticalMap.find("CriticalLow");
-
- if (criticalHigh != criticalMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), criticalHigh->second);
- if (std::isfinite(value))
- {
- assertionEnabledMsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- upperCriticalGoingHigh);
- deassertionEnabledMsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::upperCriticalGoingLow);
- }
- }
- if (criticalLow != criticalMap.end())
- {
- double value =
- std::visit(VariantToDoubleVisitor(), criticalLow->second);
- if (std::isfinite(value))
- {
- assertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
- deassertionEnabledLsb |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::
- lowerCriticalGoingHigh);
- }
- }
- }
- }
-
- return ipmi::responseSuccess(enabled, assertionEnabledLsb,
- assertionEnabledMsb, deassertionEnabledLsb,
- deassertionEnabledMsb);
-}
-
-/** @brief implements the get Sensor event status command
- * @param sensorNumber - sensor number, FFh = reserved
- *
- * @returns IPMI completion code plus response data
- * - sensorEventStatus - Sensor Event messages state
- * - assertions - Assertion event messages
- * - deassertions - Deassertion event messages
- */
-ipmi::RspType<uint8_t, // sensorEventStatus
- std::bitset<16>, // assertions
- std::bitset<16> // deassertion
- >
- ipmiSenGetSensorEventStatus(ipmi::Context::ptr ctx, uint8_t sensorNum)
-{
- if (sensorNum == reservedSensorNumber)
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- std::string connection;
- std::string path;
- auto status = getSensorConnection(ctx, sensorNum, connection, path);
- if (status)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiSenGetSensorEventStatus: Sensor connection Error",
- phosphor::logging::entry("SENSOR=%d", sensorNum));
- return ipmi::response(status);
- }
-
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiSenGetSensorEventStatus: Sensor Mapping Error",
- phosphor::logging::entry("SENSOR=%s", path.c_str()));
- return ipmi::responseResponseError();
- }
- auto warningInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Warning");
- auto criticalInterface =
- sensorMap.find("xyz.openbmc_project.Sensor.Threshold.Critical");
-
- uint8_t sensorEventStatus =
- static_cast<uint8_t>(IPMISensorEventEnableByte2::sensorScanningEnable);
-
- std::optional<bool> criticalDeassertHigh =
- thresholdDeassertMap[path]["CriticalAlarmHigh"];
- std::optional<bool> criticalDeassertLow =
- thresholdDeassertMap[path]["CriticalAlarmLow"];
- std::optional<bool> warningDeassertHigh =
- thresholdDeassertMap[path]["WarningAlarmHigh"];
- std::optional<bool> warningDeassertLow =
- thresholdDeassertMap[path]["WarningAlarmLow"];
-
- std::bitset<16> assertions = 0;
- std::bitset<16> deassertions = 0;
-
- if (criticalDeassertHigh && !*criticalDeassertHigh)
- {
- deassertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::upperCriticalGoingHigh));
- }
- if (criticalDeassertLow && !*criticalDeassertLow)
- {
- deassertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::upperCriticalGoingLow));
- }
- if (warningDeassertHigh && !*warningDeassertHigh)
- {
- deassertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::upperNonCriticalGoingHigh));
- }
- if (warningDeassertLow && !*warningDeassertLow)
- {
- deassertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::lowerNonCriticalGoingHigh));
- }
- if ((warningInterface != sensorMap.end()) ||
- (criticalInterface != sensorMap.end()))
- {
- sensorEventStatus = static_cast<size_t>(
- IPMISensorEventEnableByte2::eventMessagesEnable);
- if (warningInterface != sensorMap.end())
- {
- auto& warningMap = warningInterface->second;
-
- auto warningHigh = warningMap.find("WarningAlarmHigh");
- auto warningLow = warningMap.find("WarningAlarmLow");
- auto warningHighAlarm = false;
- auto warningLowAlarm = false;
-
- if (warningHigh != warningMap.end())
- {
- warningHighAlarm = std::get<bool>(warningHigh->second);
- }
- if (warningLow != warningMap.end())
- {
- warningLowAlarm = std::get<bool>(warningLow->second);
- }
- if (warningHighAlarm)
- {
- assertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::
- upperNonCriticalGoingHigh));
- }
- if (warningLowAlarm)
- {
- assertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::
- lowerNonCriticalGoingLow));
- }
- }
- if (criticalInterface != sensorMap.end())
- {
- auto& criticalMap = criticalInterface->second;
-
- auto criticalHigh = criticalMap.find("CriticalAlarmHigh");
- auto criticalLow = criticalMap.find("CriticalAlarmLow");
- auto criticalHighAlarm = false;
- auto criticalLowAlarm = false;
-
- if (criticalHigh != criticalMap.end())
- {
- criticalHighAlarm = std::get<bool>(criticalHigh->second);
- }
- if (criticalLow != criticalMap.end())
- {
- criticalLowAlarm = std::get<bool>(criticalLow->second);
- }
- if (criticalHighAlarm)
- {
- assertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::
- upperCriticalGoingHigh));
- }
- if (criticalLowAlarm)
- {
- assertions.set(static_cast<size_t>(
- IPMIGetSensorEventEnableThresholds::lowerCriticalGoingLow));
- }
- }
- }
-
- return ipmi::responseSuccess(sensorEventStatus, assertions, deassertions);
-}
-
-static inline uint16_t getNumberOfSensors(void)
-{
- return sensorTree.size() > maxIPMISensors ? maxIPMISensors
- : sensorTree.size();
-}
-
-static int getSensorDataRecord(ipmi::Context::ptr ctx,
- std::vector<uint8_t>& recordData,
- uint16_t recordID)
-{
- size_t fruCount = 0;
- ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
- if (ret != ipmi::ccSuccess)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: getFruSdrCount error");
- return GENERAL_ERROR;
- }
-
- size_t lastRecord =
- getNumberOfSensors() + fruCount + ipmi::storage::type12Count +
- ipmi::storage::nmDiscoverySDRCount - 1;
- if (recordID == lastRecordIndex)
- {
- recordID = lastRecord;
- }
- if (recordID > lastRecord)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: recordID > lastRecord error");
- return GENERAL_ERROR;
- }
-
- if (recordID >= getNumberOfSensors())
- {
- size_t fruIndex = recordID - getNumberOfSensors();
- size_t type12End = fruCount + ipmi::storage::type12Count;
-
- if (fruIndex >= type12End)
- {
- // NM discovery SDR
- size_t nmDiscoveryIndex = fruIndex - type12End;
- if (nmDiscoveryIndex >= ipmi::storage::nmDiscoverySDRCount)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: NM DiscoveryIndex error");
- return GENERAL_ERROR;
- }
- recordData =
- ipmi::storage::getNMDiscoverySDR(nmDiscoveryIndex, recordID);
- }
- else if (fruIndex >= fruCount)
- {
- // handle type 12 hardcoded records
- size_t type12Index = fruIndex - fruCount;
- if (type12Index >= ipmi::storage::type12Count)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: type12Index error");
- return GENERAL_ERROR;
- }
- recordData = ipmi::storage::getType12SDRs(type12Index, recordID);
- }
- else
- {
- // handle fru records
- get_sdr::SensorDataFruRecord data;
- ret = ipmi::storage::getFruSdrs(ctx, fruIndex, data);
- if (ret != IPMI_CC_OK)
- {
- return GENERAL_ERROR;
- }
- data.header.record_id_msb = recordID >> 8;
- data.header.record_id_lsb = recordID & 0xFF;
- recordData.insert(recordData.end(), (uint8_t*)&data,
- ((uint8_t*)&data) + sizeof(data));
- }
-
- return 0;
- }
-
- // Perform a incremental scan of the SDR Record ID's and translate the
- // first 765 SDR records (i.e. maxIPMISensors) into IPMI Sensor
- // Numbers. The IPMI sensor numbers are not linear, and have a reserved
- // gap at 0xff. This code creates 254 sensors per LUN, excepting LUN 2
- // which has special meaning.
- std::string connection;
- std::string path;
- uint16_t sensNumFromRecID{recordID};
- if ((recordID > lun0MaxSensorNum) && (recordID < lun1MaxSensorNum))
- {
- // LUN 0 has one reserved sensor number. Compensate here by adding one
- // to the record ID
- sensNumFromRecID = recordID + 1;
- ctx->lun = 1;
- }
- else if ((recordID >= lun1MaxSensorNum) && (recordID < maxIPMISensors))
- {
- // LUN 0, 1 have a reserved sensor number. Compensate here by adding 2
- // to the record ID. Skip all 256 sensors in LUN 2, as it has special
- // rules governing its use.
- sensNumFromRecID = recordID + (maxSensorsPerLUN + 1) + 2;
- ctx->lun = 3;
- }
-
- auto status = getSensorConnection(
- ctx, static_cast<uint8_t>(sensNumFromRecID), connection, path);
- if (status)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: getSensorConnection error");
- return GENERAL_ERROR;
- }
- SensorMap sensorMap;
- if (!getSensorMap(ctx->yield, connection, path, sensorMap,
- sensorMapUpdatePeriod))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: getSensorMap error");
- return GENERAL_ERROR;
- }
- uint16_t sensorNum = getSensorNumberFromPath(path);
- // Return an error on LUN 2 assingments, and any sensor number beyond the
- // range of LUN 3
- if (((sensorNum > lun1MaxSensorNum) && (sensorNum <= maxIPMISensors)) ||
- (sensorNum > lun3MaxSensorNum))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: invalidSensorNumber");
- return GENERAL_ERROR;
- }
- uint8_t sensornumber = static_cast<uint8_t>(sensorNum);
- uint8_t lun = static_cast<uint8_t>(sensorNum >> 8);
-
- if ((sensornumber != static_cast<uint8_t>(sensNumFromRecID)) &&
- (lun != ctx->lun))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: sensor record mismatch");
- return GENERAL_ERROR;
- }
- get_sdr::SensorDataFullRecord record = {{}, {}, {}};
-
- get_sdr::header::set_record_id(
- recordID, reinterpret_cast<get_sdr::SensorDataRecordHeader*>(&record));
-
- record.header.sdr_version = ipmiSdrVersion;
- record.header.record_type = get_sdr::SENSOR_DATA_FULL_RECORD;
- record.header.record_length = sizeof(get_sdr::SensorDataFullRecord) -
- sizeof(get_sdr::SensorDataRecordHeader);
- record.key.owner_id = 0x20;
- record.key.owner_lun = lun;
- record.key.sensor_number = sensornumber;
-
- record.body.sensor_capabilities = 0x68; // auto rearm - todo hysteresis
- record.body.sensor_type = getSensorTypeFromPath(path);
- std::string type = getSensorTypeStringFromPath(path);
- for (const auto& [unitsType, units] : sensorUnits)
- {
- if (type == unitsType)
- {
- record.body.sensor_units_2_base = static_cast<uint8_t>(units);
- }
- }
-
- record.body.event_reading_type = getSensorEventTypeFromPath(path);
-
- auto sensorObject = sensorMap.find("xyz.openbmc_project.Sensor.Value");
- if (sensorObject == sensorMap.end())
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: sensorObject error");
- return GENERAL_ERROR;
- }
-
- uint8_t entityId = 0;
- uint8_t entityInstance = 0x01;
-
- // follow the association chain to get the parent board's entityid and
- // entityInstance
- updateIpmiFromAssociation(path, sensorMap, entityId, entityInstance);
-
- record.body.entity_id = entityId;
- record.body.entity_instance = entityInstance;
-
- auto maxObject = sensorObject->second.find("MaxValue");
- auto minObject = sensorObject->second.find("MinValue");
-
- // If min and/or max are left unpopulated,
- // then default to what a signed byte would be, namely (-128,127) range.
- auto max = static_cast<double>(std::numeric_limits<int8_t>::max());
- auto min = static_cast<double>(std::numeric_limits<int8_t>::lowest());
- if (maxObject != sensorObject->second.end())
- {
- max = std::visit(VariantToDoubleVisitor(), maxObject->second);
- }
-
- if (minObject != sensorObject->second.end())
- {
- min = std::visit(VariantToDoubleVisitor(), minObject->second);
- }
-
- int16_t mValue = 0;
- int8_t rExp = 0;
- int16_t bValue = 0;
- int8_t bExp = 0;
- bool bSigned = false;
-
- if (!getSensorAttributes(max, min, mValue, rExp, bValue, bExp, bSigned))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: getSensorAttributes error");
- return GENERAL_ERROR;
- }
-
- // The record.body is a struct SensorDataFullRecordBody
- // from sensorhandler.hpp in phosphor-ipmi-host.
- // The meaning of these bits appears to come from
- // table 43.1 of the IPMI spec.
- // The above 5 sensor attributes are stuffed in as follows:
- // Byte 21 = AA000000 = analog interpretation, 10 signed, 00 unsigned
- // Byte 22-24 are for other purposes
- // Byte 25 = MMMMMMMM = LSB of M
- // Byte 26 = MMTTTTTT = MSB of M (signed), and Tolerance
- // Byte 27 = BBBBBBBB = LSB of B
- // Byte 28 = BBAAAAAA = MSB of B (signed), and LSB of Accuracy
- // Byte 29 = AAAAEE00 = MSB of Accuracy, exponent of Accuracy
- // Byte 30 = RRRRBBBB = rExp (signed), bExp (signed)
-
- // apply M, B, and exponents, M and B are 10 bit values, exponents are 4
- record.body.m_lsb = mValue & 0xFF;
-
- uint8_t mBitSign = (mValue < 0) ? 1 : 0;
- uint8_t mBitNine = (mValue & 0x0100) >> 8;
-
- // move the smallest bit of the MSB into place (bit 9)
- // the MSbs are bits 7:8 in m_msb_and_tolerance
- record.body.m_msb_and_tolerance = (mBitSign << 7) | (mBitNine << 6);
-
- record.body.b_lsb = bValue & 0xFF;
-
- uint8_t bBitSign = (bValue < 0) ? 1 : 0;
- uint8_t bBitNine = (bValue & 0x0100) >> 8;
-
- // move the smallest bit of the MSB into place (bit 9)
- // the MSbs are bits 7:8 in b_msb_and_accuracy_lsb
- record.body.b_msb_and_accuracy_lsb = (bBitSign << 7) | (bBitNine << 6);
-
- uint8_t rExpSign = (rExp < 0) ? 1 : 0;
- uint8_t rExpBits = rExp & 0x07;
-
- uint8_t bExpSign = (bExp < 0) ? 1 : 0;
- uint8_t bExpBits = bExp & 0x07;
-
- // move rExp and bExp into place
- record.body.r_b_exponents =
- (rExpSign << 7) | (rExpBits << 4) | (bExpSign << 3) | bExpBits;
-
- // Set the analog reading byte interpretation accordingly
- record.body.sensor_units_1 = (bSigned ? 1 : 0) << 7;
-
- // TODO(): Perhaps care about Tolerance, Accuracy, and so on
- // These seem redundant, but derivable from the above 5 attributes
- // Original comment said "todo fill out rest of units"
-
- // populate sensor name from path
- std::string name;
- size_t nameStart = path.rfind("/");
- if (nameStart != std::string::npos)
- {
- name = path.substr(nameStart + 1, std::string::npos - nameStart);
- }
-
- std::replace(name.begin(), name.end(), '_', ' ');
- if (name.size() > FULL_RECORD_ID_STR_MAX_LENGTH)
- {
- // try to not truncate by replacing common words
- constexpr std::array<std::pair<const char*, const char*>, 2>
- replaceWords = {std::make_pair("Output", "Out"),
- std::make_pair("Input", "In")};
- for (const auto& [find, replace] : replaceWords)
- {
- boost::replace_all(name, find, replace);
- }
-
- name.resize(FULL_RECORD_ID_STR_MAX_LENGTH);
- }
- get_sdr::body::set_id_strlen(name.size(), &record.body);
- get_sdr::body::set_id_type(3, &record.body); // "8-bit ASCII + Latin 1"
- std::strncpy(record.body.id_string, name.c_str(),
- sizeof(record.body.id_string));
-
- // Remember the sensor name, as determined for this sensor number
- details::sdrStatsTable.updateName(sensornumber, name);
-
- IPMIThresholds thresholdData;
- try
- {
- thresholdData = getIPMIThresholds(sensorMap);
- }
- catch (const std::exception&)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "getSensorDataRecord: getIPMIThresholds error");
- return GENERAL_ERROR;
- }
-
- if (thresholdData.criticalHigh)
- {
- record.body.upper_critical_threshold = *thresholdData.criticalHigh;
- record.body.supported_deassertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::criticalThreshold);
- record.body.supported_deassertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
- record.body.supported_assertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::upperCriticalGoingHigh);
- record.body.discrete_reading_setting_mask[0] |=
- static_cast<uint8_t>(IPMISensorReadingByte3::upperCritical);
- }
- if (thresholdData.warningHigh)
- {
- record.body.upper_noncritical_threshold = *thresholdData.warningHigh;
- record.body.supported_deassertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::nonCriticalThreshold);
- record.body.supported_deassertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
- record.body.supported_assertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::upperNonCriticalGoingHigh);
- record.body.discrete_reading_setting_mask[0] |=
- static_cast<uint8_t>(IPMISensorReadingByte3::upperNonCritical);
- }
- if (thresholdData.criticalLow)
- {
- record.body.lower_critical_threshold = *thresholdData.criticalLow;
- record.body.supported_assertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::criticalThreshold);
- record.body.supported_deassertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
- record.body.supported_assertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::lowerCriticalGoingLow);
- record.body.discrete_reading_setting_mask[0] |=
- static_cast<uint8_t>(IPMISensorReadingByte3::lowerCritical);
- }
- if (thresholdData.warningLow)
- {
- record.body.lower_noncritical_threshold = *thresholdData.warningLow;
- record.body.supported_assertions[1] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::nonCriticalThreshold);
- record.body.supported_deassertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
- record.body.supported_assertions[0] |= static_cast<uint8_t>(
- IPMISensorEventEnableThresholds::lowerNonCriticalGoingLow);
- record.body.discrete_reading_setting_mask[0] |=
- static_cast<uint8_t>(IPMISensorReadingByte3::lowerNonCritical);
- }
-
- // everything that is readable is setable
- record.body.discrete_reading_setting_mask[1] =
- record.body.discrete_reading_setting_mask[0];
- recordData.insert(recordData.end(), (uint8_t*)&record,
- ((uint8_t*)&record) + sizeof(record));
- return 0;
-}
-
-/** @brief implements the get SDR Info command
- * @param count - Operation
- *
- * @returns IPMI completion code plus response data
- * - sdrCount - sensor/SDR count
- * - lunsAndDynamicPopulation - static/Dynamic sensor population flag
- */
-static ipmi::RspType<uint8_t, // respcount
- uint8_t, // dynamic population flags
- uint32_t // last time a sensor was added
- >
- ipmiSensorGetDeviceSdrInfo(ipmi::Context::ptr ctx,
- std::optional<uint8_t> count)
-{
- uint8_t sdrCount = 0;
- uint16_t recordID = 0;
- std::vector<uint8_t> record;
- // Sensors are dynamically allocated, and there is at least one LUN
- uint8_t lunsAndDynamicPopulation = 0x80;
- constexpr uint8_t getSdrCount = 0x01;
- constexpr uint8_t getSensorCount = 0x00;
-
- if (!getSensorSubtree(sensorTree) || sensorTree.empty())
- {
- return ipmi::responseResponseError();
- }
- uint16_t numSensors = getNumberOfSensors();
- if (count.value_or(0) == getSdrCount)
- {
- // Count the number of Type 1 SDR entries assigned to the LUN
- while (!getSensorDataRecord(ctx, record, recordID++))
- {
- get_sdr::SensorDataRecordHeader* hdr =
- reinterpret_cast<get_sdr::SensorDataRecordHeader*>(
- record.data());
- if (hdr->record_type == get_sdr::SENSOR_DATA_FULL_RECORD)
- {
- get_sdr::SensorDataFullRecord* recordData =
- reinterpret_cast<get_sdr::SensorDataFullRecord*>(
- record.data());
- if (ctx->lun == recordData->key.owner_lun)
- {
- sdrCount++;
- }
- }
- }
- }
- else if (count.value_or(0) == getSensorCount)
- {
- // Return the number of sensors attached to the LUN
- if ((ctx->lun == 0) && (numSensors > 0))
- {
- sdrCount =
- (numSensors > maxSensorsPerLUN) ? maxSensorsPerLUN : numSensors;
- }
- else if ((ctx->lun == 1) && (numSensors > maxSensorsPerLUN))
- {
- sdrCount = (numSensors > (2 * maxSensorsPerLUN))
- ? maxSensorsPerLUN
- : (numSensors - maxSensorsPerLUN) & maxSensorsPerLUN;
- }
- else if (ctx->lun == 3)
- {
- if (numSensors <= maxIPMISensors)
- {
- sdrCount = (numSensors - (2 * maxSensorsPerLUN)) &
- maxSensorsPerLUN;
- }
- else
- {
- // error
- throw std::out_of_range(
- "Maximum number of IPMI sensors exceeded.");
- }
- }
- }
- else
- {
- return ipmi::responseInvalidFieldRequest();
- }
-
- // Get Sensor count. This returns the number of sensors
- if (numSensors > 0)
- {
- lunsAndDynamicPopulation |= 1;
- }
- if (numSensors > maxSensorsPerLUN)
- {
- lunsAndDynamicPopulation |= 2;
- }
- if (numSensors >= (maxSensorsPerLUN * 2))
- {
- lunsAndDynamicPopulation |= 8;
- }
- if (numSensors > maxIPMISensors)
- {
- // error
- throw std::out_of_range("Maximum number of IPMI sensors exceeded.");
- }
-
- return ipmi::responseSuccess(sdrCount, lunsAndDynamicPopulation,
- sdrLastAdd);
-}
-
-/* end sensor commands */
-
-/* storage commands */
-
-ipmi::RspType<uint8_t, // sdr version
- uint16_t, // record count
- uint16_t, // free space
- uint32_t, // most recent addition
- uint32_t, // most recent erase
- uint8_t // operationSupport
- >
- ipmiStorageGetSDRRepositoryInfo(ipmi::Context::ptr ctx)
-{
- constexpr const uint16_t unspecifiedFreeSpace = 0xFFFF;
- if (!getSensorSubtree(sensorTree) && sensorTree.empty())
- {
- return ipmi::responseResponseError();
- }
-
- size_t fruCount = 0;
- ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
- if (ret != ipmi::ccSuccess)
- {
- return ipmi::response(ret);
- }
-
- uint16_t recordCount =
- getNumberOfSensors() + fruCount + ipmi::storage::type12Count +
- ipmi::storage::nmDiscoverySDRCount;
-
- uint8_t operationSupport = static_cast<uint8_t>(
- SdrRepositoryInfoOps::overflow); // write not supported
-
- operationSupport |=
- static_cast<uint8_t>(SdrRepositoryInfoOps::allocCommandSupported);
- operationSupport |= static_cast<uint8_t>(
- SdrRepositoryInfoOps::reserveSDRRepositoryCommandSupported);
- return ipmi::responseSuccess(ipmiSdrVersion, recordCount,
- unspecifiedFreeSpace, sdrLastAdd,
- sdrLastRemove, operationSupport);
-}
-
-/** @brief implements the get SDR allocation info command
- *
- * @returns IPMI completion code plus response data
- * - allocUnits - Number of possible allocation units
- * - allocUnitSize - Allocation unit size in bytes.
- * - allocUnitFree - Number of free allocation units
- * - allocUnitLargestFree - Largest free block in allocation units
- * - maxRecordSize - Maximum record size in allocation units.
- */
-ipmi::RspType<uint16_t, // allocUnits
- uint16_t, // allocUnitSize
- uint16_t, // allocUnitFree
- uint16_t, // allocUnitLargestFree
- uint8_t // maxRecordSize
- >
- ipmiStorageGetSDRAllocationInfo()
-{
- // 0000h unspecified number of alloc units
- constexpr uint16_t allocUnits = 0;
-
- constexpr uint16_t allocUnitFree = 0;
- constexpr uint16_t allocUnitLargestFree = 0;
- // only allow one block at a time
- constexpr uint8_t maxRecordSize = 1;
-
- return ipmi::responseSuccess(allocUnits, maxSDRTotalSize, allocUnitFree,
- allocUnitLargestFree, maxRecordSize);
-}
-
-/** @brief implements the reserve SDR command
- * @returns IPMI completion code plus response data
- * - sdrReservationID
- */
-ipmi::RspType<uint16_t> ipmiStorageReserveSDR()
-{
- sdrReservationID++;
- if (sdrReservationID == 0)
- {
- sdrReservationID++;
- }
-
- return ipmi::responseSuccess(sdrReservationID);
-}
-
-ipmi::RspType<uint16_t, // next record ID
- std::vector<uint8_t> // payload
- >
- ipmiStorageGetSDR(ipmi::Context::ptr ctx, uint16_t reservationID,
- uint16_t recordID, uint8_t offset, uint8_t bytesToRead)
-{
- size_t fruCount = 0;
- // reservation required for partial reads with non zero offset into
- // record
- if ((sdrReservationID == 0 || reservationID != sdrReservationID) && offset)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: responseInvalidReservationId");
- return ipmi::responseInvalidReservationId();
- }
- ipmi::Cc ret = ipmi::storage::getFruSdrCount(ctx, fruCount);
- if (ret != ipmi::ccSuccess)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: getFruSdrCount error");
- return ipmi::response(ret);
- }
-
- size_t lastRecord =
- getNumberOfSensors() + fruCount + ipmi::storage::type12Count +
- ipmi::storage::nmDiscoverySDRCount - 1;
- uint16_t nextRecordId = lastRecord > recordID ? recordID + 1 : 0XFFFF;
-
- if (!getSensorSubtree(sensorTree) && sensorTree.empty())
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: getSensorSubtree error");
- return ipmi::responseResponseError();
- }
-
- std::vector<uint8_t> record;
- if (getSensorDataRecord(ctx, record, recordID))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: fail to get SDR");
- return ipmi::responseInvalidFieldRequest();
- }
- get_sdr::SensorDataRecordHeader* hdr =
- reinterpret_cast<get_sdr::SensorDataRecordHeader*>(record.data());
- if (!hdr)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: record header is null");
- return ipmi::responseSuccess(nextRecordId, record);
- }
-
- size_t sdrLength =
- sizeof(get_sdr::SensorDataRecordHeader) + hdr->record_length;
- if (offset >= sdrLength)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: offset is outside the record");
- return ipmi::responseParmOutOfRange();
- }
- if (sdrLength < (offset + bytesToRead))
- {
- bytesToRead = sdrLength - offset;
- }
-
- uint8_t* respStart = reinterpret_cast<uint8_t*>(hdr) + offset;
- if (!respStart)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "ipmiStorageGetSDR: record is null");
- return ipmi::responseSuccess(nextRecordId, record);
- }
- std::vector<uint8_t> recordData(respStart, respStart + bytesToRead);
-
- return ipmi::responseSuccess(nextRecordId, recordData);
-}
-/* end storage commands */
-
void registerSensorFunctions()
{
// <Platform Event>
ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
ipmi::sensor_event::cmdPlatformEvent,
ipmi::Privilege::Operator, ipmiSenPlatformEvent);
-
- // <Get Sensor Reading>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetSensorReading,
- ipmi::Privilege::User, ipmiSenGetSensorReading);
-
- // <Get Sensor Threshold>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetSensorThreshold,
- ipmi::Privilege::User, ipmiSenGetSensorThresholds);
-
- // <Set Sensor Threshold>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdSetSensorThreshold,
- ipmi::Privilege::Operator,
- ipmiSenSetSensorThresholds);
-
- // <Get Sensor Event Enable>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetSensorEventEnable,
- ipmi::Privilege::User, ipmiSenGetSensorEventEnable);
-
- // <Get Sensor Event Status>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetSensorEventStatus,
- ipmi::Privilege::User, ipmiSenGetSensorEventStatus);
-
- // register all storage commands for both Sensor and Storage command
- // versions
-
- // <Get SDR Repository Info>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
- ipmi::storage::cmdGetSdrRepositoryInfo,
- ipmi::Privilege::User,
- ipmiStorageGetSDRRepositoryInfo);
-
- // <Get Device SDR Info>
- ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetDeviceSdrInfo,
- ipmi::Privilege::User, ipmiSensorGetDeviceSdrInfo);
-
- // <Get SDR Allocation Info>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
- ipmi::storage::cmdGetSdrRepositoryAllocInfo,
- ipmi::Privilege::User,
- ipmiStorageGetSDRAllocationInfo);
-
- // <Reserve SDR Repo>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdReserveDeviceSdrRepository,
- ipmi::Privilege::User, ipmiStorageReserveSDR);
-
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
- ipmi::storage::cmdReserveSdrRepository,
- ipmi::Privilege::User, ipmiStorageReserveSDR);
-
- // <Get Sdr>
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnSensor,
- ipmi::sensor_event::cmdGetDeviceSdr,
- ipmi::Privilege::User, ipmiStorageGetSDR);
-
- ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnStorage,
- ipmi::storage::cmdGetSdr, ipmi::Privilege::User,
- ipmiStorageGetSDR);
}
} // namespace ipmi