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 //
364 // Per NIST 800-88r1, one or more pass of writes may be alteratively used.
365 //
366 for (TotalPassCount = 0; TotalPassCount < PassCount; TotalPassCount++) {
367 for (SectorOffset = 0; SectorOffset < Media->LastBlock; SectorOffset++ ) {
368 Status = Device->BlockIo.WriteBlocks (
369 &Device->BlockIo,
370 MediaId,
371 SectorOffset, // Sector/LBA offset (increment each pass)
372 1, // Write one sector per write
373 SectorOwBuffer // overwrite buffer
374 );
375 }
376
377 //
378 // Reset SectorOffset back to zero if another pass on namespace is needed
379 //
380 SectorOffset = 0;
381 }
382
383 return Status;
384}
385
412EFIAPI
413NvmExpressMediaPurge (
415 IN UINT32 MediaId,
416 IN UINT32 PurgeAction,
417 IN UINT32 OverwritePattern
418 )
419{
421 EFI_BLOCK_IO_MEDIA *Media;
422 NVME_SANICAP SaniCap;
423 UINT32 SanitizeAction;
424 UINT32 NoDeallocate;
425 UINT32 NamespaceId;
426 EFI_STATUS Status;
427
428 //
429 // Check parameters.
430 //
431 if (This == NULL) {
432 return EFI_INVALID_PARAMETER;
433 }
434
435 Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
436 NamespaceId = Device->NamespaceId;
437 Media = &Device->Media;
438 SaniCap = Device->Controller->ControllerData->Sanicap;
439 NoDeallocate = 0;
440
441 if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
442 return EFI_MEDIA_CHANGED;
443 }
444
445 //
446 // Purge action will directly map to sanitize action. If no valid purge
447 // action is selected, then default to no action and let the NVMe SSD handle
448 // the no-op sanitize action (as there may be other contingencies).
449 //
450 if (((PurgeAction & PURGE_ACTION_OVERWRITE) == PURGE_ACTION_OVERWRITE) && (SaniCap.Ows)) {
451 SanitizeAction = SANITIZE_ACTION_OVERWRITE;
452 } else if (((PurgeAction & PURGE_ACTION_BLOCK_ERASE) == PURGE_ACTION_BLOCK_ERASE) && (SaniCap.Bes)) {
453 SanitizeAction = SANITIZE_ACTION_BLOCK_ERASE;
454 } else if (((PurgeAction & PURGE_ACTION_CRYPTO_ERASE) == PURGE_ACTION_CRYPTO_ERASE) && (SaniCap.Ces)) {
455 SanitizeAction = SANITIZE_ACTION_CRYPTO_ERASE;
456 } else {
457 SanitizeAction = SANITIZE_ACTION_NO_ACTION;
458 }
459
460 if ((PurgeAction & PURGE_ACTION_NO_DEALLOCATE) == PURGE_ACTION_NO_DEALLOCATE) {
461 NoDeallocate = NVME_NO_DEALLOCATE_AFTER_SANITZE;
462 }
463
464 //
465 // Call NVM Express Admin command Sanitize (blocking call).
466 //
467 Status = NvmExpressSanitize (
468 &Device->BlockIo,
469 NamespaceId,
470 SanitizeAction,
471 NoDeallocate,
472 OverwritePattern
473 );
474
475 return Status;
476}
477
502EFIAPI
503NvmExpressMediaFormat (
505 IN UINT32 MediaId,
506 IN UINT32 LbaSize,
507 IN UINT32 SecureEraseAction
508 )
509{
511 EFI_BLOCK_IO_MEDIA *Media;
512 UINT32 NamespaceId;
513 UINT32 SecureEraseSettings;
514 UINT32 FlbaIndex;
515 BOOLEAN LbaSizeIsSupported;
516 EFI_STATUS Status;
517
518 //
519 // Check parameters.
520 //
521 if (This == NULL) {
522 return EFI_INVALID_PARAMETER;
523 }
524
525 Device = NVME_DEVICE_PRIVATE_DATA_FROM_MEDIA_SANITIZE (This);
526 NamespaceId = Device->NamespaceId;
527 Media = &Device->Media;
528 SecureEraseSettings = FORMAT_SES_NO_SECURE_ERASE_REQUESTED;
529 FlbaIndex = 0;
530
531 if ((MediaId != Media->MediaId) || (!Media->MediaPresent)) {
532 return EFI_MEDIA_CHANGED;
533 }
534
535 //
536 // Convert secure erase action to NVMe secure erase setting
537 //
538 switch (SecureEraseAction) {
539 case FORMAT_SES_USER_DATA_ERASE:
540 SecureEraseSettings = SES_USER_DATA_ERASE;
541 break;
542 case FORMAT_SES_CRYPTOGRAPHIC_ERASE:
543 SecureEraseSettings = SES_CRYPTO_ERASE;
544 break;
546 default:
547 //
548 // Cannot perform an equivalent FormatNVM action/operation
549 //
550 SecureEraseSettings = SES_NO_SECURE_ERASE;
551 break;
552 }
553
554 //
555 // The requested LBA size must be supported by the NVMe SSD as defined in Identify
556 // Namespace structure.
557 //
558 // Current supported LBA format sizes is in Identify Namespace LBA Format Table,
559 // indexed by FLBAS (bits 3:0). Loop through all supported LBADF sizes and check
560 // to see if requested LBA size is supported. If yes, send FormatNVM command.
561 //
562 LbaSizeIsSupported = FALSE;
563 for (FlbaIndex = 0; FlbaIndex < Device->NamespaceData.Nlbaf; FlbaIndex++) {
564 if (Device->NamespaceData.LbaFormat[FlbaIndex].Lbads == LbaSize) {
565 LbaSizeIsSupported = TRUE;
566 break;
567 }
568 }
569
570 if (LbaSizeIsSupported) {
571 Status = NvmExpressFormatNvm (
572 &Device->BlockIo,
573 NamespaceId,
574 SecureEraseSettings,
575 FlbaIndex
576 );
577 } else {
578 Status = EFI_INVALID_PARAMETER;
579 }
580
581 return Status;
582}
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 TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
#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
UINT32 BlockSize
Definition: BlockIo.h:167
EFI_LBA LastBlock
Definition: BlockIo.h:178
BOOLEAN MediaPresent
Definition: BlockIo.h:144