From 8b6def70a95ddab05ec565db1c5437ad17423d20 Mon Sep 17 00:00:00 2001
From: "Wang.Bin" <Bin-B.Wang@luxshare-ict.com>
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<uint8_t> 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<std::string, ConfigData*> 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<uint8_t, 3>({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<uint8_t, 3>({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<uint8_t, 3>({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<std::string> 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<std::vector<std::string>>
+     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<std::string> 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<std::string>({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<std::string> 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

