psu-ng: Adjust power on monitoring window

Monitor both pgood and state properties from the power control d-bus
interface in order to adjust the window in which power supply monitoring
is done. Factor in both properties to determine when system is in power
failure and adjust which power supply failures are monitored in that
window.

Signed-off-by: Jim Wright <jlwright@us.ibm.com>
Change-Id: Ib13c9cc6689f0b67c4d396eabfcf50dcab155e9b
diff --git a/phosphor-power-supply/psu_manager.cpp b/phosphor-power-supply/psu_manager.cpp
index 1dfdcb0..e166c8b 100644
--- a/phosphor-power-supply/psu_manager.cpp
+++ b/phosphor-power-supply/psu_manager.cpp
@@ -85,6 +85,62 @@
     initialize();
 }
 
+void PSUManager::initialize()
+{
+    try
+    {
+        // pgood is the latest read of the chassis pgood
+        int pgood = 0;
+        util::getProperty<int>(POWER_IFACE, "pgood", POWER_OBJ_PATH,
+                               powerService, bus, pgood);
+
+        // state is the latest requested power on / off transition
+        auto method = bus.new_method_call(POWER_IFACE, POWER_OBJ_PATH,
+                                          POWER_IFACE, "getPowerState");
+        auto reply = bus.call(method);
+        int state = 0;
+        reply.read(state);
+
+        if (state)
+        {
+            // Monitor PSUs anytime state is on
+            powerOn = true;
+            // In the power fault window if pgood is off
+            powerFaultOccurring = !pgood;
+            validationTimer->restartOnce(validationTimeout);
+        }
+        else
+        {
+            // Power is off
+            powerOn = false;
+            powerFaultOccurring = false;
+            runValidateConfig = true;
+        }
+    }
+    catch (const std::exception& e)
+    {
+        log<level::INFO>(
+            fmt::format(
+                "Failed to get power state, assuming it is off, error {}",
+                e.what())
+                .c_str());
+        powerOn = false;
+        powerFaultOccurring = false;
+        runValidateConfig = true;
+    }
+
+    onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
+    clearFaults();
+    updateMissingPSUs();
+    updateInventory();
+    setPowerConfigGPIO();
+
+    log<level::INFO>(
+        fmt::format("initialize: power on: {}, power fault occurring: {}",
+                    powerOn, powerFaultOccurring)
+            .c_str());
+}
+
 void PSUManager::getPSUConfiguration()
 {
     using namespace phosphor::power::util;
@@ -351,21 +407,20 @@
 
 void PSUManager::powerStateChanged(sdbusplus::message::message& msg)
 {
-    int32_t state = 0;
     std::string msgSensor;
-    std::map<std::string, std::variant<int32_t>> msgData;
+    std::map<std::string, std::variant<int>> msgData;
     msg.read(msgSensor, msgData);
 
-    // Check if it was the Present property that changed.
+    // Check if it was the state property that changed.
     auto valPropMap = msgData.find("state");
     if (valPropMap != msgData.end())
     {
-        state = std::get<int32_t>(valPropMap->second);
-
-        // Power is on when state=1. Clear faults.
+        int state = std::get<int>(valPropMap->second);
         if (state)
         {
+            // Power on requested
             powerOn = true;
+            powerFaultOccurring = false;
             validationTimer->restartOnce(validationTimeout);
             clearFaults();
             syncHistory();
@@ -373,10 +428,33 @@
         }
         else
         {
+            // Power off requested
             powerOn = false;
+            powerFaultOccurring = false;
             runValidateConfig = true;
         }
     }
+
+    // Check if it was the pgood property that changed.
+    valPropMap = msgData.find("pgood");
+    if (valPropMap != msgData.end())
+    {
+        int pgood = std::get<int>(valPropMap->second);
+        if (!pgood)
+        {
+            // Chassis power good has turned off
+            if (powerOn)
+            {
+                // pgood is off but state is on, in power fault window
+                powerFaultOccurring = true;
+            }
+        }
+    }
+    log<level::INFO>(
+        fmt::format(
+            "powerStateChanged: power on: {}, power fault occurring: {}",
+            powerOn, powerFaultOccurring)
+            .c_str());
 }
 
 void PSUManager::presenceChanged(sdbusplus::message::message& msg)
@@ -650,7 +728,8 @@
                 }
                 // A fan fault should have priority over a temperature fault,
                 // since a failed fan may lead to a temperature problem.
-                else if (psu->hasFanFault())
+                // Only process if not in power fault window.
+                else if (psu->hasFanFault() && !powerFaultOccurring)
                 {
                     // Include STATUS_TEMPERATURE and STATUS_FANS_1_2
                     additionalData["STATUS_TEMPERATURE"] =
@@ -702,7 +781,8 @@
 
                     psu->setFaultLogged();
                 }
-                else if (psu->hasPgoodFault())
+                // Only process if not in power fault window.
+                else if (psu->hasPgoodFault() && !powerFaultOccurring)
                 {
                     /* POWER_GOOD# is not low, or OFF is on */
                     additionalData["CALLOUT_INVENTORY_PATH"] =
diff --git a/phosphor-power-supply/psu_manager.hpp b/phosphor-power-supply/psu_manager.hpp
index fff6a19..6f58eec 100644
--- a/phosphor-power-supply/psu_manager.hpp
+++ b/phosphor-power-supply/psu_manager.hpp
@@ -95,41 +95,7 @@
      *
      * Get current BMC state, ...
      */
-    void initialize()
-    {
-        // When state = 1, system is powered on
-        int32_t state = 0;
-
-        try
-        {
-            // Use getProperty utility function to get power state.
-            util::getProperty<int32_t>(POWER_IFACE, "state", POWER_OBJ_PATH,
-                                       powerService, bus, state);
-
-            if (state)
-            {
-                powerOn = true;
-                validationTimer->restartOnce(validationTimeout);
-            }
-            else
-            {
-                powerOn = false;
-                runValidateConfig = true;
-            }
-        }
-        catch (const std::exception& e)
-        {
-            log<level::INFO>("Failed to get power state. Assuming it is off.");
-            powerOn = false;
-            runValidateConfig = true;
-        }
-
-        onOffConfig(phosphor::pmbus::ON_OFF_CONFIG_CONTROL_PIN_ONLY);
-        clearFaults();
-        updateMissingPSUs();
-        updateInventory();
-        setPowerConfigGPIO();
-    }
+    void initialize();
 
     /**
      * Starts the timer to start monitoring the list of devices.
@@ -215,6 +181,10 @@
     /** @brief True if the power is on. */
     bool powerOn = false;
 
+    /** @brief True if power control is in the window between chassis pgood loss
+     * and power off. */
+    bool powerFaultOccurring = false;
+
     /** @brief True if an error for a brownout has already been logged. */
     bool brownoutLogged = false;