From 5c0beec1c30e2702e18359989ed16052ae222767 Mon Sep 17 00:00:00 2001 From: Dhruvaraj Subhashchandran Date: Tue, 23 Jan 2018 04:47:06 -0600 Subject: Support Get Sensor Thresholds Command Adding support for sensor thresholds command Resolves openbmc/openbmc#2624 Change-Id: I904c1b18c8709bceb7ecb7eec6e8e42e1f51525a Signed-off-by: Dhruvaraj Subhashchandran --- sensorhandler.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sensorhandler.h | 11 +++++ types.hpp | 33 +++++++++++++ utils.cpp | 25 ++++++++++ utils.hpp | 11 +++++ 5 files changed, 220 insertions(+) diff --git a/sensorhandler.cpp b/sensorhandler.cpp index e6320be..de3c228 100644 --- a/sensorhandler.cpp +++ b/sensorhandler.cpp @@ -666,6 +666,141 @@ ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return rc; } +ipmi_ret_t ipmi_sen_get_sensor_thresholds(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, ipmi_response_t response, + ipmi_data_len_t data_len, ipmi_context_t context) +{ + constexpr auto warningThresholdInterface = + "xyz.openbmc_project.Sensor.Threshold.Warning"; + constexpr auto criticalThresholdInterface = + "xyz.openbmc_project.Sensor.Threshold.Critical"; + constexpr auto valueInterface = + "xyz.openbmc_project.Sensor.Value"; + constexpr auto sensorRoot = "/xyz/openbmc_project/sensors"; + + ipmi::sensor::Thresholds thresholds = + { + { + warningThresholdInterface, + { + { + "WarningLow", + ipmi::sensor::ThresholdMask::NON_CRITICAL_LOW_MASK, + ipmi::sensor::ThresholdIndex::NON_CRITICAL_LOW_IDX + }, + { + "WarningHigh", + ipmi::sensor::ThresholdMask::NON_CRITICAL_HIGH_MASK, + ipmi::sensor::ThresholdIndex::NON_CRITICAL_HIGH_IDX + } + } + }, + { + criticalThresholdInterface, + { + { + "CriticalLow", + ipmi::sensor::ThresholdMask::CRITICAL_LOW_MASK, + ipmi::sensor::ThresholdIndex::CRITICAL_LOW_IDX + }, + { + "CriticalHigh", + ipmi::sensor::ThresholdMask::CRITICAL_HIGH_MASK, + ipmi::sensor::ThresholdIndex::CRITICAL_HIGH_IDX + } + } + } + }; + + sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; + + if (*data_len != sizeof(uint8_t)) + { + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + auto sensorNum = *(reinterpret_cast(request)); + + auto responseData = + reinterpret_cast(response); + + responseData->validMask = 0; + + const auto iter = sensors.find(sensorNum); + if (iter == sensors.end()) + { + return IPMI_CC_SENSOR_INVALID; + } + + const auto sensorInfo = iter->second; + + //Proceed only if the sensor value interface is implemented. + if (sensorInfo.propertyInterfaces.find(valueInterface) == + sensorInfo.propertyInterfaces.end()) + { + //return with valid mask as 0 + return IPMI_CC_OK; + } + + std::string service; + try + { + service = ipmi::getService(bus, + sensorInfo.sensorInterface, + sensorInfo.sensorPath); + } + catch (const std::runtime_error& e) + { + log(e.what()); + return IPMI_CC_UNSPECIFIED_ERROR; + } + + //prevent divide by 0 + auto coefficientM = + sensorInfo.coefficientM ? sensorInfo.coefficientM : 1; + + try + { + auto mngObjects = ipmi::getManagedObjects(bus, + service, + sensorRoot); + + auto senIter = mngObjects.find(sensorInfo.sensorPath); + if (senIter == mngObjects.end()) + { + return IPMI_CC_SENSOR_INVALID; + } + + for (const auto& threshold : thresholds) + { + auto thresholdType = senIter->second.find(threshold.first); + if (thresholdType != senIter->second.end()) + { + for (const auto& threshLevel : threshold.second) + { + auto val = thresholdType-> + second[threshLevel.property].get(); + if (val != 0) + { + auto idx = static_cast(threshLevel.idx); + responseData->data[idx] = static_cast( + (val - sensorInfo.scaledOffset) / coefficientM); + responseData->validMask |= + static_cast(threshLevel.maskValue); + } + } + } + } + } + catch (InternalFailure& e) + { + //Not able to get the values, reset the mask. + responseData->validMask = 0; + } + + *data_len = sizeof(get_sdr::GetSensorThresholdsResponse); + return IPMI_CC_OK; +} + ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request, ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context) @@ -987,5 +1122,10 @@ void register_netfn_sen_functions() nullptr, ipmi_sen_get_sdr, PRIVILEGE_USER); + // + ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_THRESHOLDS, + nullptr, ipmi_sen_get_sensor_thresholds, + PRIVILEGE_USER); + return; } diff --git a/sensorhandler.h b/sensorhandler.h index 8995447..1cf43ca 100644 --- a/sensorhandler.h +++ b/sensorhandler.h @@ -13,6 +13,7 @@ enum ipmi_netfn_sen_cmds IPMI_CMD_GET_SENSOR_READING = 0x2D, IPMI_CMD_GET_SENSOR_TYPE = 0x2F, IPMI_CMD_SET_SENSOR = 0x30, + IPMI_CMD_GET_SENSOR_THRESHOLDS = 0x27, }; // Discrete sensor types. @@ -206,6 +207,16 @@ inline void set_owner_lun_channel(uint8_t channel, SensorDataRecordKey* key) } // namespace key +/** @struct GetSensorThresholdsResponse + * + * Response structure for Get Sensor Thresholds command + */ +struct GetSensorThresholdsResponse +{ + uint8_t validMask; //Indicates which values are valid + uint8_t data[6]; //Container for threshold values +} __attribute__((packed)); + // Body - full record #define FULL_RECORD_ID_STR_MAX_LENGTH 16 struct SensorDataFullRecordBody diff --git a/types.hpp b/types.hpp index 260deb5..61f3d68 100644 --- a/types.hpp +++ b/types.hpp @@ -27,6 +27,11 @@ using ObjectTree = std::map; +using DbusInterfaceMap = std::map; + +using ObjectValueTree = + std::map; + namespace sensor { @@ -183,6 +188,34 @@ using InventoryPath = std::string; using InvObjectIDMap = std::map; +enum class ThresholdMask +{ + NON_CRITICAL_LOW_MASK = 0x01, + CRITICAL_LOW_MASK = 0x02, + NON_CRITICAL_HIGH_MASK = 0x08, + CRITICAL_HIGH_MASK = 0x10, +}; + +enum class ThresholdIndex +{ + NON_CRITICAL_LOW_IDX = 0, + CRITICAL_LOW_IDX = 1, + NON_RECOVERABLE_LOW_IDX = 2, + NON_CRITICAL_HIGH_IDX = 3, + CRITICAL_HIGH_IDX = 4, + NON_RECOVERABLE_HIGH_IDX = 5, +}; + +struct ThresholdLevel +{ + std::string property; + ThresholdMask maskValue; + ThresholdIndex idx; +}; + +using SensorThresholds = std::vector; +using Thresholds = std::map; + }// namespace sensor namespace network diff --git a/utils.cpp b/utils.cpp index fa6bd04..bd8fade 100644 --- a/utils.cpp +++ b/utils.cpp @@ -198,6 +198,31 @@ PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus, return properties; } +ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus, + const std::string& service, + const std::string& objPath) +{ + ipmi::ObjectValueTree interfaces; + + auto method = bus.new_method_call( + service.c_str(), + objPath.c_str(), + "org.freedesktop.DBus.ObjectManager", + "GetManagedObjects"); + + auto reply = bus.call(method); + + if (reply.is_method_error()) + { + log("Failed to get managed objects", + entry("PATH=%s", objPath.c_str())); + elog(); + } + + reply.read(interfaces); + return interfaces; +} + void setDbusProperty(sdbusplus::bus::bus& bus, const std::string& service, const std::string& objPath, diff --git a/utils.hpp b/utils.hpp index 1699c52..b4f090f 100644 --- a/utils.hpp +++ b/utils.hpp @@ -87,6 +87,17 @@ PropertyMap getAllDbusProperties(sdbusplus::bus::bus& bus, const std::string& objPath, const std::string& interface); +/** @brief Gets all managed objects associated with the given object + * path and service. + * @param[in] bus - D-Bus Bus Object. + * @param[in] service - D-Bus service name. + * @param[in] objPath - D-Bus object path. + * @return On success returns the map of name value pair. + */ +ObjectValueTree getManagedObjects(sdbusplus::bus::bus& bus, + const std::string& service, + const std::string& objPath); + /** @brief Sets the property value of the given object. * @param[in] bus - DBUS Bus Object. * @param[in] service - Dbus service name. -- cgit v1.2.1