| /** @file -- NvmExpressMediaSanitize.c | |
| This driver will implement sanitize operations on all NVMe mass storage devices | |
| based on NIST purge and clear operations. These operations will then be mapped to | |
| one of two NVMe admin commands: | |
| -Format NVM | |
| -Sanitize | |
| Implementation based off NVMe spec revision 1.4c. | |
| Copyright (c) Microsoft Corporation.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "NvmExpress.h" | |
| /** | |
| Send NVM Express FormatNVM Admin Command | |
| The Format NVM command is used to low level format the NVM media. This command is used by | |
| the host to change the LBA data size and/or metadata size. | |
| A low level format may destroy all data and metadata associated with all namespaces or only | |
| the specific namespace associated with the command (refer to the Format NVM Attributes field | |
| in the Identify Controller data structure). | |
| After the Format NVM command successfully completes, the controller shall not return any user | |
| data that was previously contained in an affected namespace. | |
| @param[in] This Indicates a pointer to the calling context (Block IO Protocol) | |
| @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be | |
| allocated and built. Caller must set the NamespaceId to zero if the | |
| device path node will contain a valid UUID. | |
| @param[in] Ses Secure Erase Setting (SES) value | |
| - 000b: No secure erase operation requested | |
| - 001b: User Data Erase | |
| - 010b: Cryptographic Erase | |
| - 011b to 111b: Reserved | |
| @param[in] Flbas New LBA size (in terms of LBA Format size Index (bits 3:0) in NamespaceData). | |
| If this param is 0 (NULL), then use existing LBA size. | |
| @retval EFI_SUCCESS The device formatted correctly. | |
| @retval EFI_WRITE_PROTECTED The device can not be formatted due to write protection. | |
| @retval EFI_DEVICE_ERROR The device reported an error while performing the format. | |
| @retval EFI_NO_MEDIA There is no media in the device. | |
| @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. | |
| @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid. | |
| **/ | |
| EFI_STATUS | |
| NvmExpressFormatNvm ( | |
| IN EFI_BLOCK_IO_PROTOCOL *This, | |
| IN UINT32 NamespaceId, | |
| IN UINT32 Ses, | |
| IN UINT32 Flbas | |
| ) | |
| { | |
| NVME_DEVICE_PRIVATE_DATA *Device; | |
| EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; | |
| EFI_NVM_EXPRESS_COMMAND Command; | |
| EFI_NVM_EXPRESS_COMPLETION Completion; | |
| NVME_ADMIN_FORMAT_NVM FormatNvmCdw10; | |
| NVME_ADMIN_NAMESPACE_DATA *NewNamespaceData; | |
| UINT32 Lbads; | |
| UINT32 NewFlbas; | |
| UINT32 LbaFmtIdx; | |
| EFI_STATUS Status; | |
| UINT32 LbaFormat; | |
| UINT16 StatusField; | |
| UINT16 Sct; | |
| UINT16 Sc; | |
| Status = EFI_NOT_STARTED; | |
| LbaFormat = 0; | |
| Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This); | |
| ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); | |
| ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND)); | |
| ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION)); | |
| ZeroMem (&FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM)); | |
| NewNamespaceData = NULL; | |
| Lbads = 0; | |
| NewFlbas = 0; | |
| LbaFmtIdx = 0; | |
| StatusField = 0; | |
| Sct = 0; | |
| Sc = 0; | |
| CommandPacket.NvmeCmd = &Command; | |
| CommandPacket.NvmeCompletion = &Completion; | |
| CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; | |
| CommandPacket.QueueType = NVME_ADMIN_QUEUE; | |
| Command.Cdw0.Opcode = NVME_ADMIN_FORMAT_NVM_CMD; | |
| Command.Nsid = NamespaceId; | |
| // | |
| // SES (Secure Erase Settings) | |
| // | |
| FormatNvmCdw10.Ses = Ses; | |
| // | |
| // Change LBA size/format if LbaFormat param != NULL, otherwise keep same LBA format. | |
| // Current supported LBA format size in Identify Namespace LBA Format Table, indexed by | |
| // FLBAS (bits 3:0). | |
| // | |
| LbaFormat = (Flbas == 0 ? Device->NamespaceData.Flbas : Flbas); | |
| FormatNvmCdw10.Lbaf = LbaFormat & NVME_LBA_FORMATNVM_LBAF_MASK; | |
| CopyMem (&CommandPacket.NvmeCmd->Cdw10, &FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM)); | |
| // | |
| // Send Format NVM command via passthru and wait for completion | |
| // | |
| // If LBA size changed successfully, then update private data structures and Block IO | |
| // and Media protocols to reflect new LBA size. | |
| // | |
| Status = Device->Controller->Passthru.PassThru ( | |
| &(Device->Controller->Passthru), | |
| NamespaceId, | |
| &CommandPacket, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >> | |
| NVME_CQE_STATUS_FIELD_OFFSET); | |
| Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET; | |
| Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET; | |
| DEBUG ((DEBUG_ERROR, "%a: NVMe FormatNVM admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc)); | |
| } else { | |
| // | |
| // Update Block IO and Media Protocols only if Flbas parameter was not NULL. | |
| // Call Identify Namespace again and update all protocols fields and local | |
| // cached copies of fields related to block size. | |
| // | |
| if (Flbas != 0) { | |
| NewNamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA)); | |
| if (NewNamespaceData == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| } else { | |
| Status = NvmeIdentifyNamespace ( | |
| Device->Controller, | |
| NamespaceId, | |
| (VOID *)NewNamespaceData | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Update all fields related to LBA size, allocation, and alignment | |
| // | |
| NewFlbas = NewNamespaceData->Flbas; | |
| LbaFmtIdx = NewFlbas & NVME_LBA_FORMATNVM_LBAF_MASK; | |
| Lbads = NewNamespaceData->LbaFormat[LbaFmtIdx].Lbads; | |
| Device->Media.BlockSize = (UINT32)1 << Lbads; | |
| Device->Media.LastBlock = NewNamespaceData->Nsze - 1; | |
| CopyMem (&Device->NamespaceData, NewNamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA)); | |
| } | |
| } | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Send NVM Express Sanitize Admin Command | |
| The Sanitize command is used to start a sanitize operation or to recover from a previously | |
| failed sanitize operation. The sanitize operation types that may be supported are Block | |
| Erase, Crypto Erase, and Overwrite. | |
| All sanitize operations are processed in the background (i.e., completion of the Sanitize | |
| command does not indicate completion of the sanitize operation). | |
| @param[in] This Indicates a pointer to the calling context (Block IO Protocol) | |
| @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be | |
| allocated and built. Caller must set the NamespaceId to zero if the | |
| device path node will contain a valid UUID. | |
| @param[in] SanitizeAction Sanitize action | |
| @param[in] NoDeallocAfterSanitize No deallocate after sanitize option | |
| @param[in] OverwritePattern Pattern to overwrite old user data | |
| @retval EFI_SUCCESS The media was sanitized successfully on the device. | |
| @retval EFI_WRITE_PROTECTED The device can not be sanitized due to write protection. | |
| @retval EFI_DEVICE_ERROR The device reported an error while performing the sanitize. | |
| @retval EFI_NO_MEDIA There is no media in the device. | |
| @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device. | |
| @retval EFI_INVALID_PARAMETER The sanitize request contains parameters that are not valid. | |
| **/ | |
| EFI_STATUS | |
| NvmExpressSanitize ( | |
| IN EFI_BLOCK_IO_PROTOCOL *This, | |
| IN UINT32 NamespaceId, | |
| IN UINT32 SanitizeAction, | |
| IN UINT32 NoDeallocAfterSanitize, | |
| IN UINT32 OverwritePattern | |
| ) | |
| { | |
| NVME_DEVICE_PRIVATE_DATA *Device; | |
| EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; | |
| EFI_NVM_EXPRESS_COMMAND Command; | |
| EFI_NVM_EXPRESS_COMPLETION Completion; | |
| NVME_ADMIN_SANITIZE SanitizeCdw10Cdw11; | |
| EFI_STATUS Status; | |
| UINT16 StatusField; | |
| UINT16 Sct; | |
| UINT16 Sc; | |
| UINT32 FnvmSes; | |
| Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This); | |
| ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); | |
| ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND)); | |
| ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION)); | |
| ZeroMem (&SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE)); | |
| StatusField = 0; | |
| Sct = 0; | |
| Sc = 0; | |
| FnvmSes = 0; | |
| CommandPacket.NvmeCmd = &Command; | |
| CommandPacket.NvmeCompletion = &Completion; | |
| CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; | |
| CommandPacket.QueueType = NVME_ADMIN_QUEUE; | |
| Command.Cdw0.Opcode = NVME_ADMIN_SANITIZE_CMD; | |
| Command.Nsid = NamespaceId; | |
| SanitizeCdw10Cdw11.Nodas = NoDeallocAfterSanitize; | |
| SanitizeCdw10Cdw11.Sanact = SanitizeAction; | |
| SanitizeCdw10Cdw11.Ovrpat = OverwritePattern; | |
| CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE)); | |
| // | |
| // Send Format NVM command via passthru and wait for completion | |
| // | |
| Status = Device->Controller->Passthru.PassThru ( | |
| &(Device->Controller->Passthru), | |
| NamespaceId, | |
| &CommandPacket, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >> | |
| NVME_CQE_STATUS_FIELD_OFFSET); | |
| Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET; | |
| Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET; | |
| DEBUG ((DEBUG_ERROR, "%a: NVMe Sanitize admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc)); | |
| // | |
| // Check for an error status code of "Invalid Command Opcode" in case | |
| // the NVM Express controller does not support Sanitize. If the NVM | |
| // Exress Controller does not support Sanitize, then send a Format NVM | |
| // admin command instead to perform the Purge operation. | |
| // | |
| if ((Sct == NVME_CQE_SCT_GENERIC_CMD_STATUS) && | |
| (Sc == NVME_CQE_SC_INVALID_CMD_OPCODE)) | |
| { | |
| switch (SanitizeCdw10Cdw11.Sanact) { | |
| case SANITIZE_ACTION_BLOCK_ERASE: | |
| FnvmSes = SES_USER_DATA_ERASE; // User Data Erase (LBAs indeterminate after) | |
| break; | |
| case SANITIZE_ACTION_CRYPTO_ERASE: | |
| FnvmSes = SES_CRYPTO_ERASE; // Crypto Erase | |
| break; | |
| case SANITIZE_ACTION_OVERWRITE: | |
| case SANITIZE_ACTION_EXIT_FAILURE_MODE: | |
| default: | |
| // | |
| // Cannot perform an equivalent FormatNVM action/operation | |
| // | |
| FnvmSes = SES_NO_SECURE_ERASE; | |
| break; | |
| } | |
| if ((FnvmSes == SES_USER_DATA_ERASE) || (FnvmSes == SES_CRYPTO_ERASE)) { | |
| Status = NvmExpressFormatNvm ( | |
| This, | |
| NVME_ALL_NAMESPACES, | |
| FnvmSes, | |
| 0 // Pass in NULL so existing LBA size is used in Format NVM | |
| ); | |
| } | |
| } | |
| } | |
| return Status; | |
| } | |
| /** | |
| Clear Media utilizes transport native WRITE commands to write a fixed pattern | |
| of non-sensitive data to the media. | |
| NOTE: The caller shall send buffer of one sector/LBA size with overwrite data. | |
| NOTE: This operation is a blocking call. | |
| NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK. | |
| Functions are defined to erase and purge data at a block level from mass | |
| storage devices as well as to manage such devices in the EFI boot services | |
| environment. | |
| @param[in] This Indicates a pointer to the calling context. | |
| @param[in] MediaId The media ID that the write request is for. | |
| @param[in] PassCount The number of passes to write over media. | |
| @param[in] SectorOwBuffer A pointer to the overwrite buffer. | |
| @retval EFI_SUCCESS The data was written correctly to the device. | |
| @retval EFI_WRITE_PROTECTED The device can not be written to. | |
| @retval EFI_DEVICE_ERROR The device reported an error while performing the write. | |
| @retval EFI_NO_MEDIA There is no media in the device. | |
| @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. | |
| @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, | |
| or the buffer is not on proper alignment. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| NvmExpressMediaClear ( | |
| IN MEDIA_SANITIZE_PROTOCOL *This, | |
| IN UINT32 MediaId, | |
| IN UINT32 PassCount, | |
| IN VOID *SectorOwBuffer | |
| ) | |
| { | |
| NVME_DEVICE_PRIVATE_DATA *Device; | |
| EFI_BLOCK_IO_MEDIA *Media; | |
| EFI_LBA SectorOffset; | |
| UINT32 TotalPassCount; | |
| EFI_STATUS Status; | |
| // | |
| // Check parameters. | |
| // | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This); | |
| Media = &Device->Media; | |
| SectorOffset = 0; | |
| if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) { | |
| return EFI_MEDIA_CHANGED; | |
| } | |
| // | |
| // If an invalid buffer or buffer size is sent, the Media Clear operation | |
| // cannot be performed as it requires a native WRITE command. The overwrite | |
| // buffer must have granularity of a namespace block size. | |
| // | |
| if (SectorOwBuffer == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = EFI_SUCCESS; | |
| // | |
| // Per NIST 800-88r1, one or more pass of writes may be alteratively used. | |
| // | |
| for (TotalPassCount = 0; TotalPassCount < PassCount; TotalPassCount++) { | |
| for (SectorOffset = 0; SectorOffset < Media->LastBlock; SectorOffset++ ) { | |
| Status = Device->BlockIo.WriteBlocks ( | |
| &Device->BlockIo, | |
| MediaId, | |
| SectorOffset, // Sector/LBA offset (increment each pass) | |
| 1, // Write one sector per write | |
| SectorOwBuffer // overwrite buffer | |
| ); | |
| } | |
| // | |
| // Reset SectorOffset back to zero if another pass on namespace is needed | |
| // | |
| SectorOffset = 0; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Purge Media utilizes transport native Sanitize operations. Sanitize specific | |
| purge actions include: overwrite, block erase, or crypto erase. | |
| Functions are defined to erase and purge data at a block level from mass | |
| storage devices as well as to manage such devices in the EFI boot services | |
| environment. Sanitization refers to a process that renders access to target | |
| data on the media infeasible for a given level of effort. | |
| NOTE: This operation is a blocking call. | |
| NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK. | |
| @param[in] This Indicates a pointer to the calling context. | |
| @param[in] MediaId The media ID that the write request is for. | |
| @param[in] PurgeAction The purage action (overwrite, crypto erase, block erase). | |
| @param[in] OverwritePattern 32-bit pattern to overwrite on media (for overwrite). | |
| @retval EFI_SUCCESS The media was purged successfully on the device. | |
| @retval EFI_WRITE_PROTECTED The device can not be purged due to write protection. | |
| @retval EFI_DEVICE_ERROR The device reported an error while performing the purge. | |
| @retval EFI_NO_MEDIA There is no media in the device. | |
| @retval EFI_MEDIA_CHNAGED The MediaId does not match the current device. | |
| @retval EFI_INVALID_PARAMETER The purge request contains parameters that are not valid. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| NvmExpressMediaPurge ( | |
| IN MEDIA_SANITIZE_PROTOCOL *This, | |
| IN UINT32 MediaId, | |
| IN UINT32 PurgeAction, | |
| IN UINT32 OverwritePattern | |
| ) | |
| { | |
| NVME_DEVICE_PRIVATE_DATA *Device; | |
| EFI_BLOCK_IO_MEDIA *Media; | |
| NVME_SANICAP SaniCap; | |
| UINT32 SanitizeAction; | |
| UINT32 NoDeallocate; | |
| UINT32 NamespaceId; | |
| EFI_STATUS Status; | |
| // | |
| // Check parameters. | |
| // | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This); | |
| NamespaceId = Device->NamespaceId; | |
| Media = &Device->Media; | |
| SaniCap = Device->Controller->ControllerData->Sanicap; | |
| NoDeallocate = 0; | |
| if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) { | |
| return EFI_MEDIA_CHANGED; | |
| } | |
| // | |
| // Purge action will directly map to sanitize action. If no valid purge | |
| // action is selected, then default to no action and let the NVMe SSD handle | |
| // the no-op sanitize action (as there may be other contingencies). | |
| // | |
| if (((PurgeAction & PURGE_ACTION_OVERWRITE) == PURGE_ACTION_OVERWRITE) && (SaniCap.Ows)) { | |
| SanitizeAction = SANITIZE_ACTION_OVERWRITE; | |
| } else if (((PurgeAction & PURGE_ACTION_BLOCK_ERASE) == PURGE_ACTION_BLOCK_ERASE) && (SaniCap.Bes)) { | |
| SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE; | |
| } else if (((PurgeAction & PURGE_ACTION_CRYPTO_ERASE) == PURGE_ACTION_CRYPTO_ERASE) && (SaniCap.Ces)) { | |
| SanitizeAction = SANITIZE_ACTION_CRYPTO_ERASE; | |
| } else { | |
| SanitizeAction = SANITIZE_ACTION_NO_ACTION; | |
| } | |
| if ((PurgeAction & PURGE_ACTION_NO_DEALLOCATE) == PURGE_ACTION_NO_DEALLOCATE) { | |
| NoDeallocate = NVME_NO_DEALLOCATE_AFTER_SANITZE; | |
| } | |
| // | |
| // Call NVM Express Admin command Sanitize (blocking call). | |
| // | |
| Status = NvmExpressSanitize ( | |
| &Device->BlockIo, | |
| NamespaceId, | |
| SanitizeAction, | |
| NoDeallocate, | |
| OverwritePattern | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Format Media utilizes native format operations to modify sector/LBA size. | |
| Secure erase actions are used to define how latent user data is erased. | |
| NOTE: This function must be called from TPL_APPLICATION or TPL_CALLBACK. | |
| @param[in] This Indicates a pointer to the calling context. | |
| @param[in] MediaId The media ID that the clear request is for. | |
| @param[in] LbaSize Size of LBA (in terms of power of two: 2^n). | |
| @param[in] SecureEraseAction Secure erase action, if any, to apply to format. | |
| - 000b: No secure erase operation requested | |
| - 001b: User Data Erase | |
| - 010b: Cryptographic Erase | |
| - 011b to 111b: Reserved | |
| @retval EFI_SUCCESS The media format request comopleted successfully on the device. | |
| @retval EFI_WRITE_PROTECTED The device can't be formatted due to write protection. | |
| @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the format operation. | |
| @retval EFI_INVALID_PARAMETER The format request contains parameters that are not valid. | |
| @retval EFI_NO_MEDIA There is no media in the device. | |
| @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| NvmExpressMediaFormat ( | |
| IN MEDIA_SANITIZE_PROTOCOL *This, | |
| IN UINT32 MediaId, | |
| IN UINT32 LbaSize, | |
| IN UINT32 SecureEraseAction | |
| ) | |
| { | |
| NVME_DEVICE_PRIVATE_DATA *Device; | |
| EFI_BLOCK_IO_MEDIA *Media; | |
| UINT32 NamespaceId; | |
| UINT32 SecureEraseSettings; | |
| UINT32 FlbaIndex; | |
| BOOLEAN LbaSizeIsSupported; | |
| EFI_STATUS Status; | |
| // | |
| // Check parameters. | |
| // | |
| if (This == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This); | |
| NamespaceId = Device->NamespaceId; | |
| Media = &Device->Media; | |
| SecureEraseSettings = FORMAT_SES_NO_SECURE_ERASE_REQUESTED; | |
| FlbaIndex = 0; | |
| if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) { | |
| return EFI_MEDIA_CHANGED; | |
| } | |
| // | |
| // Convert secure erase action to NVMe secure erase setting | |
| // | |
| switch (SecureEraseAction) { | |
| case FORMAT_SES_USER_DATA_ERASE: | |
| SecureEraseSettings = SES_USER_DATA_ERASE; | |
| break; | |
| case FORMAT_SES_CRYPTOGRAPHIC_ERASE: | |
| SecureEraseSettings = SES_CRYPTO_ERASE; | |
| break; | |
| case FORMAT_SES_NO_SECURE_ERASE_REQUESTED: | |
| default: | |
| // | |
| // Cannot perform an equivalent FormatNVM action/operation | |
| // | |
| SecureEraseSettings = SES_NO_SECURE_ERASE; | |
| break; | |
| } | |
| // | |
| // The requested LBA size must be supported by the NVMe SSD as defined in Identify | |
| // Namespace structure. | |
| // | |
| // Current supported LBA format sizes is in Identify Namespace LBA Format Table, | |
| // indexed by FLBAS (bits 3:0). Loop through all supported LBADF sizes and check | |
| // to see if requested LBA size is supported. If yes, send FormatNVM command. | |
| // | |
| LbaSizeIsSupported = FALSE; | |
| for (FlbaIndex = 0; FlbaIndex < Device->NamespaceData.Nlbaf; FlbaIndex++) { | |
| if (Device->NamespaceData.LbaFormat[FlbaIndex].Lbads == LbaSize) { | |
| LbaSizeIsSupported = TRUE; | |
| break; | |
| } | |
| } | |
| if (LbaSizeIsSupported) { | |
| Status = NvmExpressFormatNvm ( | |
| &Device->BlockIo, | |
| NamespaceId, | |
| SecureEraseSettings, | |
| FlbaIndex | |
| ); | |
| } else { | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| return Status; | |
| } |