diff --git a/src/include/runtime/interface.h b/src/include/runtime/interface.h index 2d54dd1f3a2..6304ec6ba80 100644 --- a/src/include/runtime/interface.h +++ b/src/include/runtime/interface.h @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2013,2019 */ +/* Contributors Listed Below - COPYRIGHT 2013,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -599,7 +599,15 @@ typedef struct hostInterfaces // Manufacturing(MNFG) energy source(ES) health check request HBRT_FW_MNFG_ES_HEALTH_CHECK = 0x0020, // Manufacturing(MNFG) non-volatile memory(NVM) health check request - HBRT_FW_MNFG_NVM_HEALTH_CHECK = 0x0040 + HBRT_FW_MNFG_NVM_HEALTH_CHECK = 0x0040, + + /// The following operations pertain to the decommission of an NVDIMM + // Factory Default returns the NVDIMM to the factory default state + HBRT_FW_NVDIMM_FACTORY_DEFAULT = 0x0080, + // Secure Erase Verify all NAND flash blocks have been erased + HBRT_FW_NVDIMM_SECURE_EV_START = 0x0100, + // Secure Erase Verify Status checks if SEV operation has completed + HBRT_FW_NVDIMM_SECURE_EV_STATUS = 0x0200, }; // NVDIMM (PHYP -> HBRT) message to request NVDIMM operation(s) diff --git a/src/include/usr/isteps/nvdimm/nvdimm.H b/src/include/usr/isteps/nvdimm/nvdimm.H index 97655b24b76..966d4fd17e6 100644 --- a/src/include/usr/isteps/nvdimm/nvdimm.H +++ b/src/include/usr/isteps/nvdimm/nvdimm.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2018,2019 */ +/* Contributors Listed Below - COPYRIGHT 2018,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -131,6 +131,33 @@ bool nvdimm_encrypt_enable(TARGETING::TargetHandleList &i_nvdimmList); */ bool nvdimm_crypto_erase(TARGETING::TargetHandleList &i_nvdimmList); +/** + * @brief Entry function to NVDIMM factory default + * + * @param[in] i_nvdimmList - list of nvdimm targets + * + * @return true if no errors logged, else false + */ +bool nvdimmFactoryDefault(TARGETING::TargetHandleList &i_nvdimmList); + +/** + * @brief Entry function to NVDIMM secure erase verify + * + * @param[in] i_nvdimmList - list of nvdimm targets + * + * @return true if no errors logged, else false + */ +bool nvdimmSecureEraseVerifyStart(TARGETING::TargetHandleList &i_nvdimmList); + +/** + * @brief Entry function to NVDIMM secure erase verify status + * + * @param[in] i_nvdimmList - list of nvdimm targets + * + * @return true if no errors logged, else false + */ +bool nvdimmSecureEraseVerifyStatus(TARGETING::TargetHandleList &i_nvdimmList); + /** * @brief Helper function to get list of nvdimm target pointers * @@ -293,6 +320,8 @@ void nvdimmSendNvStatus(); * PROTECTED status until power is cycled again * ENCRYPTION_ENABLED - contents of nvdimm are encrypted * ENCRYPTION_DISABLED - contents of nvdimm are not encrypted + * ERASE_VERIFY_STARTED - set secure_erase_verify_complete to 0 + * ERASE_VERIFY_COMPLETE = set secure_erase_verify_complete to 1 */ enum nvdimm_protection_t { @@ -305,6 +334,8 @@ enum nvdimm_protection_t NVDIMM_ENCRYPTION_ERROR = 6, ENCRYPTION_ENABLED = 7, ENCRYPTION_DISABLED = 8, + ERASE_VERIFY_STARTED = 9, + ERASE_VERIFY_COMPLETED = 10, SEND_NV_STATUS = 11, /* deprecated, still used by PRD */ UNPROTECTED_BECAUSE_ERROR = 4, @@ -465,6 +496,7 @@ void nvdimmAddPage4Regs(TARGETING::Target *i_nvdimm, errlHndl_t& io_err); */ void nvdimm_init(TARGETING::Target *i_nvdimm); + } #endif // NVDIMM_EXT_H__ diff --git a/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H b/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H index c0215db17ae..134988be697 100644 --- a/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H +++ b/src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2019 */ +/* Contributors Listed Below - COPYRIGHT 2019,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -110,6 +110,7 @@ enum nvdimmModuleId NVDIMM_ARM_PRE_CHECK = 0x3C, NVDIMM_ARM = 0x3D, CLEAR_FW_OPS_STATUS = 0x3E, + NVDIMM_SECURE_ERASE_VERIFY_STATUS = 0x3F, }; /** @@ -207,6 +208,8 @@ enum nvdimmReasonCode NVDIMM_ARM_RETRY = NVDIMM_COMP_ID | 0x54, NVDIMM_CLEAR_FW_OPS_STATUS_TIMEOUT = NVDIMM_COMP_ID | 0x55, // Failed to clear FW_OPS_STATUS NVDIMM_NOT_RUNNING_LATEST_LEVEL = NVDIMM_COMP_ID | 0x56, // Either running from slot 0 or level was not updated + NVDIMM_ERASE_VERIFY_STATUS_NONZERO = NVDIMM_COMP_ID | 0x57, + NVDIMM_ERASE_VERIFY_RESULT_NONZERO = NVDIMM_COMP_ID | 0x58, }; enum UserDetailsTypes diff --git a/src/usr/isteps/nvdimm/ReadMe.md b/src/usr/isteps/nvdimm/ReadMe.md index 2b4fd49018f..1f98438b215 100644 --- a/src/usr/isteps/nvdimm/ReadMe.md +++ b/src/usr/isteps/nvdimm/ReadMe.md @@ -222,3 +222,57 @@ in the JEDEC document JESD245B 12. Disable firmware update mode 13. Switch from slot0 to slot1 which contains the new image code 14. Validate running new code level + +# NVDIMM Secure Erase Verify Flow +DS8K lpar -> HBRT NVDIMM operation = factory_default + secure_erase_verify_start + HBRT executes factory_default and steps 1) and 2) +DS8K lpar -> HBRT NVDIMM operation = secure_erase_verify_complete + HBRT executes step 3) + If secure erase verify has not completed, return status with verify_complete bit = 0 + DS8K lpar is responsible for monitoring elapsed time (2/4 hours) and restart process (step 6) + If secure erase verify has completed + HBRT executes steps 4) and 5), generating error logs for any non-zero register values + Return status with verify_complete bit = 1 + +## Procedure Flow for NVDIMM Secure Erase Verify + *Note: Secure Erase Verify should only be run after a Factory Default operation. + Secure Erase Verify is intended to verify whether all NAND blocks have been erased. + *Note: Full breakout of all Page 5 Secure Erase Verify registers can be found in + SMART document "JEDEC NVDIMM Vendor Page 2 Extensions". + 1) Set Page 5 Register 0x1B to value "0x00" + // this clears the status register + 2) Set Page 5 Register 0x1A to value "0xC0" + // this kicks off the erase verify operation + 3) Wait for Page 5 Register 0x1A Bit 7 to be reset to value "0" + // i.e., the overall register value should be "0x40"; + this means that erase verify has completed + a. If Page 5 Register 0x1A Bit 7 has not reset to value "0" + after 2 hours (16GB NVDIMM) or after 4 hours (32GB NVDIMM), + report a timeout error and skip to step (6) + 4) Read Page 5 Register 0x1B; value should be "0x00" + // this is the erase verify status register + a. If Page 5 Register 0x1B value is not "0x00", + report any/all errors as outlined in the table at the end of this document, + then skip to step (6) + 5) Read Page 5 Registers 0x1D (MSB) and 0x1C (LSB); + combined the two registers should have a value of "0x0000" + // this is the number of chunks failing Secure Erase Verify + a. If the combined value of the two registers is not "0x0000", + report a threshold exceeded error along with the combined value of the two registers, + then skip to step (6) + 6) If any errors have been reported in steps (3), (4), or (5), + retry the secure erase verify operation starting again from step (1) + a. If the secure erase verify operation fails even after retrying, + report that secure erase verify operation has failed + 7) If no errors have been reported, report that secure erase verify operation + has been completed successfully + *Addendum: Breakout of Page 5 Register 0x1B Erase Verify Status bit values referenced in step (4) above. + All these bits should return as "0". Any bits returning as "1" should be reported with the error name below. + Bits 7:6 - Reserved + Bit 5 - BAD BLOCK + Bit 4 - OTHER + Bit 3 - ENCRYPTION LOCKED + Bit 2 - INVALID PARAMETER + Bit 1 - INTERRUPTED + Bit 0 - NAND ERROR + diff --git a/src/usr/isteps/nvdimm/nvdimm.C b/src/usr/isteps/nvdimm/nvdimm.C index 2f9f96c2bc2..a7e263cf382 100644 --- a/src/usr/isteps/nvdimm/nvdimm.C +++ b/src/usr/isteps/nvdimm/nvdimm.C @@ -119,6 +119,8 @@ static constexpr uint8_t NV_STATUS_UNPROTECTED_SET = 0x01; static constexpr uint8_t NV_STATUS_UNPROTECTED_CLR = 0xFE; static constexpr uint8_t NV_STATUS_ENCRYPTION_SET = 0x10; static constexpr uint8_t NV_STATUS_ENCRYPTION_CLR = 0xEF; +static constexpr uint8_t NV_STATUS_ERASE_VERIFY_SET = 0x20; +static constexpr uint8_t NV_STATUS_ERASE_VERIFY_CLR = 0xDF; static constexpr uint8_t NV_STATUS_POSSIBLY_UNPROTECTED_SET = 0x40; // NVDIMM key consts @@ -157,6 +159,11 @@ static constexpr uint8_t RUNNING_FW_SLOT = 0xF0; static constexpr size_t ARM_MAX_RETRY_COUNT = 1; static constexpr uint8_t FW_OPS_UPDATE = 0x04; +// Secure erase verify operations +static constexpr uint8_t ERASE_VERIFY_CLEAR = 0x00; +static constexpr uint8_t ERASE_VERIFY_START = 0xC0; +static constexpr uint8_t ERASE_VERIFY_TRIGGER = 0x80; + #ifndef __HOSTBOOT_RUNTIME // Warning thresholds static constexpr uint8_t THRESHOLD_ES_LIFETIME = 0x07; // 7% @@ -1953,95 +1960,6 @@ void nvdimm_restore(TargetHandleList &i_nvdimmList) TRACUCOMP(g_trac_nvdimm, EXIT_MRK"nvdimm_restore()"); } -/** - * @brief Force a factory reset of the NV logic and flash - * - * @param[in] i_nvdimm - NVDIMM Target - */ -errlHndl_t nvdimm_factory_reset(Target *i_nvdimm) -{ - TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_factory_reset() nvdimm[%X]", - get_huid(i_nvdimm)); - errlHndl_t l_err = nullptr; - - do - { - // Send the reset command - l_err = nvdimmWriteReg(i_nvdimm, NVDIMM_FUNC_CMD, FACTORY_DEFAULT); - if( l_err ) - { - break; - } - - // Poll 2 minutes for completion - // We could get the timeout value from the dimm but since we're - // doing a hard reset anyway I just want to use a big number that - // can handle any lies that the controller might tell us. - uint8_t l_data = 0; - constexpr uint64_t MAX_POLL_SECONDS = 120; - uint64_t poll = 0; - for( poll = 0; poll < MAX_POLL_SECONDS; poll++ ) - { - l_err = nvdimmReadReg(i_nvdimm, NVDIMM_CMD_STATUS0, l_data); - if( l_err ) - { - break; - } - - if( l_data != FACTORY_RESET_IN_PROGRESS ) - { - break; - } - -#ifndef __HOSTBOOT_RUNTIME - // kick the watchdog since this can take awhile - INITSERVICE::sendProgressCode(); -#endif - - // sleep 1 second - nanosleep(1, 0); - } - if( l_err ) { break; } - - // Make an error if it never finished - if( poll >= MAX_POLL_SECONDS ) - { - TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_factory_reset() nvdimm[%X] - factory reset never completed[%d]", - get_huid(i_nvdimm), l_data); - /*@ - *@errortype - *@reasoncode NVDIMM_NOT_READY - *@severity ERRORLOG_SEV_UNRECOVERABLE - *@moduleid NVDIMM_FACTORY_RESET - *@userdata1[0:31] Ret value from ready register - *@userdata1[32:63] Target Huid - *@userdata2 Number of seconds waited - *@devdesc NVDIMM factory reset never completed - *@custdesc NVDIMM still in reset - */ - l_err = new ERRORLOG::ErrlEntry( - ERRORLOG::ERRL_SEV_UNRECOVERABLE, - NVDIMM_FACTORY_RESET, - NVDIMM_NOT_READY, - NVDIMM_SET_USER_DATA_1(l_data, get_huid(i_nvdimm)), - MAX_POLL_SECONDS, - ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); - - l_err->collectTrace(NVDIMM_COMP_NAME); - nvdimmAddVendorLog(i_nvdimm, l_err); - - // If nvdimm is not ready for access by now, this is - // a failing indication on the NV controller - l_err->addPartCallout( i_nvdimm, - HWAS::NV_CONTROLLER_PART_TYPE, - HWAS::SRCI_PRIORITY_HIGH); - nvdimmAddPage4Regs(i_nvdimm,l_err); - } - } while(0); - - return l_err; -} - /** * @brief NVDIMM initialization * - Checks for ready state @@ -2544,6 +2462,96 @@ errlHndl_t nvdimm_getTPM(Target*& o_tpm) #endif +/** + * @brief Force a factory reset of the NV logic and flash + * + * @param[in] i_nvdimm - NVDIMM Target + */ +errlHndl_t nvdimm_factory_reset(Target *i_nvdimm) +{ + TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_factory_reset() nvdimm[%X]", + get_huid(i_nvdimm)); + errlHndl_t l_err = nullptr; + + do + { + // Send the reset command + l_err = nvdimmWriteReg(i_nvdimm, NVDIMM_FUNC_CMD, FACTORY_DEFAULT); + if( l_err ) + { + break; + } + + // Poll 2 minutes for completion + // We could get the timeout value from the dimm but since we're + // doing a hard reset anyway I just want to use a big number that + // can handle any lies that the controller might tell us. + uint8_t l_data = 0; + constexpr uint64_t MAX_POLL_SECONDS = 120; + uint64_t poll = 0; + for( poll = 0; poll < MAX_POLL_SECONDS; poll++ ) + { + l_err = nvdimmReadReg(i_nvdimm, NVDIMM_CMD_STATUS0, l_data); + if( l_err ) + { + break; + } + + if( l_data != FACTORY_RESET_IN_PROGRESS ) + { + break; + } + +#ifndef __HOSTBOOT_RUNTIME + // kick the watchdog since this can take awhile + INITSERVICE::sendProgressCode(); +#endif + + // sleep 1 second + nanosleep(1, 0); + } + if( l_err ) { break; } + + // Make an error if it never finished + if( poll >= MAX_POLL_SECONDS ) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_factory_reset() nvdimm[%X] - factory reset never completed[%d]", + get_huid(i_nvdimm), l_data); + /*@ + *@errortype + *@reasoncode NVDIMM_NOT_READY + *@severity ERRORLOG_SEV_UNRECOVERABLE + *@moduleid NVDIMM_FACTORY_RESET + *@userdata1[0:31] Ret value from ready register + *@userdata1[32:63] Target Huid + *@userdata2 Number of seconds waited + *@devdesc NVDIMM factory reset never completed + *@custdesc NVDIMM still in reset + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_UNRECOVERABLE, + NVDIMM_FACTORY_RESET, + NVDIMM_NOT_READY, + NVDIMM_SET_USER_DATA_1(l_data, get_huid(i_nvdimm)), + MAX_POLL_SECONDS, + ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + + l_err->collectTrace(NVDIMM_COMP_NAME); + nvdimmAddVendorLog(i_nvdimm, l_err); + + // If nvdimm is not ready for access by now, this is + // a failing indication on the NV controller + l_err->addPartCallout( i_nvdimm, + HWAS::NV_CONTROLLER_PART_TYPE, + HWAS::SRCI_PRIORITY_HIGH); + nvdimmAddPage4Regs(i_nvdimm,l_err); + } + } while(0); + + return l_err; +} + + bool nvdimm_encrypt_unlock(TargetHandleList &i_nvdimmList) { TRACFCOMP(g_trac_nvdimm, ENTER_MRK"nvdimm_encrypt_unlock()"); @@ -3663,6 +3671,8 @@ errlHndl_t notifyNvdimmProtectionChange(Target* i_target, bool l_armed_change = false; bool l_set_encryption = false; bool l_clr_encryption = false; + bool l_sev_started = false; + bool l_sev_completed = false; switch (i_state) { @@ -3695,6 +3705,12 @@ errlHndl_t notifyNvdimmProtectionChange(Target* i_target, case ENCRYPTION_DISABLED: l_clr_encryption = true; break; + case ERASE_VERIFY_STARTED: + l_sev_started = true; + break; + case ERASE_VERIFY_COMPLETED: + l_sev_completed = true; + break; case SEND_NV_STATUS: // no action, just send status break; @@ -3737,6 +3753,18 @@ errlHndl_t notifyNvdimmProtectionChange(Target* i_target, l_nv_status &= NV_STATUS_ENCRYPTION_CLR; } + // Clear bit 5 if secure erase verify started + if (l_sev_started) + { + l_nv_status &= NV_STATUS_ERASE_VERIFY_CLR; + } + + // Set bit 5 if secure erase verify comlpleted + if (l_sev_completed) + { + l_nv_status |= NV_STATUS_ERASE_VERIFY_SET; + } + // Set bit 6 if risky error if (l_armed_state.risky_error_detected) { @@ -5585,7 +5613,263 @@ bool nvdimmDisarm(TargetHandleList &i_nvdimmTargetList) TRACFCOMP(g_trac_nvdimm, EXIT_MRK"nvdimmDisarm() returning %d", o_disarm_successful); - return o_disarm_successful; + + return o_disarm_successful; + +} + + +/* + * @brief Wrapper function to return NVDIMMs to factory default + */ +bool nvdimmFactoryDefault(TargetHandleList &i_nvdimmList) +{ + errlHndl_t l_err = nullptr; + bool l_success = true; + + // Factory default for all nvdimms in the list + for (const auto & l_nvdimm : i_nvdimmList) + { + l_err = nvdimm_factory_reset(l_nvdimm); + if (l_err) + { + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; + } + + // Update nvdimm status + l_err = notifyNvdimmProtectionChange(l_nvdimm, NVDIMM_DISARMED); + if (l_err) + { + errlCommit( l_err, NVDIMM_COMP_ID ); + } + } + + return l_success; +} + + +/* + * @brief Function to start secure erase verify of NVDIMMs + */ +bool nvdimmSecureEraseVerifyStart(TargetHandleList &i_nvdimmList) +{ + errlHndl_t l_err = nullptr; + bool l_success = true; + + // Secure erase verify for all nvdimms in the list + for (const auto & l_nvdimm : i_nvdimmList) + { + // Clear the erase_verify_status reg + l_err = nvdimmWriteReg(l_nvdimm, + ERASE_VERIFY_STATUS, + ERASE_VERIFY_CLEAR); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStart() HUID 0x%X" + "Failed to write ERASE_VERIFY_STATUS register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; + } + + // Start the erase verify operation + l_err = nvdimmWriteReg(l_nvdimm, + ERASE_VERIFY_CONTROL, + ERASE_VERIFY_START); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStart() HUID 0x%X" + "Failed to write ERASE_VERIFY_CONTROL register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; + } + + // Call notify to clear NV_STATUS bit + l_err = notifyNvdimmProtectionChange(l_nvdimm, + ERASE_VERIFY_STARTED); + if (l_err) + { + l_success = false; + errlCommit(l_err, NVDIMM_COMP_ID); + continue; + } + } + + return l_success; +} + + +/* + * @brief Function to check status of secure erase verify of NVDIMMs + */ +bool nvdimmSecureEraseVerifyStatus(TargetHandleList &i_nvdimmList) +{ + errlHndl_t l_err = nullptr; + bool l_success = true; + uint8_t l_data = 0; + + // Check secure erase verify status for all nvdimms in the list + for (const auto & l_nvdimm : i_nvdimmList) + { + // Check if secure-erase-verify is already complete for this nvdimm + ATTR_NV_STATUS_FLAG_type l_nv_status = + l_nvdimm->getAttr(); + if (l_nv_status & NV_STATUS_ERASE_VERIFY_SET) + { + continue; + } + + l_err = nvdimmReadReg(l_nvdimm, ERASE_VERIFY_CONTROL, l_data); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStatus() HUID 0x%X" + "Failed to read ERASE_VERIFY_CONTROL register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; // Continue to next nvdimm + } + + // If trigger is set the operation is not yet complete + if (l_data & ERASE_VERIFY_TRIGGER) + { + continue; // Continue to next nvdimm + } + + // Secure erase verify on this nvdimm is complete + // Call notify to set NV_STATUS bit + l_err = notifyNvdimmProtectionChange(l_nvdimm, + ERASE_VERIFY_COMPLETED); + if (l_err) + { + l_success = false; + errlCommit(l_err, NVDIMM_COMP_ID); + } + + + // Check the status register + l_err = nvdimmReadReg(l_nvdimm, ERASE_VERIFY_STATUS, l_data); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStatus() HUID 0x%X" + "Failed to read ERASE_VERIFY_STATUS register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; // Continue to next nvdimm + } + + // Non-zero status is an error + if (l_data) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmSecureEraseVerifyStatus() " + "HUID 0x%X ERASE_VERIFY_STATUS returned non-zero status", + get_huid(l_nvdimm)); + /*@ + *@errortype + *@reasoncode NVDIMM_ERASE_VERIFY_STATUS_NONZERO + *@severity ERRORLOG_SEV_PREDICTIVE + *@moduleid NVDIMM_SECURE_ERASE_VERIFY_STATUS + *@userdata1 NVDIMM HUID + *@userdata2 ERASE_VERIFY_STATUS + *@devdesc Error detected during secure erase verify + *@custdesc NVDIMM erase error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_PREDICTIVE, + NVDIMM_SECURE_ERASE_VERIFY_STATUS, + NVDIMM_ERASE_VERIFY_STATUS_NONZERO, + get_huid(l_nvdimm), + l_data, + ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + l_err->collectTrace(NVDIMM_COMP_NAME); + l_err->addPartCallout( l_nvdimm, + HWAS::NV_CONTROLLER_PART_TYPE, + HWAS::SRCI_PRIORITY_HIGH); + nvdimmAddVendorLog(l_nvdimm, l_err); + errlCommit( l_err, NVDIMM_COMP_ID ); + l_success = false; + continue; // Continue to next nvdimm + } + + + // Check the result registers + uint16_t l_result = 0; + l_err = nvdimmReadReg(l_nvdimm, ERASE_VERIFY_RESULT_MSB, l_data); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStatus() HUID 0x%X" + "Failed to read ERASE_VERIFY_RESULT_MSB register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; // Continue to next nvdimm + } + + // Save result + l_result = l_data << 8; + + l_err = nvdimmReadReg(l_nvdimm, ERASE_VERIFY_RESULT_LSB, l_data); + if (l_err) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK + "nvdimmSecureEraseVerifyStatus() HUID 0x%X" + "Failed to read ERASE_VERIFY_RESULT_LSB register", + get_huid(l_nvdimm)); + l_success = false; + errlCommit( l_err, NVDIMM_COMP_ID ); + continue; // Continue to next nvdimm + } + + // Save result + l_result |= l_data; + + // Non-zero result is an error + if (l_result) + { + TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimmSecureEraseVerifyStatus() " + "HUID 0x%X ERASE_VERIFY_RESULT returned non-zero data", + get_huid(l_nvdimm)); + /*@ + *@errortype + *@reasoncode NVDIMM_ERASE_VERIFY_RESULT_NONZERO + *@severity ERRORLOG_SEV_PREDICTIVE + *@moduleid NVDIMM_SECURE_ERASE_VERIFY_STATUS + *@userdata1 NVDIMM HUID + *@userdata2 ERASE_VERIFY_RESULT + *@devdesc Error detected during secure erase verify + *@custdesc NVDIMM erase error + */ + l_err = new ERRORLOG::ErrlEntry( + ERRORLOG::ERRL_SEV_PREDICTIVE, + NVDIMM_SECURE_ERASE_VERIFY_STATUS, + NVDIMM_ERASE_VERIFY_RESULT_NONZERO, + get_huid(l_nvdimm), + l_result, + ERRORLOG::ErrlEntry::NO_SW_CALLOUT ); + l_err->collectTrace(NVDIMM_COMP_NAME); + l_err->addPartCallout( l_nvdimm, + HWAS::NV_CONTROLLER_PART_TYPE, + HWAS::SRCI_PRIORITY_HIGH); + nvdimmAddVendorLog(l_nvdimm, l_err); + errlCommit( l_err, NVDIMM_COMP_ID ); + l_success = false; + continue; // Continue to next nvdimm + } + + } + + return l_success; } diff --git a/src/usr/isteps/nvdimm/nvdimm.H b/src/usr/isteps/nvdimm/nvdimm.H index 1e4e1596c29..e66e42470e8 100644 --- a/src/usr/isteps/nvdimm/nvdimm.H +++ b/src/usr/isteps/nvdimm/nvdimm.H @@ -305,18 +305,23 @@ enum i2cReg : uint16_t BPM_PAYLOAD_LENGTH = 0x442, BPM_REG_ERR_STATUS = 0x443, BPM_REG_PAYLOAD_START = 0x444, - ENCRYPTION_COMMAND = 0x51F, - ENCRYPTION_CONFIG_STATUS = 0x520, - ENCRYPTION_ACCESS_KEY_SET = 0x521, - ENCRYPTION_ACCESS_KEY_VERIFY = 0x522, - ENCRYPTION_ACCESS_KEY_UNLOCK = 0x523, - ENCRYPTION_RAMDOM_STRING_SET = 0x524, - ENCRYPTION_RANDOM_STRING_VERIFY = 0x525, - ENCRYPTION_ERASE_KEY_SET = 0x526, - ENCRYPTION_ERASE_KEY_VERIFY = 0x527, - ENCRYPTION_ERASE_KEY_TEST = 0x528, + ERASE_VERIFY_CONTROL = 0x51A, + ERASE_VERIFY_STATUS = 0x51B, + ERASE_VERIFY_RESULT_LSB = 0x51C, + ERASE_VERIFY_RESULT_MSB = 0x51D, + ERASE_VERIFY_TEST = 0x51E, + ENCRYPTION_COMMAND = 0x51F, + ENCRYPTION_CONFIG_STATUS = 0x520, + ENCRYPTION_ACCESS_KEY_SET = 0x521, + ENCRYPTION_ACCESS_KEY_VERIFY = 0x522, + ENCRYPTION_ACCESS_KEY_UNLOCK = 0x523, + ENCRYPTION_RAMDOM_STRING_SET = 0x524, + ENCRYPTION_RANDOM_STRING_VERIFY = 0x525, + ENCRYPTION_ERASE_KEY_SET = 0x526, + ENCRYPTION_ERASE_KEY_VERIFY = 0x527, + ENCRYPTION_ERASE_KEY_TEST = 0x528, ENCRYPTION_ERASE_KEY_TEST_VERIFY = 0x529, - ENCRYPTION_KEY_VALIDATION = 0x52A, + ENCRYPTION_KEY_VALIDATION = 0x52A, }; // i2cReg macros @@ -715,6 +720,17 @@ void nvdimmSetEncryptionError(TARGETING::Target *i_nvdimm); errlHndl_t nvdimmResetController(TARGETING::Target *i_nvdimm); +/** + * @brief Helper function to factory reset NVDIMM + * + * @param[in] i_nvdimm - nvdimm target + * + * @return errlHndl_t - Null if successful, otherwise a pointer to + * the error log + */ +errlHndl_t nvdimm_factory_reset(TARGETING::Target *i_nvdimm); + + #ifndef __HOSTBOOT_RUNTIME /** diff --git a/src/usr/targeting/common/xmltohb/attribute_types.xml b/src/usr/targeting/common/xmltohb/attribute_types.xml index 0fb3ff9aafb..e15880f87e9 100644 --- a/src/usr/targeting/common/xmltohb/attribute_types.xml +++ b/src/usr/targeting/common/xmltohb/attribute_types.xml @@ -5,7 +5,7 @@ - + @@ -5454,7 +5454,7 @@ 0x04: Contents preserved 0x08: Contents not preserved 0x10: Contents are encrypted - 0x20: Reserved + 0x20: Secure erase verify complete 0x40: Error detected, but save/restore might work 0x80: Reserved 0xFF: Memory is invalid diff --git a/src/usr/util/runtime/rt_fwnotify.C b/src/usr/util/runtime/rt_fwnotify.C index 6ef3e8fc4ed..148d3bbeb2e 100644 --- a/src/usr/util/runtime/rt_fwnotify.C +++ b/src/usr/util/runtime/rt_fwnotify.C @@ -5,7 +5,7 @@ /* */ /* OpenPOWER HostBoot Project */ /* */ -/* Contributors Listed Below - COPYRIGHT 2017,2019 */ +/* Contributors Listed Below - COPYRIGHT 2017,2020 */ /* [+] International Business Machines Corp. */ /* */ /* */ @@ -645,6 +645,57 @@ int doNvDimmOperation(const hostInterfaces::nvdimm_operation_t& i_nvDimmOp) } } + // Perform the factory default operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_FACTORY_DEFAULT) + { + if (!nvdimmFactoryDefault(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Factory Default operation failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Factory Default operation succeeded."); + } + } + + // Perform the secure erase verify start operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_SECURE_EV_START) + { + if (!nvdimmSecureEraseVerifyStart(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Start failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Start succeeded."); + } + } + + // Perform the secure erase verify status operation + if (i_nvDimmOp.opType & hostInterfaces::HBRT_FW_NVDIMM_SECURE_EV_STATUS) + { + if (!nvdimmSecureEraseVerifyStatus(l_nvDimmTargetList)) + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Status failed."); + rc = -1; + break; + } + else + { + TRACFCOMP(g_trac_runtime, "doNvDimmOperation: " + "Call to do NVDIMM Secure Erase Verify Status succeeded."); + } + } + } while(0); // end Perform the operations requested if (l_err)