Add in support for power supply fan fault

If the FAN FAULT OR WARN bit in the STATUS_WORD turns on, log an error
calling out the power supply, include the contents from STATUS_WORD,
MFR_SPECIFIC, STATUS_TEMPERATURE, and STATUS_FANS_1_2 in the metadata.

Change-Id: Ic9261cf08517344f594a4616a91dbec47bb07d7e
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index b3d556c..d9e870c 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -109,6 +109,7 @@
                 checkPGOrUnitOffFault(statusWord);
                 checkCurrentOutOverCurrentFault(statusWord);
                 checkOutputOvervoltageFault(statusWord);
+                checkFanFault(statusWord);
             }
         }
     }
@@ -143,6 +144,7 @@
             inputFault = false;
             outputOCFault = false;
             outputOVFault = false;
+            fanFault = false;
         }
     }
 
@@ -194,6 +196,7 @@
             powerOnFault = false;
             outputOCFault = false;
             outputOVFault = false;
+            fanFault = false;
             powerOnTimer.start(powerOnInterval, Timer::TimerType::oneshot);
         }
         else
@@ -418,6 +421,39 @@
     }
 }
 
+void PowerSupply::checkFanFault(const uint16_t statusWord)
+{
+    using namespace witherspoon::pmbus;
+
+    std::uint8_t statusMFR  = 0;
+    std::uint8_t statusTemperature = 0;
+    std::uint8_t statusFans12 = 0;
+
+    // Check for an output overcurrent fault.
+    if ((statusWord & status_word::FAN_FAULT) &&
+        !fanFault)
+    {
+        statusMFR = pmbusIntf.read(STATUS_MFR, Type::Debug);
+        statusTemperature = pmbusIntf.read(STATUS_TEMPERATURE, Type::Debug);
+        statusFans12 = pmbusIntf.read(STATUS_FANS_1_2, Type::Debug);
+
+        util::NamesValues nv;
+        nv.add("STATUS_WORD", statusWord);
+        nv.add("MFR_SPECIFIC", statusMFR);
+        nv.add("STATUS_TEMPERATURE", statusTemperature);
+        nv.add("STATUS_FANS_1_2", statusFans12);
+
+        using metadata = xyz::openbmc_project::Power::Fault::
+                PowerSupplyFanFault;
+
+        report<PowerSupplyFanFault>(
+                metadata::RAW_STATUS(nv.get().c_str()),
+                metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
+
+        fanFault = true;
+    }
+}
+
 void PowerSupply::clearFaults()
 {
     //TODO - Clear faults at pre-poweron. openbmc/openbmc#1736