TianoCore EDK2 master
Loading...
Searching...
No Matches
NvmExpressMediaSanitize.c
1
16#include "NvmExpress.h"
17
52NvmExpressFormatNvm (
54 IN UINT32 NamespaceId,
55 IN UINT32 Ses,
56 IN UINT32 Flbas
57 )
58{
63 NVME_ADMIN_FORMAT_NVM FormatNvmCdw10;
64 NVME_ADMIN_NAMESPACE_DATA *NewNamespaceData;
65 UINT32 Lbads;
66 UINT32 NewFlbas;
67 UINT32 LbaFmtIdx;
68 EFI_STATUS Status;
69 UINT32 LbaFormat;
70 UINT16 StatusField;
71 UINT16 Sct;
72 UINT16 Sc;
73
74 Status = EFI_NOT_STARTED;
75 LbaFormat = 0;
76 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
77
78 ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
79 ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
80 ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
81 ZeroMem (&FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
82
83 NewNamespaceData = NULL;
84 Lbads = 0;
85 NewFlbas = 0;
86 LbaFmtIdx = 0;
87 StatusField = 0;
88 Sct = 0;
89 Sc = 0;
90
91 CommandPacket.NvmeCmd = &Command;
92 CommandPacket.NvmeCompletion = &Completion;
93 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
94 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
95 Command.Cdw0.Opcode = NVME_ADMIN_FORMAT_NVM_CMD;
96 Command.Nsid = NamespaceId;
97
98 //
99 // SES (Secure Erase Settings)
100 //
101 FormatNvmCdw10.Ses = Ses;
102
103 //
104 // Change LBA size/format if LbaFormat param != NULL, otherwise keep same LBA format.
105 // Current supported LBA format size in Identify Namespace LBA Format Table, indexed by
106 // FLBAS (bits 3:0).
107 //
108 LbaFormat = (Flbas == 0 ? Device->NamespaceData.Flbas : Flbas);
109 FormatNvmCdw10.Lbaf = LbaFormat & NVME_LBA_FORMATNVM_LBAF_MASK;
110 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &FormatNvmCdw10, sizeof (NVME_ADMIN_FORMAT_NVM));
111
112 //
113 // Send Format NVM command via passthru and wait for completion
114 //
115 // If LBA size changed successfully, then update private data structures and Block IO
116 // and Media protocols to reflect new LBA size.
117 //
118 Status = Device->Controller->Passthru.PassThru (
119 &(Device->Controller->Passthru),
120 NamespaceId,
121 &CommandPacket,
122 NULL
123 );
124
125 if (EFI_ERROR (Status)) {
126 StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >>
127 NVME_CQE_STATUS_FIELD_OFFSET);
128
129 Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET;
130 Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET;
131
132 DEBUG ((DEBUG_ERROR, "%a: NVMe FormatNVM admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc));
133 } else {
134 //
135 // Update Block IO and Media Protocols only if Flbas parameter was not NULL.
136 // Call Identify Namespace again and update all protocols fields and local
137 // cached copies of fields related to block size.
138 //
139 if (Flbas != 0) {
140 NewNamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
141 if (NewNamespaceData == NULL) {
142 Status = EFI_OUT_OF_RESOURCES;
143 } else {
144 Status = NvmeIdentifyNamespace (
145 Device->Controller,
146 NamespaceId,
147 (VOID *)NewNamespaceData
148 );
149
150 if (!EFI_ERROR (Status)) {
151 //
152 // Update all fields related to LBA size, allocation, and alignment
153 //
154 NewFlbas = NewNamespaceData->Flbas;
155 LbaFmtIdx = NewFlbas & NVME_LBA_FORMATNVM_LBAF_MASK;
156 Lbads = NewNamespaceData->LbaFormat[LbaFmtIdx].Lbads;
157 Device->Media.BlockSize = (UINT32)1 << Lbads;
158 Device->Media.LastBlock = NewNamespaceData->Nsze - 1;
159
160 CopyMem (&Device->NamespaceData, NewNamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));
161 }
162 }
163 }
164 }
165
166 return Status;
167}
168
196NvmExpressSanitize (
198 IN UINT32 NamespaceId,
199 IN UINT32 SanitizeAction,
200 IN UINT32 NoDeallocAfterSanitize,
201 IN UINT32 OverwritePattern
202 )
203{
208 NVME_ADMIN_SANITIZE SanitizeCdw10Cdw11;
209 EFI_STATUS Status;
210 UINT16 StatusField;
211 UINT16 Sct;
212 UINT16 Sc;
213 UINT32 FnvmSes;
214
215 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
216
217 ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
218 ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
219 ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
220 ZeroMem (&SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE));
221
222 StatusField = 0;
223 Sct = 0;
224 Sc = 0;
225 FnvmSes = 0;
226
227 CommandPacket.NvmeCmd = &Command;
228 CommandPacket.NvmeCompletion = &Completion;
229 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
230 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
231 Command.Cdw0.Opcode = NVME_ADMIN_SANITIZE_CMD;
232 Command.Nsid = NamespaceId;
233
234 SanitizeCdw10Cdw11.Nodas = NoDeallocAfterSanitize;
235 SanitizeCdw10Cdw11.Sanact = SanitizeAction;
236 SanitizeCdw10Cdw11.Ovrpat = OverwritePattern;
237 CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SanitizeCdw10Cdw11, sizeof (NVME_ADMIN_SANITIZE));
238
239 //
240 // Send Format NVM command via passthru and wait for completion
241 //
242 Status = Device->Controller->Passthru.PassThru (
243 &(Device->Controller->Passthru),
244 NamespaceId,
245 &CommandPacket,
246 NULL
247 );
248
249 if (EFI_ERROR (Status)) {
250 StatusField = (UINT16)((CommandPacket.NvmeCompletion->DW3 & NVME_CQE_STATUS_FIELD_MASK) >>
251 NVME_CQE_STATUS_FIELD_OFFSET);
252
253 Sc = (StatusField & NVME_CQE_STATUS_FIELD_SC_MASK) >> NVME_CQE_STATUS_FIELD_SC_OFFSET;
254 Sct = (StatusField & NVME_CQE_STATUS_FIELD_SCT_MASK) >> NVME_CQE_STATUS_FIELD_SCT_OFFSET;
255
256 DEBUG ((DEBUG_ERROR, "%a: NVMe Sanitize admin command failed SCT = 0x%x, SC = 0x%x\n", __func__, Sct, Sc));
257
258 //
259 // Check for an error status code of "Invalid Command Opcode" in case
260 // the NVM Express controller does not support Sanitize. If the NVM
261 // Exress Controller does not support Sanitize, then send a Format NVM
262 // admin command instead to perform the Purge operation.
263 //
264 if ((Sct == NVME_CQE_SCT_GENERIC_CMD_STATUS) &&
265 (Sc == NVME_CQE_SC_INVALID_CMD_OPCODE))
266 {
267 switch (SanitizeCdw10Cdw11.Sanact) {
268 case SANITIZE_ACTION_BLOCK_ERASE:
269 FnvmSes = SES_USER_DATA_ERASE; // User Data Erase (LBAs indeterminate after)
270 break;
271 case SANITIZE_ACTION_CRYPTO_ERASE:
272 FnvmSes = SES_CRYPTO_ERASE; // Crypto Erase
273 break;
274 case SANITIZE_ACTION_OVERWRITE:
275 case SANITIZE_ACTION_EXIT_FAILURE_MODE:
276 default:
277 //
278 // Cannot perform an equivalent FormatNVM action/operation
279 //
280 FnvmSes = SES_NO_SECURE_ERASE;
281 break;
282 }
283
284 if ((FnvmSes == SES_USER_DATA_ERASE) || (FnvmSes == SES_CRYPTO_ERASE)) {
285 Status = NvmExpressFormatNvm (
286 This,
287 NVME_ALL_NAMESPACES,
288 FnvmSes,
289 0 // Pass in NULL so existing LBA size is used in Format NVM
290 );
291 }
292 }
293 }
294
295 return Status;
296}
297
325EFIAPI
326NvmExpressMediaClear (
328 IN UINT32 MediaId,
329 IN UINT32 PassCount,
330 IN VOID *SectorOwBuffer
331 )
332{
334 EFI_BLOCK_IO_MEDIA *Media;
335 EFI_LBA SectorOffset;
336 UINT32 TotalPassCount;
337 EFI_STATUS Status;
338
339 //
340 // Check parameters.
341 //
342 if (This == NULL) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
347 Media = &Device->Media;
348 SectorOffset = 0;
349
350 if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
351 return EFI_MEDIA_CHANGED;
352 }
353
354 //
355 // If an invalid buffer or buffer size is sent, the Media Clear operation
356 // cannot be performed as it requires a native WRITE command. The overwrite
357 // buffer must have granularity of a namespace block size.
358 //
359 if (SectorOwBuffer == NULL) {
360 return EFI_INVALID_PARAMETER;
361 }
362
363 Status = EFI_SUCCESS;
364
365 //
366 // Per NIST 800-88r1, one or more pass of writes may be alteratively used.
367 //
368 for (TotalPassCount = 0; TotalPassCount < PassCount; TotalPassCount++) {
369 for (SectorOffset = 0; SectorOffset < Media->LastBlock; SectorOffset++ ) {
370 Status = Device->BlockIo.WriteBlocks (
371 &Device->BlockIo,
372 MediaId,
373 SectorOffset, // Sector/LBA offset (increment each pass)
374 1, // Write one sector per write
375 SectorOwBuffer // overwrite buffer
376 );
377 }
378
379 //
380 // Reset SectorOffset back to zero if another pass on namespace is needed
381 //
382 SectorOffset = 0;
383 }
384
385 return Status;
386}
387
414EFIAPI
415NvmExpressMediaPurge (
417 IN UINT32 MediaId,
418 IN UINT32 PurgeAction,
419 IN UINT32 OverwritePattern
420 )
421{
423 EFI_BLOCK_IO_MEDIA *Media;
424 NVME_SANICAP SaniCap;
425 UINT32 SanitizeAction;
426 UINT32 NoDeallocate;
427 UINT32 NamespaceId;
428 EFI_STATUS Status;
429
430 //
431 // Check parameters.
432 //
433 if (This == NULL) {
434 return EFI_INVALID_PARAMETER;
435 }
436
437 Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
438 NamespaceId = Device->NamespaceId;
439 Media = &Device->Media;
440 SaniCap = Device->Controller->ControllerData->Sanicap;
441 NoDeallocate = 0;
442
443 if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
444 return EFI_MEDIA_CHANGED;
445 }
446
447 //
448 // Purge action will directly map to sanitize action. If no valid purge
449 // action is selected, then default to no action and let the NVMe SSD handle
450 // the no-op sanitize action (as there may be other contingencies).
451 //
452 if (((PurgeAction & PURGE_ACTION_OVERWRITE) == PURGE_ACTION_OVERWRITE) && (SaniCap.Ows)) {
453 SanitizeAction = SANITIZE_ACTION_OVERWRITE;
454 } else if (((PurgeAction & PURGE_ACTION_BLOCK_ERASE) == PURGE_ACTION_BLOCK_ERASE) && (SaniCap.Bes)) {
455 SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
456 } else if (((PurgeAction & PURGE_ACTION_CRYPTO_ERASE) == PURGE_ACTION_CRYPTO_ERASE) && (SaniCap.Ces)) {
457 SanitizeAction = SANITIZE_ACTION_CRYPTO_ERASE;
458 } else {
459 SanitizeAction = SANITIZE_ACTION_NO_ACTION;
460 }
461
462 if ((PurgeAction & PURGE_ACTION_NO_DEALLOCATE) == PURGE_ACTION_NO_DEALLOCATE) {
463 NoDeallocate = NVME_NO_DEALLOCATE_AFTER_SANITZE;
464 }
465
466 //
467 // Call NVM Express Admin command Sanitize (blocking call).
468 //
469 Status = NvmExpressSanitize (
470 &Device->BlockIo,
471 NamespaceId,
472 SanitizeAction,
473 NoDeallocate,
474 OverwritePattern
475 );
476
477 return Status;
478}
479
504EFIAPI
505NvmExpressMediaFormat (
507 IN UINT32 MediaId,
508 IN UINT32 LbaSize,
509 IN UINT32 SecureEraseAction
510 )
511{
513 EFI_BLOCK_IO_MEDIA *Media;
514 UINT32 NamespaceId;
515 UINT32 SecureEraseSettings;
516 UINT32 FlbaIndex;
517 BOOLEAN LbaSizeIsSupported;
518 EFI_STATUS Status;
519
520 //
521 // Check parameters.
522 //
523 if (This == NULL) {
524 return EFI_INVALID_PARAMETER;
525 }
526
527 Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
528 NamespaceId = Device->NamespaceId;
529 Media = &Device->Media;
530 SecureEraseSettings = FORMAT_SES_NO_SECURE_ERASE_REQUESTED;
531 FlbaIndex = 0;
532
533 if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
534 return EFI_MEDIA_CHANGED;
535 }
536
537 //
538 // Convert secure erase action to NVMe secure erase setting
539 //
540 switch (SecureEraseAction) {
541 case FORMAT_SES_USER_DATA_ERASE:
542 SecureEraseSettings = SES_USER_DATA_ERASE;
543 break;
544 case FORMAT_SES_CRYPTOGRAPHIC_ERASE:
545 SecureEraseSettings = SES_CRYPTO_ERASE;
546 break;
548 default:
549 //
550 // Cannot perform an equivalent FormatNVM action/operation
551 //
552 SecureEraseSettings = SES_NO_SECURE_ERASE;
553 break;
554 }
555
556 //
557 // The requested LBA size must be supported by the NVMe SSD as defined in Identify
558 // Namespace structure.
559 //
560 // Current supported LBA format sizes is in Identify Namespace LBA Format Table,
561 // indexed by FLBAS (bits 3:0). Loop through all supported LBADF sizes and check
562 // to see if requested LBA size is supported. If yes, send FormatNVM command.
563 //
564 LbaSizeIsSupported = FALSE;
565 for (FlbaIndex = 0; FlbaIndex < Device->NamespaceData.Nlbaf; FlbaIndex++) {
566 if (Device->NamespaceData.LbaFormat[FlbaIndex].Lbads == LbaSize) {
567 LbaSizeIsSupported = TRUE;
568 break;
569 }
570 }
571
572 if (LbaSizeIsSupported) {
573 Status = NvmExpressFormatNvm (
574 &Device->BlockIo,
575 NamespaceId,
576 SecureEraseSettings,
577 FlbaIndex
578 );
579 } else {
580 Status = EFI_INVALID_PARAMETER;
581 }
582
583 return Status;
584}
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define VOID
Definition: Base.h:269
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:435
#define FORMAT_SES_NO_SECURE_ERASE_REQUESTED
Definition: MediaSanitize.h:39
EFI_STATUS NvmeIdentifyNamespace(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN UINT32 NamespaceId, IN VOID *Buffer)
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINT32 BlockSize
Definition: BlockIo.h:167
EFI_LBA LastBlock
Definition: BlockIo.h:178
BOOLEAN MediaPresent
Definition: BlockIo.h:144