Skip to content

Commit

Permalink
feat: Adding option to restore max LBA before erasing a device
Browse files Browse the repository at this point in the history
Adding a new option that a user can provide to restore the max LBA before starting a drive erasure.
While not necessary for purge capable commands, this is very useful for clear commands to ensure all user data is wiped.
This also helps provide a ready to validate and reuse a drive.

If the restore cannot complete successfully, then an error is generated and the erase will NOT continue until the user has intervened to try to resolve the issue or the option is removed from the command line.

This will handle restoring max LBA regardless of the feature that has reduced it to the best it can.
HPA, AMAC, and DCO are all handled for restoration.
If HPA security is active and an error is encountered, it may be because of this feature and the user will either need to unlock it or power cycle the drive.
The messages printed to the screen help indicate these possible scenarios as well as tips to try connecting the drive a different way or trying a different system.

[#52]
[#105]

Signed-off-by: Tyler Erickson <[email protected]>
  • Loading branch information
vonericsen committed Aug 1, 2023
1 parent e57c12c commit d12fcc3
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 2 deletions.
9 changes: 9 additions & 0 deletions include/openseachest_util_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,12 @@ extern "C"
#define ZERO_VERIFY_LONG_OPT_STRING "zeroVerify"
#define ZERO_VERIFY_LONG_OPT { ZERO_VERIFY_LONG_OPT_STRING, required_argument, NULL, 0 }

//before erasing a drive, restore the max LBA to make sure all user accessible spaces will be erased.
#define ERASE_RESTORE_MAX_PREP eraseRestoreMaxLBAPrep
#define ERASE_RESTORE_MAX_VAR getOptBool ERASE_RESTORE_MAX_PREP = goFalse;
#define ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING "eraseRestoreMaxPrep"
#define ERASE_RESTORE_MAX_PREP_LONG_OPT { ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING, no_argument, &ERASE_RESTORE_MAX_PREP, goTrue }

//Generic read test options
#define GENERIC_TEST_MODE_FLAG genericTestMode
#define GENERIC_TEST_MODE_VAR int genericTestMode = 0; //0 = read, 1 = write, 2 = verify
Expand Down Expand Up @@ -3483,6 +3489,9 @@ extern "C"
void print_Persistent_Reservations_Preempt_Abort_Help(bool shortHelp);

void print_Zero_Verify_Help(bool shortHelp);

void print_Erase_Restore_Max_Prep_Help(bool shortHelp);

void print_NVME_Health_Help(bool shortHelp);

void print_Delay_CMD_Segment_Help(bool shortHelp);
Expand Down
24 changes: 24 additions & 0 deletions src/openseachest_util_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -4346,6 +4346,30 @@ void print_Persistent_Reservations_Preempt_Abort_Help(bool shortHelp)
}
}

void print_Erase_Restore_Max_Prep_Help(bool shortHelp)
{
printf("\t--%s\n", ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING);
if (!shortHelp)
{
printf("\t\tThis option will attempt to restore the max LBA to the highest\n");
printf("\t\tuser addressable sector prior to beginning a drive erasure.\n");
printf("\t\tIf any failure is encountered while restoring the maxLBA, then\n");
printf("\t\tan error will be indicated and the erase will not be started or\n");
printf("\t\tattempted until other user intervention can be completed.\n");
printf("\t\tIf a feature is frozen, locked, or has already been used during\n");
printf("\t\tthe current power cycle, then these things can cause a failure.\n");
printf("\t\tThe solution is to power cycle the drive, but in some cases it may\n");
printf("\t\tbe necessary to try a different computer or adapter as commands may\n");
printf("\t\tbe blocked by the system or automatically issued by the BIOS to lock\n");
printf("\t\taccess to capacity changing commands.\n");
printf("\t\tThis option will handle the ATA HPA (Host Protected Area), AMAC (Accessible\n");
printf("\t\tMax Address Configuration), HPA Security Extension, and DCO (Device\n");
printf("\t\tConfiguration Overlay) features in accordance with the specifications.\n");
printf("\t\tIf the restore completes without error, then the erase will proceed\n");
printf("\t\tand additional errors will only be in relation to those erasure methods.\n\n");
}
}

void print_Zero_Verify_Help(bool shortHelp)
{
printf("\t--%s [full | quick]\n", ZERO_VERIFY_LONG_OPT_STRING);
Expand Down
2 changes: 1 addition & 1 deletion subprojects/opensea-operations
86 changes: 85 additions & 1 deletion utils/C/openSeaChest/openSeaChest_Erase.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@
#include "format.h"
#include "platform_helper.h"
#include "generic_tests.h"
#include "set_max_lba.h"
////////////////////////
// Global Variables //
////////////////////////
const char *util_name = "openSeaChest_Erase";
const char *buildVersion = "4.2.0";
const char *buildVersion = "4.3.0";

typedef enum _eSeaChestEraseExitCodes
{
Expand Down Expand Up @@ -150,6 +151,7 @@ int32_t main(int argc, char *argv[])
#endif
HIDE_LBA_COUNTER_VAR
LOWLEVEL_INFO_VAR
ERASE_RESTORE_MAX_VAR

int args = 0;
int argIndex = 0;
Expand Down Expand Up @@ -219,6 +221,7 @@ int32_t main(int argc, char *argv[])
NVM_FORMAT_LONG_OPT,
NVM_FORMAT_OPTIONS_LONG_OPTS,
ZERO_VERIFY_LONG_OPT,
ERASE_RESTORE_MAX_PREP_LONG_OPT,
LONG_OPT_TERMINATOR
};

Expand Down Expand Up @@ -1647,6 +1650,86 @@ int32_t main(int argc, char *argv[])
}
}

