pseq: Check STATUS_VOUT first to find pgood fault

Enhance the support for finding the correct voltage rail when a pgood
fault occurs.

First check the PMBus STATUS_VOUT register for all rails.  Check the
rails in power-on-sequence order.

Checking STATUS_VOUT is usually the most accurate method.  For example,
if a pgood fault occurs, the power sequencer device may automatically
shut off related rails.  Ideally the device will only set fault bits in
STATUS_VOUT for the rail with the pgood fault.  However, all the related
rails will likely appear to be faulted by the other methods.

If no fault is found by checking STATUS_VOUT, then check the GPIOs and
output voltage for all rails.  Check the rails in power-on-sequence
order.

Tested:
* Verified all automated test cases run successfully.

Change-Id: Ida8732db573013f1b72edac8ed54e3cfc38da146
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
diff --git a/phosphor-power-sequencer/src/rail.cpp b/phosphor-power-sequencer/src/rail.cpp
index 18866c5..ec97108 100644
--- a/phosphor-power-sequencer/src/rail.cpp
+++ b/phosphor-power-sequencer/src/rail.cpp
@@ -121,46 +121,9 @@
                          const std::vector<int>& gpioValues,
                          std::map<std::string, std::string>& additionalData)
 {
-    // If rail is not present, return false and don't check anything else
-    if (!isPresent(services))
-    {
-        services.logInfoMsg(std::format("Rail {} is not present", name));
-        return false;
-    }
-
-    // Check if STATUS_VOUT indicates a pgood fault occurred
-    bool hasFault = hasPgoodFaultStatusVout(device, services, additionalData);
-
-    // Check if a GPIO value indicates a pgood fault occurred
-    if (!hasFault)
-    {
-        hasFault = hasPgoodFaultGPIO(services, gpioValues, additionalData);
-    }
-
-    // Check if output voltage is below UV limit indicating pgood fault occurred
-    if (!hasFault)
-    {
-        hasFault = hasPgoodFaultOutputVoltage(device, services, additionalData);
-    }
-
-    // If fault detected, store debug data in additional data map
-    if (hasFault)
-    {
-        services.logErrorMsg(
-            std::format("Pgood fault detected in rail {}", name));
-        storePgoodFaultDebugData(device, services, additionalData);
-    }
-
-    return hasFault;
-}
-
-void Rail::verifyHasPage()
-{
-    if (!page)
-    {
-        throw std::runtime_error{
-            std::format("No PAGE number defined for rail {}", name)};
-    }
+    return (hasPgoodFaultStatusVout(device, services, additionalData) ||
+            hasPgoodFaultGPIO(device, services, gpioValues, additionalData) ||
+            hasPgoodFaultOutputVoltage(device, services, additionalData));
 }
 
 bool Rail::hasPgoodFaultStatusVout(
@@ -169,8 +132,8 @@
 {
     bool hasFault{false};
 
-    // If we are checking the value of STATUS_VOUT for the rail
-    if (checkStatusVout)
+    // If rail is present and we are checking the value of STATUS_VOUT
+    if (isPresent(services) && checkStatusVout)
     {
         // Read STATUS_VOUT value from device
         uint8_t statusVout = getStatusVout(device);
@@ -184,6 +147,7 @@
                 statusVout));
             additionalData.emplace("STATUS_VOUT",
                                    std::format("{:#04x}", statusVout));
+            storePgoodFaultDebugData(device, services, additionalData);
         }
         else if (statusVout != 0)
         {
@@ -196,14 +160,14 @@
     return hasFault;
 }
 
-bool Rail::hasPgoodFaultGPIO(Services& services,
+bool Rail::hasPgoodFaultGPIO(PowerSequencerDevice& device, Services& services,
                              const std::vector<int>& gpioValues,
                              std::map<std::string, std::string>& additionalData)
 {
     bool hasFault{false};
 
-    // If a GPIO is defined for checking pgood status
-    if (gpio)
+    // If rail is present and a GPIO is defined for checking pgood status
+    if (isPresent(services) && gpio)
     {
         // Get GPIO value
         unsigned int line = gpio->line;
@@ -225,6 +189,7 @@
                 line, value));
             additionalData.emplace("GPIO_LINE", std::format("{}", line));
             additionalData.emplace("GPIO_VALUE", std::format("{}", value));
+            storePgoodFaultDebugData(device, services, additionalData);
         }
     }
 
@@ -237,8 +202,8 @@
 {
     bool hasFault{false};
 
-    // If we are comparing output voltage to UV limit to check pgood status
-    if (compareVoltageToLimit)
+    // If rail is present and we are comparing output voltage to UV limit
+    if (isPresent(services) && compareVoltageToLimit)
     {
         // Read output voltage and UV fault limit values from device
         double vout = getReadVout(device);
@@ -254,16 +219,27 @@
             additionalData.emplace("READ_VOUT", std::format("{}", vout));
             additionalData.emplace("VOUT_UV_FAULT_LIMIT",
                                    std::format("{}", uvLimit));
+            storePgoodFaultDebugData(device, services, additionalData);
         }
     }
 
     return hasFault;
 }
 
+void Rail::verifyHasPage()
+{
+    if (!page)
+    {
+        throw std::runtime_error{
+            std::format("No PAGE number defined for rail {}", name)};
+    }
+}
+
 void Rail::storePgoodFaultDebugData(
     PowerSequencerDevice& device, Services& services,
     std::map<std::string, std::string>& additionalData)
 {
+    services.logErrorMsg(std::format("Pgood fault detected in rail {}", name));
     additionalData.emplace("RAIL_NAME", name);
     if (page)
     {