summaryrefslogtreecommitdiffstats
path: root/src/usr/isteps
diff options
context:
space:
mode:
authorMatt Derksen <mderkse1@us.ibm.com>2019-09-19 11:52:30 -0500
committerDaniel M Crowell <dcrowell@us.ibm.com>2019-11-05 09:06:10 -0600
commite01fc4be9a402a42d26a154ec80cdebae9665163 (patch)
treefce543720ac39d8c5f5b56ec2645f8cd76cb2d43 /src/usr/isteps
parent51aae24611b4e6e39c02e4f23411e9c7c5c117ce (diff)
downloadtalos-hostboot-e01fc4be9a402a42d26a154ec80cdebae9665163.tar.gz
talos-hostboot-e01fc4be9a402a42d26a154ec80cdebae9665163.zip
NVDIMM update - Clear FW Ops Status verification
SMART is recommending after 0x41=0x02 (Clear FW Ops Status) that the IBM utility read 0x71 to verify that the OPS_SUCCESS and OPS_ERROR bits have been cleared and that only Bit 2 (FIRMWARE_UPDATE_MODE) is set. First of two fixes for SW469894 Change-Id: Id9e9d7fa5abd5bcd3bae806b27332513f48956b2 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/83946 Reviewed-by: TSUNG K YEUNG <tyeung@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com> Reviewed-by: Corey V Swenson <cswenson@us.ibm.com> Reviewed-by: Daniel M Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/isteps')
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.C119
-rw-r--r--src/usr/isteps/nvdimm/nvdimm_update.H3
2 files changed, 115 insertions, 7 deletions
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.C b/src/usr/isteps/nvdimm/nvdimm_update.C
index 0d8828715..a7687d556 100644
--- a/src/usr/isteps/nvdimm/nvdimm_update.C
+++ b/src/usr/isteps/nvdimm/nvdimm_update.C
@@ -266,7 +266,8 @@ NvdimmInstalledImage::NvdimmInstalledImage(TARGETING::Target * i_nvDimm) :
iv_dimm(i_nvDimm), iv_version(INVALID_VERSION),
iv_manufacturer_id(INVALID_ID), iv_product_id(INVALID_ID),
iv_timeout(INVALID_TIMEOUT),
- iv_max_blocks_per_region(INVALID_REGION_BLOCK_SIZE)
+ iv_max_blocks_per_region(INVALID_REGION_BLOCK_SIZE),
+ iv_fw_update_mode_enabled(false)
{
// initialize to invalid values
}
@@ -356,8 +357,7 @@ errlHndl_t NvdimmInstalledImage::getVersion(uint16_t & o_version,
errlHndl_t NvdimmInstalledImage::updateImage(NvdimmLidImage * i_lidImage)
{
errlHndl_t l_err = nullptr;
- // need to always disable this after it gets enabled
- bool l_fw_update_mode_enabled = false;
+
do {
INITSERVICE::sendProgressCode();
////////////////////////////////////////////////////////////////////////
@@ -432,8 +432,6 @@ errlHndl_t NvdimmInstalledImage::updateImage(NvdimmLidImage * i_lidImage)
TARGETING::get_huid(iv_dimm));
break;
}
- // Set this flag so we will disable the update mode on error
- l_fw_update_mode_enabled = true;
// 5. Clear the Firmware Operation status
TRACUCOMP(g_trac_nvdimm_upd, "updateImage: step 5");
@@ -649,7 +647,6 @@ errlHndl_t NvdimmInstalledImage::updateImage(NvdimmLidImage * i_lidImage)
// 12. Disable firmware update mode
TRACUCOMP(g_trac_nvdimm_upd, "updateImage: step 12");
- l_fw_update_mode_enabled = false; // don't retry the disable on error
l_err = changeFwUpdateMode(FW_UPDATE_MODE_DISABLED);
if (l_err)
{
@@ -709,7 +706,7 @@ errlHndl_t NvdimmInstalledImage::updateImage(NvdimmLidImage * i_lidImage)
} while (0);
// If update operation is aborted, we need to disable update mode
- if (l_fw_update_mode_enabled)
+ if (iv_fw_update_mode_enabled)
{
TRACFCOMP(g_trac_nvdimm_upd, "updateImage: update was aborted, so disable FW_UPDATE_MODE");
errlHndl_t l_err2 = changeFwUpdateMode(FW_UPDATE_MODE_DISABLED);
@@ -1034,6 +1031,17 @@ errlHndl_t NvdimmInstalledImage::changeFwUpdateMode(fw_update_mode i_mode)
nvdimmAddPage4Regs(iv_dimm,l_err);
nvdimmAddUpdateRegs(iv_dimm,l_err);
}
+ else
+ {
+ if (opStatus.fw_ops_update_mode == 1)
+ {
+ iv_fw_update_mode_enabled = true;
+ }
+ else
+ {
+ iv_fw_update_mode_enabled = false;
+ }
+ }
}
}
}
@@ -1259,6 +1267,103 @@ errlHndl_t NvdimmInstalledImage::clearFwOpsStatus()
"NVDIMM 0x%.8X clear FIRMWARE_OPS_STATUS register failed",
TARGETING::get_huid(iv_dimm));
}
+ else
+ {
+ // Verify expected bits cleared
+
+ // Setup expected cleared status byte
+ fw_ops_status_t l_cleared_ops_status;
+ l_cleared_ops_status.whole = 0x00;
+ if (iv_fw_update_mode_enabled)
+ {
+ // set BIT 2 -- this should not be cleared by the command
+ l_cleared_ops_status.fw_ops_update_mode = 1;
+ }
+
+ // Set some timeout so this doesn't cause endless loop
+ uint16_t timeout_val = INVALID_TIMEOUT;
+ l_err = getFwOpsTimeout(timeout_val);
+ // Note: potential error will just exit the while loop and be returned
+
+ // convert seconds to ms value
+ // double the timeout to ensure enough time has elapsed for the clear
+ // note: doubling here instead of just doubling timeout_val since that
+ // variable is only a bit16 vs bit32
+ uint32_t timeout_ms_val = timeout_val * 1000 * 2;
+
+ fw_ops_status_t l_ops_status;
+
+ while (!l_err)
+ {
+ l_err = nvdimmReadReg(iv_dimm, FIRMWARE_OPS_STATUS, l_ops_status.whole);
+ if (l_err)
+ {
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"clearFwOpsStatus: "
+ "NVDIMM 0x%.8X read FIRMWARE_OPS_STATUS register failed "
+ " (0x%02X)",
+ TARGETING::get_huid(iv_dimm), l_ops_status.whole);
+ break;
+ }
+
+ // Exit if expected cleared status is found
+ if (l_ops_status.whole == l_cleared_ops_status.whole)
+ {
+ break;
+ }
+
+ // wait 1 millisecond between checking status
+ if (timeout_ms_val > 0)
+ {
+ timeout_ms_val -= 1;
+ nanosleep(0, NS_PER_MSEC);
+ }
+ else
+ {
+ // timeout hit
+ TRACFCOMP(g_trac_nvdimm_upd, ERR_MRK"clearFwOpsStatus: "
+ "NVDIMM 0x%.8X FIRMWARE_OPS_STATUS register reads 0x%02X "
+ "instead of cleared value of 0x%02X after %lld seconds",
+ TARGETING::get_huid(iv_dimm), l_ops_status.whole,
+ l_cleared_ops_status.whole, timeout_val*2);
+
+ /*@
+ *@errortype
+ *@moduleid CLEAR_FW_OPS_STATUS
+ *@reasoncode NVDIMM_CLEAR_FW_OPS_STATUS_TIMEOUT
+ *@userdata1 NVDIMM Target Huid
+ *@userdata2[0:7] Last FIRMWARE_OPS_STATUS read
+ *@userdata2[8:15] Expected cleared status
+ *@userdata2[16:31] Reserved
+ *@userdata2[32:63] Timeout (seconds)
+ *@devdesc FIRMWARE_OPS_STATUS not cleared
+ *@custdesc NVDIMM not updated
+ */
+ l_err = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_PREDICTIVE,
+ CLEAR_FW_OPS_STATUS,
+ NVDIMM_CLEAR_FW_OPS_STATUS_TIMEOUT,
+ TARGETING::get_huid(iv_dimm),
+ TWO_UINT16_ONE_UINT32_TO_UINT64
+ (
+ TWO_UINT8_TO_UINT16(
+ l_ops_status.whole,
+ l_cleared_ops_status.whole),
+ 0x0000,
+ timeout_val * 2
+ ),
+ ERRORLOG::ErrlEntry::NO_SW_CALLOUT );
+ l_err->collectTrace(NVDIMM_COMP_NAME, 256);
+ l_err->addPartCallout( iv_dimm,
+ HWAS::NV_CONTROLLER_PART_TYPE,
+ HWAS::SRCI_PRIORITY_HIGH );
+ l_err->addProcedureCallout( HWAS::EPUB_PRC_HB_CODE,
+ HWAS::SRCI_PRIORITY_LOW );
+
+ break;
+ }
+ } // end of while (!l_err) loop
+ } // end of Verify expected bits cleared
+
return l_err;
}
diff --git a/src/usr/isteps/nvdimm/nvdimm_update.H b/src/usr/isteps/nvdimm/nvdimm_update.H
index e544d98b3..5e8a88eda 100644
--- a/src/usr/isteps/nvdimm/nvdimm_update.H
+++ b/src/usr/isteps/nvdimm/nvdimm_update.H
@@ -255,6 +255,9 @@ class NvdimmInstalledImage
// maximum blocks allowed per region (REGION_BLOCK_SIZE)
uint8_t iv_max_blocks_per_region;
+ // set to true when doing update
+ bool iv_fw_update_mode_enabled;
+
// Helper functions for updating the installed lid
/**
* @brief Transfer a region of bytes in multiple 32-byte blocks
OpenPOWER on IntegriCloud