psu-ng: Include STATUS_INPUT in input fault error
Read the value of STATUS_INPUT if STATUS_WORD is not zero. Include the
value of STATUS_INPUT if logging an error for an input fault.
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
Change-Id: I0463377a3e67faf1f32ab4a4b30ff73cbb8f5631
diff --git a/phosphor-power-supply/power_supply.cpp b/phosphor-power-supply/power_supply.cpp
index 9d8c914..64e0f26 100644
--- a/phosphor-power-supply/power_supply.cpp
+++ b/phosphor-power-supply/power_supply.cpp
@@ -208,16 +208,17 @@
if (statusWord)
{
+ statusInput = pmbusIntf->read(STATUS_INPUT, Type::Debug);
statusMFR = pmbusIntf->read(STATUS_MFR, Type::Debug);
if (statusWord & status_word::INPUT_FAULT_WARN)
{
if (!inputFault)
{
log<level::INFO>(
- fmt::format("INPUT fault: "
- "STATUS_WORD = {:#04x}, "
- "STATUS_MFR_SPECIFIC = {:#02x}",
- statusWord, statusMFR)
+ fmt::format("INPUT fault: STATUS_WORD = {:#04x}, "
+ "STATUS_MFR_SPECIFIC = {:#02x}, "
+ "STATUS_INPUT = {:#02x}",
+ statusWord, statusMFR, statusInput)
.c_str());
}
@@ -245,10 +246,10 @@
if (!vinUVFault)
{
log<level::INFO>(
- fmt::format("VIN_UV fault: "
- "STATUS_WORD = {:#04x}, "
- "STATUS_MFR_SPECIFIC = {:#02x}",
- statusWord, statusMFR)
+ fmt::format("VIN_UV fault: STATUS_WORD = {:#04x}, "
+ "STATUS_MFR_SPECIFIC = {:#02x}, "
+ "STATUS_INPUT = {:#02x}",
+ statusWord, statusMFR, statusInput)
.c_str());
}
diff --git a/phosphor-power-supply/power_supply.hpp b/phosphor-power-supply/power_supply.hpp
index 2660f32..86ce57c 100644
--- a/phosphor-power-supply/power_supply.hpp
+++ b/phosphor-power-supply/power_supply.hpp
@@ -145,6 +145,14 @@
}
/**
+ * @brief Returns the last read value from STATUS_INPUT.
+ */
+ uint64_t getStatusInput() const
+ {
+ return statusInput;
+ }
+
+ /**
* @brief Returns the last read value from STATUS_MFR.
*/
uint64_t getMFRFault() const
@@ -263,6 +271,9 @@
/** @brief Will be updated to the latest/lastvalue read from STATUS_WORD.*/
uint64_t statusWord = 0;
+ /** @brief Will be updated to the latest/lastvalue read from STATUS_INPUT.*/
+ uint64_t statusInput = 0;
+
/** @brief Will be updated to the latest/lastvalue read from STATUS_MFR.*/
uint64_t statusMFR = 0;
diff --git a/phosphor-power-supply/psu_manager.cpp b/phosphor-power-supply/psu_manager.cpp
index e5d4dfb..24006aa 100644
--- a/phosphor-power-supply/psu_manager.cpp
+++ b/phosphor-power-supply/psu_manager.cpp
@@ -408,6 +408,10 @@
if ((psu->hasInputFault() || psu->hasVINUVFault()))
{
+ // Include STATUS_INPUT for input faults.
+ additionalData["STATUS_INPUT"] =
+ fmt::format("{:#02x}", psu->getStatusInput());
+
/* The power supply location might be needed if the input
* fault is due to a problem with the power supply itself.
* Include the inventory path with a call out priority of
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 45999fb..7411c34 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -151,10 +151,14 @@
EXPECT_EQ(psu2.isPresent(), false);
- // STATUS_WORD 0x0000 is powered on, no faults.
- // It will read STATUS_MFR at the same time, so there are 2 reads.
+ // STATUS_WORD 0x0000 is powered on, no faults (0x0000).
MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
- EXPECT_CALL(mockPMBus, read(_, _)).Times(2).WillRepeatedly(Return(0x0000));
+ // Presence change from missing to present will trigger in1_input read in
+ // an attempt to get CLEAR_FAULTS called.
+ EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
EXPECT_EQ(psu2.isFaulted(), false);
@@ -163,10 +167,18 @@
EXPECT_EQ(psu2.hasVINUVFault(), false);
// STATUS_WORD input fault/warn
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(status_word::INPUT_FAULT_WARN))
- .WillOnce(Return(0x0000));
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(status_word::INPUT_FAULT_WARN));
+ // Due to the fault bit on in STATUS_WORD, there will also be a read of
+ // STATUS_INPUT and STATUS_MFR, so there should be 3 reads total expected.
+ // STATUS_INPUT fault bits ... on.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x38));
+ // STATUS_MFR don't care
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0));
+
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
EXPECT_EQ(psu2.isFaulted(), true);
@@ -176,23 +188,39 @@
// STATUS_WORD INPUT/UV fault.
// First need it to return good status, then the fault
- EXPECT_CALL(mockPMBus, read(_, _))
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(2)
.WillOnce(Return(0x0000))
- .WillOnce(Return(status_word::VIN_UV_FAULT))
- .WillOnce(Return(0x0000));
+ .WillOnce(Return(
+ (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT)));
+ // STATUS_INPUT fault bits ... on.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x38));
+ // STATUS_MFR don't care
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0));
+
psu2.analyze();
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
EXPECT_EQ(psu2.isFaulted(), true);
- EXPECT_EQ(psu2.hasInputFault(), false);
+ EXPECT_EQ(psu2.hasInputFault(), true);
EXPECT_EQ(psu2.hasMFRFault(), false);
EXPECT_EQ(psu2.hasVINUVFault(), true);
// STATUS_WORD MFR fault.
- EXPECT_CALL(mockPMBus, read(_, _))
+ // First need it to return good status, then the fault
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(2)
.WillOnce(Return(0x0000))
- .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT))
- .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
+ .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
+ // STATUS_INPUT fault bits ... don't care.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x00));
+ // STATUS_MFR bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF));
+
psu2.analyze();
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
@@ -202,10 +230,19 @@
EXPECT_EQ(psu2.hasVINUVFault(), false);
// Ignore Temperature fault.
- EXPECT_CALL(mockPMBus, read(_, _))
+ // First STATUS_WORD with no bits set, then with temperature fault.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(2)
.WillOnce(Return(0x0000))
- .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN))
- .WillOnce(Return(0x0000));
+ .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN));
+ // If STATUS_WORD bits set, should read STATUS_MFR_SPECIFIC and STATUS_INPUT
+ // STATUS_INPUT fault bits ... don't care.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x00));
+ // STATUS_MFR don't care
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0));
+
psu2.analyze();
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
@@ -215,10 +252,18 @@
EXPECT_EQ(psu2.hasVINUVFault(), false);
// Ignore fan fault
- EXPECT_CALL(mockPMBus, read(_, _))
+ // First STATUS_WORD with no bits set, then with fan fault.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(2)
.WillOnce(Return(0x0000))
- .WillOnce(Return(status_word::FAN_FAULT))
- .WillOnce(Return(0x0000));
+ .WillOnce(Return(status_word::FAN_FAULT));
+ // STATUS_WORD bits set causes read STATUS_MFR_SPECIFIC and STATUS_INPUT.
+ // Don't care if bits set or not.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x00));
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0));
+
psu2.analyze();
psu2.analyze();
EXPECT_EQ(psu2.isPresent(), true);
@@ -284,17 +329,25 @@
// GPIO read return 1 to indicate present.
ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
- ON_CALL(mockPMBus, read(_, _)).WillByDefault(Return(0));
+ ON_CALL(mockPMBus, read(STATUS_WORD, _)).WillByDefault(Return(0));
psu.analyze();
EXPECT_EQ(psu.isPresent(), true);
EXPECT_EQ(psu.isFaulted(), false);
EXPECT_EQ(psu.hasInputFault(), false);
EXPECT_EQ(psu.hasMFRFault(), false);
EXPECT_EQ(psu.hasVINUVFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(0xFFFF))
- .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
+ // STATUS_WORD with fault bits galore!
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0xFFFF));
+ // If STATUS_WORD has any fault bits on, STATUS_MFR_SPECIFIC and
+ // STATUS_INPUT will be read.
+ // STATUS_INPUT with fault bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0xFF));
+ // STATUS_MFR_SPEFIC with bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF));
psu.analyze();
EXPECT_EQ(psu.isPresent(), true);
EXPECT_EQ(psu.isFaulted(), true);
@@ -388,10 +441,17 @@
psu.analyze();
EXPECT_EQ(psu.isFaulted(), false);
MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(0xFFFF))
- .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
+ // STATUS_WORD with fault bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0xFFFF));
+ // If STATUS_WORD has bit(s) on, STATUS_MFR_SPECIFIC and STATUS_INPUT read.
+ // STATUS_INPUT with fault bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0xFF));
+ // STATUS_MFR_SPECIFIC with faults bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF));
psu.analyze();
EXPECT_EQ(psu.isFaulted(), true);
}
@@ -411,13 +471,23 @@
EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasInputFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(status_word::INPUT_FAULT_WARN))
- .WillOnce(Return(0));
+ // STATUS_WORD with input fault/warn on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(status_word::INPUT_FAULT_WARN));
+ // If STATUS_WORD has bit(s) on, STATUS_MFR_SPECIFIC and STATUS_INPUT read.
+ // STATUS_INPUT with an input fault bit on.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x80));
+ // STATUS_MFR don't care.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0x00));
psu.analyze();
EXPECT_EQ(psu.hasInputFault(), true);
- EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ // STATUS_WORD with no bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasInputFault(), false);
}
@@ -434,16 +504,29 @@
psu.analyze();
MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
EXPECT_EQ(psu.hasMFRFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ // First return STATUS_WORD with no bits on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasMFRFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT))
- .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
+ // Next return STATUS_WORD with MFR fault bit on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
+ // If STATUS_WORD has bits on, STATUS_MFR_SPECIFIC and STATUS_INPUT read.
+ // STATUS_INPUT don't care
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x00));
+ // STATUS_MFR_SPEFIC with bit(s) on.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF));
psu.analyze();
EXPECT_EQ(psu.hasMFRFault(), true);
- EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ // Back to no bits on in STATUS_WORD
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasMFRFault(), false);
}
@@ -460,16 +543,31 @@
psu.analyze();
MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
EXPECT_EQ(psu.hasVINUVFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasVINUVFault(), false);
- EXPECT_CALL(mockPMBus, read(_, _))
- .Times(2)
- .WillOnce(Return(status_word::VIN_UV_FAULT))
- .WillOnce(Return(0));
+ // Turn fault on.
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(status_word::VIN_UV_FAULT));
+ // Fault bits on in STATUS_WORD causes read of STATUS_MFR_SPECIFIC and
+ // STATUS_INPUT.
+ // Curious disagreement between PMBus Spec. Part II Figure 16 and 33.
+ // Go by Figure 16, and assume bits on in STATUS_INPUT.
+ EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
+ .Times(1)
+ .WillOnce(Return(0x18));
+ // STATUS_MFR don't care.
+ EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0x00));
+
psu.analyze();
EXPECT_EQ(psu.hasVINUVFault(), true);
- EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
+ // Back to no fault bits on in STATUS_WORD
+ EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
+ .Times(1)
+ .WillOnce(Return(0x0000));
psu.analyze();
EXPECT_EQ(psu.hasVINUVFault(), false);
}