From 80cb5c7e022af367dd17981f2a0ffe7d5cf4052a Mon Sep 17 00:00:00 2001 From: "Wang.Bin" Date: Wed, 20 Nov 2024 19:14:14 +0800 Subject: [PATCH 4/4] Support discrete generic sensors --- fault-monitor/fru-fault-monitor.cpp | 393 ++++++++++++++++++++++++++-- fault-monitor/fru-fault-monitor.hpp | 3 +- 2 files changed, 379 insertions(+), 17 deletions(-) diff --git a/fault-monitor/fru-fault-monitor.cpp b/fault-monitor/fru-fault-monitor.cpp index aa7b8cc..737c90d 100644 --- a/fault-monitor/fru-fault-monitor.cpp +++ b/fault-monitor/fru-fault-monitor.cpp @@ -69,6 +69,37 @@ using InvalidArgumentErr = constexpr const char* discreteSensorNs = "No state defined"; +enum AlarmType : uint64_t +{ + NORMAL = 0, + NONCRITICAL = 1, + CRITICAL = 2, + NONRECOV = 4, +}; + +/*alarms bits: nr, nc, c*/ +constexpr auto ALARM_BIT_NUM = 3; +constexpr auto ALARM_ALL_BITS = NONCRITICAL | CRITICAL | NONRECOV; +constexpr uint64_t ALARM_STATUS_MASK_NR = 0x4924924924924924; +constexpr uint64_t ALARM_STATUS_MASK_C = 0x2492492492492492; +constexpr uint64_t ALARM_STATUS_MASK_NC = 0x1249249249249249; + +/*discrete generic offset*/ + +constexpr auto EVENT_TYPE_03H_STATE_DEASSERT = 0; +constexpr auto EVENT_TYPE_03H_STATE_ASSERT = 1; + +constexpr auto EVENT_TYPE_07H_TRANSITION_TO_OK = 0; +constexpr auto EVENT_TYPE_07H_TRANSITION_TO_NC_FROM_OK = 1; + +constexpr auto EVENT_TYPE_08H_ABSENT = 0; +constexpr auto EVENT_TYPE_08H_PRESENT = 1; + +constexpr auto EVENT_TYPE_0BH_FULLY_REDUNDANT = 0; +constexpr auto EVENT_TYPE_0BH_REDUNDANT_LOST = 1; + +/*discrete sensor specific offset*/ + /*discrete sensor specific offset*/ // 07H constexpr auto IPMI_CPU_IERR = 0; @@ -164,16 +195,8 @@ constexpr auto FIRMWARE_UPDATE_SUCCESS = 7; /*sensor object, SensorStatusInfo*/ std::unordered_map sensorStatusRec; -std::unordered_map> driveStatusRec; - - -enum AlarmType -{ - NORMAL = 0, - NONCRITICAL = 1, - CRITICAL = 2, - NONRECOV = 4, -}; +std::unordered_map> driveStatusRec; +std::unordered_map powerFaultStatusRec; struct SelSeverityInfo { @@ -204,6 +227,30 @@ using sensorCodes = std::vector; using ipmiSensorsInfo = std::unordered_map; std::optional ipmiSensors; +const std::unordered_map genericEventTypes{ + {0x03, + { + {EVENT_TYPE_03H_STATE_DEASSERT, "State Deasserted"}, + {EVENT_TYPE_03H_STATE_ASSERT, "State Asserted"}, + }}, + {0x07, + { + {EVENT_TYPE_07H_TRANSITION_TO_OK, "Transition to OK"}, + {EVENT_TYPE_07H_TRANSITION_TO_NC_FROM_OK, + "Transition to Non-critical from OK"}, + }}, + {0x08, + { + {EVENT_TYPE_08H_ABSENT, "Device Absent"}, + {EVENT_TYPE_08H_PRESENT, "Device Present"}, + }}, + {0x0B, + { + {EVENT_TYPE_0BH_FULLY_REDUNDANT, "Fully Redundant"}, + {EVENT_TYPE_0BH_REDUNDANT_LOST, "Redundancy Lost"}, + }}, +}; + const std::unordered_map sensorSpecificTypes{ {SENSOR_TYPE_PROCESSOR, { @@ -316,6 +363,15 @@ const std::unordered_map sensorSpecificTypes{ }}, }; +static const std::unordered_map> + flipStateSel = { + {"Redundant_PSU", + {EVENT_TYPE_0BH_FULLY_REDUNDANT, EVENT_TYPE_0BH_REDUNDANT_LOST}}, + {"SYS_FAN_Status", + {EVENT_TYPE_07H_TRANSITION_TO_OK, + EVENT_TYPE_07H_TRANSITION_TO_NC_FROM_OK}}, +}; + std::optional initIPMISensorInfo(sdbusplus::bus::bus& bus) { constexpr auto service = "xyz.openbmc_project.Ipmi.Host"; @@ -557,13 +613,192 @@ enum { UNSPECIFY_SENSOR_TYPE = 0x00, THRESHOLD_SENSOR_TYPE = 0x01, - GENERIC_S_SENSOR_TYPE = 0x02, - GENERIC_E_SENSOR_TYPE = 0x0C, + GENERIC_START_SENSOR_TYPE = 0x02, + GENERIC_END_SENSOR_TYPE = 0x0C, SPECIFIC_SENSOR_TYPE = 0x6F, - OEM_S_SENSOR_TYPE = 0x70, - OEM_E_SENSOR_TYPE = 0x7F + OEM_START_SENSOR_TYPE = 0x70, + OEM_END_SENSOR_TYPE = 0x7F +}; + +inline void recordAlarmStatus(const std::string& sensorPath, + AlarmType alarmStatus, int evOffset, int ed, + bool assertAlarm, + const bool& isGenericDiscreteSensor) +{ + uint64_t statusBit = static_cast(alarmStatus); + + std::string sensorName{sensorPath}; + size_t lastPos = sensorPath.find_last_of('/'); + if (lastPos != std::string::npos) + { + // Get sensor name from the sensor full path + sensorName = sensorPath.substr(lastPos + 1); + } + + if (assertAlarm) + { + if (ed != 0) + { + sensorStatusRec[sensorPath].alarmStatus |= + statusBit << (evOffset * ALARM_BIT_NUM); + + auto it = flipStateSel.find(sensorName); + if (it != flipStateSel.end()) + { + auto eventOffsets = it->second; + auto targetIt = std::find(eventOffsets.begin(), + eventOffsets.begin(), evOffset); + if (targetIt != eventOffsets.end()) + { + for (const auto& offset : eventOffsets) + { + if (offset == evOffset) + { + continue; + } + sensorStatusRec[sensorPath].alarmStatus &= + ~(statusBit << (offset * ALARM_BIT_NUM)); + } + } + } + } + else + { + sensorStatusRec[sensorPath].alarmStatus &= + ~(statusBit << (evOffset * ALARM_BIT_NUM)); + } + } + else + { + if (ed != 0) + { + sensorStatusRec[sensorPath].alarmStatus &= + ~(statusBit << (evOffset * ALARM_BIT_NUM)); + + auto it = flipStateSel.find(sensorName); + if (it != flipStateSel.end()) + { + auto eventOffsets = it->second; + auto targetIt = std::find(eventOffsets.begin(), + eventOffsets.end(), evOffset); + if (targetIt != eventOffsets.end()) + { + for (const auto& offset : eventOffsets) + { + if (offset == evOffset) + { + continue; + } + sensorStatusRec[sensorPath].alarmStatus &= + ~(statusBit << (offset * ALARM_BIT_NUM)); + } + } + } + } + else + { + sensorStatusRec[sensorPath].alarmStatus |= + statusBit << (evOffset * ALARM_BIT_NUM); + } + } + + if (isGenericDiscreteSensor) + { + if (ed != 0) + { + // Generic discrete sensor's events are mutually exclusive, + // and at the same time, only one bit of 'sensorStatus' will be set, + // so there is '=', not '|=' + sensorStatusRec[sensorPath].sensorStatus = 1 << evOffset; + } + else + { + sensorStatusRec[sensorPath].sensorStatus &= ~(1 << evOffset); + } + } + else + { + if (ed != 0) + { + sensorStatusRec[sensorPath].sensorStatus |= 1 << evOffset; + } + else + { + sensorStatusRec[sensorPath].sensorStatus &= ~(1 << evOffset); + } + } +} + +/*record led status and entity manager status*/ +inline void recordAlarmStatus(SensorStatus& statusRec, + const AlarmType& alarmStatus, const int& evOffset, + const int& ed, const bool& assertAlarm, + const bool& isGenericDiscreteSensor) +{ + uint64_t statusBit = static_cast(alarmStatus); + if (assertAlarm) + { + if (ed) + { + statusRec.alarmStatus |= statusBit << (evOffset * ALARM_BIT_NUM); + } + else + { + statusRec.alarmStatus &= ~(statusBit << (evOffset * ALARM_BIT_NUM)); + } + } + else + { + if (ed) + { + statusRec.alarmStatus &= ~(statusBit << (evOffset * ALARM_BIT_NUM)); + } + else + { + statusRec.alarmStatus |= statusBit << (evOffset * ALARM_BIT_NUM); + } + } + + if (isGenericDiscreteSensor) + { + if (ed) + { + // Generic discrete sensor's events are mutually exclusive, + // and at the same time, only one bit of 'sensorStatus' will be set, + // so there is '=', not '|=' + statusRec.sensorStatus = 1 << evOffset; + } + else + { + statusRec.sensorStatus &= ~(1 << evOffset); + } + } + else + { + if (ed) + { + statusRec.sensorStatus |= 1 << evOffset; + } + else + { + statusRec.sensorStatus &= ~(1 << evOffset); + } + } +} + +enum +{ + SYSTEM_FIRMWARE_ERROR_INDEX_START = 0x00, + SYSTEM_FIRMWARE_ERROR_INDEX_END = 0x0D, +}; + +enum +{ + POWER_FAULT_START_EVENT_INDEX = 0x00, + POWER_FAULT_END_EVENT_INDEX = 0x08, }; + void fillSensorDescription(const std::string& sensorPath, int eventOffset) { sensorStatusRec[sensorPath].description = discreteSensorNs; @@ -599,6 +834,7 @@ void fillSensorDescription(const std::string& sensorPath, int eventOffset) //} } + void parseSpecificSensorSelSeverity(sdbusplus::bus::bus& bus, const std::string& sensorPath, const SensorType& sensorType, @@ -698,6 +934,109 @@ void parseSpecificSensorSelSeverity(sdbusplus::bus::bus& bus, return; } +void powerFaultRecAlarmStatus(const std::string& sensorPath) +{ + uint16_t sensorStatus = 0; + uint64_t alarmStatus = 0; + constexpr uint64_t eventType03hStateMask = + (1 << EVENT_TYPE_03H_STATE_DEASSERT) | + (1 << EVENT_TYPE_03H_STATE_ASSERT); + + for (const auto& [evIndex, status] : powerFaultStatusRec) + { + sensorStatus |= (status.sensorStatus & eventType03hStateMask); + /*only need to record an alarm on bit0-bit2*/ + uint64_t alarm = status.alarmStatus; + if (ALARM_STATUS_MASK_C & alarm) + { + alarmStatus |= CRITICAL; + } + else if (ALARM_STATUS_MASK_NR & alarm) + { + alarmStatus |= NONRECOV; + } + else if (ALARM_STATUS_MASK_NC & alarm) + { + alarmStatus |= NONCRITICAL; + } + } + + sensorStatusRec[sensorPath].sensorStatus = sensorStatus; + sensorStatusRec[sensorPath].alarmStatus = alarmStatus; +} + +struct AlarmAction +{ + AlarmType alarmStatus; + bool assertToAlarm; /*true: assert to alarm; false: deassert to alarm*/ +}; + +/*event offset, action*/ +using EventActions = std::unordered_map; + +/*event type, all actions*/ +using EventAlarm = std::unordered_map; + + void parseDiscreteGenericSelSeverity( + sdbusplus::bus::bus& bus, const std::string& sensorPath, + const SensorType& sensorType, const uint8_t& eventType, + const std::string& eventData, const std::string& eventDir, + const AlarmType& severity, const bool& assertToAlarm) +{ + // The sensorStatusRec[sensorPath] obj will be created when init the + // 'Status'. See: initDiscreteSensorStatusInfo() and sensorMatchHandler(). + // If true, it means that the 'Status' has been initialized + // and the status sensor object on the entity-manager has been created. + + // if (sensorStatusRec.find(sensorPath) == sensorStatusRec.end()) + // { + // lg2::error( + // "sensorPath not found in sensorStatusRec: {PATH}, add sensorPath into getPathfailedRec", + // "PATH", sensorPath); + // SelSeverityInfo severityInfo(sensorPath, sensorType, eventType, + // eventData, eventDir, severity, + // assertToAlarm); + // getPathfailedRec[sensorPath].push_back(severityInfo); + // return; + // } + + std::string eventData1 = eventData.substr(0, 2); + int ev = std::stol(eventData1, nullptr, 16); + int ed = std::stol(eventDir); + int ev1Offset = ev & SENSOR_EVENT_DATA1_EVENT_OFFSET; + + if (sensorType != SENSOR_TYPE_POWER_FAULT) + { + recordAlarmStatus(sensorPath, severity, ev1Offset, ed, assertToAlarm, + true); + } + else + { + std::string eventData2 = eventData.substr(2, 2); + int ev2Index = std::stol(eventData2, nullptr, 16); + + if (ev2Index < POWER_FAULT_START_EVENT_INDEX || + ev2Index > POWER_FAULT_END_EVENT_INDEX) + { + lg2::error("Invalid event index = {INDEX}", "INDEX", ev2Index); + return; + } + + recordAlarmStatus(powerFaultStatusRec[ev2Index], severity, ev1Offset, + ed, assertToAlarm, true); + powerFaultRecAlarmStatus(sensorPath); + } + + sensorStatusRec[sensorPath].eventType = eventType; + sensorStatusRec[sensorPath].sensorType = sensorType; + + setDiscreteSensorStatusValue(bus, sensorPath, eventData); + + //updateSensorStatus(bus, sensorPath); + + //controlHealthLed(bus); +} + void Add::filterSEL(sdbusplus::bus::bus& bus, const std::string& path) { //AlarmType severity = NORMAL; @@ -728,7 +1067,9 @@ void Add::filterSEL(sdbusplus::bus::bus& bus, const std::string& path) uint8_t typeCode = 0; uint8_t sensorType = 0; - std::string sensorData, sensorPath, eventDir; + std::string sensorData, sensorPath, eventDir, assertAlarm; + bool assertToAlarm; + AlarmType confSeverity = AlarmType::NORMAL; for (auto& item : additionalDatas) { std::string::size_type nStr; @@ -760,6 +1101,16 @@ void Add::filterSEL(sdbusplus::bus::bus& bus, const std::string& path) std::cerr << "sensorPath " << sensorPath <<"\n"; } } + + if (assertAlarm.empty()) + { + nStr = item.find("ASSERT_ALARM="); + if (std::string::npos != nStr) + { + assertAlarm = item.substr(nStr + strlen("ASSERT_ALARM=")); + assertToAlarm = std::stol(assertAlarm, nullptr, 10); + } + } } if (!ipmiSensors) @@ -795,9 +1146,19 @@ void Add::filterSEL(sdbusplus::bus::bus& bus, const std::string& path) else if (typeCode == SPECIFIC_SENSOR_TYPE) { // discrete - parseSpecificSensorSelSeverity( + parseSpecificSensorSelSeverity( bus, sensorPath, static_cast(sensorType), sensorData, eventDir); + }else if (typeCode >= GENERIC_START_SENSOR_TYPE && + typeCode <= GENERIC_END_SENSOR_TYPE) + { + parseDiscreteGenericSelSeverity( + bus, sensorPath, static_cast(sensorType), typeCode, + sensorData, eventDir, confSeverity, assertToAlarm); + } + else + { + return; } //controlHealthLed(bus); diff --git a/fault-monitor/fru-fault-monitor.hpp b/fault-monitor/fru-fault-monitor.hpp index bd4a852..0dacc0c 100644 --- a/fault-monitor/fru-fault-monitor.hpp +++ b/fault-monitor/fru-fault-monitor.hpp @@ -118,9 +118,10 @@ struct SensorStatusInfo uint16_t sensorStatus; uint64_t alarmStatus; std::string description; // add description for discrete sensor + uint8_t sdrType; // Only for discrete sensors }; -struct DriveStatus +struct SensorStatus { uint16_t sensorStatus; /*entity status*/ uint64_t alarmStatus; /*alarm status*/ -- 2.25.1