summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/usr/isteps/nvdimm/bpmreasoncodes.H7
-rw-r--r--src/usr/isteps/nvdimm/bpm_update.C677
-rw-r--r--src/usr/isteps/nvdimm/bpm_update.H33
3 files changed, 547 insertions, 170 deletions
diff --git a/src/include/usr/isteps/nvdimm/bpmreasoncodes.H b/src/include/usr/isteps/nvdimm/bpmreasoncodes.H
index bceee7bfc..820364c05 100644
--- a/src/include/usr/isteps/nvdimm/bpmreasoncodes.H
+++ b/src/include/usr/isteps/nvdimm/bpmreasoncodes.H
@@ -50,6 +50,10 @@ namespace BPM_RC
BPM_WAIT_FOR_CMD_BIT_RESET = 0x0A,
BPM_WAIT_FOR_BUSY_BIT_RESET = 0x0B,
BPM_CHECK_FIRMWARE_CRC = 0x0C,
+ BPM_VERIFY_GOOD_BPM_STATE = 0x0D,
+ BPM_RUN_FW_UPDATES = 0x0F,
+ BPM_START_UPDATE = 0xFD,
+ BPM_END_UPDATE = 0xFE,
BPM_DUMMY_ERROR = 0xFF,
};
@@ -67,6 +71,9 @@ namespace BPM_RC
BPM_EXCEEDED_RETRY_LIMIT = BPM_COMP_ID | 0x09,
BPM_CMD_STATUS_ERROR_BIT_SET = BPM_COMP_ID | 0x0A,
BPM_FIRMWARE_CRC_VERIFY_FAILURE = BPM_COMP_ID | 0x0B,
+ BPM_VERSION_MISMATCH = BPM_COMP_ID | 0x0C,
+ BPM_ENTER_UPDATE_MODE = BPM_COMP_ID | 0xFD,
+ BPM_EXIT_UPDATE_MODE = BPM_COMP_ID | 0xFE,
BPM_DUMMY_REASONCODE = BPM_COMP_ID | 0xFF,
};
diff --git a/src/usr/isteps/nvdimm/bpm_update.C b/src/usr/isteps/nvdimm/bpm_update.C
index b630e59ef..445ad0b63 100644
--- a/src/usr/isteps/nvdimm/bpm_update.C
+++ b/src/usr/isteps/nvdimm/bpm_update.C
@@ -63,6 +63,9 @@ const size_t BPM_PASSWORD_LENGTH = 4;
// These are the production magic values for the BPM that should be written in
// BPM_MAGIC_REG1 and BPM_MAGIC_REG2 respectively.
const uint8_t PRODUCTION_MAGIC_VALUES[NUM_MAGIC_REGISTERS] = {0x55, 0xAA};
+// These magic values to enable nvdimm-bpm interface. They must be written to
+// the magic registers BEFORE writing flash updates to the BPM in BSL mode.
+const uint8_t UPDATE_MODE_MAGIC_VALUES[NUM_MAGIC_REGISTERS] = {0xB0, 0xDA};
// These are the segment codes used to dump out a particular config data segment
// on the BPM.
@@ -378,7 +381,6 @@ void runBpmUpdates(bpmList_t * const i_16gb_BPMs,
} while(0);
}
-
// =============================================================================
// BpmFirmwareLidImage Class Functions
// =============================================================================
@@ -501,7 +503,8 @@ Bpm::Bpm(const TARGETING::TargetHandle_t i_nvdimm)
iv_firmwareStartAddress(0),
iv_attemptAnotherUpdate(false),
iv_segmentDMerged(false),
- iv_segmentBMerged(false)
+ iv_segmentBMerged(false),
+ iv_updateAttempted(false)
{
assert((i_nvdimm != nullptr) && (isNVDIMM(i_nvdimm)),
"BPM::Bpm(): An nvdimm target must be given.");
@@ -516,6 +519,27 @@ bool Bpm::attemptAnotherUpdate()
return iv_attemptAnotherUpdate;
}
+void Bpm::setAttemptAnotherUpdate()
+{
+
+ if (iv_updateAttempted)
+ {
+ // Since iv_updateAttempted is true that means that this function was
+ // called on a subsequent update attempt, meaning we should no longer
+ // attempt updates if the current attempt fails.
+ iv_attemptAnotherUpdate = false;
+ }
+ else
+ {
+ // Since iv_updateAttempted is false that means that this function was
+ // called on the first update attempt because by default
+ // iv_updateAttempted is false and is only set to true as the last part
+ // of the update procedure.
+ iv_attemptAnotherUpdate = true;
+ }
+
+}
+
const TARGETING::TargetHandle_t Bpm::getNvdimm()
{
return iv_nvdimm;
@@ -583,11 +607,14 @@ errlHndl_t Bpm::readBslVersion()
TRACFCOMP(g_trac_bpm, "Bpm::readBslVersion(): BSL Version is 0x%X",
iv_bslVersion);
+ } while(0);
+ do {
// Reset the device. This will exit BSL mode.
errlHndl_t exitErrl = resetDevice();
if (exitErrl != nullptr)
{
+ handleMultipleErrors(errl, exitErrl);
break;
}
@@ -595,10 +622,9 @@ errlHndl_t Bpm::readBslVersion()
exitErrl = exitUpdateMode();
if (exitErrl != nullptr)
{
+ handleMultipleErrors(errl, exitErrl);
break;
}
-
-
} while(0);
return errl;
@@ -821,12 +847,13 @@ errlHndl_t Bpm::runUpdate(BpmFirmwareLidImage i_fwImage,
break;
}
+ TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runUpdate(): "
+ "Firmware version on the BPM 0x%.4X, "
+ "Firmware version of image 0x%.4X.",
+ bpmFwVersion, i_fwImage.getVersion());
+
if (i_fwImage.getVersion() == bpmFwVersion)
{
- TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runUpdate(): "
- "Firmware version on the BPM matches the version in the "
- "image. Skipping update.");
-
break;
}
@@ -844,144 +871,35 @@ errlHndl_t Bpm::runUpdate(BpmFirmwareLidImage i_fwImage,
{
TRACFCOMP(g_trac_bpm, "Bpm::runUpdate(): "
"Unsupported BSL Version 0x%.2X detected on BPM. "
- "Skipping Update.");
-
- break;
- }
-
- TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runUpdate(): "
- "Firmware version on the BPM 0x%.4X, "
- "Firmware version of image 0x%.4X. Running Update",
- bpmFwVersion, i_fwImage.getVersion());
-
- // Before the update begins, we must do some preprocessing prior to the
- // config part of the update. Segment D and B need to be dumped from the
- // BPM into buffers and then the config data from the image needs to be
- // inserted into them. This must happen before enterUpdateMode() as both
- // tamper with the BPM_MAGIC_REGs. Additionally, to dump segment data,
- // it is required to have working firmware which will not be the case
- // during update.
- errl = preprocessSegments(i_configImage);
- if (errl != nullptr)
- {
- break;
- }
-
- // Enter Update mode
- errl = enterUpdateMode();
- if (errl != nullptr)
- {
- break;
- }
-
- // Verify in Update mode
- errl = inUpdateMode();
- if (errl != nullptr)
- {
- break;
- }
-
- // Enter Bootstrap Loader (BSL) mode to perform firmware update
- errl = enterBootstrapLoaderMode();
- if (errl != nullptr)
- {
- break;
- }
+ "Cancelling Update.");
- // Unlock the device. This is a BSL command so we must already be in
- // BSL mode to execute it.
- errl = unlockDevice();
- if (errl != nullptr)
- {
break;
}
- // Run Firmware Update
- errl = updateFirmware(i_fwImage);
+ errl = runConfigUpdates(i_configImage);
if (errl != nullptr)
{
break;
}
- // Perform the configuration data segment updates.
- // As of BSL 1.4 this is done via the BSL interface instead of SCAP
- // registers.
- errl = updateConfig();
+ errl = runFirmwareUpdates(i_fwImage);
if (errl != nullptr)
{
break;
}
- errl = checkFirmwareCrc();
- if (errl != nullptr)
- {
- TRACFCOMP(g_trac_bpm, "Bpm:: runUpdate(): "
- "Final CRC check failed. Attempting update again...");
- iv_attemptAnotherUpdate = !iv_attemptAnotherUpdate;
- break;
- }
-
- } while(0);
-
- do {
- // Reset the device. This will exit BSL mode.
- errlHndl_t exitErrl = resetDevice();
- if (exitErrl != nullptr)
- {
- TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runUpdate(): "
- "Failed to reset the device");
- handleMultipleErrors(errl, exitErrl);
- break;
- }
-
- // Exit update mode
- exitErrl = exitUpdateMode();
- if (exitErrl != nullptr)
- {
- TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runUpdate(): "
- "Failed to exit update mode");
- handleMultipleErrors(errl, exitErrl);
- break;
- }
-
- // To see the BPM firmware level updated we must reset the controller
- exitErrl = nvdimmWriteReg(iv_nvdimm,
- NVDIMM_MGT_CMD0,
- 0x01);
- if (exitErrl != nullptr)
- {
- TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runUpdate(): "
- "Could not reset NVDIMM Controller");
- handleMultipleErrors(errl, exitErrl);
- break;
- }
-
- TRACFCOMP(g_trac_bpm, "Bpm::runUpdate(): "
- "Reset command sent to NVDIMM controller, sleep for 15 seconds");
- longSleep(15);
-
- uint16_t bpmFwVersion = INVALID_VERSION;
- exitErrl = getFwVersion(bpmFwVersion);
- if (exitErrl != nullptr)
- {
- TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runUpdate(): "
- "Could not determine firmware version on the BPM");
- handleMultipleErrors(errl, exitErrl);
- break;
- }
-
- if (i_fwImage.getVersion() == bpmFwVersion)
- {
- TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runUpdate(): "
- "Firmware version on the BPM matches the version in the "
- "image. Update Successful.");
- }
-
} while(0);
TRACFCOMP(g_trac_bpm, EXIT_MRK"Bpm::runUpdate(): "
- "Concluding BPM Update for NVDIMM 0x%.8X",
- TARGETING::get_huid(iv_nvdimm));
+ "Concluding BPM Update for NVDIMM 0x%.8X %s",
+ TARGETING::get_huid(iv_nvdimm),
+ (errl != nullptr) ? "with errors" : "without errors");
+
+ // An update has been attempted at least once. Set member variable to true
+ // to dictate future update attempts. This variable should only be set at
+ // the end of the update procedure in order to properly control future
+ // update attempts.
+ iv_updateAttempted = true;
return errl;
}
@@ -1053,8 +971,7 @@ errlHndl_t Bpm::enterUpdateMode()
}
// Write the magic values to enable nvdimm-bpm interface
- const uint8_t magic_values[NUM_MAGIC_REGISTERS] = {0xB0, 0xDA};
- errl = writeToMagicRegisters(magic_values);
+ errl = writeToMagicRegisters(UPDATE_MODE_MAGIC_VALUES);
if (errl != nullptr)
{
TRACFCOMP(g_trac_bpm, "Bpm::enterUpdateMode(): "
@@ -1071,6 +988,23 @@ errlHndl_t Bpm::enterUpdateMode()
nanosleep(2,0);
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_INFORMATIONAL
+ * @moduleid BPM_RC::BPM_START_UPDATE
+ * @reasoncode BPM_RC::BPM_ENTER_UPDATE_MODE
+ * @userdata1 NVDIMM Target HUID associated with this BPM
+ * @devdesc BPM has entered update mode.
+ * @custdesc Informational log associated with DIMM updates.
+ */
+ errlHndl_t infoErrl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ BPM_RC::BPM_START_UPDATE,
+ BPM_RC::BPM_ENTER_UPDATE_MODE,
+ TARGETING::get_huid(iv_nvdimm));
+ infoErrl->collectTrace(BPM_COMP_NAME);
+ ERRORLOG::errlCommit(infoErrl, BPM_COMP_ID);
+
} while(0);
return errl;
@@ -1083,12 +1017,33 @@ errlHndl_t Bpm::exitUpdateMode()
do {
- errl = issueCommand(BPM_LOCAL, BCL_END_UPDATE, WRITE);
+
+ errl = issueCommand(BPM_LOCAL, BCL_IS_UPDATE_IN_PROGRESS, READ);
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ uint8_t isUpdateInProgress = 0;
+ errl = nvdimmReadReg(iv_nvdimm,
+ BPM_REG_ERR_STATUS,
+ isUpdateInProgress);
if (errl != nullptr)
{
+ TRACFCOMP(g_trac_bpm, "Bpm::inUpdateMode(): "
+ "Failed to read error status register");
break;
}
+ if (isUpdateInProgress)
+ {
+ errl = issueCommand(BPM_LOCAL, BCL_END_UPDATE, WRITE);
+ if (errl != nullptr)
+ {
+ break;
+ }
+ }
+
// Write back the production magic values
errl = writeToMagicRegisters(PRODUCTION_MAGIC_VALUES);
if (errl != nullptr)
@@ -1099,6 +1054,22 @@ errlHndl_t Bpm::exitUpdateMode()
break;
}
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_INFORMATIONAL
+ * @moduleid BPM_RC::BPM_END_UPDATE
+ * @reasoncode BPM_RC::BPM_EXIT_UPDATE_MODE
+ * @userdata1 NVDIMM Target HUID associated with this BPM
+ * @devdesc BPM has exited update mode.
+ * @custdesc Informational log associated with DIMM updates.
+ */
+ errlHndl_t infoErrl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_INFORMATIONAL,
+ BPM_RC::BPM_END_UPDATE,
+ BPM_RC::BPM_EXIT_UPDATE_MODE);
+ infoErrl->collectTrace(BPM_COMP_NAME);
+ ERRORLOG::errlCommit(infoErrl, BPM_COMP_ID);
+
} while(0);
return errl;
@@ -1160,8 +1131,24 @@ errlHndl_t Bpm::updateFirmware(BpmFirmwareLidImage i_image)
}
TRACFCOMP(g_trac_bpm, "Bpm::updateFirmware(): "
- "Performing BSL_MASS_ERASE, sleep for 5 seconds.");
+ "Performing BSL_MASS_ERASE on BPM, sleep for 5 seconds.",
+ iv_firmwareStartAddress);
longSleep(5);
+
+ TRACFCOMP(g_trac_bpm, "Bpm::updateFirmware(): "
+ "Begin writing flash image to BPM "
+ "with a starting address of 0x%.4X",
+ iv_firmwareStartAddress);
+
+ }
+
+ if (block->iv_addressOffset % 0x400 == 0)
+ {
+ TRACFCOMP(g_trac_bpm, "Bpm::updateFirmware(): "
+ "Writing to address offset 0x%.4X. "
+ "Firmware blocks written: %d; Remaining: %d",
+ block->iv_addressOffset,
+ i, NUMBER_OF_BLOCKS);
}
// Construct the payload for this block in the image
@@ -1174,6 +1161,11 @@ errlHndl_t Bpm::updateFirmware(BpmFirmwareLidImage i_image)
if (block->iv_addressOffset == RESET_VECTOR_ADDRESS)
{
+ TRACFCOMP(g_trac_bpm, "Bpm::updateFirmware(): "
+ "Encountered RESET_VECTOR_ADDRESS 0x%.4X. "
+ "Attempt to write RESET_VECTOR to BPM up to %d times.",
+ RESET_VECTOR_ADDRESS,
+ MAX_RETRY);
// Attempting to BSL_VERIFY_BLOCK on the reset vector data will
// fail. To verify that this data is written correctly we will check
// the response packet sent by the BPM.
@@ -1233,9 +1225,9 @@ errlHndl_t Bpm::updateFirmware(BpmFirmwareLidImage i_image)
TARGETING::get_huid(iv_nvdimm));
errl->collectTrace(BPM_COMP_NAME);
- // Flip the status of iv_attemptAnotherUpdate to signal
+ // Change the state of iv_attemptAnotherUpdate to signal
// if another update attempt should occur.
- iv_attemptAnotherUpdate = !iv_attemptAnotherUpdate;
+ setAttemptAnotherUpdate();
break;
}
@@ -1267,7 +1259,6 @@ errlHndl_t Bpm::updateFirmware(BpmFirmwareLidImage i_image)
}
}
-
// Move to the next block
// iv_blocksize doesn't include the sizeof itself. So, add another byte
// for it.
@@ -1275,6 +1266,11 @@ errlHndl_t Bpm::updateFirmware(BpmFirmwareLidImage i_image)
block = reinterpret_cast<firmware_image_block_t const *>(data);
}
+ TRACFCOMP(g_trac_bpm, EXIT_MRK"Bpm::updateFirmware(): "
+ "Firmware flash image write and verification completed "
+ "%s",
+ (errl == nullptr) ? "without errors" : "with errors");
+
return errl;
}
@@ -1965,13 +1961,27 @@ errlHndl_t Bpm::dumpSegment(uint16_t const i_segmentCode,
TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::dumpSegment(): "
"BSL Mode is enabled. Attempting to exit BSL mode.");
- // Try to exit BSL mode
+ // Try to exit BSL mode. This function will exit BSL.
errl = resetDevice();
if (errl != nullptr)
{
break;
}
+ // To maintain proper update flow we must exit and re-enter update
+ // mode.
+ errl = exitUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ errl = enterUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
errl = nvdimmReadReg(iv_nvdimm,
SCAP_STATUS,
status.full);
@@ -2133,11 +2143,11 @@ errlHndl_t Bpm::dumpSegment(uint16_t const i_segmentCode,
if (magicValuesChanged)
{
// Write back the production magic values.
- errlHndl_t magicErrl = writeToMagicRegisters(PRODUCTION_MAGIC_VALUES);
+ errlHndl_t magicErrl = writeToMagicRegisters(UPDATE_MODE_MAGIC_VALUES);
if (magicErrl != nullptr)
{
TRACFCOMP(g_trac_bpm, "Bpm::dumpSegment(): "
- "Failed to write production magic numbers.");
+ "Failed to write update mode magic numbers.");
handleMultipleErrors(errl, magicErrl);
}
}
@@ -2161,10 +2171,10 @@ errlHndl_t Bpm::mergeSegment(BpmConfigLidImage const i_configImage,
}
else
{
- //@TODO RTC 212447 Error
TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::mergeSegment(): "
"Couldn't find start offset for Segment %X",
getSegmentIdentifier(i_segmentCode));
+ assert(false, "Add the missing Segment %X Start Offset to the offset map", getSegmentIdentifier(i_segmentCode));
}
TRACFCOMP(g_trac_bpm, "Bpm::mergeSegment(): "
@@ -2280,6 +2290,12 @@ errlHndl_t Bpm::eraseSegment(uint16_t i_segmentCode)
} while(0);
+ TRACFCOMP(g_trac_bpm, EXIT_MRK"Bpm::eraseSegment(): "
+ "Segment %X erase operation completed "
+ "%s",
+ getSegmentIdentifier(i_segmentCode),
+ (errl == nullptr) ? "without errors" : "with errors");
+
return errl;
}
@@ -2327,6 +2343,15 @@ errlHndl_t Bpm::writeSegment(uint8_t const (&i_buffer)[SEGMENT_SIZE],
break;
}
+ if (addressOffset % 0x20 == 0)
+ {
+ TRACFCOMP(g_trac_bpm, "Bpm::writeSegment(): "
+ "Writing to address offset 0x%.4X. "
+ "Config bytes written: 0x%X; Remaining: 0x%X",
+ addressOffset,
+ offset, SEGMENT_SIZE);
+ }
+
// Attempt to write the payload using a retry loop.
errl = blockWrite(payload);
if (errl != nullptr)
@@ -2341,6 +2366,12 @@ errlHndl_t Bpm::writeSegment(uint8_t const (&i_buffer)[SEGMENT_SIZE],
} while(0);
+ TRACFCOMP(g_trac_bpm, EXIT_MRK"Bpm::writeSegment(): "
+ "Segment %X write and verification completed "
+ "%s",
+ getSegmentIdentifier(i_segmentCode),
+ (errl == nullptr) ? "without errors" : "with errors");
+
return errl;
}
@@ -2362,14 +2393,6 @@ errlHndl_t Bpm::preprocessSegments(BpmConfigLidImage const i_configImage)
break;
}
- // Disable write protection on the BPM. Otherwise, we can't write the
- // magic values that will enable segment preprocessing.
- errl = disableWriteProtection();
- if (errl != nullptr)
- {
- break;
- }
-
// Merge the fragments for D with the data from the BPM.
if (!iv_segmentDMerged)
{
@@ -2564,13 +2587,14 @@ errlHndl_t Bpm::verifyBlockWrite(payload_t i_payload,
do {
// Pull the address to verify out of the payload. It was inserted in
- // little endian form so it needs to be converted back to big endian.
- uint16_t address = (i_payload[PAYLOAD_HEADER_SIZE])
- & (i_payload[PAYLOAD_HEADER_SIZE + 1] << 8);
+ // little endian form so it needs to be converted back to big endian
+ // because setupPayload expects an address in big endian.
+ uint16_t address = (i_payload[PAYLOAD_ADDRESS_START_INDEX])
+ | (i_payload[PAYLOAD_ADDRESS_START_INDEX + 1] << 8);
// The data section of the payload is organized in the following way:
// 2 bytes: uint16_t size of data to verify in little endian format
- // 2 bytes: CRC of the data to be verified on the BPM.
+ // 2 bytes: CRC of the data to be verified on the BPM in little endian.
const size_t VERIFY_BLOCK_PAYLOAD_DATA_SIZE = 4;
uint8_t data[VERIFY_BLOCK_PAYLOAD_DATA_SIZE] = {0};
@@ -2583,8 +2607,8 @@ errlHndl_t Bpm::verifyBlockWrite(payload_t i_payload,
// Calculate the uint16_t CRC for the data that was written to the BPM.
// The BPM will compare its calculated CRC with this one to verify if
// the block was written correctly.
- uint16_t crc = crc16_calc(&i_payload[PAYLOAD_DATA_START_INDEX],
- i_dataLength);
+ uint16_t crc = htole16(crc16_calc(&i_payload[PAYLOAD_DATA_START_INDEX],
+ i_dataLength));
memcpy(&data[2], &crc, sizeof(uint16_t));
@@ -2624,8 +2648,11 @@ errlHndl_t Bpm::blockWrite(payload_t i_payload)
"Can only retry for BSL_RX_DATA_BLOCK commands");
errlHndl_t errl = nullptr;
- uint8_t retry = 1;
+ uint8_t retry = 0;
+ // Any status from verifyBlockWrite that is non-zero is considered a
+ // fail. So, assume a fail and check.
+ uint8_t wasVerified = 0xFF;
do {
// Send the payload data over as a pass-through command
@@ -2638,9 +2665,6 @@ errlHndl_t Bpm::blockWrite(payload_t i_payload)
// Sleep for 0.001 second
nanosleep(0, 1 * NS_PER_MSEC);
- // Any status from verifyBlockWrite that is non-zero is considered a
- // fail. So, assume a fail and check.
- uint8_t wasVerified = 0xFF;
uint8_t dataLength = i_payload[PAYLOAD_HEADER_DATA_LENGTH_INDEX]
- PAYLOAD_HEADER_SIZE;
errl = verifyBlockWrite(i_payload,
@@ -2651,11 +2675,11 @@ errlHndl_t Bpm::blockWrite(payload_t i_payload)
break;
}
- if (!wasVerified)
+ if (wasVerified != 0)
{
TRACFCOMP(g_trac_bpm, "Bpm::blockWrite(): "
- "BSL_VERIFY_BLOCK failed. Retry %d/%d",
- retry,
+ "BSL_VERIFY_BLOCK failed. Attempt %d/%d",
+ (retry + 1),
MAX_RETRY);
}
else
@@ -2663,9 +2687,12 @@ errlHndl_t Bpm::blockWrite(payload_t i_payload)
break;
}
- } while (++retry <= MAX_RETRY);
- if (retry > MAX_RETRY)
+ } while (++retry < MAX_RETRY);
+ if ((retry >= MAX_RETRY) && (wasVerified != 0))
{
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::blockWrite(): "
+ "Failed to write payload data to BPM after %d retries.",
+ MAX_RETRY);
/*@
* @errortype
* @severity ERRORLOG::ERRL_SEV_PREDICTIVE
@@ -2683,9 +2710,9 @@ errlHndl_t Bpm::blockWrite(payload_t i_payload)
TARGETING::get_huid(iv_nvdimm));
errl->collectTrace(BPM_COMP_NAME);
- // Flip the state of iv_attemptAnotherUpdate. This will signal
+ // Change the state of iv_attemptAnotherUpdate. This will signal
// another update attempt or cease further attempts.
- iv_attemptAnotherUpdate = !iv_attemptAnotherUpdate;
+ setAttemptAnotherUpdate();
}
return errl;
@@ -2707,7 +2734,9 @@ errlHndl_t Bpm::waitForCommandStatusBitReset(
break;
}
- int retry = 10;
+ // Give the BPM 20 seconds to complete any given command before we time
+ // out and cancel the update procedure.
+ int retry = 20 * MS_PER_SEC;
while (i_commandStatus.bits.Bsp_Cmd_In_Progress)
{
@@ -2793,6 +2822,66 @@ errlHndl_t Bpm::waitForCommandStatusBitReset(
return errl;
}
+errlHndl_t Bpm::verifyGoodBpmState()
+{
+ errlHndl_t errl = nullptr;
+ int retry = 100;
+ scap_status_register_t status;
+ const uint8_t BPM_PRESENT_AND_ENABLED = 0x11;
+
+ while (retry > 0)
+ {
+
+ errl = nvdimmReadReg(iv_nvdimm,
+ SCAP_STATUS,
+ status.full);
+ if (errl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, "Bpm::verifyGoodBpmState(): "
+ "Failed to read SCAP_STATUS to determine "
+ "state of BPM.");
+ break;
+ }
+
+ if ((status.full & 0xFF) == BPM_PRESENT_AND_ENABLED)
+ {
+ // BPM is present and enabled. Stop retries.
+ break;
+ }
+
+ if (retry <= 0)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::verifyGoodBpmState(): "
+ "BPM failed to become present and enabled "
+ "in 100 retries.");
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_PREDICTIVE
+ * @moduleid BPM_RC::BPM_VERIFY_GOOD_BPM_STATE
+ * @reasoncode BPM_RC::BPM_EXCEEDED_RETRY_LIMIT
+ * @userdata1 NVDIMM Target HUID associated with this BPM
+ * @userdata2 SCAP_STATUS register contents. See nvdimm.H
+ * for bits associated with this register.
+ * @devdesc The BPM did not become present and enabled
+ * in given number of retries.
+ * @custdesc A problem occurred during IPL of the system.
+ */
+ errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_PREDICTIVE,
+ BPM_RC::BPM_VERIFY_GOOD_BPM_STATE,
+ BPM_RC::BPM_EXCEEDED_RETRY_LIMIT,
+ TARGETING::get_huid(iv_nvdimm),
+ status.full);
+ errl->collectTrace(BPM_COMP_NAME);
+ break;
+ }
+
+ --retry;
+ nanosleep(0, 1 * NS_PER_MSEC);
+ }
+
+ return errl;
+}
+
errlHndl_t Bpm::waitForBusyBit()
{
errlHndl_t errl = nullptr;
@@ -2849,6 +2938,254 @@ errlHndl_t Bpm::waitForBusyBit()
return errl;
}
+errlHndl_t Bpm::runConfigUpdates(BpmConfigLidImage i_configImage)
+{
+ TRACFCOMP(g_trac_bpm, ENTER_MRK"Bpm::runConfigUpdates()");
+ errlHndl_t errl = nullptr;
+
+ do {
+ // Enter Update mode
+ errl = enterUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Verify in Update mode
+ errl = inUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Before the entering BSL mode, we must do preprocessing prior to the
+ // config part of the update. Segment D and B need to be dumped from the
+ // BPM into buffers and then the config data from the image needs to be
+ // inserted into them. To dump segment data, it is required to have
+ // working firmware which will not be the case during BSL mode.
+ errl = preprocessSegments(i_configImage);
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Enter Bootstrap Loader (BSL) mode to perform firmware update
+ errl = enterBootstrapLoaderMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Unlock the device. This is a BSL command so we must already be in
+ // BSL mode to execute it.
+ errl = unlockDevice();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Perform the configuration data segment updates.
+ // As of BSL 1.4 this is done via the BSL interface instead of SCAP
+ // registers.
+ errl = updateConfig();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ } while(0);
+
+ do {
+
+ // Reset the device. This will exit BSL mode.
+ errlHndl_t exitErrl = resetDevice();
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runConfigUpdates(): "
+ "Failed to reset the device");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ // Exit update mode
+ exitErrl = exitUpdateMode();
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runConfigUpdates(): "
+ "Failed to exit update mode");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ } while(0);
+
+ return errl;
+}
+
+errlHndl_t Bpm::runFirmwareUpdates(BpmFirmwareLidImage i_image)
+{
+ TRACFCOMP(g_trac_bpm, ENTER_MRK"bpm::runFirmwareUpdates()");
+ errlHndl_t errl = nullptr;
+
+ do {
+
+ // Enter Update mode
+ errl = enterUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Verify in Update mode
+ errl = inUpdateMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Enter Bootstrap Loader (BSL) mode to perform firmware update
+ errl = enterBootstrapLoaderMode();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Unlock the device. This is a BSL command so we must already be in
+ // BSL mode to execute it.
+ errl = unlockDevice();
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ // Run Firmware Update
+ errl = updateFirmware(i_image);
+ if (errl != nullptr)
+ {
+ break;
+ }
+
+ TRACFCOMP(g_trac_bpm, "Bpm::runFirmwareUpdates(): "
+ "Perform final CRC check on entire BPM flash to load "
+ "new firmware.");
+
+ errl = checkFirmwareCrc();
+ if (errl != nullptr)
+ {
+ setAttemptAnotherUpdate();
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm:: runFirmwareUpdates(): "
+ "Final CRC check failed. %s ",
+ (iv_attemptAnotherUpdate == false) ?
+ "Attempt another update..."
+ : "Attempts to update the BPM have failed. Firmware will not load.");
+ break;
+ }
+
+ } while(0);
+
+ do {
+
+ // Reset the device. This will exit BSL mode.
+ errlHndl_t exitErrl = resetDevice();
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runFirmwareUpdates(): "
+ "Failed to reset the device");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ // Exit update mode
+ exitErrl = exitUpdateMode();
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runFirmwareUpdates(): "
+ "Failed to exit update mode");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ // If the update was successful then we must wait for 10 seconds before
+ // polling the status of the BPM since it has to finish updating its
+ // firmware and resetting.
+ TRACFCOMP(g_trac_bpm, "Bpm::runFirmwareUpdates(): "
+ "Wait for the BPM to finish update and reset procedure, "
+ "sleep for 15 seconds");
+ longSleep(15);
+
+ // Poll SCAP_STATUS register for BPM state before we check final
+ // firmware version.
+ exitErrl = verifyGoodBpmState();
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runFirmwareUpdates(): "
+ "Could not verify that BPM was present and enabled!");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ uint16_t bpmFwVersion = INVALID_VERSION;
+ exitErrl = getFwVersion(bpmFwVersion);
+ if (exitErrl != nullptr)
+ {
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm::runFirmwareUpdates(): "
+ "Could not determine firmware version on the BPM");
+ handleMultipleErrors(errl, exitErrl);
+ break;
+ }
+
+ TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runFirmwareUpdates(): "
+ "Firmware version on the BPM 0x%.4X, "
+ "Firmware version of image 0x%.4X.",
+ bpmFwVersion, i_image.getVersion());
+
+ if (i_image.getVersion() == bpmFwVersion)
+ {
+ TRACFCOMP(g_trac_bpm, INFO_MRK"Bpm::runFirmwareUpdates(): "
+ "Firmware version on the BPM matches the version in the "
+ "image. Update Successful.");
+ iv_attemptAnotherUpdate = false;
+ }
+ else
+ {
+ // Attempt another update if one hasn't already been attempted.
+ setAttemptAnotherUpdate();
+ TRACFCOMP(g_trac_bpm, ERR_MRK"Bpm:: runFirmwareUpdates(): "
+ "Version on BPM didn't match image. %s ",
+ iv_attemptAnotherUpdate ?
+ "Attempt another update..."
+ : "Attempts to update the BPM have failed.");
+ if (iv_attemptAnotherUpdate == false)
+ {
+ /*@
+ * @errortype
+ * @severity ERRORLOG::ERRL_SEV_UNRECOVERABLE
+ * @moduleid BPM_RC::BPM_RUN_FW_UPDATES
+ * @reasoncode BPM_RC::BPM_VERSION_MISMATCH
+ * @userdata1[00:31] Version on the BPM
+ * @userdata1[32:63] Version of the flash image
+ * @userdata2 NVDIMM Target HUID associated with this BPM
+ * @devdesc The version on the BPM didn't match the
+ * version in the flash image.
+ * @custdesc A problem occurred during IPL of the system.
+ */
+ exitErrl = new ERRORLOG::ErrlEntry(
+ ERRORLOG::ERRL_SEV_UNRECOVERABLE,
+ BPM_RC::BPM_RUN_FW_UPDATES,
+ BPM_RC::BPM_VERSION_MISMATCH,
+ TWO_UINT32_TO_UINT64(bpmFwVersion,
+ i_image.getVersion()),
+ TARGETING::get_huid(iv_nvdimm));
+ exitErrl->collectTrace(BPM_COMP_NAME);
+ handleMultipleErrors(errl, exitErrl);
+ }
+ }
+
+ } while(0);
+
+ return errl;
+}
+
errlHndl_t Bpm::checkFirmwareCrc()
{
TRACFCOMP(g_trac_bpm, ENTER_MRK"Bpm::checkFirmwareCrc()");
@@ -2900,8 +3237,8 @@ errlHndl_t Bpm::checkFirmwareCrc()
}
// Wait 10 seconds for the CRC check to complete.
- TRACFCOMP(g_trac_bpm, "Bpm::checkFirmwareCrc(): "
- "Allow CRC check to complete on BPM by waiting 10 seconds.");
+ TRACFCOMP(g_trac_bpm, "Bpm::checkFirmwareCrc(): "
+ "Allow CRC check to complete on BPM by waiting 10 seconds.");
longSleep(10);
errl = getResponse(responseData, CRC_CHECK_RESPONSE_SIZE);
@@ -2911,8 +3248,8 @@ errlHndl_t Bpm::checkFirmwareCrc()
}
TRACFCOMP(g_trac_bpm, "Bpm::checkFirmwareCrc(): "
- "Response Packet CRC check status = 0x%.X, CRC_Low = 0x%.X, "
- "CRC_Hi = 0x%.X",
+ "Response Packet CRC check status = 0x%X, CRC_Low = 0x%X, "
+ "CRC_Hi = 0x%X",
responseData[0],
responseData[1],
responseData[2]);
diff --git a/src/usr/isteps/nvdimm/bpm_update.H b/src/usr/isteps/nvdimm/bpm_update.H
index e577e0ad7..17517f85d 100644
--- a/src/usr/isteps/nvdimm/bpm_update.H
+++ b/src/usr/isteps/nvdimm/bpm_update.H
@@ -177,6 +177,7 @@ constexpr uint8_t PAYLOAD_HEADER_SIZE = 4;
// These indices have been subtracted by 1 from the given payload format because
// after a payload is constructed the sync byte is removed from the front.
constexpr uint8_t PAYLOAD_COMMAND_INDEX = 0;
+constexpr uint8_t PAYLOAD_ADDRESS_START_INDEX = 3;
constexpr uint8_t PAYLOAD_DATA_START_INDEX = 7;
constexpr uint8_t PAYLOAD_HEADER_DATA_LENGTH_INDEX = 1;
@@ -437,6 +438,15 @@ private:
// yet.
bool iv_segmentDMerged;
bool iv_segmentBMerged;
+
+ // Keeps track of if an update has been attempted at least once.
+ bool iv_updateAttempted;
+
+ /**
+ * @brief Determines if another update attempt should occur for this BPM.
+ */
+ void setAttemptAnotherUpdate();
+
/**
* @brief Gets the BSL version from the BPM and sets the iv_bslVersion
* member. Only needs to be called once.
@@ -531,6 +541,17 @@ private:
errlHndl_t updateFirmware(BpmFirmwareLidImage i_image);
/**
+ * @brief Helper function that executes the firmware portion of the BPM
+ * update by calling all necessary functions in order.
+ *
+ * @param[in] i_image The BPM firmware LID image to apply to the BPM.
+ *
+ * @return errlHndl_t nullptr if no errors occurred.
+ * Otherwise, pointer to an errlEntry.
+ */
+ errlHndl_t runFirmwareUpdates(BpmFirmwareLidImage i_image);
+
+ /**
* @brief Executes the config portion of the BPM update.
*
* @return errlHndl_t nullptr on success. Otherwise, an Error.
@@ -538,6 +559,16 @@ private:
errlHndl_t updateConfig();
/**
+ * @brief Helper function that executes the config portion of the BPM
+ * update by calling all necessary functions in order.
+ *
+ * @param[in] i_image The BPM config LID image to apply to the BPM.
+ *
+ * @return errlHndl_t nullptr on success. Otherwise, an Error.
+ */
+ errlHndl_t runConfigUpdates(BpmConfigLidImage i_image);
+
+ /**
* @brief Commands the BPM to enter BSL mode to allow for BSL commands to be
* executed.
*
@@ -768,6 +799,8 @@ private:
errlHndl_t waitForCommandStatusBitReset(
command_status_register_t i_commandStatus);
+ errlHndl_t verifyGoodBpmState();
+
/**
* @brief Helper function for the SCAP register functions that will poll
* the busy bit in SCAP_STATUS until it is zero.
OpenPOWER on IntegriCloud