if (ERASE_RESTORE_MAX_PREP)
{
bool doNotContinueToErase = true;
switch (restore_Max_LBA_For_Erase(&deviceList[deviceIter]))
{
case SUCCESS:
doNotContinueToErase = false;//successfully restored so continuing onwards to erase is fine.
fill_Drive_Info_Data(&deviceList[deviceIter]);//refresh stale data
if (VERBOSITY_QUIET < toolVerbosity)
{
double mCapacity = 0, capacity = 0;
char mCapUnits[UNIT_STRING_LENGTH] = { 0 }, capUnits[UNIT_STRING_LENGTH] = { 0 };
char* mCapUnit = &mCapUnits[0], * capUnit = &capUnits[0];
mCapacity = C_CAST(double, deviceList[deviceIter].drive_info.deviceMaxLba * deviceList[deviceIter].drive_info.deviceBlockSize);
capacity = mCapacity;
metric_Unit_Convert(&mCapacity, &mCapUnit);
capacity_Unit_Convert(&capacity, &capUnit);
printf("Successfully restored maxLBA to highest possible user addressable LBA!\n");
printf("New Drive Capacity (%s/%s): %0.02f/%0.02f\n", mCapUnit, capUnit, mCapacity, capacity);
printf("Continuing to erase!\n");
}
break;
case DEVICE_ACCESS_DENIED:
case FROZEN:
case ABORTED:
if (VERBOSITY_QUIET < toolVerbosity)
{
printf("Drive aborted the command to restore max LBA. The device may already be at maxLBA,\n");
printf("the restore command may have been blocked, the feature may be locked/frozen\n");
printf("or some other unknown reason caused the abort.\n");
printf("Try power cycling the drive/system and try again or try a different system\n");
printf("or method of attaching the drive to run this command.\n");
printf("When a feature is \"frozen\" the drive must be power cycled to clear this condition.\n");
printf("Some systems will issue the freeze commands on boot which is why changing which system\n");
printf("is used or how the drive is attached to the system can get around this issue.\n");
printf("If the device supports the HPA security extension feature, then changes to HPA may be\n");
printf("blocked by the password set by this feature. You must either unlock the HPA security\n");
printf("feature, or power cycle the drive to remove the password and lock.\n");
printf("If you think that the device is already at maxLBA or want to proceed to erase anyways,\n");
printf("remove the --%s option from the command line and try again.\n", ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING);
printf("Erase will not be started while this is failing.\n\n");
}
exitCode = UTIL_EXIT_OPERATION_FAILURE;
break;
case NOT_SUPPORTED:
if (VERBOSITY_QUIET < toolVerbosity)
{
printf("Restoring maxLBA does not appear to be supported on this device.\n");
printf("If you believe this is an error, try changing how the device is\n");
printf("attached to the system (move from USB to SATA or from SAS HBA to\n");
printf("the motherboard) and try again.\n");
printf("If this does not work, try another system.\n");
printf("If you think that the device is already at maxLBA or want to proceed to erase anyways,\n");
printf("remove the --%s option from the command line and try again.\n", ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING);
printf("Erase will not be started while this is failing.\n\n");
}
exitCode = UTIL_EXIT_OPERATION_NOT_SUPPORTED;
break;
case FAILURE:
default:
if (VERBOSITY_QUIET < toolVerbosity)
{
printf("Failed to restore max LBA. The device may already be at maxLBA, the restore\n");
printf("command may have been blocked, or some other unknown reason caused the failure.\n");
printf("Try power cycling the drive/system and try again or try a different system\n");
printf("or method of attaching the drive to run this command.\n");
printf("If you think that the device is already at maxLBA or want to proceed to erase anyways,\n");
printf("remove the --%s option from the command line and try again.\n", ERASE_RESTORE_MAX_PREP_LONG_OPT_STRING);
printf("Erase will not be started while this is failing.\n\n");
}
exitCode = UTIL_EXIT_OPERATION_FAILURE;
break;
}
if (doNotContinueToErase)
{
//continue the loop to any additional drives since they may pass
continue;
}
}

#ifdef DISABLE_TCG_SUPPORT

#else
Expand Down Expand Up @@ -2943,6 +3026,7 @@ void utility_Usage(bool shortUsage)
print_TCG_PSID_Help(shortUsage);
#endif
print_Time_Seconds_Help(shortUsage);
print_Erase_Restore_Max_Prep_Help(shortUsage);
print_Show_Supported_Erase_Modes_Help(shortUsage);
#if !defined(DISABLE_TCG_SUPPORT)
print_TCG_SID_Help(shortUsage);
Expand Down

0 comments on commit d12fcc3

Please sign in to comment.