Skip to content

Commit

Permalink
HSD2206923523-ARS-Cancel-Before-FW-Update: Abort ARS before FW update
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel K Osawa <[email protected]>
  • Loading branch information
dkosawa authored and gldiviney committed Mar 12, 2019
1 parent 2233f74 commit 0320099
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 22 deletions.
124 changes: 124 additions & 0 deletions DcpmPkg/driver/Core/Dimm.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ InitializeCpuCommands(

#endif /** !OS_BUILD **/


STATIC EFI_STATUS PollOnArsDeviceBusy(IN DIMM *pDimm, IN UINT32 TimeoutSecs);

/**
Get dimm by Dimm ID
Scan the dimm list for a dimm identified by Dimm ID
Expand Down Expand Up @@ -1526,6 +1529,64 @@ FwCmdGetSecurityInfo(
return ReturnCode;
}

/**
Firmware command to disable ARS
@param[in] pDimm Pointer to the DIMM to disable ARS on
@retval EFI_SUCCESS Success
@retval EFI_INVALID_PARAMETER One or more parameters are NULL
@retval EFI_OUT_OF_RESOURCES Memory allocation failure
@retval Various errors from FW
**/
EFI_STATUS
FwCmdDisableARS(
IN DIMM *pDimm
)
{
FW_CMD *pFwCmd = NULL;
PT_PAYLOAD_SET_ADDRESS_RANGE_SCRUB *pARSInpugPayload = NULL;
EFI_STATUS ReturnCode = EFI_SUCCESS;

NVDIMM_ENTRY();

if (pDimm == NULL) {
ReturnCode = EFI_INVALID_PARAMETER;
goto Finish;
}

pFwCmd = AllocateZeroPool(sizeof(*pFwCmd));
if (pFwCmd == NULL) {
ReturnCode = EFI_OUT_OF_RESOURCES;
goto Finish;
}

pFwCmd->DimmID = pDimm->DimmID;
pFwCmd->Opcode = PtSetFeatures;
pFwCmd->SubOpcode = SubopAddressRangeScrub;

pARSInpugPayload = (PT_PAYLOAD_SET_ADDRESS_RANGE_SCRUB*)pFwCmd->InputPayload;
pARSInpugPayload->Enable = 0;

pFwCmd->InputPayloadSize = sizeof(PT_PAYLOAD_SET_ADDRESS_RANGE_SCRUB);

ReturnCode = PassThru(pDimm, pFwCmd, PT_TIMEOUT_INTERVAL);
if (EFI_ERROR(ReturnCode)) {
NVDIMM_DBG("Error detected when sending Firmware Set AddressRangeScrub command (RC = " FORMAT_EFI_STATUS ", Status = %d)", ReturnCode, pFwCmd->Status);
FW_CMD_ERROR_TO_EFI_STATUS(pFwCmd, ReturnCode);
goto Finish;
}

NVDIMM_DBG("Polling ARS long op status to verify ARS disabled completed.");
ReturnCode = PollOnArsDeviceBusy(pDimm, DISABLE_ARS_TOTAL_TIMEOUT_SEC);
NVDIMM_DBG("Finished polling long op, return val = %x", ReturnCode);

Finish:
FREE_POOL_SAFE(pFwCmd);
NVDIMM_EXIT_I64(ReturnCode);
return ReturnCode;
}

/**
Firmware command to retrieve the ARS status of a particular DIMM.
Expand Down Expand Up @@ -6250,6 +6311,69 @@ GetOverwriteDimmStatus(
return ReturnCode;
}

/**
Poll while ARS long operation status reports DEVICE BUSY
@param[in] pDimm DIMM to retrieve overwrite DIMM operation status from
@parma[in] TimeoutSecs - Poll timeout in seconds
@retval EFI_SUCCESS Success
@retval EFI_TIMEOUT Timeout expired and did not receive something other than FW_DEVICE_BUSY
@retval EFI_INVALID_PARAMETER One or more parameters are NULL
@retval EFI_DEVICE_ERROR Retrieved an unexpeced opcode/subopcode when requesting long op status
**/
EFI_STATUS
PollOnArsDeviceBusy(
IN DIMM *pDimm,
IN UINT32 TimeoutSecs
)
{
EFI_STATUS ReturnCode = EFI_INVALID_PARAMETER;
UINT8 FwStatus = FW_SUCCESS;
PT_OUTPUT_PAYLOAD_FW_LONG_OP_STATUS LongOpStatus;
UINT32 RetryMax = 0;
UINT32 RetryCount = 0;

NVDIMM_ENTRY();

ZeroMem(&LongOpStatus, sizeof(LongOpStatus));

if (pDimm == NULL) {
goto Finish;
}

RetryMax = (TimeoutSecs * 1000000) / POLL_ARS_LONG_OP_DELAY_US;

for(RetryCount = 0; RetryCount < RetryMax; ++RetryCount) {
ReturnCode = FwCmdGetLongOperationStatus(pDimm, &FwStatus, &LongOpStatus);
if (EFI_ERROR(ReturnCode)) {
NVDIMM_ERR("Error occured while polling for ARS enable/disable state.\n");
break;
}

if (LongOpStatus.CmdOpcode == PtSetFeatures && LongOpStatus.CmdSubcode == SubopAddressRangeScrub) {
if (FW_DEVICE_BUSY != LongOpStatus.Status) {
ReturnCode = EFI_SUCCESS;
goto Finish;
}
}
else {
NVDIMM_ERR("Unexpected opcode/subopcodes retrieved with Get Long Op Status\n");
ReturnCode = EFI_DEVICE_ERROR;
break;
}
gBS->Stall(POLL_ARS_LONG_OP_DELAY_US);
ZeroMem(&LongOpStatus, sizeof(LongOpStatus));
}

if (EFI_SUCCESS == ReturnCode && RetryCount == RetryMax) {
ReturnCode = EFI_TIMEOUT;
}
Finish:
NVDIMM_EXIT_I64(ReturnCode);
return ReturnCode;
}

/**
Customer Format Dimm
Send a customer format command through the smbus
Expand Down
18 changes: 18 additions & 0 deletions DcpmPkg/driver/Core/Dimm.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ typedef struct _MEMMAP_RANGE {
#define MEMMAP_RANGE_SIGNATURE SIGNATURE_64('M', 'M', 'A', 'P', 'R', 'N', 'G', 'E')
#define MEMMAP_RANGE_FROM_NODE(a) CR(a, MEMMAP_RANGE, MemmapNode, MEMMAP_RANGE_SIGNATURE)

#define DISABLE_ARS_TOTAL_TIMEOUT_SEC 2
#define POLL_ARS_LONG_OP_DELAY_US 100000 //100ms delay between calls to retreive long op

#ifdef OS_BUILD
#define INI_PREFERENCES_LARGE_PAYLOAD_DISABLED L"LARGE_PAYLOAD_DISABLED"
/*
Expand Down Expand Up @@ -691,6 +694,21 @@ FwCmdGetARS(
OUT UINT8 *pDimmARSStatus
);

/**
Firmware command to disable ARS
@param[in] pDimm Pointer to the DIMM to retrieve ARSStatus on
@retval EFI_SUCCESS Success
@retval EFI_INVALID_PARAMETER One or more parameters are NULL
@retval EFI_OUT_OF_RESOURCES Memory allocation failure
@retval Various errors from FW
**/
EFI_STATUS
FwCmdDisableARS(
IN DIMM *pDimm
);

/**
This helper function is used to determine the ARS status for the
particular DIMM by inspecting the firmware ARS return payload.
Expand Down
17 changes: 15 additions & 2 deletions DcpmPkg/driver/Core/NvmDimmPassThru.h
Original file line number Diff line number Diff line change
Expand Up @@ -712,13 +712,26 @@ typedef struct {
**/
typedef struct {
UINT8 Enable; //!< Indicates whether an Address Range Scrub is in progress.
UINT8 Reserved1[2];
UINT8 Reserved1[3];
UINT64 DPAStartAddress; //!< Address from which to start the range scrub.
UINT64 DPAEndAddress; //!< Address to end the range scrub.
UINT64 DPACurrentAddress; //!< Address that is being currently scrubbed.
UINT8 Reserved2[101];
UINT8 Reserved2[100];
} PT_PAYLOAD_ADDRESS_RANGE_SCRUB;

/**
Passthrough Payload:
Opcode: 0x04h (Get Features)
Sub-Opcode: 0x04h (Address Range Scrub)
**/
typedef struct {
UINT8 Enable; //!< Indicates whether an Address Range Scrub is in progress.
UINT8 Reserved1[3];
UINT64 DPAStartAddress; //!< Address from which to start the range scrub.
UINT64 DPAEndAddress; //!< Address to end the range scrub.
UINT8 Reserved2[108];
} PT_PAYLOAD_SET_ADDRESS_RANGE_SCRUB;

typedef union _SMART_VALIDATION_FLAGS {
UINT32 AllFlags;
struct {
Expand Down
Loading

0 comments on commit 0320099

Please sign in to comment.