Skip to content

Commit

Permalink
Add option to factory reset nvdimms
Browse files Browse the repository at this point in the history
Added a factory reset function along with a overridable attribute
(ATTR_FORCE_NVDIMM_RESET) to trigger the reset during boot.

Change-Id: Ib39675e53d693ede897ace0f4432e104dcf8062e
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/80293
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: Daniel M Crowell <dcrowell@us.ibm.com>
  • Loading branch information
dcrowell77 committed Jul 16, 2019
1 parent a22884e commit d0e2fdd
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/include/usr/isteps/nvdimm/nvdimmreasoncodes.H
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ enum nvdimmModuleId
NVDIMM_KEYIFY_RANDOM_NUMBER = 0x2F,
SET_ATTR_NVDIMM_ENCRYPTION_KEYS_FW = 0x30,
SEND_ATTR_NVDIMM_ARMED = 0x31,
NVDIMM_FACTORY_RESET = 0x32,
};

/**
Expand Down
112 changes: 109 additions & 3 deletions src/usr/isteps/nvdimm/nvdimm.C
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
#ifdef __HOSTBOOT_RUNTIME
#include <runtime/hbrt_utilities.H>
#include <usr/runtime/rt_targeting.H>
#else
#include <initservice/istepdispatcherif.H>
#endif

using namespace TARGETING;
Expand Down Expand Up @@ -1580,6 +1582,93 @@ 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);

// 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);
}
} while(0);

return l_err;
}

/**
* @brief NVDIMM initialization
* - Checks for ready state
Expand All @@ -1600,12 +1689,29 @@ void nvdimm_init(Target *i_nvdimm)

do
{
// Force a factory reset if told to via attribute override
// This will allow us to recover from bad images, lost keys, etc
Target* l_sys = nullptr;
targetService().getTopLevelTarget( l_sys );
assert(l_sys, "nvdimm_init: no TopLevelTarget");
if( l_sys->getAttr<ATTR_FORCE_NVDIMM_RESET>() )
{
l_err = nvdimm_factory_reset(i_nvdimm);
if (l_err)
{
nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR);
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_init() nvdimm[%X], factory reset failed",
get_huid(i_nvdimm));
errlCommit(l_err, NVDIMM_COMP_ID);
}
}

l_err = nvdimmReady(i_nvdimm);

if (l_err)
{
nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR);
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], controller not ready",
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_init() nvdimm[%X], controller not ready",
get_huid(i_nvdimm));
errlCommit(l_err, NVDIMM_COMP_ID);
break;
Expand All @@ -1616,7 +1722,7 @@ void nvdimm_init(Target *i_nvdimm)
if (l_err)
{
nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR);
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], error retrieving timeout values",
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_init() nvdimm[%X], error retrieving timeout values",
get_huid(i_nvdimm));
errlCommit(l_err, NVDIMM_COMP_ID);
break;
Expand All @@ -1629,7 +1735,7 @@ void nvdimm_init(Target *i_nvdimm)
if (l_err)
{
nvdimmSetStatusFlag(i_nvdimm, NSTD_ERR_NOPRSV);
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_int() nvdimm[%X], error backing up the DRAM!",
TRACFCOMP(g_trac_nvdimm, ERR_MRK"nvdimm_init() nvdimm[%X], error backing up the DRAM!",
get_huid(i_nvdimm));
errlCommit(l_err, NVDIMM_COMP_ID);
break;
Expand Down
6 changes: 4 additions & 2 deletions src/usr/isteps/nvdimm/nvdimm.H
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ enum i2cReg : uint16_t
SET_ES_POLICY_STATUS = 0x070,
FIRMWARE_OPS_STATUS = 0x071,
OPERATIONAL_UNIT_OPS_STATUS = 0x072,
RESTORE_FAIL_INFO = 0x088,
OPERATIONAL_UNIT_FAIL_INFO = 0x08F,
CSAVE_INFO = 0x080,
CSAVE_FAIL_INFO0 = 0x084,
CSAVE_FAIL_INFO1 = 0x085,
RESTORE_FAIL_INFO = 0x088,
OPERATIONAL_UNIT_FAIL_INFO = 0x08F,
NVM_LIFETIME_ERROR_THRESHOLD = 0x090,
ES_LIFETIME_ERROR_THRESHOLD = 0x091,
ES_TEMP_ERROR_HIGH_THRESHOLD0 = 0x094,
Expand Down Expand Up @@ -320,6 +320,7 @@ enum i2c_in_values : uint8_t
RESET_CTRLR = 0x01,
VALID_IMAGE = 0x01,
RESET_CONTROLLER = 0x01,
FACTORY_DEFAULT = 0x01,
};

enum i2c_out_values : uint8_t
Expand All @@ -336,6 +337,7 @@ enum i2c_out_values : uint8_t
ES_SUCCESS = 0x05,
CHARGE_SUCCESS = 0x00,
NV_READY = 0xA5,
FACTORY_RESET_IN_PROGRESS = 0x03,
};

// Timeout-related enum
Expand Down
15 changes: 15 additions & 0 deletions src/usr/targeting/common/xmltohb/attribute_types.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,21 @@
</simpleType>
</attribute>

<attribute>
<description>
Lab-only trigger to force a factory reset of the NVDIMMs.
NOTE: This will erase any saved image and encryption keys.
</description>
<id>FORCE_NVDIMM_RESET</id>
<persistency>volatile-zeroed</persistency>
<readable/>
<simpleType>
<uint8_t>
<default>0</default>
</uint8_t>
</simpleType>
</attribute>

<attribute>
<id>FREQ_CORE_CEILING_MHZ</id>
<description>
Expand Down
3 changes: 3 additions & 0 deletions src/usr/targeting/common/xmltohb/target_types.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,9 @@
<attribute>
<id>FIELD_TH_P8EX_L3_LINE_DELETES</id>
</attribute>
<attribute>
<id>FORCE_NVDIMM_RESET</id>
</attribute>
<attribute>
<id>FREQ_CORE_CEILING_MHZ</id>
</attribute>
Expand Down

0 comments on commit d0e2fdd

Please sign in to comment.