From 8b6def70a95ddab05ec565db1c5437ad17423d20 Mon Sep 17 00:00:00 2001 From: "Wang.Bin" Date: Tue, 3 Dec 2024 21:23:28 +0800 Subject: [PATCH 10/10] Fix soft-shutdown without SEL --- src/power_control.cpp | 275 +++++++++++++++++++++++++++++++++++------- 1 file changed, 233 insertions(+), 42 deletions(-) diff --git a/src/power_control.cpp b/src/power_control.cpp index 2a72473..cfe6e57 100644 --- a/src/power_control.cpp +++ b/src/power_control.cpp @@ -94,6 +94,22 @@ static ConfigData idButtonConfig; static ConfigData nmiButtonConfig; static ConfigData slotPowerConfig; +struct LogData +{ + bool assert; + uint16_t generatorID; + std::vector selData; + std::string sensorPath; +}; + +struct LogData acpiStatusOffSensor = {true, 0x0020, {6, 255, 255}, "null"}; +struct LogData acpiStatusOnSensor = {true, 0x0020, {0, 255, 255}, "null"}; +struct LogData osBootSensor = {true, 0x0020, {6, 255, 255}, "null"}; +struct LogData sysBootPowerUpSensor = {true, 0x0020, {0, 255, 255}, "null"}; +struct LogData sysBootHardResetSensor = {true, 0x0020, {1, 255, 255}, "null"}; +struct LogData sysBootWarmResetSensor = {true, 0x0020, {2, 255, 255}, "null"}; +struct LogData powerButtonPressedSensor = {true, 0x0020, {0, 255, 255}, "null"}; + // map for storing list of gpio parameters whose config are to be read from x86 // power control json config boost::container::flat_map powerSignalMap = { @@ -578,47 +594,48 @@ static void powerStateLog(const PowerState state) constexpr const char* selPath = "/xyz/openbmc_project/Logging/IPMI"; constexpr const char* selInterface = "xyz.openbmc_project.Logging.IPMI"; constexpr const char* selMethod = "IpmiSelAdd"; - std::string sensorPath = - "/xyz/openbmc_project/inventory/system/board/Lux_Baseboard/ACPI_State"; + struct LogData powerStatusSensor; auto bus = sdbusplus::bus::new_default(); - std::string stateStr = std::string(getChassisState(state)); + auto method = bus.new_method_call(selService, selPath, selInterface, selMethod); - method.append("SEL Entry"); - - if (stateStr == "xyz.openbmc_project.State.Chassis.PowerState.On") - { - std::cerr << "Send Power State On SEL Log\n"; - method.append(sensorPath.c_str()); - method.append( - std::array({0x00, 0xFF, 0xFF})); // S0/G0: working - } - else if (stateStr == "xyz.openbmc_project.State.Chassis.PowerState.Off") - { - std::cerr << "Send Power State Off SEL Log\n"; - method.append(sensorPath.c_str()); - method.append( - std::array({0x06, 0xFF, 0xFF})); // S4/S5: soft-off - } - else if (stateStr == "ButtonPressed") - { - std::cerr << "Send Power State Button Pressed SEL Log\n"; - sensorPath = "/xyz/openbmc_project/inventory/system/board/Lux_Baseboard/Power_Button"; - method.append(sensorPath.c_str()); - method.append( - std::array({0x00, 0xFF, 0xFF})); // power button pressed - } - else + switch (state) { - std::cerr << "Send Power State SEL Log Error\n"; - return; + case PowerState::on: + std::cout << "PowerState:: on" << std::endl; + powerStatusSensor = acpiStatusOnSensor; + break; + // both off and cycleOff will call acpiStatusOffSensor + case PowerState::off: + case PowerState::cycleOff: + std::cout << "PowerState:: off" << std::endl; + powerStatusSensor = acpiStatusOffSensor; + break; + case PowerState::transitionToCycleOff: + powerStatusSensor = sysBootHardResetSensor; + break; + case PowerState::waitForPSPowerOK: + powerStatusSensor = sysBootPowerUpSensor; + break; + case PowerState::checkForWarmReset: + powerStatusSensor = sysBootWarmResetSensor; + break; + case PowerState::powerButtonPressed: + powerStatusSensor = powerButtonPressedSensor; + break; + default: + break; } - method.append(true); // assert is true and deassert is false - method.append(uint16_t(0x0020)); // generator ID + method.append("SEL Entry"); + method.append(powerStatusSensor.sensorPath); + method.append(powerStatusSensor.selData); + method.append( + powerStatusSensor.assert); // assert is true and deassert is false + method.append(powerStatusSensor.generatorID); // generator ID try { bus.call_noreply(method); @@ -851,6 +868,7 @@ static void powerButtonPressLog() // sd_journal_send("MESSAGE=PowerControl: power button pressed", "PRIORITY=%i", // LOG_INFO, "REDFISH_MESSAGE_ID=%s", // "OpenBMC.0.1.PowerButtonPressed", NULL); + std::cout << "power button pressed" << __LINE__ << std::endl; powerStateLog(PowerState::powerButtonPressed); } @@ -1829,9 +1847,10 @@ static void currentHostStateMonitor() pohCounterTimerStart(); // Clear the restart cause set for the next restart clearRestartCause(); - sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i", - LOG_INFO, "REDFISH_MESSAGE_ID=%s", - "OpenBMC.0.1.DCPowerOn", NULL); + std::cout << "Host system DC power is on" << __LINE__ << std::endl; + //sd_journal_send("MESSAGE=Host system DC power is on", "PRIORITY=%i", + // LOG_INFO, "REDFISH_MESSAGE_ID=%s", + // "OpenBMC.0.1.DCPowerOn", NULL); } else { @@ -1848,9 +1867,10 @@ static void currentHostStateMonitor() #ifdef USE_ACBOOT resetACBootProperty(); #endif // USE_ACBOOT - sd_journal_send("MESSAGE=Host system DC power is off", - "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", - "OpenBMC.0.1.DCPowerOff", NULL); + std::cout << "Host system DC power is off" << __LINE__ << std::endl; + //sd_journal_send("MESSAGE=Host system DC power is off", + // "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s", + // "OpenBMC.0.1.DCPowerOff", NULL); } }); } @@ -1966,6 +1986,7 @@ static void powerStateWaitForPSPowerOK(const Event event) else { setPowerState(PowerState::on); + std::cout << "powerStateWaitForPSPowerOK" << __LINE__ << std::endl; powerStateLog(PowerState::on); } break; @@ -2018,7 +2039,6 @@ static void powerStateOff(const Event event) else { setPowerState(PowerState::on); - powerStateLog(PowerState::on); } break; } @@ -2053,6 +2073,7 @@ static void powerStateTransitionToOff(const Event event) // Cancel any GPIO assertions held during the transition gpioAssertTimer.cancel(); setPowerState(PowerState::off); + std::cout << "powerStateTransitionToOff" << __LINE__ << std::endl; powerStateLog(PowerState::off); break; default: @@ -2069,6 +2090,8 @@ static void powerStateGracefulTransitionToOff(const Event event) case Event::psPowerOKDeAssert: gracefulPowerOffTimer.cancel(); setPowerState(PowerState::off); + std::cout << "powerStateGracefulTransitionToOff power off" << __LINE__ << std::endl; + powerStateLog(PowerState::off); break; case Event::gracefulPowerOffTimerExpired: setPowerState(PowerState::on); @@ -2110,6 +2133,7 @@ static void powerStateCycleOff(const Event event) else { setPowerState(PowerState::on); + std::cout << "powerStateCycleOff:power on" << __LINE__ << std::endl; } break; } @@ -2143,6 +2167,7 @@ static void powerStateTransitionToCycleOff(const Event event) // Cancel any GPIO assertions held during the transition gpioAssertTimer.cancel(); setPowerState(PowerState::cycleOff); + std::cout << "powerStateTransitionToCycleOff power off" << __LINE__ << std::endl; powerStateLog(PowerState::cycleOff); powerCycleTimerStart(); break; @@ -2160,6 +2185,8 @@ static void powerStateGracefulTransitionToCycleOff(const Event event) case Event::psPowerOKDeAssert: gracefulPowerOffTimer.cancel(); setPowerState(PowerState::cycleOff); + std::cout << "powerStateGracefulTransitionToCycleOff power off" << __LINE__ << std::endl; + powerStateLog(PowerState::cycleOff); powerCycleTimerStart(); break; case Event::gracefulPowerOffTimerExpired: @@ -2201,6 +2228,8 @@ static void powerStateCheckForWarmReset(const Event event) case Event::psPowerOKDeAssert: warmResetCheckTimer.cancel(); setPowerState(PowerState::off); + std::cout << "powerStateCheckForWarmReset power off" << __LINE__ << std::endl; + powerStateLog(PowerState::cycleOff); // DC power is unexpectedly lost, beep beep(beepPowerFail); break; @@ -2496,12 +2525,43 @@ static void pltRstHandler(bool pltRst) } } +static void postCompleteLog() +{ + constexpr const char* selService = "xyz.openbmc_project.Logging.IPMI"; + constexpr const char* selPath = "/xyz/openbmc_project/Logging/IPMI"; + constexpr const char* selInterface = "xyz.openbmc_project.Logging.IPMI"; + constexpr const char* selMethod = "IpmiSelAdd"; + + auto bus = sdbusplus::bus::new_default(); + + auto method = + bus.new_method_call(selService, selPath, selInterface, selMethod); + + method.append("SEL Entry"); + method.append(osBootSensor.sensorPath); + method.append(osBootSensor.selData); + method.append(osBootSensor.assert); // assert is true and deassert is false + method.append(osBootSensor.generatorID); // generator ID + try + { + bus.call_noreply(method); + } + catch (const sdbusplus::exception::SdBusError& ex) + { + lg2::error( + "Failed to call sel log {SELPATH}, {SELINTERFACE}, {SELMRTHOD}", + "SELPATH", selPath, "SELINTERFACE", selInterface, "SELMRTHOD", + selMethod); + } +} + static void postCompleteHandler(bool state) { if (!state) { sendPowerControlEvent(Event::postCompleteAssert); setOperatingSystemState(OperatingSystemStateStage::Inactive); + //postCompleteLog(); } else { @@ -2510,6 +2570,107 @@ static void postCompleteHandler(bool state) } } +std::optional getDiscretePrefixFromFile() +{ + constexpr auto boardNameFile = "/usr/share/boardname/boardname.conf"; + constexpr auto boardPrefix = "/xyz/openbmc_project/inventory/system/board/"; + + std::ifstream file(boardNameFile); + if (!file.is_open()) + { + lg2::error("Fail to open {FILE}", "FILE", boardNameFile); + return std::nullopt; + } + + std::string boardName{}; + std::getline(file, boardName); + if (boardName.empty()) + { + lg2::error("Fail to read {FILE}", "FILE", boardNameFile); + return std::nullopt; + } + lg2::info("Board name is {BOARD}", "BOARD", boardName); + return boardPrefix + boardName; +} + +std::optional> + getSubTreePaths(sdbusplus::bus::bus& bus, const std::string& objectPath, + const std::string& interface) +{ + constexpr auto mapperBusname = "xyz.openbmc_project.ObjectMapper"; + constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; + constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; + std::vector paths; + + auto method = bus.new_method_call(mapperBusname, mapperObjPath, mapperIface, + "GetSubTreePaths"); + method.append(objectPath.c_str()); + method.append(0); // Depth 0 to search all + method.append(std::vector({interface.c_str()})); + + try + { + auto reply = bus.call(method); + reply.read(paths); + return paths; + } + catch (const sdbusplus::exception::SdBusError& e) + { + lg2::error("Fail to get chassis path"); + return std::nullopt; + } + + return std::nullopt; +} + +std::optional getDiscreteSensorPath(const std::string& sensorName) +{ + static std::string discreteSensorPathPrefix{}; + if (discreteSensorPathPrefix.empty()) + { + // First try to get the path from the file + auto prefix = getDiscretePrefixFromFile(); + if (prefix) + { + discreteSensorPathPrefix = *prefix; + } + else + { + // If the file doesn't exist, get the path from the dbus + constexpr auto discreteSensorUpperPath = + "/xyz/openbmc_project/inventory"; + constexpr auto discreteSensorInterface = + "xyz.openbmc_project.Configuration.Status"; + auto bus = sdbusplus::bus::new_default(); + auto sensorPaths = getSubTreePaths(bus, discreteSensorUpperPath, + discreteSensorInterface); + // if call fail or empty, return nullopt + if (!sensorPaths || sensorPaths.value().size() == 0) + { + return std::nullopt; + } + // if any sensor path is find, get the prefix of the path + // because all discrete sensor path in the inventory has the same + // prefix + for (const auto& sensorPath : sensorPaths.value()) + { + discreteSensorPathPrefix = + sensorPath.substr(0, sensorPath.find_last_of('/')); + break; + } + if (discreteSensorPathPrefix.empty()) + { + return std::nullopt; + } + } + } + + std::string path = discreteSensorPathPrefix; + path.append("/"); + path.append(sensorName); + return path; +} + static int loadConfigValues() { const std::string configFilePath = @@ -2661,6 +2822,33 @@ static int loadConfigValues() nmiWhenPoweredOff = events.value("NMIWhenPoweredOff", true); } + auto acpiSensorPath = getDiscreteSensorPath("ACPI_State"); + if (acpiSensorPath != std::nullopt) + { + acpiStatusOnSensor.sensorPath = acpiSensorPath.value(); + acpiStatusOffSensor.sensorPath = acpiSensorPath.value(); + } + + auto sysbootSensorPath = getDiscreteSensorPath("SYS_Boot"); + if (sysbootSensorPath != std::nullopt) + { + sysBootPowerUpSensor.sensorPath = sysbootSensorPath.value(); + sysBootHardResetSensor.sensorPath = sysbootSensorPath.value(); + sysBootWarmResetSensor.sensorPath = sysbootSensorPath.value(); + } + + auto osbootSensorPath = getDiscreteSensorPath("OS_Boot"); + if (osbootSensorPath != std::nullopt) + { + osBootSensor.sensorPath = osbootSensorPath.value(); + } + + auto powerbuttonSensorPath = getDiscreteSensorPath("Power_Button"); + if (powerbuttonSensorPath != std::nullopt) + { + powerButtonPressedSensor.sensorPath = powerbuttonSensorPath.value(); + } + return 0; } @@ -2840,7 +3028,7 @@ void reschedulePropertyRead(const ConfigData& configData) } }); } - +bool bmcReset = true; static void ACPIStateSel(void) { const static constexpr int TimeMs = 20000; @@ -2856,8 +3044,11 @@ static void ACPIStateSel(void) ec.message()); } } - lg2::info("ACPI State sel"); - powerStateLog(powerState); + std::cout << "BMC reboot:power state" << __LINE__ << std::endl; + if (bmcReset == true){ + powerStateLog(powerState); + } + bmcReset = false; }); } -- 2.25.1