psu-ng: Clear faults when voltage back in range

If the last read voltage (via READ_VIN) was below the minimum and
now it is back in a valid range (100 or 200 volt range valid), clear all
the faults to allow for re-detection of faults and logging of new errors.

Trace if INPUT_FAULT_WARN or VIN_UV clear. We should not expect to see
that without sending a CLEAR_FAULTS command (or a power cycle).

Tested:
    Rainier 2S2U real hardware.
    ePDU outlet off/on allows re-detection of injected CML fault.
    - input fault, vin_uv fault, pgood/off fault.
    - repeat shows faults cleared, and new faults logged.
    Simulator pgood fault, then low voltage followed by good voltage.
    Verify simulator can re-detect faults after voltage back in range.
    Simulator fake input fault/warn on, then off and other fault on.
    - verified tracing input going off without clear faults sent.
    Simulator fake input fault/warn on, then no faults.
    - verified tracing input going off without clear faults sent.

Change-Id: Ic8022cf137978ff660680e9680f778853cbecf0d
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/power_supply.cpp b/phosphor-power-supply/power_supply.cpp
index d416c94..c2dccfb 100644
--- a/phosphor-power-supply/power_supply.cpp
+++ b/phosphor-power-supply/power_supply.cpp
@@ -220,6 +220,20 @@
 
         inputFault = true;
     }
+
+    // If had INPUT/VIN_UV fault, and now off.
+    // Trace that odd behavior.
+    if (inputFault &&
+        !(statusWord & phosphor::pmbus::status_word::INPUT_FAULT_WARN))
+    {
+        log<level::INFO>(
+            fmt::format("INPUT fault cleared: STATUS_WORD = {:#04x}, "
+                        "STATUS_MFR_SPECIFIC = {:#02x}, "
+                        "STATUS_INPUT = {:#02x}",
+                        statusWord, statusMFR, statusInput)
+                .c_str());
+        inputFault = false;
+    }
 }
 
 void PowerSupply::analyzeVoutOVFault()
@@ -390,6 +404,18 @@
 
         vinUVFault = true;
     }
+
+    if (vinUVFault &&
+        !(statusWord & phosphor::pmbus::status_word::VIN_UV_FAULT))
+    {
+        log<level::INFO>(
+            fmt::format("VIN_UV fault cleared: STATUS_WORD = {:#04x}, "
+                        "STATUS_MFR_SPECIFIC = {:#02x}, "
+                        "STATUS_INPUT = {:#02x}",
+                        statusWord, statusMFR, statusInput)
+                .c_str());
+        vinUVFault = false;
+    }
 }
 
 void PowerSupply::analyze()
@@ -470,6 +496,24 @@
 
                 clearFaultFlags();
             }
+
+            // Save off old inputVoltage value.
+            // Get latest inputVoltage.
+            // If voltage went from below minimum, and now is not, clear faults.
+            // Note: getInputVoltage() has its own try/catch.
+            int inputVoltageOld = inputVoltage;
+            double actualInputVoltage;
+            getInputVoltage(actualInputVoltage, inputVoltage);
+            if ((inputVoltageOld == in_input::VIN_VOLTAGE_0) &&
+                (inputVoltage != in_input::VIN_VOLTAGE_0))
+            {
+                log<level::INFO>(
+                    fmt::format(
+                        "READ_VIN back in range: inputVoltageOld = {} inputVoltage = {}",
+                        inputVoltageOld, inputVoltage)
+                        .c_str());
+                clearFaults();
+            }
         }
         catch (const ReadFailure& e)
         {
@@ -505,6 +549,8 @@
 
 void PowerSupply::clearFaults()
 {
+    log<level::DEBUG>(
+        fmt::format("clearFaults() inventoryPath: {}", inventoryPath).c_str());
     faultLogged = false;
     // The PMBus device driver does not allow for writing CLEAR_FAULTS
     // directly. However, the pmbus hwmon device driver code will send a