]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c
734e1286c61e501cf39c5d4410e28cef5dea01a5
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpressBlockIo.c
1 /** @file
2 NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
3 NVM Express specification.
4
5 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "NvmExpress.h"
17
18 /**
19 Read some sectors from the device.
20
21 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
22 @param Buffer The buffer used to store the data read from the device.
23 @param Lba The start block number.
24 @param Blocks Total block number to be read.
25
26 @retval EFI_SUCCESS Datum are read from the device.
27 @retval Others Fail to read all the datum.
28
29 **/
30 EFI_STATUS
31 ReadSectors (
32 IN NVME_DEVICE_PRIVATE_DATA *Device,
33 IN UINT64 Buffer,
34 IN UINT64 Lba,
35 IN UINT32 Blocks
36 )
37 {
38 NVME_CONTROLLER_PRIVATE_DATA *Private;
39 UINT32 Bytes;
40 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
41 EFI_NVM_EXPRESS_COMMAND Command;
42 EFI_NVM_EXPRESS_COMPLETION Completion;
43 EFI_STATUS Status;
44 UINT32 BlockSize;
45
46 Private = Device->Controller;
47 BlockSize = Device->Media.BlockSize;
48 Bytes = Blocks * BlockSize;
49
50 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
51 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
52 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
53
54 CommandPacket.NvmeCmd = &Command;
55 CommandPacket.NvmeCompletion = &Completion;
56
57 CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
58 CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
59 CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;
60
61 CommandPacket.TransferLength = Bytes;
62 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
63 CommandPacket.QueueType = NVME_IO_QUEUE;
64
65 CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
66 CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
67 CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
68
69 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
70
71 Status = Private->Passthru.PassThru (
72 &Private->Passthru,
73 Device->NamespaceId,
74 &CommandPacket,
75 NULL
76 );
77
78 return Status;
79 }
80
81 /**
82 Write some sectors to the device.
83
84 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
85 @param Buffer The buffer to be written into the device.
86 @param Lba The start block number.
87 @param Blocks Total block number to be written.
88
89 @retval EFI_SUCCESS Datum are written into the buffer.
90 @retval Others Fail to write all the datum.
91
92 **/
93 EFI_STATUS
94 WriteSectors (
95 IN NVME_DEVICE_PRIVATE_DATA *Device,
96 IN UINT64 Buffer,
97 IN UINT64 Lba,
98 IN UINT32 Blocks
99 )
100 {
101 NVME_CONTROLLER_PRIVATE_DATA *Private;
102 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
103 EFI_NVM_EXPRESS_COMMAND Command;
104 EFI_NVM_EXPRESS_COMPLETION Completion;
105 EFI_STATUS Status;
106 UINT32 Bytes;
107 UINT32 BlockSize;
108
109 Private = Device->Controller;
110 BlockSize = Device->Media.BlockSize;
111 Bytes = Blocks * BlockSize;
112
113 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
114 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
115 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
116
117 CommandPacket.NvmeCmd = &Command;
118 CommandPacket.NvmeCompletion = &Completion;
119
120 CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
121 CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
122 CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;
123
124 CommandPacket.TransferLength = Bytes;
125 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
126 CommandPacket.QueueType = NVME_IO_QUEUE;
127
128 CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
129 CommandPacket.NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
130 //
131 // Set Force Unit Access bit (bit 30) to use write-through behaviour
132 //
133 CommandPacket.NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
134
135 CommandPacket.MetadataBuffer = NULL;
136 CommandPacket.MetadataLength = 0;
137
138 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
139
140 Status = Private->Passthru.PassThru (
141 &Private->Passthru,
142 Device->NamespaceId,
143 &CommandPacket,
144 NULL
145 );
146
147 return Status;
148 }
149
150 /**
151 Read some blocks from the device.
152
153 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
154 @param Buffer The buffer used to store the data read from the device.
155 @param Lba The start block number.
156 @param Blocks Total block number to be read.
157
158 @retval EFI_SUCCESS Datum are read from the device.
159 @retval Others Fail to read all the datum.
160
161 **/
162 EFI_STATUS
163 NvmeRead (
164 IN NVME_DEVICE_PRIVATE_DATA *Device,
165 OUT VOID *Buffer,
166 IN UINT64 Lba,
167 IN UINTN Blocks
168 )
169 {
170 EFI_STATUS Status;
171 UINT32 BlockSize;
172 NVME_CONTROLLER_PRIVATE_DATA *Private;
173 UINT32 MaxTransferBlocks;
174 UINTN OrginalBlocks;
175 BOOLEAN IsEmpty;
176 EFI_TPL OldTpl;
177
178 //
179 // Wait for the device's asynchronous I/O queue to become empty.
180 //
181 while (TRUE) {
182 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
183 IsEmpty = IsListEmpty (&Device->AsyncQueue);
184 gBS->RestoreTPL (OldTpl);
185
186 if (IsEmpty) {
187 break;
188 }
189
190 gBS->Stall (100);
191 }
192
193 Status = EFI_SUCCESS;
194 Private = Device->Controller;
195 BlockSize = Device->Media.BlockSize;
196 OrginalBlocks = Blocks;
197
198 if (Private->ControllerData->Mdts != 0) {
199 MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
200 } else {
201 MaxTransferBlocks = 1024;
202 }
203
204 while (Blocks > 0) {
205 if (Blocks > MaxTransferBlocks) {
206 Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
207
208 Blocks -= MaxTransferBlocks;
209 Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
210 Lba += MaxTransferBlocks;
211 } else {
212 Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
213 Blocks = 0;
214 }
215
216 if (EFI_ERROR(Status)) {
217 break;
218 }
219 }
220
221 DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
222 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
223 (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
224
225 return Status;
226 }
227
228 /**
229 Write some blocks to the device.
230
231 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
232 @param Buffer The buffer to be written into the device.
233 @param Lba The start block number.
234 @param Blocks Total block number to be written.
235
236 @retval EFI_SUCCESS Datum are written into the buffer.
237 @retval Others Fail to write all the datum.
238
239 **/
240 EFI_STATUS
241 NvmeWrite (
242 IN NVME_DEVICE_PRIVATE_DATA *Device,
243 IN VOID *Buffer,
244 IN UINT64 Lba,
245 IN UINTN Blocks
246 )
247 {
248 EFI_STATUS Status;
249 UINT32 BlockSize;
250 NVME_CONTROLLER_PRIVATE_DATA *Private;
251 UINT32 MaxTransferBlocks;
252 UINTN OrginalBlocks;
253 BOOLEAN IsEmpty;
254 EFI_TPL OldTpl;
255
256 //
257 // Wait for the device's asynchronous I/O queue to become empty.
258 //
259 while (TRUE) {
260 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
261 IsEmpty = IsListEmpty (&Device->AsyncQueue);
262 gBS->RestoreTPL (OldTpl);
263
264 if (IsEmpty) {
265 break;
266 }
267
268 gBS->Stall (100);
269 }
270
271 Status = EFI_SUCCESS;
272 Private = Device->Controller;
273 BlockSize = Device->Media.BlockSize;
274 OrginalBlocks = Blocks;
275
276 if (Private->ControllerData->Mdts != 0) {
277 MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
278 } else {
279 MaxTransferBlocks = 1024;
280 }
281
282 while (Blocks > 0) {
283 if (Blocks > MaxTransferBlocks) {
284 Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);
285
286 Blocks -= MaxTransferBlocks;
287 Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
288 Lba += MaxTransferBlocks;
289 } else {
290 Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);
291 Blocks = 0;
292 }
293
294 if (EFI_ERROR(Status)) {
295 break;
296 }
297 }
298
299 DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
300 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
301 (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
302
303 return Status;
304 }
305
306 /**
307 Flushes all modified data to the device.
308
309 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.
310
311 @retval EFI_SUCCESS Datum are written into the buffer.
312 @retval Others Fail to write all the datum.
313
314 **/
315 EFI_STATUS
316 NvmeFlush (
317 IN NVME_DEVICE_PRIVATE_DATA *Device
318 )
319 {
320 NVME_CONTROLLER_PRIVATE_DATA *Private;
321 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
322 EFI_NVM_EXPRESS_COMMAND Command;
323 EFI_NVM_EXPRESS_COMPLETION Completion;
324 EFI_STATUS Status;
325
326 Private = Device->Controller;
327
328 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
329 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
330 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
331
332 CommandPacket.NvmeCmd = &Command;
333 CommandPacket.NvmeCompletion = &Completion;
334
335 CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
336 CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;
337 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
338 CommandPacket.QueueType = NVME_IO_QUEUE;
339
340 Status = Private->Passthru.PassThru (
341 &Private->Passthru,
342 Device->NamespaceId,
343 &CommandPacket,
344 NULL
345 );
346
347 return Status;
348 }
349
350 /**
351 Nonblocking I/O callback funtion when the event is signaled.
352
353 @param[in] Event The Event this notify function registered to.
354 @param[in] Context Pointer to the context data registered to the
355 Event.
356
357 **/
358 VOID
359 EFIAPI
360 AsyncIoCallback (
361 IN EFI_EVENT Event,
362 IN VOID *Context
363 )
364 {
365 NVME_BLKIO2_SUBTASK *Subtask;
366 NVME_BLKIO2_REQUEST *Request;
367 NVME_CQ *Completion;
368 EFI_BLOCK_IO2_TOKEN *Token;
369
370 gBS->CloseEvent (Event);
371
372 Subtask = (NVME_BLKIO2_SUBTASK *) Context;
373 Completion = (NVME_CQ *) Subtask->CommandPacket->NvmeCompletion;
374 Request = Subtask->BlockIo2Request;
375 Token = Request->Token;
376
377 if (Token->TransactionStatus == EFI_SUCCESS) {
378 //
379 // If previous subtask already fails, do not check the result of
380 // subsequent subtasks.
381 //
382 if ((Completion->Sct != 0) || (Completion->Sc != 0)) {
383 Token->TransactionStatus = EFI_DEVICE_ERROR;
384
385 //
386 // Dump completion entry status for debugging.
387 //
388 DEBUG_CODE_BEGIN();
389 NvmeDumpStatus (Completion);
390 DEBUG_CODE_END();
391 }
392 }
393
394 //
395 // Remove the subtask from the BlockIo2 subtasks list.
396 //
397 RemoveEntryList (&Subtask->Link);
398
399 if (IsListEmpty (&Request->SubtasksQueue) && Request->LastSubtaskSubmitted) {
400 //
401 // Remove the BlockIo2 request from the device asynchronous queue.
402 //
403 RemoveEntryList (&Request->Link);
404 FreePool (Request);
405 gBS->SignalEvent (Token->Event);
406 }
407
408 FreePool (Subtask->CommandPacket->NvmeCmd);
409 FreePool (Subtask->CommandPacket->NvmeCompletion);
410 FreePool (Subtask->CommandPacket);
411 FreePool (Subtask);
412 }
413
414 /**
415 Read some sectors from the device in an asynchronous manner.
416
417 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
418 structure.
419 @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.
420 @param Buffer The buffer used to store the data read from the device.
421 @param Lba The start block number.
422 @param Blocks Total block number to be read.
423 @param IsLast The last subtask of an asynchronous read request.
424
425 @retval EFI_SUCCESS Asynchronous read request has been queued.
426 @retval Others Fail to send the asynchronous request.
427
428 **/
429 EFI_STATUS
430 AsyncReadSectors (
431 IN NVME_DEVICE_PRIVATE_DATA *Device,
432 IN NVME_BLKIO2_REQUEST *Request,
433 IN UINT64 Buffer,
434 IN UINT64 Lba,
435 IN UINT32 Blocks,
436 IN BOOLEAN IsLast
437 )
438 {
439 NVME_CONTROLLER_PRIVATE_DATA *Private;
440 UINT32 Bytes;
441 NVME_BLKIO2_SUBTASK *Subtask;
442 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
443 EFI_NVM_EXPRESS_COMMAND *Command;
444 EFI_NVM_EXPRESS_COMPLETION *Completion;
445 EFI_STATUS Status;
446 UINT32 BlockSize;
447 EFI_TPL OldTpl;
448
449 Private = Device->Controller;
450 BlockSize = Device->Media.BlockSize;
451 Bytes = Blocks * BlockSize;
452 CommandPacket = NULL;
453 Command = NULL;
454 Completion = NULL;
455
456 Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
457 if (Subtask == NULL) {
458 Status = EFI_OUT_OF_RESOURCES;
459 goto ErrorExit;
460 }
461
462 Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;
463 Subtask->IsLast = IsLast;
464 Subtask->NamespaceId = Device->NamespaceId;
465 Subtask->BlockIo2Request = Request;
466
467 CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
468 if (CommandPacket == NULL) {
469 Status = EFI_OUT_OF_RESOURCES;
470 goto ErrorExit;
471 } else {
472 Subtask->CommandPacket = CommandPacket;
473 }
474
475 Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
476 if (Command == NULL) {
477 Status = EFI_OUT_OF_RESOURCES;
478 goto ErrorExit;
479 }
480
481 Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
482 if (Completion == NULL) {
483 Status = EFI_OUT_OF_RESOURCES;
484 goto ErrorExit;
485 }
486
487 //
488 // Create Event
489 //
490 Status = gBS->CreateEvent (
491 EVT_NOTIFY_SIGNAL,
492 TPL_NOTIFY,
493 AsyncIoCallback,
494 Subtask,
495 &Subtask->Event
496 );
497 if (EFI_ERROR(Status)) {
498 goto ErrorExit;
499 }
500
501 CommandPacket->NvmeCmd = Command;
502 CommandPacket->NvmeCompletion = Completion;
503
504 CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
505 CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;
506 CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;
507
508 CommandPacket->TransferLength = Bytes;
509 CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
510 CommandPacket->QueueType = NVME_IO_QUEUE;
511
512 CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
513 CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
514 CommandPacket->NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
515
516 CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
517
518 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
519 InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
520 Request->UnsubmittedSubtaskNum++;
521 gBS->RestoreTPL (OldTpl);
522
523 return EFI_SUCCESS;
524
525 ErrorExit:
526 //
527 // Resource cleanup if asynchronous read request has not been queued.
528 //
529 if (Completion != NULL) {
530 FreePool (Completion);
531 }
532
533 if (Command != NULL) {
534 FreePool (Command);
535 }
536
537 if (CommandPacket != NULL) {
538 FreePool (CommandPacket);
539 }
540
541 if (Subtask != NULL) {
542 if (Subtask->Event != NULL) {
543 gBS->CloseEvent (Subtask->Event);
544 }
545
546 FreePool (Subtask);
547 }
548
549 return Status;
550 }
551
552 /**
553 Write some sectors from the device in an asynchronous manner.
554
555 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
556 structure.
557 @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.
558 @param Buffer The buffer used to store the data written to the
559 device.
560 @param Lba The start block number.
561 @param Blocks Total block number to be written.
562 @param IsLast The last subtask of an asynchronous write request.
563
564 @retval EFI_SUCCESS Asynchronous write request has been queued.
565 @retval Others Fail to send the asynchronous request.
566
567 **/
568 EFI_STATUS
569 AsyncWriteSectors (
570 IN NVME_DEVICE_PRIVATE_DATA *Device,
571 IN NVME_BLKIO2_REQUEST *Request,
572 IN UINT64 Buffer,
573 IN UINT64 Lba,
574 IN UINT32 Blocks,
575 IN BOOLEAN IsLast
576 )
577 {
578 NVME_CONTROLLER_PRIVATE_DATA *Private;
579 UINT32 Bytes;
580 NVME_BLKIO2_SUBTASK *Subtask;
581 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
582 EFI_NVM_EXPRESS_COMMAND *Command;
583 EFI_NVM_EXPRESS_COMPLETION *Completion;
584 EFI_STATUS Status;
585 UINT32 BlockSize;
586 EFI_TPL OldTpl;
587
588 Private = Device->Controller;
589 BlockSize = Device->Media.BlockSize;
590 Bytes = Blocks * BlockSize;
591 CommandPacket = NULL;
592 Command = NULL;
593 Completion = NULL;
594
595 Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));
596 if (Subtask == NULL) {
597 Status = EFI_OUT_OF_RESOURCES;
598 goto ErrorExit;
599 }
600
601 Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;
602 Subtask->IsLast = IsLast;
603 Subtask->NamespaceId = Device->NamespaceId;
604 Subtask->BlockIo2Request = Request;
605
606 CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
607 if (CommandPacket == NULL) {
608 Status = EFI_OUT_OF_RESOURCES;
609 goto ErrorExit;
610 } else {
611 Subtask->CommandPacket = CommandPacket;
612 }
613
614 Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));
615 if (Command == NULL) {
616 Status = EFI_OUT_OF_RESOURCES;
617 goto ErrorExit;
618 }
619
620 Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));
621 if (Completion == NULL) {
622 Status = EFI_OUT_OF_RESOURCES;
623 goto ErrorExit;
624 }
625
626 //
627 // Create Event
628 //
629 Status = gBS->CreateEvent (
630 EVT_NOTIFY_SIGNAL,
631 TPL_NOTIFY,
632 AsyncIoCallback,
633 Subtask,
634 &Subtask->Event
635 );
636 if (EFI_ERROR(Status)) {
637 goto ErrorExit;
638 }
639
640 CommandPacket->NvmeCmd = Command;
641 CommandPacket->NvmeCompletion = Completion;
642
643 CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
644 CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;
645 CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;
646
647 CommandPacket->TransferLength = Bytes;
648 CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;
649 CommandPacket->QueueType = NVME_IO_QUEUE;
650
651 CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;
652 CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);
653 //
654 // Set Force Unit Access bit (bit 30) to use write-through behaviour
655 //
656 CommandPacket->NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;
657
658 CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
659
660 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
661 InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);
662 Request->UnsubmittedSubtaskNum++;
663 gBS->RestoreTPL (OldTpl);
664
665 return EFI_SUCCESS;
666
667 ErrorExit:
668 //
669 // Resource cleanup if asynchronous read request has not been queued.
670 //
671 if (Completion != NULL) {
672 FreePool (Completion);
673 }
674
675 if (Command != NULL) {
676 FreePool (Command);
677 }
678
679 if (CommandPacket != NULL) {
680 FreePool (CommandPacket);
681 }
682
683 if (Subtask != NULL) {
684 if (Subtask->Event != NULL) {
685 gBS->CloseEvent (Subtask->Event);
686 }
687
688 FreePool (Subtask);
689 }
690
691 return Status;
692 }
693
694 /**
695 Read some blocks from the device in an asynchronous manner.
696
697 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
698 structure.
699 @param Buffer The buffer used to store the data read from the device.
700 @param Lba The start block number.
701 @param Blocks Total block number to be read.
702 @param Token A pointer to the token associated with the transaction.
703
704 @retval EFI_SUCCESS Data are read from the device.
705 @retval Others Fail to read all the data.
706
707 **/
708 EFI_STATUS
709 NvmeAsyncRead (
710 IN NVME_DEVICE_PRIVATE_DATA *Device,
711 OUT VOID *Buffer,
712 IN UINT64 Lba,
713 IN UINTN Blocks,
714 IN EFI_BLOCK_IO2_TOKEN *Token
715 )
716 {
717 EFI_STATUS Status;
718 UINT32 BlockSize;
719 NVME_CONTROLLER_PRIVATE_DATA *Private;
720 NVME_BLKIO2_REQUEST *BlkIo2Req;
721 UINT32 MaxTransferBlocks;
722 UINTN OrginalBlocks;
723 BOOLEAN IsEmpty;
724 EFI_TPL OldTpl;
725
726 Status = EFI_SUCCESS;
727 Private = Device->Controller;
728 BlockSize = Device->Media.BlockSize;
729 OrginalBlocks = Blocks;
730 BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
731 if (BlkIo2Req == NULL) {
732 return EFI_OUT_OF_RESOURCES;
733 }
734
735 BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
736 BlkIo2Req->Token = Token;
737
738 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
739 InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
740 gBS->RestoreTPL (OldTpl);
741
742 InitializeListHead (&BlkIo2Req->SubtasksQueue);
743
744 if (Private->ControllerData->Mdts != 0) {
745 MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
746 } else {
747 MaxTransferBlocks = 1024;
748 }
749
750 while (Blocks > 0) {
751 if (Blocks > MaxTransferBlocks) {
752 Status = AsyncReadSectors (
753 Device,
754 BlkIo2Req, (UINT64)(UINTN)Buffer,
755 Lba,
756 MaxTransferBlocks,
757 FALSE
758 );
759
760 Blocks -= MaxTransferBlocks;
761 Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
762 Lba += MaxTransferBlocks;
763 } else {
764 Status = AsyncReadSectors (
765 Device,
766 BlkIo2Req,
767 (UINT64)(UINTN)Buffer,
768 Lba,
769 (UINT32)Blocks,
770 TRUE
771 );
772
773 Blocks = 0;
774 }
775
776 if (EFI_ERROR(Status)) {
777 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
778 IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
779 (BlkIo2Req->UnsubmittedSubtaskNum == 0);
780
781 if (IsEmpty) {
782 //
783 // Remove the BlockIo2 request from the device asynchronous queue.
784 //
785 RemoveEntryList (&BlkIo2Req->Link);
786 FreePool (BlkIo2Req);
787 Status = EFI_DEVICE_ERROR;
788 } else {
789 //
790 // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
791 // should be returned to make sure that the caller does not free
792 // resources still using by these requests.
793 //
794 Status = EFI_SUCCESS;
795 Token->TransactionStatus = EFI_DEVICE_ERROR;
796 BlkIo2Req->LastSubtaskSubmitted = TRUE;
797 }
798
799 gBS->RestoreTPL (OldTpl);
800
801 break;
802 }
803 }
804
805 DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
806 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
807 (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
808
809 return Status;
810 }
811
812 /**
813 Write some blocks from the device in an asynchronous manner.
814
815 @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data
816 structure.
817 @param Buffer The buffer used to store the data written to the
818 device.
819 @param Lba The start block number.
820 @param Blocks Total block number to be written.
821 @param Token A pointer to the token associated with the transaction.
822
823 @retval EFI_SUCCESS Data are written to the device.
824 @retval Others Fail to write all the data.
825
826 **/
827 EFI_STATUS
828 NvmeAsyncWrite (
829 IN NVME_DEVICE_PRIVATE_DATA *Device,
830 IN VOID *Buffer,
831 IN UINT64 Lba,
832 IN UINTN Blocks,
833 IN EFI_BLOCK_IO2_TOKEN *Token
834 )
835 {
836 EFI_STATUS Status;
837 UINT32 BlockSize;
838 NVME_CONTROLLER_PRIVATE_DATA *Private;
839 NVME_BLKIO2_REQUEST *BlkIo2Req;
840 UINT32 MaxTransferBlocks;
841 UINTN OrginalBlocks;
842 BOOLEAN IsEmpty;
843 EFI_TPL OldTpl;
844
845 Status = EFI_SUCCESS;
846 Private = Device->Controller;
847 BlockSize = Device->Media.BlockSize;
848 OrginalBlocks = Blocks;
849 BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));
850 if (BlkIo2Req == NULL) {
851 return EFI_OUT_OF_RESOURCES;
852 }
853
854 BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;
855 BlkIo2Req->Token = Token;
856
857 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
858 InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);
859 gBS->RestoreTPL (OldTpl);
860
861 InitializeListHead (&BlkIo2Req->SubtasksQueue);
862
863 if (Private->ControllerData->Mdts != 0) {
864 MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;
865 } else {
866 MaxTransferBlocks = 1024;
867 }
868
869 while (Blocks > 0) {
870 if (Blocks > MaxTransferBlocks) {
871 Status = AsyncWriteSectors (
872 Device,
873 BlkIo2Req,
874 (UINT64)(UINTN)Buffer,
875 Lba,
876 MaxTransferBlocks,
877 FALSE
878 );
879
880 Blocks -= MaxTransferBlocks;
881 Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);
882 Lba += MaxTransferBlocks;
883 } else {
884 Status = AsyncWriteSectors (
885 Device,
886 BlkIo2Req,
887 (UINT64)(UINTN)Buffer,
888 Lba,
889 (UINT32)Blocks,
890 TRUE
891 );
892
893 Blocks = 0;
894 }
895
896 if (EFI_ERROR(Status)) {
897 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
898 IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&
899 (BlkIo2Req->UnsubmittedSubtaskNum == 0);
900
901 if (IsEmpty) {
902 //
903 // Remove the BlockIo2 request from the device asynchronous queue.
904 //
905 RemoveEntryList (&BlkIo2Req->Link);
906 FreePool (BlkIo2Req);
907 Status = EFI_DEVICE_ERROR;
908 } else {
909 //
910 // There are previous BlockIo2 subtasks still running, EFI_SUCCESS
911 // should be returned to make sure that the caller does not free
912 // resources still using by these requests.
913 //
914 Status = EFI_SUCCESS;
915 Token->TransactionStatus = EFI_DEVICE_ERROR;
916 BlkIo2Req->LastSubtaskSubmitted = TRUE;
917 }
918
919 gBS->RestoreTPL (OldTpl);
920
921 break;
922 }
923 }
924
925 DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "
926 "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,
927 (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));
928
929 return Status;
930 }
931
932 /**
933 Reset the Block Device.
934
935 @param This Indicates a pointer to the calling context.
936 @param ExtendedVerification Driver may perform diagnostics on reset.
937
938 @retval EFI_SUCCESS The device was reset.
939 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
940 not be reset.
941
942 **/
943 EFI_STATUS
944 EFIAPI
945 NvmeBlockIoReset (
946 IN EFI_BLOCK_IO_PROTOCOL *This,
947 IN BOOLEAN ExtendedVerification
948 )
949 {
950 EFI_TPL OldTpl;
951 NVME_CONTROLLER_PRIVATE_DATA *Private;
952 NVME_DEVICE_PRIVATE_DATA *Device;
953 EFI_STATUS Status;
954
955 if (This == NULL) {
956 return EFI_INVALID_PARAMETER;
957 }
958
959 //
960 // For Nvm Express subsystem, reset block device means reset controller.
961 //
962 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
963
964 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
965
966 Private = Device->Controller;
967
968 Status = NvmeControllerInit (Private);
969
970 if (EFI_ERROR (Status)) {
971 Status = EFI_DEVICE_ERROR;
972 }
973
974 gBS->RestoreTPL (OldTpl);
975
976 return Status;
977 }
978
979 /**
980 Read BufferSize bytes from Lba into Buffer.
981
982 @param This Indicates a pointer to the calling context.
983 @param MediaId Id of the media, changes every time the media is replaced.
984 @param Lba The starting Logical Block Address to read from.
985 @param BufferSize Size of Buffer, must be a multiple of device block size.
986 @param Buffer A pointer to the destination buffer for the data. The caller is
987 responsible for either having implicit or explicit ownership of the buffer.
988
989 @retval EFI_SUCCESS The data was read correctly from the device.
990 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
991 @retval EFI_NO_MEDIA There is no media in the device.
992 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
993 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
994 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
995 or the buffer is not on proper alignment.
996
997 **/
998 EFI_STATUS
999 EFIAPI
1000 NvmeBlockIoReadBlocks (
1001 IN EFI_BLOCK_IO_PROTOCOL *This,
1002 IN UINT32 MediaId,
1003 IN EFI_LBA Lba,
1004 IN UINTN BufferSize,
1005 OUT VOID *Buffer
1006 )
1007 {
1008 NVME_DEVICE_PRIVATE_DATA *Device;
1009 EFI_STATUS Status;
1010 EFI_BLOCK_IO_MEDIA *Media;
1011 UINTN BlockSize;
1012 UINTN NumberOfBlocks;
1013 UINTN IoAlign;
1014 EFI_TPL OldTpl;
1015
1016 //
1017 // Check parameters.
1018 //
1019 if (This == NULL) {
1020 return EFI_INVALID_PARAMETER;
1021 }
1022
1023 Media = This->Media;
1024
1025 if (MediaId != Media->MediaId) {
1026 return EFI_MEDIA_CHANGED;
1027 }
1028
1029 if (Buffer == NULL) {
1030 return EFI_INVALID_PARAMETER;
1031 }
1032
1033 if (BufferSize == 0) {
1034 return EFI_SUCCESS;
1035 }
1036
1037 BlockSize = Media->BlockSize;
1038 if ((BufferSize % BlockSize) != 0) {
1039 return EFI_BAD_BUFFER_SIZE;
1040 }
1041
1042 NumberOfBlocks = BufferSize / BlockSize;
1043 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1044 return EFI_INVALID_PARAMETER;
1045 }
1046
1047 IoAlign = Media->IoAlign;
1048 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
1049 return EFI_INVALID_PARAMETER;
1050 }
1051
1052 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1053
1054 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
1055
1056 Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
1057
1058 gBS->RestoreTPL (OldTpl);
1059 return Status;
1060 }
1061
1062 /**
1063 Write BufferSize bytes from Lba into Buffer.
1064
1065 @param This Indicates a pointer to the calling context.
1066 @param MediaId The media ID that the write request is for.
1067 @param Lba The starting logical block address to be written. The caller is
1068 responsible for writing to only legitimate locations.
1069 @param BufferSize Size of Buffer, must be a multiple of device block size.
1070 @param Buffer A pointer to the source buffer for the data.
1071
1072 @retval EFI_SUCCESS The data was written correctly to the device.
1073 @retval EFI_WRITE_PROTECTED The device can not be written to.
1074 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1075 @retval EFI_NO_MEDIA There is no media in the device.
1076 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
1077 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
1078 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
1079 or the buffer is not on proper alignment.
1080
1081 **/
1082 EFI_STATUS
1083 EFIAPI
1084 NvmeBlockIoWriteBlocks (
1085 IN EFI_BLOCK_IO_PROTOCOL *This,
1086 IN UINT32 MediaId,
1087 IN EFI_LBA Lba,
1088 IN UINTN BufferSize,
1089 IN VOID *Buffer
1090 )
1091 {
1092 NVME_DEVICE_PRIVATE_DATA *Device;
1093 EFI_STATUS Status;
1094 EFI_BLOCK_IO_MEDIA *Media;
1095 UINTN BlockSize;
1096 UINTN NumberOfBlocks;
1097 UINTN IoAlign;
1098 EFI_TPL OldTpl;
1099
1100 //
1101 // Check parameters.
1102 //
1103 if (This == NULL) {
1104 return EFI_INVALID_PARAMETER;
1105 }
1106
1107 Media = This->Media;
1108
1109 if (MediaId != Media->MediaId) {
1110 return EFI_MEDIA_CHANGED;
1111 }
1112
1113 if (Buffer == NULL) {
1114 return EFI_INVALID_PARAMETER;
1115 }
1116
1117 if (BufferSize == 0) {
1118 return EFI_SUCCESS;
1119 }
1120
1121 BlockSize = Media->BlockSize;
1122 if ((BufferSize % BlockSize) != 0) {
1123 return EFI_BAD_BUFFER_SIZE;
1124 }
1125
1126 NumberOfBlocks = BufferSize / BlockSize;
1127 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1128 return EFI_INVALID_PARAMETER;
1129 }
1130
1131 IoAlign = Media->IoAlign;
1132 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
1133 return EFI_INVALID_PARAMETER;
1134 }
1135
1136 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1137
1138 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
1139
1140 Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
1141
1142 gBS->RestoreTPL (OldTpl);
1143
1144 return Status;
1145 }
1146
1147 /**
1148 Flush the Block Device.
1149
1150 @param This Indicates a pointer to the calling context.
1151
1152 @retval EFI_SUCCESS All outstanding data was written to the device.
1153 @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.
1154 @retval EFI_NO_MEDIA There is no media in the device.
1155
1156 **/
1157 EFI_STATUS
1158 EFIAPI
1159 NvmeBlockIoFlushBlocks (
1160 IN EFI_BLOCK_IO_PROTOCOL *This
1161 )
1162 {
1163 NVME_DEVICE_PRIVATE_DATA *Device;
1164 EFI_STATUS Status;
1165 EFI_TPL OldTpl;
1166
1167 //
1168 // Check parameters.
1169 //
1170 if (This == NULL) {
1171 return EFI_INVALID_PARAMETER;
1172 }
1173
1174 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1175
1176 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);
1177
1178 Status = NvmeFlush (Device);
1179
1180 gBS->RestoreTPL (OldTpl);
1181
1182 return Status;
1183 }
1184
1185 /**
1186 Reset the block device hardware.
1187
1188 @param[in] This Indicates a pointer to the calling context.
1189 @param[in] ExtendedVerification Indicates that the driver may perform a more
1190 exhausive verfication operation of the
1191 device during reset.
1192
1193 @retval EFI_SUCCESS The device was reset.
1194 @retval EFI_DEVICE_ERROR The device is not functioning properly and could
1195 not be reset.
1196
1197 **/
1198 EFI_STATUS
1199 EFIAPI
1200 NvmeBlockIoResetEx (
1201 IN EFI_BLOCK_IO2_PROTOCOL *This,
1202 IN BOOLEAN ExtendedVerification
1203 )
1204 {
1205 EFI_STATUS Status;
1206 NVME_DEVICE_PRIVATE_DATA *Device;
1207 NVME_CONTROLLER_PRIVATE_DATA *Private;
1208 BOOLEAN IsEmpty;
1209 EFI_TPL OldTpl;
1210
1211 if (This == NULL) {
1212 return EFI_INVALID_PARAMETER;
1213 }
1214
1215 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
1216 Private = Device->Controller;
1217
1218 //
1219 // Wait for the asynchronous PassThru queue to become empty.
1220 //
1221 while (TRUE) {
1222 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1223 IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&
1224 IsListEmpty (&Private->UnsubmittedSubtasks);
1225 gBS->RestoreTPL (OldTpl);
1226
1227 if (IsEmpty) {
1228 break;
1229 }
1230
1231 gBS->Stall (100);
1232 }
1233
1234 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1235
1236 Status = NvmeControllerInit (Private);
1237
1238 if (EFI_ERROR (Status)) {
1239 Status = EFI_DEVICE_ERROR;
1240 }
1241
1242 gBS->RestoreTPL (OldTpl);
1243
1244 return Status;
1245 }
1246
1247 /**
1248 Read BufferSize bytes from Lba into Buffer.
1249
1250 This function reads the requested number of blocks from the device. All the
1251 blocks are read, or an error is returned.
1252 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
1253 non-blocking I/O is being used, the Event associated with this request will
1254 not be signaled.
1255
1256 @param[in] This Indicates a pointer to the calling context.
1257 @param[in] MediaId Id of the media, changes every time the media is
1258 replaced.
1259 @param[in] Lba The starting Logical Block Address to read from.
1260 @param[in, out] Token A pointer to the token associated with the
1261 transaction.
1262 @param[in] BufferSize Size of Buffer, must be a multiple of device
1263 block size.
1264 @param[out] Buffer A pointer to the destination buffer for the data.
1265 The caller is responsible for either having
1266 implicit or explicit ownership of the buffer.
1267
1268 @retval EFI_SUCCESS The read request was queued if Token->Event is
1269 not NULL.The data was read correctly from the
1270 device if the Token->Event is NULL.
1271 @retval EFI_DEVICE_ERROR The device reported an error while performing
1272 the read.
1273 @retval EFI_NO_MEDIA There is no media in the device.
1274 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1275 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
1276 the intrinsic block size of the device.
1277 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
1278 valid, or the buffer is not on proper
1279 alignment.
1280 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
1281 lack of resources.
1282
1283 **/
1284 EFI_STATUS
1285 EFIAPI
1286 NvmeBlockIoReadBlocksEx (
1287 IN EFI_BLOCK_IO2_PROTOCOL *This,
1288 IN UINT32 MediaId,
1289 IN EFI_LBA Lba,
1290 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1291 IN UINTN BufferSize,
1292 OUT VOID *Buffer
1293 )
1294 {
1295 NVME_DEVICE_PRIVATE_DATA *Device;
1296 EFI_STATUS Status;
1297 EFI_BLOCK_IO_MEDIA *Media;
1298 UINTN BlockSize;
1299 UINTN NumberOfBlocks;
1300 UINTN IoAlign;
1301 EFI_TPL OldTpl;
1302
1303 //
1304 // Check parameters.
1305 //
1306 if (This == NULL) {
1307 return EFI_INVALID_PARAMETER;
1308 }
1309
1310 Media = This->Media;
1311
1312 if (MediaId != Media->MediaId) {
1313 return EFI_MEDIA_CHANGED;
1314 }
1315
1316 if (Buffer == NULL) {
1317 return EFI_INVALID_PARAMETER;
1318 }
1319
1320 if (BufferSize == 0) {
1321 if ((Token != NULL) && (Token->Event != NULL)) {
1322 Token->TransactionStatus = EFI_SUCCESS;
1323 gBS->SignalEvent (Token->Event);
1324 }
1325 return EFI_SUCCESS;
1326 }
1327
1328 BlockSize = Media->BlockSize;
1329 if ((BufferSize % BlockSize) != 0) {
1330 return EFI_BAD_BUFFER_SIZE;
1331 }
1332
1333 NumberOfBlocks = BufferSize / BlockSize;
1334 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1335 return EFI_INVALID_PARAMETER;
1336 }
1337
1338 IoAlign = Media->IoAlign;
1339 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
1340 return EFI_INVALID_PARAMETER;
1341 }
1342
1343 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1344
1345 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
1346
1347 if ((Token != NULL) && (Token->Event != NULL)) {
1348 Token->TransactionStatus = EFI_SUCCESS;
1349 Status = NvmeAsyncRead (Device, Buffer, Lba, NumberOfBlocks, Token);
1350 } else {
1351 Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);
1352 }
1353
1354 gBS->RestoreTPL (OldTpl);
1355 return Status;
1356 }
1357
1358 /**
1359 Write BufferSize bytes from Lba into Buffer.
1360
1361 This function writes the requested number of blocks to the device. All blocks
1362 are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
1363 EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
1364 being used, the Event associated with this request will not be signaled.
1365
1366 @param[in] This Indicates a pointer to the calling context.
1367 @param[in] MediaId The media ID that the write request is for.
1368 @param[in] Lba The starting logical block address to be written.
1369 The caller is responsible for writing to only
1370 legitimate locations.
1371 @param[in, out] Token A pointer to the token associated with the
1372 transaction.
1373 @param[in] BufferSize Size of Buffer, must be a multiple of device
1374 block size.
1375 @param[in] Buffer A pointer to the source buffer for the data.
1376
1377 @retval EFI_SUCCESS The write request was queued if Event is not
1378 NULL.
1379 The data was written correctly to the device if
1380 the Event is NULL.
1381 @retval EFI_WRITE_PROTECTED The device can not be written to.
1382 @retval EFI_NO_MEDIA There is no media in the device.
1383 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current
1384 device.
1385 @retval EFI_DEVICE_ERROR The device reported an error while performing
1386 the write.
1387 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size
1388 of the device.
1389 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
1390 valid, or the buffer is not on proper
1391 alignment.
1392 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
1393 lack of resources.
1394
1395 **/
1396 EFI_STATUS
1397 EFIAPI
1398 NvmeBlockIoWriteBlocksEx (
1399 IN EFI_BLOCK_IO2_PROTOCOL *This,
1400 IN UINT32 MediaId,
1401 IN EFI_LBA Lba,
1402 IN OUT EFI_BLOCK_IO2_TOKEN *Token,
1403 IN UINTN BufferSize,
1404 IN VOID *Buffer
1405 )
1406 {
1407 NVME_DEVICE_PRIVATE_DATA *Device;
1408 EFI_STATUS Status;
1409 EFI_BLOCK_IO_MEDIA *Media;
1410 UINTN BlockSize;
1411 UINTN NumberOfBlocks;
1412 UINTN IoAlign;
1413 EFI_TPL OldTpl;
1414
1415 //
1416 // Check parameters.
1417 //
1418 if (This == NULL) {
1419 return EFI_INVALID_PARAMETER;
1420 }
1421
1422 Media = This->Media;
1423
1424 if (MediaId != Media->MediaId) {
1425 return EFI_MEDIA_CHANGED;
1426 }
1427
1428 if (Buffer == NULL) {
1429 return EFI_INVALID_PARAMETER;
1430 }
1431
1432 if (BufferSize == 0) {
1433 if ((Token != NULL) && (Token->Event != NULL)) {
1434 Token->TransactionStatus = EFI_SUCCESS;
1435 gBS->SignalEvent (Token->Event);
1436 }
1437 return EFI_SUCCESS;
1438 }
1439
1440 BlockSize = Media->BlockSize;
1441 if ((BufferSize % BlockSize) != 0) {
1442 return EFI_BAD_BUFFER_SIZE;
1443 }
1444
1445 NumberOfBlocks = BufferSize / BlockSize;
1446 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
1447 return EFI_INVALID_PARAMETER;
1448 }
1449
1450 IoAlign = Media->IoAlign;
1451 if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {
1452 return EFI_INVALID_PARAMETER;
1453 }
1454
1455 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1456
1457 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
1458
1459 if ((Token != NULL) && (Token->Event != NULL)) {
1460 Token->TransactionStatus = EFI_SUCCESS;
1461 Status = NvmeAsyncWrite (Device, Buffer, Lba, NumberOfBlocks, Token);
1462 } else {
1463 Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);
1464 }
1465
1466 gBS->RestoreTPL (OldTpl);
1467 return Status;
1468 }
1469
1470 /**
1471 Flush the Block Device.
1472
1473 If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
1474 is returned and non-blocking I/O is being used, the Event associated with
1475 this request will not be signaled.
1476
1477 @param[in] This Indicates a pointer to the calling context.
1478 @param[in,out] Token A pointer to the token associated with the
1479 transaction.
1480
1481 @retval EFI_SUCCESS The flush request was queued if Event is not
1482 NULL.
1483 All outstanding data was written correctly to
1484 the device if the Event is NULL.
1485 @retval EFI_DEVICE_ERROR The device reported an error while writting back
1486 the data.
1487 @retval EFI_WRITE_PROTECTED The device cannot be written to.
1488 @retval EFI_NO_MEDIA There is no media in the device.
1489 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1490 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
1491 of resources.
1492
1493 **/
1494 EFI_STATUS
1495 EFIAPI
1496 NvmeBlockIoFlushBlocksEx (
1497 IN EFI_BLOCK_IO2_PROTOCOL *This,
1498 IN OUT EFI_BLOCK_IO2_TOKEN *Token
1499 )
1500 {
1501 NVME_DEVICE_PRIVATE_DATA *Device;
1502 BOOLEAN IsEmpty;
1503 EFI_TPL OldTpl;
1504
1505 //
1506 // Check parameters.
1507 //
1508 if (This == NULL) {
1509 return EFI_INVALID_PARAMETER;
1510 }
1511
1512 Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);
1513
1514 //
1515 // Wait for the asynchronous I/O queue to become empty.
1516 //
1517 while (TRUE) {
1518 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1519 IsEmpty = IsListEmpty (&Device->AsyncQueue);
1520 gBS->RestoreTPL (OldTpl);
1521
1522 if (IsEmpty) {
1523 break;
1524 }
1525
1526 gBS->Stall (100);
1527 }
1528
1529 //
1530 // Signal caller event
1531 //
1532 if ((Token != NULL) && (Token->Event != NULL)) {
1533 Token->TransactionStatus = EFI_SUCCESS;
1534 gBS->SignalEvent (Token->Event);
1535 }
1536
1537 return EFI_SUCCESS;
1538 }
1539
1540 /**
1541 Trust transfer data from/to NVMe device.
1542
1543 This function performs one NVMe transaction to do a trust transfer from/to NVMe device.
1544
1545 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
1546 @param Buffer The pointer to the current transaction buffer.
1547 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1548 the security protocol command to be sent.
1549 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1550 of the security protocol command to be sent.
1551 @param TransferLength The block number or sector count of the transfer.
1552 @param IsTrustSend Indicates whether it is a trust send operation or not.
1553 @param Timeout The timeout, in 100ns units, to use for the execution
1554 of the security protocol command. A Timeout value of 0
1555 means that this function will wait indefinitely for the
1556 security protocol command to execute. If Timeout is greater
1557 than zero, then this function will return EFI_TIMEOUT
1558 if the time required to execute the receive data command
1559 is greater than Timeout.
1560 @param TransferLengthOut A pointer to a buffer to store the size in bytes of the data
1561 written to the buffer. Ignore it when IsTrustSend is TRUE.
1562
1563 @retval EFI_SUCCESS The data transfer is complete successfully.
1564 @return others Some error occurs when transferring data.
1565
1566 **/
1567 EFI_STATUS
1568 TrustTransferNvmeDevice (
1569 IN OUT NVME_CONTROLLER_PRIVATE_DATA *Private,
1570 IN OUT VOID *Buffer,
1571 IN UINT8 SecurityProtocolId,
1572 IN UINT16 SecurityProtocolSpecificData,
1573 IN UINTN TransferLength,
1574 IN BOOLEAN IsTrustSend,
1575 IN UINT64 Timeout,
1576 OUT UINTN *TransferLengthOut
1577 )
1578 {
1579 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
1580 EFI_NVM_EXPRESS_COMMAND Command;
1581 EFI_NVM_EXPRESS_COMPLETION Completion;
1582 EFI_STATUS Status;
1583 UINT16 SpecificData;
1584
1585 ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
1586 ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
1587 ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
1588
1589 CommandPacket.NvmeCmd = &Command;
1590 CommandPacket.NvmeCompletion = &Completion;
1591
1592 //
1593 // Change Endianness of SecurityProtocolSpecificData
1594 //
1595 SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));
1596
1597 if (IsTrustSend) {
1598 Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_SEND_CMD;
1599 CommandPacket.TransferBuffer = Buffer;
1600 CommandPacket.TransferLength = (UINT32)TransferLength;
1601 CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
1602 CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
1603 } else {
1604 Command.Cdw0.Opcode = NVME_ADMIN_SECURITY_RECEIVE_CMD;
1605 CommandPacket.TransferBuffer = Buffer;
1606 CommandPacket.TransferLength = (UINT32)TransferLength;
1607 CommandPacket.NvmeCmd->Cdw10 = (UINT32)((SecurityProtocolId << 24) | (SpecificData << 8));
1608 CommandPacket.NvmeCmd->Cdw11 = (UINT32)TransferLength;
1609 }
1610
1611 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
1612 CommandPacket.NvmeCmd->Nsid = NVME_CONTROLLER_ID;
1613 CommandPacket.CommandTimeout = Timeout;
1614 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
1615
1616 Status = Private->Passthru.PassThru (
1617 &Private->Passthru,
1618 NVME_CONTROLLER_ID,
1619 &CommandPacket,
1620 NULL
1621 );
1622
1623 if (!IsTrustSend) {
1624 if (EFI_ERROR (Status)) {
1625 *TransferLengthOut = 0;
1626 } else {
1627 *TransferLengthOut = (UINTN) TransferLength;
1628 }
1629 }
1630
1631 return Status;
1632 }
1633
1634 /**
1635 Send a security protocol command to a device that receives data and/or the result
1636 of one or more commands sent by SendData.
1637
1638 The ReceiveData function sends a security protocol command to the given MediaId.
1639 The security protocol command sent is defined by SecurityProtocolId and contains
1640 the security protocol specific data SecurityProtocolSpecificData. The function
1641 returns the data from the security protocol command in PayloadBuffer.
1642
1643 For devices supporting the SCSI command set, the security protocol command is sent
1644 using the SECURITY PROTOCOL IN command defined in SPC-4.
1645
1646 For devices supporting the ATA command set, the security protocol command is sent
1647 using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
1648 is non-zero.
1649
1650 If the PayloadBufferSize is zero, the security protocol command is sent using the
1651 Trusted Non-Data command defined in ATA8-ACS.
1652
1653 If PayloadBufferSize is too small to store the available data from the security
1654 protocol command, the function shall copy PayloadBufferSize bytes into the
1655 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
1656
1657 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
1658 the function shall return EFI_INVALID_PARAMETER.
1659
1660 If the given MediaId does not support security protocol commands, the function shall
1661 return EFI_UNSUPPORTED. If there is no media in the device, the function returns
1662 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
1663 the function returns EFI_MEDIA_CHANGED.
1664
1665 If the security protocol fails to complete within the Timeout period, the function
1666 shall return EFI_TIMEOUT.
1667
1668 If the security protocol command completes without an error, the function shall
1669 return EFI_SUCCESS. If the security protocol command completes with an error, the
1670 function shall return EFI_DEVICE_ERROR.
1671
1672 @param This Indicates a pointer to the calling context.
1673 @param MediaId ID of the medium to receive data from.
1674 @param Timeout The timeout, in 100ns units, to use for the execution
1675 of the security protocol command. A Timeout value of 0
1676 means that this function will wait indefinitely for the
1677 security protocol command to execute. If Timeout is greater
1678 than zero, then this function will return EFI_TIMEOUT
1679 if the time required to execute the receive data command
1680 is greater than Timeout.
1681 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1682 the security protocol command to be sent.
1683 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1684 of the security protocol command to be sent.
1685 @param PayloadBufferSize Size in bytes of the payload data buffer.
1686 @param PayloadBuffer A pointer to a destination buffer to store the security
1687 protocol command specific payload data for the security
1688 protocol command. The caller is responsible for having
1689 either implicit or explicit ownership of the buffer.
1690 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
1691 data written to the payload data buffer.
1692
1693 @retval EFI_SUCCESS The security protocol command completed successfully.
1694 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
1695 data from the device. The PayloadBuffer contains the truncated data.
1696 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1697 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1698 @retval EFI_NO_MEDIA There is no media in the device.
1699 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1700 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
1701 PayloadBufferSize is non-zero.
1702 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1703 protocol command to execute.
1704
1705 **/
1706 EFI_STATUS
1707 EFIAPI
1708 NvmeStorageSecurityReceiveData (
1709 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1710 IN UINT32 MediaId,
1711 IN UINT64 Timeout,
1712 IN UINT8 SecurityProtocolId,
1713 IN UINT16 SecurityProtocolSpecificData,
1714 IN UINTN PayloadBufferSize,
1715 OUT VOID *PayloadBuffer,
1716 OUT UINTN *PayloadTransferSize
1717 )
1718 {
1719 EFI_STATUS Status;
1720 NVME_DEVICE_PRIVATE_DATA *Device;
1721
1722 Status = EFI_SUCCESS;
1723
1724 if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {
1725 return EFI_INVALID_PARAMETER;
1726 }
1727
1728 Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
1729
1730 if (MediaId != Device->BlockIo.Media->MediaId) {
1731 return EFI_MEDIA_CHANGED;
1732 }
1733
1734 if (!Device->BlockIo.Media->MediaPresent) {
1735 return EFI_NO_MEDIA;
1736 }
1737
1738 Status = TrustTransferNvmeDevice (
1739 Device->Controller,
1740 PayloadBuffer,
1741 SecurityProtocolId,
1742 SecurityProtocolSpecificData,
1743 PayloadBufferSize,
1744 FALSE,
1745 Timeout,
1746 PayloadTransferSize
1747 );
1748
1749 return Status;
1750 }
1751
1752 /**
1753 Send a security protocol command to a device.
1754
1755 The SendData function sends a security protocol command containing the payload
1756 PayloadBuffer to the given MediaId. The security protocol command sent is
1757 defined by SecurityProtocolId and contains the security protocol specific data
1758 SecurityProtocolSpecificData. If the underlying protocol command requires a
1759 specific padding for the command payload, the SendData function shall add padding
1760 bytes to the command payload to satisfy the padding requirements.
1761
1762 For devices supporting the SCSI command set, the security protocol command is sent
1763 using the SECURITY PROTOCOL OUT command defined in SPC-4.
1764
1765 For devices supporting the ATA command set, the security protocol command is sent
1766 using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
1767 is non-zero. If the PayloadBufferSize is zero, the security protocol command is
1768 sent using the Trusted Non-Data command defined in ATA8-ACS.
1769
1770 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
1771 return EFI_INVALID_PARAMETER.
1772
1773 If the given MediaId does not support security protocol commands, the function
1774 shall return EFI_UNSUPPORTED. If there is no media in the device, the function
1775 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
1776 device, the function returns EFI_MEDIA_CHANGED.
1777
1778 If the security protocol fails to complete within the Timeout period, the function
1779 shall return EFI_TIMEOUT.
1780
1781 If the security protocol command completes without an error, the function shall return
1782 EFI_SUCCESS. If the security protocol command completes with an error, the function
1783 shall return EFI_DEVICE_ERROR.
1784
1785 @param This Indicates a pointer to the calling context.
1786 @param MediaId ID of the medium to receive data from.
1787 @param Timeout The timeout, in 100ns units, to use for the execution
1788 of the security protocol command. A Timeout value of 0
1789 means that this function will wait indefinitely for the
1790 security protocol command to execute. If Timeout is greater
1791 than zero, then this function will return EFI_TIMEOUT
1792 if the time required to execute the send data command
1793 is greater than Timeout.
1794 @param SecurityProtocolId The value of the "Security Protocol" parameter of
1795 the security protocol command to be sent.
1796 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
1797 of the security protocol command to be sent.
1798 @param PayloadBufferSize Size in bytes of the payload data buffer.
1799 @param PayloadBuffer A pointer to a destination buffer to store the security
1800 protocol command specific payload data for the security
1801 protocol command.
1802
1803 @retval EFI_SUCCESS The security protocol command completed successfully.
1804 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
1805 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
1806 @retval EFI_NO_MEDIA There is no media in the device.
1807 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
1808 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
1809 @retval EFI_TIMEOUT A timeout occurred while waiting for the security
1810 protocol command to execute.
1811
1812 **/
1813 EFI_STATUS
1814 EFIAPI
1815 NvmeStorageSecuritySendData (
1816 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
1817 IN UINT32 MediaId,
1818 IN UINT64 Timeout,
1819 IN UINT8 SecurityProtocolId,
1820 IN UINT16 SecurityProtocolSpecificData,
1821 IN UINTN PayloadBufferSize,
1822 IN VOID *PayloadBuffer
1823 )
1824 {
1825 EFI_STATUS Status;
1826 NVME_DEVICE_PRIVATE_DATA *Device;
1827
1828 Status = EFI_SUCCESS;
1829
1830 if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {
1831 return EFI_INVALID_PARAMETER;
1832 }
1833
1834 Device = NVME_DEVICE_PRIVATE_DATA_FROM_STORAGE_SECURITY (This);
1835
1836 if (MediaId != Device->BlockIo.Media->MediaId) {
1837 return EFI_MEDIA_CHANGED;
1838 }
1839
1840 if (!Device->BlockIo.Media->MediaPresent) {
1841 return EFI_NO_MEDIA;
1842 }
1843
1844 Status = TrustTransferNvmeDevice (
1845 Device->Controller,
1846 PayloadBuffer,
1847 SecurityProtocolId,
1848 SecurityProtocolSpecificData,
1849 PayloadBufferSize,
1850 TRUE,
1851 Timeout,
1852 NULL
1853 );
1854
1855 return Status;
1856 }
1857
1858
1859
1860