From bbc1ef63af759ef39c4f430f1040fe8ef8201d1c Mon Sep 17 00:00:00 2001 From: roly Date: Thu, 12 Dec 2024 13:35:12 +0800 Subject: [PATCH] parse message when sel is created --- elog_entry.hpp | 3 + log_manager.cpp | 128 ++++++++++++- log_manager.hpp | 15 ++ meson.build | 10 + sel_message.cpp | 481 ++++++++++++++++++++++++++++++++++++++++++++++++ sel_message.hpp | 166 +++++++++++++++++ sensors.cpp | 119 ++++++++++++ sensors.hpp | 44 +++++ 8 files changed, 964 insertions(+), 2 deletions(-) create mode 100644 sel_message.cpp create mode 100644 sel_message.hpp create mode 100644 sensors.cpp create mode 100644 sensors.hpp diff --git a/elog_entry.hpp b/elog_entry.hpp index 87cc7ea..822fb1a 100644 --- a/elog_entry.hpp +++ b/elog_entry.hpp @@ -148,6 +148,9 @@ class Entry : public EntryIfaces */ sdbusplus::message::unix_fd getEntry() override; + /** @brief The original sensor name */ + std::string originalSensorName; + private: /** @brief This entry's associations */ AssociationList assocs = {}; diff --git a/log_manager.cpp b/log_manager.cpp index d3a50cd..2bfab30 100644 --- a/log_manager.cpp +++ b/log_manager.cpp @@ -232,12 +232,24 @@ void Manager::createEntry(std::string errMsg, Entry::Level errLvl, AssociationList objects{}; processMetadata(errMsg, additionalData, objects); + std::string originalSensorName; + auto result = processSel(additionalData, errLvl, originalSensorName); + + std::get<2>(result) ? additionalData.emplace_back("ASSERT_ALARM=1") + : additionalData.emplace_back("ASSERT_ALARM=0"); + + additionalData.emplace_back( + "SEVERITY_CONF=" + + std::to_string(static_cast(std::get<3>(result)))); auto e = std::make_unique( busLog, objPath, entryId, ms, // Milliseconds since 1970 - errLvl, std::move(errMsg), std::move(additionalData), - std::move(objects), fwVersion, getEntrySerializePath(entryId), *this); + std::get<1>(result), std::move(std::get<0>(result)), + std::move(additionalData), std::move(objects), fwVersion, + getEntrySerializePath(entryId), *this); + + e->originalSensorName = originalSensorName; serialize(*e); @@ -641,6 +653,118 @@ void Manager::createWithFFDC( createEntry(message, severity, ad, ffdc); } +std::tuple + Manager::processSel(const std::vector& additionalData, + Entry::Level defaultLevel, + std::string& originalSensorName) +{ + std::string_view eventDir; + std::string_view sensorData; + std::string sensorPath; + std::string_view recordTypeStr; + std::string msg; + std::string generatorId; + std::string sensorName; + + if (additionalData.empty()) + { + return std::make_tuple(msg, defaultLevel, true, + sel::message::AlarmType::NORMAL); + } + + for (std::string_view ite : additionalData) + { + auto pos = ite.find_first_of('='); + if (pos == std::string::npos) + { + continue; + } + + auto tempData = ite.substr(0, pos); + if (tempData == "EVENT_DIR") + { + eventDir = ite.substr(pos + 1); + } + else if (tempData == "SENSOR_DATA") + { + sensorData = ite.substr(pos + 1); + } + else if (tempData == "SENSOR_PATH") + { + sensorPath = ite.substr(pos + 1); + } + else if (tempData == "RECORD_TYPE") + { + recordTypeStr = ite.substr(pos + 1); + } + else if (tempData == "GENERATOR_ID") + { + generatorId = ite.substr(pos + 1); + } + } + + uint8_t recordType = 0; + if (!recordTypeStr.empty()) + { + std::from_chars(recordTypeStr.begin(), recordTypeStr.end(), recordType); + } + + sel::message::AlarmType alarm = sel::message::AlarmType::NORMAL; + sel::message::AlarmType confAlarm = sel::message::AlarmType::NORMAL; + + bool assert = true; + if (recordType >= 0xc0) + { + // TODO parse oem sel + } + else + { + auto sensorInfo = sensors::SensorManager::getSensorInfo(sensorPath); + if (sensorInfo == std::nullopt) + { + msg = "reserved #0xff | | "; + msg += assert ? "Asserted" : "Deasserted"; + return std::make_tuple(msg, defaultLevel, true, + sel::message::AlarmType::NORMAL); + } + auto sensorReadingType = sensorInfo->readingType; + auto sensorType = sensorInfo->sensorType; + sensorName = sensorInfo->sensorName; + originalSensorName = sensorName; + uint8_t value = 0; + std::from_chars(eventDir.begin(), eventDir.end(), value, 10); + assert = (value == 0) ? false : true; + + msg = sel::message::getSystemSelMessage(sensorPath, sensorType, + sensorReadingType, sensorData, + sensorName, assert); + auto alarmValue = sel::message::getSystemSelAlarm( + sensorPath, sensorType, sensorReadingType, sensorData, assert); + alarm = alarmValue.first; + confAlarm = alarmValue.second; + } + + bool assertAlarm = assert; + Entry::Level severity = defaultLevel; + switch (alarm) + { + case sel::message::AlarmType::NONCRITICAL: + severity = Entry::Level::Warning; + break; + case sel::message::AlarmType::CRITICAL: + severity = Entry::Level::Error; + break; + case sel::message::AlarmType::NONRECOV: + severity = Entry::Level::Alert; + break; + default: + assertAlarm = !assert; + break; + } + + return std::make_tuple(msg, severity, assertAlarm, confAlarm); +} + } // namespace internal } // namespace logging } // namespace phosphor diff --git a/log_manager.hpp b/log_manager.hpp index 275530e..0b9056f 100644 --- a/log_manager.hpp +++ b/log_manager.hpp @@ -2,6 +2,8 @@ #include "elog_block.hpp" #include "elog_entry.hpp" +#include "sel_message.hpp" +#include "sensors.hpp" #include "xyz/openbmc_project/Collection/DeleteAll/server.hpp" #include "xyz/openbmc_project/Logging/Create/server.hpp" #include "xyz/openbmc_project/Logging/Entry/server.hpp" @@ -307,6 +309,19 @@ class Manager : public details::ServerObject */ void checkAndQuiesceHost(); + /** @brief Parse sel. + * @param[in] additionalData - list of metadata (in key=value format) + * @param[in] defaultLevel - default severity + * + * @return std::string - the message string + * Entry::Level - the alarm level + * bool - true: assert alarm, false: deassert alarm + * sel::message::AlarmType - the alarm level in config + */ + std::tuple + processSel(const std::vector& additionalData, + Entry::Level defaultLevel, std::string& originalSensorName); + /** @brief Persistent sdbusplus DBus bus connection. */ sdbusplus::bus_t& busLog; diff --git a/meson.build b/meson.build index 2add463..4f3f8d0 100644 --- a/meson.build +++ b/meson.build @@ -60,6 +60,12 @@ if not has_cereal cereal_dep = cereal_proj.dependency('cereal') endif +if cpp.has_header('nlohmann/json.hpp') + nlohmann_json_dep = declare_dependency() +else + nlohmann_json_dep = dependency('nlohmann-json') +endif +ipmitool_dep = cpp.find_library('ipmitool') # Generate sdbus++ files. generated_sources = [] generated_others = [] @@ -128,6 +134,8 @@ log_manager_sources = [ 'elog_serialize.cpp', 'extensions.cpp', 'log_manager.cpp', + 'sel_message.cpp', + 'sensors.cpp', 'util.cpp', ) ] @@ -138,6 +146,8 @@ log_manager_deps = [ phosphor_logging_dep, sdbusplus_dep, sdeventplus_dep, + nlohmann_json_dep, + ipmitool_dep, ] executable('phosphor-log-manager', log_manager_sources, diff --git a/sel_message.cpp b/sel_message.cpp new file mode 100644 index 0000000..8952cec --- /dev/null +++ b/sel_message.cpp @@ -0,0 +1,481 @@ +extern "C" +{ +#include +} +#include "sel_message.hpp" +#include "sensors.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace sel +{ +namespace message +{ + +enum class SensorUnits : uint8_t +{ + unspecified = 0x0, + degreesC = 0x1, + volts = 0x4, + amps = 0x5, + watts = 0x6, + rpm = 0x12, +}; + +const static std::map sensorUnits = { + {"temperature", SensorUnits::degreesC}, + {"voltage", SensorUnits::volts}, + {"current", SensorUnits::amps}, + {"fan_tach", SensorUnits::rpm}, + {"power", SensorUnits::watts}}; + +inline uint8_t bit(uint8_t bit) +{ + return 1 << bit; +} + +inline std::string getSensorTypeDesc(uint8_t sensorType) +{ + if (sensorType <= SENSOR_TYPE_MAX) + { + return sensor_type_desc[sensorType]; + } + return ""; +} + +inline std::optional> + getEventDataTypeDesc(uint8_t eventData, struct ipmi_event_data_types* evt) +{ + struct ipmi_event_data_types* event = nullptr; + if (evt == nullptr) + { + return std::nullopt; + } + event = evt; + size_t num_types = 0; + + switch (event->flag) + { + case HDD_NVME_STATUS_EVT2: + { + return std::nullopt; + } + case EXPANDER_ERR_EVT2: + { + return std::nullopt; + } + case EXPANDER_ERR_EVT3: + { + return std::nullopt; + } + case RETIMER_ERR_EVT2: + { + return std::make_pair(event->data, + ", Retimer " + std::to_string(eventData)); + } + case POWER_FAULT_EVT2: + { + return std::nullopt; + } + case BMC_BOOT_EVT2: + { + num_types = sizeof(BMC_BOOT_evt2) / + sizeof(struct ipmi_event_data_types); + break; + } + case BMC_BOOT_EVT3: + { + num_types = sizeof(BMC_BOOT_evt3) / + sizeof(struct ipmi_event_data_types); + break; + } + case LEAKAGE_EVT2: + { + num_types = sizeof(Leakage_evt2) / + sizeof(struct ipmi_event_data_types); + break; + } + case FW_UPDATE_EVT2: + { + num_types = sizeof(FW_Update_evt2) / + sizeof(struct ipmi_event_data_types); + break; + } + case FW_UPDATE_EVT3: + { + num_types = sizeof(FW_Update_evt3) / + sizeof(struct ipmi_event_data_types); + break; + } + default: + break; + } + + for (size_t i = 0; i < num_types; i++) + { + if (event->data == eventData) + { + return std::make_pair(event->data, evt[i].desc); + } + event++; + } + return std::nullopt; +} + +inline std::string getEventDesc(SensorRecord rec) +{ + uint8_t code = 0xFF; + std::optional> evtOpt2; + std::optional> evtOpt3; + + auto getEventTypes = [rec, &code]() { + if (rec.eventType == 0x6F) + { + code = rec.sensorType; + return sensor_specific_event_types; + } + else if (rec.eventType == 0x03 && rec.sensorType == 0x15) + { + code = rec.eventType; + return sensor_retimer_event_types; + } + else + { + code = rec.eventType; + return generic_event_types; + } + }; + + for (auto ite = getEventTypes(); ite->desc != nullptr; ite++) + { + if (ite->code != code || ite->offset != (rec.eventData1 & 0x0F)) + { + continue; + } + + if (ite->evt2) + { + evtOpt2 = getEventDataTypeDesc(rec.eventData2, ite->evt2); + } + if ((evtOpt2 != std::nullopt) && ite->evt3) + { + evtOpt3 = getEventDataTypeDesc(rec.eventData3, ite->evt3); + } + + auto data = (evtOpt2 != std::nullopt) ? evtOpt2->first : ite->data; + if ((ite->data == ALL_OFFSETS_SPECIFIED) || + ((rec.eventData1 & 0xC0) && (data == rec.eventData2))) + { + std::string msg = + std::string(ite->desc) + + (evtOpt2 != std::nullopt ? (evtOpt2->second) : "") + + (evtOpt3 != std::nullopt ? (evtOpt3->second) : ""); + if (rec.eventType == 0x6F && rec.sensorType == 0x13) + { + msg += std::format(", BDF: {0:02x}.{1:02x}.{2:02x}", + rec.eventData2, rec.eventData3 >> 3, + rec.eventData3 & 0x07); + } + + else if (rec.eventType == 0x03 && rec.sensorType == 0x09) + { + if (rec.eventData2 == 0xFF) + { + msg += ", ErrorType: Power-on timeout"; + } + else if (rec.eventData2 >= SIZE_OF_POWER_FAULT) + { + msg += ", ErrorType: Unknown"; + } + else + { + msg += + ", ErrorType: " + + std::string(sensor_power_fault[rec.eventData2 & 0x0F]); + } + } + + else if (rec.eventType == 0x6F && code == 0x0D) + { + msg += std::format(", Drive Slot({:02d})", rec.eventData2); + } + else if (rec.eventType == 0x07 && + (rec.sensorType == 0x04 || rec.sensorType == 0x21)) + { + msg = ite->desc; + } + else if (rec.eventType == 0x6F && code == 0x1B) + { + msg += std::format(", PSU PDB Cable{:d}", rec.eventData2); + } + return msg; + } + } + + return ""; +} + +inline std::vector convertVec(std::string_view str) +{ + std::vector ret; + auto len = str.size() / 2; + ret.reserve(len); + for (size_t i = 0; i < len; ++i) + { + uint8_t value; + std::from_chars(str.begin() + i * 2, str.begin() + (i + 1) * 2, value, + 16); + ret.emplace_back(value); + } + return ret; +} + +inline std::string getBacdEvents(const std::vector& event) +{ + std::string msg; + for (const auto& item : sensor_oem_bacd_types) + { + if (item.flag == 3 && (event[item.flag] & bit(item.code))) + { + msg += ", " + std::string(item.desc); + } + else if (item.flag == 2 && event[item.flag] == item.code) + { + msg += ", " + std::string(item.desc); + } + } + + return msg; +} + +inline std::string getPprEvents(const std::vector& event) +{ + std::string msg; + msg += ", CPU" + std::to_string(event[2]) + " Channel" + + std::to_string(event[3]) + " Dimm" + std::to_string(event[4]); + + for (const auto& item : sensor_oem_ppr_types) + { + if (event[item.flag] == item.code && item.desc != nullptr) + { + msg += " " + std::string(item.desc); + } + } + + return msg; +} + +inline std::pair + parseThresholdSelSeverity(uint8_t eventData1, bool assert) +{ + auto ite = thresholdAlarmTypes.find(eventData1); + if (ite != thresholdAlarmTypes.end()) + { + return std::make_pair( + assert ? ite->second.assertAlarm : ite->second.deassertAlarm, + ite->second.assertAlarm > ite->second.deassertAlarm + ? ite->second.assertAlarm + : ite->second.deassertAlarm); + } + return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL); +} + +inline std::pair parseSpecificSensorSelSeverity( + [[maybe_unused]] const std::string& sensorPath, uint8_t sensorType, + uint8_t eventData1, uint8_t eventData2, bool assert) +{ + for (const auto& ite : specificAlarmTypes) + { + if (ite.sensorType == sensorType && ite.offset == eventData1) + { + if (ite.evt2.size() == 0 || + (ite.evt2.size() > 0 && + std::find(ite.evt2.begin(), ite.evt2.end(), eventData2) != + ite.evt2.end())) + { + return std::make_pair( + assert ? ite.assertAlarm : ite.deassertAlarm, + ite.assertAlarm > ite.deassertAlarm ? ite.assertAlarm + : ite.deassertAlarm); + } + } + } + return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL); +} + +inline std::pair + parseDiscreteGenericSelSeverity(uint8_t sensorType, uint8_t eventType, + uint8_t eventData1, uint8_t eventData2, + bool assert) +{ + for (const auto& ite : discreteAlarmTypes) + { + if (ite.sensorType == sensorType && ite.eventType == eventType && + ite.offset == eventData1) + { + if (ite.evt2.size() == 0 || + (ite.evt2.size() > 0 && + std::find(ite.evt2.begin(), ite.evt2.end(), eventData2) != + ite.evt2.end())) + { + return std::make_pair( + assert ? ite.assertAlarm : ite.deassertAlarm, + ite.assertAlarm > ite.deassertAlarm ? ite.assertAlarm + : ite.deassertAlarm); + } + break; + } + } + return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL); +} + +inline double scaleIPMIValueToDouble(const double value, const int16_t mValue, + const int8_t rExp, const int16_t bValue, + const int8_t bExp) +{ + double result = + (double)(((mValue * value) + (bValue * std::pow(10, bExp))) * + std::pow(10, rExp)); + return result; +} + +inline std::string getUnitDesc(const std::string& path) +{ + SensorUnits unitType = SensorUnits::unspecified; + size_t typeEnd = path.rfind("/"); + if (typeEnd == std::string::npos) + { + return unit_desc[static_cast(unitType)]; + } + size_t typeStart = path.rfind("/", typeEnd - 1); + if (typeStart == std::string::npos) + { + return unit_desc[static_cast(unitType)]; + } + // Start at the character after the '/' + typeStart++; + std::string typeStr = path.substr(typeStart, typeEnd - typeStart); + + auto it = sensorUnits.find(typeStr); + if (it != sensorUnits.end()) + { + unitType = it->second; + } + + if (static_cast(unitType) <= UNIT_TYPE_MAX) + { + return unit_desc[static_cast(unitType)]; + } + else + { + return unit_desc[static_cast(SensorUnits::unspecified)]; + } +} + +inline std::string getThresholdDesc(const std::string sensorPath, + SensorRecord rec) +{ + std::string msg; + msg = "Reading "; + auto scaleParam = sensors::SensorManager::getSensorScaleParam(sensorPath); + if (scaleParam.size() < 5) + { + // Not found or the sensor config is not expected + return ""; + } + + int16_t mValue = static_cast(scaleParam[2]); + int16_t bValue = static_cast(scaleParam[3]); + int8_t bExp = static_cast(scaleParam[4]); + int8_t rExp = static_cast(scaleParam[5]); + auto triggerReading = scaleIPMIValueToDouble(rec.eventData2, mValue, rExp, + bValue, bExp); + auto thresholdReading = scaleIPMIValueToDouble(rec.eventData3, mValue, rExp, + bValue, bExp); + msg += (triggerReading == (int)triggerReading) + ? std::format("{0:.0f} ", triggerReading) + : std::format("{0:.2f} ", triggerReading); + msg += (rec.eventData1 & 0xf) % 2 ? ">" : "<"; + msg += " Threshold " + ((thresholdReading == (int)thresholdReading) + ? std::format("{0:.0f} ", thresholdReading) + : std::format("{0:.2f} ", thresholdReading)); + + msg += getUnitDesc(sensorPath); + + return msg; +} + +std::string getSystemSelMessage(const std::string& sensorPath, + uint8_t sensorType, uint8_t sensorReadingType, + std::string_view sensorData, + const std::string& sensorName, bool assert) +{ + std::string msg; + SensorRecord rec; + std::from_chars(sensorData.begin(), sensorData.begin() + 2, rec.eventData1, + 16); + std::from_chars(sensorData.begin() + 2, sensorData.begin() + 4, + rec.eventData2, 16); + std::from_chars(sensorData.begin() + 4, sensorData.begin() + 6, + + rec.eventData3, 16); + rec.eventType = sensorReadingType; + rec.sensorType = sensorType; + + auto sensorTypeDesc = getSensorTypeDesc(sensorType); + msg += sensorTypeDesc + " " + sensorName + " | "; + + msg += getEventDesc(rec); + msg += " | "; + msg += assert ? "Asserted" : "Deasserted"; + + if (rec.eventType == 0x01) + { + auto thresholdDesc = getThresholdDesc(sensorPath, rec); + msg += " | " + thresholdDesc; + } + + return msg; +} + +std::pair getSystemSelAlarm(const std::string& sensorPath, + uint8_t sensorType, + uint8_t eventType, + std::string_view sensorData, + bool assert) +{ + uint8_t eventData1; + uint8_t eventData2; + std::from_chars(sensorData.begin(), sensorData.begin() + 2, eventData1, 16); + std::from_chars(sensorData.begin() + 2, sensorData.begin() + 4, eventData2, + 16); + eventData1 &= 0x0F; + + if (EventType(eventType) == EventType::THRESHOLD_SENSOR_TYPE) + { + return parseThresholdSelSeverity(eventData1, assert); + } + else if (EventType(eventType) == EventType::SPECIFIC_SENSOR_TYPE) + { + return parseSpecificSensorSelSeverity(sensorPath, sensorType, + eventData1, eventData2, assert); + } + else if (EventType(eventType) >= EventType::GENERIC_START_SENSOR_TYPE && + EventType(eventType) <= EventType::GENERIC_END_SENSOR_TYPE) + { + return parseDiscreteGenericSelSeverity(sensorType, eventType, + eventData1, eventData2, assert); + } + else + { + return std::make_pair(AlarmType::NORMAL, AlarmType::NORMAL); + } +} +} // namespace message +} // namespace sel diff --git a/sel_message.hpp b/sel_message.hpp new file mode 100644 index 0000000..167ee24 --- /dev/null +++ b/sel_message.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace sel +{ +namespace message +{ + +struct SensorRecord +{ + uint8_t sensorType; + uint8_t eventType; + uint8_t eventData1; + uint8_t eventData2; + uint8_t eventData3; +}; + +std::string getSystemSelMessage(const std::string& sensorPath, + uint8_t sensorType, uint8_t sensorReadingType, + std::string_view sensorData, + const std::string& sensorName, bool assert); +const std::vector null_alarm = {}; +enum class AlarmType +{ + NORMAL = 0, + NONCRITICAL = 1, + CRITICAL = 2, + NONRECOV = 4, +}; +enum class EventType +{ + UNSPECIFY_SENSOR_TYPE = 0x00, + THRESHOLD_SENSOR_TYPE = 0x01, + GENERIC_START_SENSOR_TYPE = 0x02, + GENERIC_END_SENSOR_TYPE = 0x0C, + SPECIFIC_SENSOR_TYPE = 0x6F, + OEM_START_SENSOR_TYPE = 0x70, + OEM_END_SENSOR_TYPE = 0x7F +}; +struct threshold_alarm_types +{ + AlarmType assertAlarm = AlarmType::NORMAL; + AlarmType deassertAlarm = AlarmType::NORMAL; +}; +struct discrete_alarm_types +{ + uint8_t sensorType; + uint8_t eventType; + uint8_t offset; + AlarmType assertAlarm = AlarmType::NORMAL; + AlarmType deassertAlarm = AlarmType::NORMAL; + const std::vector& evt2 = null_alarm; +}; +struct specific_alarm_types +{ + uint8_t sensorType; + uint8_t offset; + AlarmType assertAlarm = AlarmType::NORMAL; + AlarmType deassertAlarm = AlarmType::NORMAL; + const std::vector& evt2 = null_alarm; +}; + +const std::map thresholdAlarmTypes = { + {0x00, {AlarmType::NONCRITICAL}}, {0x02, {AlarmType::CRITICAL}}, + {0x04, {AlarmType::NONRECOV}}, {0x07, {AlarmType::NONCRITICAL}}, + {0x09, {AlarmType::CRITICAL}}, {0x0b, {AlarmType::NONRECOV}}}; + +const std::vector power_fault_alarm_evt2 = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + +constexpr std::array discreteAlarmTypes = { + {{0x04, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x04, 0x07, 0x01, AlarmType::CRITICAL}, + {0x04, 0x08, 0x00, AlarmType::CRITICAL}, + {0x04, 0x08, 0x01, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x08, 0x0B, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x08, 0x0B, 0x01, AlarmType::CRITICAL}, + {0x09, 0x03, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL, + power_fault_alarm_evt2}, + {0x09, 0x03, 0x01, AlarmType::CRITICAL, AlarmType::NORMAL, + power_fault_alarm_evt2}, + {0x15, 0x03, 0x00, AlarmType::NORMAL, AlarmType::NONCRITICAL}, + {0x15, 0x03, 0x01, AlarmType::NONCRITICAL}, + {0x19, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x19, 0x07, 0x01, AlarmType::CRITICAL}, + {0x21, 0x08, 0x00, AlarmType::CRITICAL}, + {0x21, 0x08, 0x01, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x24, 0x07, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x24, 0x07, 0x01, AlarmType::CRITICAL}}}; + +const std::vector system_firmware_critical_alarm_evt2 = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x0D}; + +const std::vector system_firmware_noncritical_alarm_evt2 = {0x0A}; + +const std::vector hcurr_connector_alarm_evt2 = {0x00, 0x01}; + +constexpr std::array specificAlarmTypes = {{ + {0x07, 0x00, AlarmType::CRITICAL}, + {0x07, 0x01, AlarmType::NONCRITICAL}, + {0x07, 0x03, AlarmType::CRITICAL}, + {0x07, 0x05, AlarmType::NONCRITICAL}, + {0x07, 0x07, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x07, 0x08, AlarmType::CRITICAL}, + {0x07, 0x0A, AlarmType::NONCRITICAL}, + {0x07, 0x0B, AlarmType::CRITICAL}, + {0x07, 0x0C, AlarmType::NONCRITICAL}, + {0x08, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x08, 0x01, AlarmType::CRITICAL}, + {0x08, 0x02, AlarmType::NONCRITICAL}, + {0x08, 0x03, AlarmType::CRITICAL}, + {0x08, 0x05, AlarmType::CRITICAL}, + {0x08, 0x06, AlarmType::CRITICAL}, + {0x0C, 0x00, AlarmType::NORMAL}, + {0x0C, 0x01, AlarmType::CRITICAL}, + {0x0C, 0x02, AlarmType::NONCRITICAL}, + {0x0C, 0x03, AlarmType::NONCRITICAL}, + {0x0C, 0x04, AlarmType::CRITICAL}, + {0x0C, 0x05, AlarmType::NONCRITICAL}, + {0x0C, 0x08, AlarmType::NONCRITICAL}, + {0x0C, 0x0A, AlarmType::CRITICAL}, + {0x0D, 0x00, AlarmType::NORMAL, AlarmType::CRITICAL}, + {0x0D, 0x01, AlarmType::CRITICAL}, + {0x0F, 0x00, AlarmType::CRITICAL, AlarmType::NORMAL, + system_firmware_critical_alarm_evt2}, + {0x0F, 0x00, AlarmType::NONCRITICAL, AlarmType::NORMAL, + system_firmware_noncritical_alarm_evt2}, + {0x10, 0x02}, + {0x13, 0x04, AlarmType::CRITICAL}, + {0x13, 0x05, AlarmType::CRITICAL}, + {0x13, 0x07, AlarmType::NORMAL}, + {0x13, 0x08, AlarmType::CRITICAL}, + {0x13, 0x0A, AlarmType::CRITICAL}, + {0x13, 0x0B, AlarmType::CRITICAL}, + {0x14, 0x00}, + {0x14, 0x01}, + {0x14, 0x02}, + {0x1B, 0x01, AlarmType::CRITICAL, AlarmType::NORMAL, + hcurr_connector_alarm_evt2}, + {0x1D, 0x00}, + {0x1D, 0x01}, + {0x1D, 0x02}, + {0x1E, 0x00, AlarmType::NORMAL}, + {0x1E, 0x01}, + {0x1E, 0x02}, + {0x1E, 0x03}, + {0x1F, 0x06}, + {0x22, 0x00}, + {0x22, 0x05}, + {0x2B, 0x07, AlarmType::NORMAL, AlarmType::CRITICAL}, +}}; + +std::pair getSystemSelAlarm(const std::string& sensorPath, + uint8_t sensorType, + uint8_t eventType, + std::string_view sensorData, + bool assert); +} // namespace message +} // namespace sel diff --git a/sensors.cpp b/sensors.cpp new file mode 100644 index 0000000..01a559e --- /dev/null +++ b/sensors.cpp @@ -0,0 +1,119 @@ +#include "sensors.hpp" + +#include +#include +#include + +#include +#include +#include + +namespace sensors +{ + +static constexpr auto sensorJsonPath = + "/usr/share/ipmi-providers/sensor-data-record.json"; + +SensorMessages loadSensorFromJson() +{ + try + { + const std::filesystem::path path(sensorJsonPath); + SensorMessages sensorMessages; + const nlohmann::json empty{}; + nlohmann::json js; + if (!std::filesystem::exists(path) || std::filesystem::is_empty(path)) + { + std::cout << "Incorrect File Path or empty file, FILE_PATH = " + << path << std::endl; + return sensorMessages; + } + + try + { + std::ifstream jsonFile(path); + js = nlohmann::json::parse(jsonFile); + } + catch (const std::exception& e) + { + std::cout << "Failed to parse config file, ERROR = " << e.what() + << ", FILE_PATH = " << path << std::endl; + throw std::runtime_error("Failed to parse config file"); + } + + for (const auto& sensor : js.items()) + { + SensorInfo info; + std::string sensorPath = sensor.key(); + auto sensorParam = sensor.value(); + info.sensorName = sensorParam["sensorName"]; + info.readingType = sensorParam["sensorReadingType"]; + info.sensorType = sensorParam["sensorType"]; + sensorMessages.insert(std::make_pair(sensorPath, std::move(info))); + } + return sensorMessages; + } + catch (const std::exception& e) + { + throw std::runtime_error("Failed to parse sensor config file"); + } +} + +const SensorMessages& SensorManager::getSensorMessages() +{ + static const SensorMessages sensorMessages = loadSensorFromJson(); + return sensorMessages; +} + +std::optional + SensorManager::getSensorInfo(const std::string& sensorPath) +{ + const auto& sensorMessages = SensorManager::getSensorMessages(); + auto ite = sensorMessages.find(sensorPath); + if (ite == sensorMessages.end()) + { + return std::nullopt; + } + return std::make_optional(ite->second); +} + +ScaleInfo SensorManager::getSensorScaleParam(const SensorPath& path) +{ + static std::optional ipmiSensors = std::nullopt; + if (ipmiSensors == std::nullopt) + { + constexpr auto service = "xyz.openbmc_project.Ipmi.Host"; + constexpr auto obj = "/xyz/openbmc_project/Ipmi/SensorInfo"; + constexpr auto interface = "xyz.openbmc_project.IPMI.SensorInfo"; + constexpr auto property = "SensorInfo"; + using SensorInfoVariant = std::variant; + SensorInfoVariant val; + + auto bus = sdbusplus::bus::new_default(); + auto method = bus.new_method_call( + service, obj, "org.freedesktop.DBus.Properties", "Get"); + method.append(interface, property); + try + { + auto reply = bus.call(method); + reply.read(val); + } + catch (const sdbusplus::exception_t& e) + { + lg2::warning( + "Failed to get IPMI sensor info, error: {ERROR}, retry...", + "ERROR", e.what()); + return ScaleInfo{}; + } + + ipmiSensors = std::get(val); + } + auto it = ipmiSensors->find(path); + if (it == ipmiSensors->end()) + { + return ScaleInfo{}; + } + return it->second; +} + +} // namespace sensors diff --git a/sensors.hpp b/sensors.hpp new file mode 100644 index 0000000..da9a9ff --- /dev/null +++ b/sensors.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace sensors +{ +using ScaleInfo = std::vector; +using ipmiSensorsInfo = std::unordered_map; +using SensorPath = std::string; +struct SensorInfo +{ + std::string sensorName; + uint8_t readingType; + uint8_t sensorType; +}; + +using SensorMessages = std::unordered_map; + +/** + * @class SensorManager + * + * Manage sensor message + */ +class SensorManager +{ + public: + SensorManager() = default; + ~SensorManager() = default; + SensorManager(const SensorManager&) = delete; + SensorManager& operator=(const SensorManager&) = delete; + SensorManager(SensorManager&&) = delete; + SensorManager& operator=(SensorManager&&) = delete; + + static const SensorMessages& getSensorMessages(); + + static std::optional getSensorInfo(const SensorPath& path); + + static ScaleInfo getSensorScaleParam(const SensorPath& path); +}; +} // namespace sensors -- 2.25.1