psu-ng: Add in handling of specific MFR faults

Add in a function to determine what the various bits in statusMFR may be
indicating for a fault, based on the type of power supply (device driver
bound).

Add in PS_Kill, 12Vcs, and 12V CS faults for IBM power supply types.

Add in creating error logs for PS_Kill, 12Vcs, and 12V CS faults. The
12Vcs and 12V CS faults can essentially be treated the same as VOUT_UV
faults (same error type, same call out).

Tested:
Verified no PS_Kill, 12Vcs, or 12V CS fault on normal Rainier 2S4U

Simulated PS_Kill fault:
MFR fault: STATUS_WORD = 0x1840 STATUS_MFR_SPECIFIC = 0x10

Simulated 12Vcs fault:
PGOOD fault: STATUS_WORD = 0x1840, STATUS_MFR_SPECIFIC = 0x40
MFR fault: STATUS_WORD = 0x1840 STATUS_MFR_SPECIFIC = 0x40

Simulated 12V CS fault/warning:
MFR fault: STATUS_WORD = 0x1000 STATUS_MFR_SPECIFIC = 0x80

Change-Id: Ie89a58836ecec86dfa2e124eb6ab03e9dccce929
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 222d9c3..a762ecb 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -159,6 +159,9 @@
         EXPECT_EQ(psu->hasFanFault(), false);
         EXPECT_EQ(psu->hasTempFault(), false);
         EXPECT_EQ(psu->hasPgoodFault(), false);
+        EXPECT_EQ(psu->hasPSKillFault(), false);
+        EXPECT_EQ(psu->hasPS12VcsFault(), false);
+        EXPECT_EQ(psu->hasPSCS12VFault(), false);
     }
     catch (...)
     {
@@ -209,6 +212,9 @@
         EXPECT_EQ(psu.hasFanFault(), false);
         EXPECT_EQ(psu.hasTempFault(), false);
         EXPECT_EQ(psu.hasPgoodFault(), false);
+        EXPECT_EQ(psu.hasPSKillFault(), false);
+        EXPECT_EQ(psu.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu.hasPSCS12VFault(), false);
     }
 
     PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
@@ -219,7 +225,6 @@
     // Always return 1 to indicate present.
     // Each analyze() call will trigger a read of the presence GPIO.
     EXPECT_CALL(*mockPresenceGPIO2, read()).WillRepeatedly(Return(1));
-    // Not present until analyze() does the GPIO read.
     EXPECT_EQ(psu2.isPresent(), false);
 
     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
@@ -255,6 +260,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
 
         // Update expectations for STATUS_WORD input fault/warn
         // STATUS_INPUT fault bits ... on.
@@ -274,6 +282,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // STATUS_WORD INPUT/UV fault.
@@ -301,6 +312,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // STATUS_WORD MFR fault.
@@ -327,6 +341,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), true);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), true);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), true);
     }
 
     // Temperature fault.
@@ -353,6 +370,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), true);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // CML fault
@@ -379,6 +399,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // VOUT_OV_FAULT fault
@@ -407,6 +430,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // IOUT_OC_FAULT fault
@@ -433,6 +459,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // VOUT_UV_FAULT
@@ -459,6 +488,9 @@
         EXPECT_EQ(psu2.hasFanFault(), false);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // Fan fault
@@ -484,6 +516,9 @@
         EXPECT_EQ(psu2.hasFanFault(), true);
         EXPECT_EQ(psu2.hasTempFault(), false);
         EXPECT_EQ(psu2.hasPgoodFault(), false);
+        EXPECT_EQ(psu2.hasPSKillFault(), false);
+        EXPECT_EQ(psu2.hasPS12VcsFault(), false);
+        EXPECT_EQ(psu2.hasPSCS12VFault(), false);
     }
 
     // PGOOD/OFF fault. Deglitched, needs to reach DEGLITCH_LIMIT.
@@ -614,6 +649,9 @@
     EXPECT_EQ(psu.hasFanFault(), false);
     EXPECT_EQ(psu.hasTempFault(), false);
     EXPECT_EQ(psu.hasPgoodFault(), false);
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
 
     // STATUS_WORD with fault bits galore!
     expectations.statusWordValue = 0xFFFF;
@@ -655,6 +693,9 @@
     psu.analyze();
     // DEGLITCH_LIMIT reached for pgoodFault
     EXPECT_EQ(psu.hasPgoodFault(), true);
+    EXPECT_EQ(psu.hasPSKillFault(), true);
+    EXPECT_EQ(psu.hasPS12VcsFault(), true);
+    EXPECT_EQ(psu.hasPSCS12VFault(), true);
 
     EXPECT_CALL(mockPMBus, read("in1_input", _))
         .Times(1)
@@ -672,6 +713,9 @@
     EXPECT_EQ(psu.hasFanFault(), false);
     EXPECT_EQ(psu.hasTempFault(), false);
     EXPECT_EQ(psu.hasPgoodFault(), false);
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
 
     // TODO: Faults clear on missing/present?
 }
@@ -1083,3 +1127,129 @@
     psu.analyze();
     EXPECT_EQ(psu.hasPgoodFault(), false);
 }
+
+TEST_F(PowerSupplyTests, HasPSKillFault)
+{
+    auto bus = sdbusplus::bus::new_default();
+    PowerSupply psu{bus, PSUInventoryPath, 4, 0x6d, PSUGPIOLineName};
+    MockedGPIOInterface* mockPresenceGPIO =
+        static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+    // Always return 1 to indicate present.
+    EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    // STATUS_WORD 0x0000 is powered on, no faults.
+    PMBusExpectations expectations;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit(s) on.
+    expectations.statusMFRValue = 0xFF;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit 4 on.
+    expectations.statusMFRValue = 0x10;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSKillFault(), false);
+}
+
+TEST_F(PowerSupplyTests, HasPS12VcsFault)
+{
+    auto bus = sdbusplus::bus::new_default();
+    PowerSupply psu{bus, PSUInventoryPath, 5, 0x6e, PSUGPIOLineName};
+    MockedGPIOInterface* mockPresenceGPIO =
+        static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+    // Always return 1 to indicate present.
+    EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    // STATUS_WORD 0x0000 is powered on, no faults.
+    PMBusExpectations expectations;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit(s) on.
+    expectations.statusMFRValue = 0xFF;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit 6 on.
+    expectations.statusMFRValue = 0x40;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPS12VcsFault(), false);
+}
+
+TEST_F(PowerSupplyTests, HasPSCS12VFault)
+{
+    auto bus = sdbusplus::bus::new_default();
+    PowerSupply psu{bus, PSUInventoryPath, 6, 0x6f, PSUGPIOLineName};
+    MockedGPIOInterface* mockPresenceGPIO =
+        static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+    // Always return 1 to indicate present.
+    EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
+    MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    // STATUS_WORD 0x0000 is powered on, no faults.
+    PMBusExpectations expectations;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit(s) on.
+    expectations.statusMFRValue = 0xFF;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
+    // Next return STATUS_WORD with MFR fault bit on.
+    expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
+    // STATUS_MFR_SPEFIC with bit 7 on.
+    expectations.statusMFRValue = 0x80;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), true);
+    // Back to no bits on in STATUS_WORD
+    expectations.statusWordValue = 0;
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasPSCS12VFault(), false);
+}