TianoCore EDK2 master
Loading...
Searching...
No Matches
NvmExpressPassthru.c
Go to the documentation of this file.
1
11#include "NvmExpress.h"
12
19VOID
21 IN NVME_CQ *Cq
22 )
23{
24 DEBUG ((DEBUG_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));
25
26 DEBUG ((DEBUG_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));
27
28 DEBUG ((DEBUG_VERBOSE, " NVMe Cmd Execution Result - "));
29
30 switch (Cq->Sct) {
31 case 0x0:
32 switch (Cq->Sc) {
33 case 0x0:
34 DEBUG ((DEBUG_VERBOSE, "Successful Completion\n"));
35 break;
36 case 0x1:
37 DEBUG ((DEBUG_VERBOSE, "Invalid Command Opcode\n"));
38 break;
39 case 0x2:
40 DEBUG ((DEBUG_VERBOSE, "Invalid Field in Command\n"));
41 break;
42 case 0x3:
43 DEBUG ((DEBUG_VERBOSE, "Command ID Conflict\n"));
44 break;
45 case 0x4:
46 DEBUG ((DEBUG_VERBOSE, "Data Transfer Error\n"));
47 break;
48 case 0x5:
49 DEBUG ((DEBUG_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));
50 break;
51 case 0x6:
52 DEBUG ((DEBUG_VERBOSE, "Internal Device Error\n"));
53 break;
54 case 0x7:
55 DEBUG ((DEBUG_VERBOSE, "Command Abort Requested\n"));
56 break;
57 case 0x8:
58 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to SQ Deletion\n"));
59 break;
60 case 0x9:
61 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Failed Fused Command\n"));
62 break;
63 case 0xA:
64 DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Missing Fused Command\n"));
65 break;
66 case 0xB:
67 DEBUG ((DEBUG_VERBOSE, "Invalid Namespace or Format\n"));
68 break;
69 case 0xC:
70 DEBUG ((DEBUG_VERBOSE, "Command Sequence Error\n"));
71 break;
72 case 0xD:
73 DEBUG ((DEBUG_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));
74 break;
75 case 0xE:
76 DEBUG ((DEBUG_VERBOSE, "Invalid Number of SGL Descriptors\n"));
77 break;
78 case 0xF:
79 DEBUG ((DEBUG_VERBOSE, "Data SGL Length Invalid\n"));
80 break;
81 case 0x10:
82 DEBUG ((DEBUG_VERBOSE, "Metadata SGL Length Invalid\n"));
83 break;
84 case 0x11:
85 DEBUG ((DEBUG_VERBOSE, "SGL Descriptor Type Invalid\n"));
86 break;
87 case 0x80:
88 DEBUG ((DEBUG_VERBOSE, "LBA Out of Range\n"));
89 break;
90 case 0x81:
91 DEBUG ((DEBUG_VERBOSE, "Capacity Exceeded\n"));
92 break;
93 case 0x82:
94 DEBUG ((DEBUG_VERBOSE, "Namespace Not Ready\n"));
95 break;
96 case 0x83:
97 DEBUG ((DEBUG_VERBOSE, "Reservation Conflict\n"));
98 break;
99 }
100
101 break;
102
103 case 0x1:
104 switch (Cq->Sc) {
105 case 0x0:
106 DEBUG ((DEBUG_VERBOSE, "Completion Queue Invalid\n"));
107 break;
108 case 0x1:
109 DEBUG ((DEBUG_VERBOSE, "Invalid Queue Identifier\n"));
110 break;
111 case 0x2:
112 DEBUG ((DEBUG_VERBOSE, "Maximum Queue Size Exceeded\n"));
113 break;
114 case 0x3:
115 DEBUG ((DEBUG_VERBOSE, "Abort Command Limit Exceeded\n"));
116 break;
117 case 0x5:
118 DEBUG ((DEBUG_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));
119 break;
120 case 0x6:
121 DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Slot\n"));
122 break;
123 case 0x7:
124 DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Image\n"));
125 break;
126 case 0x8:
127 DEBUG ((DEBUG_VERBOSE, "Invalid Interrupt Vector\n"));
128 break;
129 case 0x9:
130 DEBUG ((DEBUG_VERBOSE, "Invalid Log Page\n"));
131 break;
132 case 0xA:
133 DEBUG ((DEBUG_VERBOSE, "Invalid Format\n"));
134 break;
135 case 0xB:
136 DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires Conventional Reset\n"));
137 break;
138 case 0xC:
139 DEBUG ((DEBUG_VERBOSE, "Invalid Queue Deletion\n"));
140 break;
141 case 0xD:
142 DEBUG ((DEBUG_VERBOSE, "Feature Identifier Not Saveable\n"));
143 break;
144 case 0xE:
145 DEBUG ((DEBUG_VERBOSE, "Feature Not Changeable\n"));
146 break;
147 case 0xF:
148 DEBUG ((DEBUG_VERBOSE, "Feature Not Namespace Specific\n"));
149 break;
150 case 0x10:
151 DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));
152 break;
153 case 0x80:
154 DEBUG ((DEBUG_VERBOSE, "Conflicting Attributes\n"));
155 break;
156 case 0x81:
157 DEBUG ((DEBUG_VERBOSE, "Invalid Protection Information\n"));
158 break;
159 case 0x82:
160 DEBUG ((DEBUG_VERBOSE, "Attempted Write to Read Only Range\n"));
161 break;
162 }
163
164 break;
165
166 case 0x2:
167 switch (Cq->Sc) {
168 case 0x80:
169 DEBUG ((DEBUG_VERBOSE, "Write Fault\n"));
170 break;
171 case 0x81:
172 DEBUG ((DEBUG_VERBOSE, "Unrecovered Read Error\n"));
173 break;
174 case 0x82:
175 DEBUG ((DEBUG_VERBOSE, "End-to-end Guard Check Error\n"));
176 break;
177 case 0x83:
178 DEBUG ((DEBUG_VERBOSE, "End-to-end Application Tag Check Error\n"));
179 break;
180 case 0x84:
181 DEBUG ((DEBUG_VERBOSE, "End-to-end Reference Tag Check Error\n"));
182 break;
183 case 0x85:
184 DEBUG ((DEBUG_VERBOSE, "Compare Failure\n"));
185 break;
186 case 0x86:
187 DEBUG ((DEBUG_VERBOSE, "Access Denied\n"));
188 break;
189 }
190
191 break;
192
193 default:
194 break;
195 }
196}
197
212VOID *
214 IN EFI_PCI_IO_PROTOCOL *PciIo,
215 IN EFI_PHYSICAL_ADDRESS PhysicalAddr,
216 IN UINTN Pages,
217 OUT VOID **PrpListHost,
218 IN OUT UINTN *PrpListNo,
219 OUT VOID **Mapping
220 )
221{
222 UINTN PrpEntryNo;
223 UINT64 PrpListBase;
224 UINTN PrpListIndex;
225 UINTN PrpEntryIndex;
226 UINT64 Remainder;
227 EFI_PHYSICAL_ADDRESS PrpListPhyAddr;
228 UINTN Bytes;
229 EFI_STATUS Status;
230
231 //
232 // The number of Prp Entry in a memory page.
233 //
234 PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
235
236 //
237 // Calculate total PrpList number.
238 //
239 *PrpListNo = (UINTN)DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo - 1, &Remainder);
240 if (*PrpListNo == 0) {
241 *PrpListNo = 1;
242 } else if ((Remainder != 0) && (Remainder != 1)) {
243 *PrpListNo += 1;
244 } else if (Remainder == 1) {
245 Remainder = PrpEntryNo;
246 } else if (Remainder == 0) {
247 Remainder = PrpEntryNo - 1;
248 }
249
250 Status = PciIo->AllocateBuffer (
251 PciIo,
254 *PrpListNo,
255 PrpListHost,
256 0
257 );
258
259 if (EFI_ERROR (Status)) {
260 return NULL;
261 }
262
263 Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);
264 Status = PciIo->Map (
265 PciIo,
267 *PrpListHost,
268 &Bytes,
269 &PrpListPhyAddr,
270 Mapping
271 );
272
273 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (*PrpListNo))) {
274 DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));
275 goto EXIT;
276 }
277
278 //
279 // Fill all PRP lists except of last one.
280 //
281 ZeroMem (*PrpListHost, Bytes);
282 for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {
283 PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
284
285 for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
286 if (PrpEntryIndex != PrpEntryNo - 1) {
287 //
288 // Fill all PRP entries except of last one.
289 //
290 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;
291 PhysicalAddr += EFI_PAGE_SIZE;
292 } else {
293 //
294 // Fill last PRP entries with next PRP List pointer.
295 //
296 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;
297 }
298 }
299 }
300
301 //
302 // Fill last PRP list.
303 //
304 PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
305 for (PrpEntryIndex = 0; PrpEntryIndex < Remainder; ++PrpEntryIndex) {
306 *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;
307 PhysicalAddr += EFI_PAGE_SIZE;
308 }
309
310 return (VOID *)(UINTN)PrpListPhyAddr;
311
312EXIT:
313 PciIo->FreeBuffer (PciIo, *PrpListNo, *PrpListHost);
314 return NULL;
315}
316
330 )
331{
332 EFI_PCI_IO_PROTOCOL *PciIo;
333 LIST_ENTRY *Link;
334 LIST_ENTRY *NextLink;
335 NVME_BLKIO2_SUBTASK *Subtask;
336 NVME_BLKIO2_REQUEST *BlkIo2Request;
337 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
338 EFI_BLOCK_IO2_TOKEN *Token;
339 EFI_TPL OldTpl;
340 EFI_STATUS Status;
341
342 PciIo = Private->PciIo;
343 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
344
345 //
346 // Cancel the unsubmitted subtasks.
347 //
348 for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
349 !IsNull (&Private->UnsubmittedSubtasks, Link);
350 Link = NextLink)
351 {
352 NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);
353 Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
354 BlkIo2Request = Subtask->BlockIo2Request;
355 Token = BlkIo2Request->Token;
356
357 BlkIo2Request->UnsubmittedSubtaskNum--;
358 if (Subtask->IsLast) {
359 BlkIo2Request->LastSubtaskSubmitted = TRUE;
360 }
361
362 Token->TransactionStatus = EFI_ABORTED;
363
364 RemoveEntryList (Link);
365 InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
366 gBS->SignalEvent (Subtask->Event);
367 }
368
369 //
370 // Cleanup the resources for the asynchronous PassThru requests.
371 //
372 for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
373 !IsNull (&Private->AsyncPassThruQueue, Link);
374 Link = NextLink)
375 {
376 NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
377 AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);
378
379 if (AsyncRequest->MapData != NULL) {
380 PciIo->Unmap (PciIo, AsyncRequest->MapData);
381 }
382
383 if (AsyncRequest->MapMeta != NULL) {
384 PciIo->Unmap (PciIo, AsyncRequest->MapMeta);
385 }
386
387 if (AsyncRequest->MapPrpList != NULL) {
388 PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);
389 }
390
391 if (AsyncRequest->PrpListHost != NULL) {
392 PciIo->FreeBuffer (
393 PciIo,
394 AsyncRequest->PrpListNo,
395 AsyncRequest->PrpListHost
396 );
397 }
398
399 RemoveEntryList (Link);
400 gBS->SignalEvent (AsyncRequest->CallerEvent);
401 FreePool (AsyncRequest);
402 }
403
404 if (IsListEmpty (&Private->AsyncPassThruQueue) &&
405 IsListEmpty (&Private->UnsubmittedSubtasks))
406 {
407 Status = EFI_SUCCESS;
408 } else {
409 Status = EFI_DEVICE_ERROR;
410 }
411
412 gBS->RestoreTPL (OldTpl);
413
414 return Status;
415}
416
450EFIAPI
453 IN UINT32 NamespaceId,
455 IN EFI_EVENT Event OPTIONAL
456 )
457{
459 EFI_STATUS Status;
460 EFI_STATUS PreviousStatus;
461 EFI_PCI_IO_PROTOCOL *PciIo;
462 NVME_SQ *Sq;
463 volatile NVME_CQ *Cq;
464 UINT16 QueueId;
465 UINT16 QueueSize;
466 UINT32 Bytes;
467 UINT16 Offset;
468 EFI_EVENT TimerEvent;
470 EFI_PHYSICAL_ADDRESS PhyAddr;
471 VOID *MapData;
472 VOID *MapMeta;
473 VOID *MapPrpList;
474 UINTN MapLength;
475 UINT64 *Prp;
476 VOID *PrpListHost;
477 UINTN PrpListNo;
478 UINT32 Attributes;
479 UINT32 IoAlign;
480 UINT32 MaxTransLen;
481 UINT32 Data;
482 NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
483 EFI_TPL OldTpl;
484
485 //
486 // check the data fields in Packet parameter.
487 //
488 if ((This == NULL) || (Packet == NULL)) {
489 return EFI_INVALID_PARAMETER;
490 }
491
492 if ((Packet->NvmeCmd == NULL) || (Packet->NvmeCompletion == NULL)) {
493 return EFI_INVALID_PARAMETER;
494 }
495
496 if ((Packet->QueueType != NVME_ADMIN_QUEUE) && (Packet->QueueType != NVME_IO_QUEUE)) {
497 return EFI_INVALID_PARAMETER;
498 }
499
500 //
501 // 'Attributes' with neither EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL nor
502 // EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL set is an illegal
503 // configuration.
504 //
505 Attributes = This->Mode->Attributes;
506 if ((Attributes & (EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |
507 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0)
508 {
509 return EFI_INVALID_PARAMETER;
510 }
511
512 //
513 // Buffer alignment check for TransferBuffer & MetadataBuffer.
514 //
515 IoAlign = This->Mode->IoAlign;
516 if ((IoAlign > 0) && (((UINTN)Packet->TransferBuffer & (IoAlign - 1)) != 0)) {
517 return EFI_INVALID_PARAMETER;
518 }
519
520 if ((IoAlign > 0) && (((UINTN)Packet->MetadataBuffer & (IoAlign - 1)) != 0)) {
521 return EFI_INVALID_PARAMETER;
522 }
523
524 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
525
526 //
527 // Check NamespaceId is valid or not.
528 //
529 if ((NamespaceId > Private->ControllerData->Nn) &&
530 (NamespaceId != (UINT32)-1))
531 {
532 return EFI_INVALID_PARAMETER;
533 }
534
535 //
536 // Check whether TransferLength exceeds the maximum data transfer size.
537 //
538 if (Private->ControllerData->Mdts != 0) {
539 MaxTransLen = (1 << (Private->ControllerData->Mdts)) *
540 (1 << (Private->Cap.Mpsmin + 12));
541 if (Packet->TransferLength > MaxTransLen) {
542 Packet->TransferLength = MaxTransLen;
543 return EFI_BAD_BUFFER_SIZE;
544 }
545 }
546
547 PciIo = Private->PciIo;
548 MapData = NULL;
549 MapMeta = NULL;
550 MapPrpList = NULL;
551 PrpListHost = NULL;
552 PrpListNo = 0;
553 Prp = NULL;
554 TimerEvent = NULL;
555 Status = EFI_SUCCESS;
556 QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;
557
558 if (Packet->QueueType == NVME_ADMIN_QUEUE) {
559 QueueId = 0;
560 } else {
561 if (Event == NULL) {
562 QueueId = 1;
563 } else {
564 QueueId = 2;
565
566 //
567 // Submission queue full check.
568 //
569 if ((Private->SqTdbl[QueueId].Sqt + 1) % QueueSize ==
570 Private->AsyncSqHead)
571 {
572 return EFI_NOT_READY;
573 }
574 }
575 }
576
577 Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;
578 Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
579
580 if (Packet->NvmeCmd->Nsid != NamespaceId) {
581 return EFI_INVALID_PARAMETER;
582 }
583
584 ZeroMem (Sq, sizeof (NVME_SQ));
585 Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
586 Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
587 Sq->Cid = Private->Cid[QueueId]++;
588 Sq->Nsid = Packet->NvmeCmd->Nsid;
589
590 //
591 // Currently we only support PRP for data transfer, SGL is NOT supported.
592 //
593 ASSERT (Sq->Psdt == 0);
594 if (Sq->Psdt != 0) {
595 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));
596 return EFI_UNSUPPORTED;
597 }
598
599 Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;
600 if ((Packet->QueueType == NVME_ADMIN_QUEUE) &&
601 ((Sq->Opc == NVME_ADMIN_CRIOCQ_CMD) || (Sq->Opc == NVME_ADMIN_CRIOSQ_CMD)))
602 {
603 //
604 // Currently, we only use the IO Completion/Submission queues created internally
605 // by this driver during controller initialization. Any other IO queues created
606 // will not be consumed here. The value is little to accept external IO queue
607 // creation requests, so here we will return EFI_UNSUPPORTED for external IO
608 // queue creation request.
609 //
610 if (!Private->CreateIoQueue) {
611 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Does not support external IO queues creation request.\n"));
612 return EFI_UNSUPPORTED;
613 }
614 } else if ((Sq->Opc & (BIT0 | BIT1)) != 0) {
615 //
616 // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.
617 //
618 if (((Packet->TransferLength != 0) && (Packet->TransferBuffer == NULL)) ||
619 ((Packet->TransferLength == 0) && (Packet->TransferBuffer != NULL)))
620 {
621 return EFI_INVALID_PARAMETER;
622 }
623
624 if ((Sq->Opc & BIT0) != 0) {
626 } else {
628 }
629
630 if ((Packet->TransferLength != 0) && (Packet->TransferBuffer != NULL)) {
631 MapLength = Packet->TransferLength;
632 Status = PciIo->Map (
633 PciIo,
634 Flag,
635 Packet->TransferBuffer,
636 &MapLength,
637 &PhyAddr,
638 &MapData
639 );
640 if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {
641 return EFI_OUT_OF_RESOURCES;
642 }
643
644 Sq->Prp[0] = PhyAddr;
645 Sq->Prp[1] = 0;
646 }
647
648 if ((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {
649 MapLength = Packet->MetadataLength;
650 Status = PciIo->Map (
651 PciIo,
652 Flag,
653 Packet->MetadataBuffer,
654 &MapLength,
655 &PhyAddr,
656 &MapMeta
657 );
658 if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) {
659 PciIo->Unmap (
660 PciIo,
661 MapData
662 );
663
664 return EFI_OUT_OF_RESOURCES;
665 }
666
667 Sq->Mptr = PhyAddr;
668 }
669 }
670
671 //
672 // If the buffer size spans more than two memory pages (page size as defined in CC.Mps),
673 // then build a PRP list in the second PRP submission queue entry.
674 //
675 Offset = ((UINT16)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
676 Bytes = Packet->TransferLength;
677
678 if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
679 //
680 // Create PrpList for remaining data buffer.
681 //
682 PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
683 Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES (Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);
684 if (Prp == NULL) {
685 Status = EFI_OUT_OF_RESOURCES;
686 goto EXIT;
687 }
688
689 Sq->Prp[1] = (UINT64)(UINTN)Prp;
690 } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
691 Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
692 }
693
694 if (Packet->NvmeCmd->Flags & CDW2_VALID) {
695 Sq->Rsvd2 = (UINT64)Packet->NvmeCmd->Cdw2;
696 }
697
698 if (Packet->NvmeCmd->Flags & CDW3_VALID) {
699 Sq->Rsvd2 |= LShiftU64 ((UINT64)Packet->NvmeCmd->Cdw3, 32);
700 }
701
702 if (Packet->NvmeCmd->Flags & CDW10_VALID) {
703 Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
704 }
705
706 if (Packet->NvmeCmd->Flags & CDW11_VALID) {
707 Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
708 }
709
710 if (Packet->NvmeCmd->Flags & CDW12_VALID) {
711 Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
712 }
713
714 if (Packet->NvmeCmd->Flags & CDW13_VALID) {
715 Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
716 }
717
718 if (Packet->NvmeCmd->Flags & CDW14_VALID) {
719 Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
720 }
721
722 if (Packet->NvmeCmd->Flags & CDW15_VALID) {
723 Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
724 }
725
726 //
727 // Ring the submission queue doorbell.
728 //
729 if ((Event != NULL) && (QueueId != 0)) {
730 Private->SqTdbl[QueueId].Sqt =
731 (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;
732 } else {
733 Private->SqTdbl[QueueId].Sqt ^= 1;
734 }
735
736 Data = ReadUnaligned32 ((UINT32 *)&Private->SqTdbl[QueueId]);
737 Status = PciIo->Mem.Write (
738 PciIo,
739 EfiPciIoWidthUint32,
740 NVME_BAR,
741 NVME_SQTDBL_OFFSET (QueueId, Private->Cap.Dstrd),
742 1,
743 &Data
744 );
745
746 if (EFI_ERROR (Status)) {
747 goto EXIT;
748 }
749
750 //
751 // For non-blocking requests, return directly if the command is placed
752 // in the submission queue.
753 //
754 if ((Event != NULL) && (QueueId != 0)) {
755 AsyncRequest = AllocateZeroPool (sizeof (NVME_PASS_THRU_ASYNC_REQ));
756 if (AsyncRequest == NULL) {
757 Status = EFI_DEVICE_ERROR;
758 goto EXIT;
759 }
760
761 AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;
762 AsyncRequest->Packet = Packet;
763 AsyncRequest->CommandId = Sq->Cid;
764 AsyncRequest->CallerEvent = Event;
765 AsyncRequest->MapData = MapData;
766 AsyncRequest->MapMeta = MapMeta;
767 AsyncRequest->MapPrpList = MapPrpList;
768 AsyncRequest->PrpListNo = PrpListNo;
769 AsyncRequest->PrpListHost = PrpListHost;
770
771 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
772 InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link);
773 gBS->RestoreTPL (OldTpl);
774
775 return EFI_SUCCESS;
776 }
777
778 Status = gBS->CreateEvent (
779 EVT_TIMER,
780 TPL_CALLBACK,
781 NULL,
782 NULL,
783 &TimerEvent
784 );
785 if (EFI_ERROR (Status)) {
786 goto EXIT;
787 }
788
789 Status = gBS->SetTimer (TimerEvent, TimerRelative, Packet->CommandTimeout);
790
791 if (EFI_ERROR (Status)) {
792 goto EXIT;
793 }
794
795 //
796 // Wait for completion queue to get filled in.
797 //
798 Status = EFI_TIMEOUT;
799 while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {
800 if (Cq->Pt != Private->Pt[QueueId]) {
801 Status = EFI_SUCCESS;
802 break;
803 }
804 }
805
806 //
807 // Check the NVMe cmd execution result
808 //
809 if (Status != EFI_TIMEOUT) {
810 if ((Cq->Sct == 0) && (Cq->Sc == 0)) {
811 Status = EFI_SUCCESS;
812 } else {
813 Status = EFI_DEVICE_ERROR;
814 //
815 // Dump every completion entry status for debugging.
816 //
818 NvmeDumpStatus ((NVME_CQ *)Cq);
820 }
821
822 //
823 // Copy the Respose Queue entry for this command to the callers response buffer
824 //
825 CopyMem (Packet->NvmeCompletion, (VOID *)Cq, sizeof (EFI_NVM_EXPRESS_COMPLETION));
826 } else {
827 ReportStatusCode ((EFI_ERROR_MAJOR | EFI_ERROR_CODE), (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR));
828
829 //
830 // Timeout occurs for an NVMe command. Reset the controller to abort the
831 // outstanding commands.
832 //
833 DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe command.\n"));
834
835 //
836 // Disable the timer to trigger the process of async transfers temporarily.
837 //
838 Status = gBS->SetTimer (Private->TimerEvent, TimerCancel, 0);
839 if (EFI_ERROR (Status)) {
840 goto EXIT;
841 }
842
843 //
844 // Reset the NVMe controller.
845 //
846 Status = NvmeControllerInit (Private);
847 if (!EFI_ERROR (Status)) {
848 Status = AbortAsyncPassThruTasks (Private);
849 if (!EFI_ERROR (Status)) {
850 //
851 // Re-enable the timer to trigger the process of async transfers.
852 //
853 Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME_HC_ASYNC_TIMER);
854 if (!EFI_ERROR (Status)) {
855 //
856 // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe PassThru command.
857 //
858 Status = EFI_TIMEOUT;
859 }
860 }
861 } else {
862 Status = EFI_DEVICE_ERROR;
863 }
864
865 goto EXIT;
866 }
867
868 if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {
869 Private->Pt[QueueId] ^= 1;
870 }
871
872 Data = ReadUnaligned32 ((UINT32 *)&Private->CqHdbl[QueueId]);
873 PreviousStatus = Status;
874 Status = PciIo->Mem.Write (
875 PciIo,
876 EfiPciIoWidthUint32,
877 NVME_BAR,
878 NVME_CQHDBL_OFFSET (QueueId, Private->Cap.Dstrd),
879 1,
880 &Data
881 );
882 // The return status of PciIo->Mem.Write should not override
883 // previous status if previous status contains error.
884 Status = EFI_ERROR (PreviousStatus) ? PreviousStatus : Status;
885
886 //
887 // For now, the code does not support the non-blocking feature for admin queue.
888 // If Event is not NULL for admin queue, signal the caller's event here.
889 //
890 if (Event != NULL) {
891 ASSERT (QueueId == 0);
892 gBS->SignalEvent (Event);
893 }
894
895EXIT:
896 if (MapData != NULL) {
897 PciIo->Unmap (
898 PciIo,
899 MapData
900 );
901 }
902
903 if (MapMeta != NULL) {
904 PciIo->Unmap (
905 PciIo,
906 MapMeta
907 );
908 }
909
910 if (MapPrpList != NULL) {
911 PciIo->Unmap (
912 PciIo,
913 MapPrpList
914 );
915 }
916
917 if (Prp != NULL) {
918 PciIo->FreeBuffer (PciIo, PrpListNo, PrpListHost);
919 }
920
921 if (TimerEvent != NULL) {
922 gBS->CloseEvent (TimerEvent);
923 }
924
925 return Status;
926}
927
962EFIAPI
965 IN OUT UINT32 *NamespaceId
966 )
967{
969 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
970 UINT32 NextNamespaceId;
971 EFI_STATUS Status;
972
973 if ((This == NULL) || (NamespaceId == NULL)) {
974 return EFI_INVALID_PARAMETER;
975 }
976
977 NamespaceData = NULL;
978 Status = EFI_NOT_FOUND;
979
980 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
981 //
982 // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID
983 //
984 if (*NamespaceId == 0xFFFFFFFF) {
985 //
986 // Start with the first namespace ID
987 //
988 NextNamespaceId = 1;
989 //
990 // Allocate buffer for Identify Namespace data.
991 //
993
994 if (NamespaceData == NULL) {
995 return EFI_NOT_FOUND;
996 }
997
998 Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);
999 if (EFI_ERROR (Status)) {
1000 goto Done;
1001 }
1002
1003 *NamespaceId = NextNamespaceId;
1004 } else {
1005 if (*NamespaceId > Private->ControllerData->Nn) {
1006 return EFI_INVALID_PARAMETER;
1007 }
1008
1009 NextNamespaceId = *NamespaceId + 1;
1010 if (NextNamespaceId > Private->ControllerData->Nn) {
1011 return EFI_NOT_FOUND;
1012 }
1013
1014 //
1015 // Allocate buffer for Identify Namespace data.
1016 //
1018 if (NamespaceData == NULL) {
1019 return EFI_NOT_FOUND;
1020 }
1021
1022 Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);
1023 if (EFI_ERROR (Status)) {
1024 goto Done;
1025 }
1026
1027 *NamespaceId = NextNamespaceId;
1028 }
1029
1030Done:
1031 if (NamespaceData != NULL) {
1032 FreePool (NamespaceData);
1033 }
1034
1035 return Status;
1036}
1037
1063EFIAPI
1066 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1067 OUT UINT32 *NamespaceId
1068 )
1069{
1072
1073 if ((This == NULL) || (DevicePath == NULL) || (NamespaceId == NULL)) {
1074 return EFI_INVALID_PARAMETER;
1075 }
1076
1077 if (DevicePath->Type != MESSAGING_DEVICE_PATH) {
1078 return EFI_UNSUPPORTED;
1079 }
1080
1081 Node = (NVME_NAMESPACE_DEVICE_PATH *)DevicePath;
1082 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
1083
1084 if (DevicePath->SubType == MSG_NVME_NAMESPACE_DP) {
1085 if (DevicePathNodeLength (DevicePath) != sizeof (NVME_NAMESPACE_DEVICE_PATH)) {
1086 return EFI_NOT_FOUND;
1087 }
1088
1089 //
1090 // Check NamespaceId in the device path node is valid or not.
1091 //
1092 if ((Node->NamespaceId == 0) ||
1093 (Node->NamespaceId > Private->ControllerData->Nn))
1094 {
1095 return EFI_NOT_FOUND;
1096 }
1097
1098 *NamespaceId = Node->NamespaceId;
1099
1100 return EFI_SUCCESS;
1101 } else {
1102 return EFI_UNSUPPORTED;
1103 }
1104}
1105
1138EFIAPI
1141 IN UINT32 NamespaceId,
1142 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
1143 )
1144{
1147 EFI_STATUS Status;
1148 NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
1149
1150 //
1151 // Validate parameters
1152 //
1153 if ((This == NULL) || (DevicePath == NULL)) {
1154 return EFI_INVALID_PARAMETER;
1155 }
1156
1157 Status = EFI_SUCCESS;
1158 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);
1159
1160 //
1161 // Check NamespaceId is valid or not.
1162 //
1163 if ((NamespaceId == 0) ||
1164 (NamespaceId > Private->ControllerData->Nn))
1165 {
1166 return EFI_NOT_FOUND;
1167 }
1168
1170 if (Node == NULL) {
1171 return EFI_OUT_OF_RESOURCES;
1172 }
1173
1174 Node->Header.Type = MESSAGING_DEVICE_PATH;
1175 Node->Header.SubType = MSG_NVME_NAMESPACE_DP;
1176 SetDevicePathNodeLength (&Node->Header, sizeof (NVME_NAMESPACE_DEVICE_PATH));
1177 Node->NamespaceId = NamespaceId;
1178
1179 //
1180 // Allocate a buffer for Identify Namespace data.
1181 //
1182 NamespaceData = NULL;
1183 NamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));
1184 if (NamespaceData == NULL) {
1185 Status = EFI_OUT_OF_RESOURCES;
1186 goto Exit;
1187 }
1188
1189 //
1190 // Get UUID from specified Identify Namespace data.
1191 //
1192 Status = NvmeIdentifyNamespace (
1193 Private,
1194 NamespaceId,
1195 (VOID *)NamespaceData
1196 );
1197
1198 if (EFI_ERROR (Status)) {
1199 goto Exit;
1200 }
1201
1202 Node->NamespaceUuid = NamespaceData->Eui64;
1203
1204 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;
1205
1206Exit:
1207 if (NamespaceData != NULL) {
1208 FreePool (NamespaceData);
1209 }
1210
1211 if (EFI_ERROR (Status)) {
1212 FreePool (Node);
1213 }
1214
1215 return Status;
1216}
UINT64 UINTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI DivU64x64Remainder(IN UINT64 Dividend, IN UINT64 Divisor, OUT UINT64 *Remainder OPTIONAL)
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
UINT32 EFIAPI ReadUnaligned32(IN CONST UINT32 *Buffer)
Definition: Unaligned.c:145
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define MSG_NVME_NAMESPACE_DP
Definition: DevicePath.h:833
#define MESSAGING_DEVICE_PATH
Definition: DevicePath.h:321
UINT16 EFIAPI SetDevicePathNodeLength(IN OUT VOID *Node, IN UINTN Length)
UINTN EFIAPI DevicePathNodeLength(IN CONST VOID *Node)
EFI_STATUS EFIAPI ReportStatusCode(IN EFI_STATUS_CODE_TYPE Type, IN EFI_STATUS_CODE_VALUE Value)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG_CODE_BEGIN()
Definition: DebugLib.h:564
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE_END()
Definition: DebugLib.h:578
EFI_PCI_IO_PROTOCOL_OPERATION
Definition: PciIo.h:77
@ EfiPciIoOperationBusMasterWrite
Definition: PciIo.h:85
@ EfiPciIoOperationBusMasterRead
Definition: PciIo.h:81
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
EFI_STATUS NvmeIdentifyNamespace(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN UINT32 NamespaceId, IN VOID *Buffer)
EFI_STATUS NvmeControllerInit(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
EFI_STATUS EFIAPI NvmExpressPassThru(IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, IN UINT32 NamespaceId, IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet, IN EFI_EVENT Event OPTIONAL)
EFI_STATUS EFIAPI NvmExpressGetNamespace(IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT UINT32 *NamespaceId)
EFI_STATUS EFIAPI NvmExpressBuildDevicePath(IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, IN UINT32 NamespaceId, IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath)
VOID NvmeDumpStatus(IN NVME_CQ *Cq)
VOID * NvmeCreatePrpList(IN EFI_PCI_IO_PROTOCOL *PciIo, IN EFI_PHYSICAL_ADDRESS PhysicalAddr, IN UINTN Pages, OUT VOID **PrpListHost, IN OUT UINTN *PrpListNo, OUT VOID **Mapping)
EFI_STATUS EFIAPI NvmExpressGetNextNamespace(IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This, IN OUT UINT32 *NamespaceId)
EFI_STATUS AbortAsyncPassThruTasks(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
VOID EFIAPI Exit(IN EFI_STATUS Status)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
UINTN EFI_TPL
Definition: UefiBaseType.h:41
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EfiBootServicesData
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerRelative
Definition: UefiSpec.h:539
@ TimerPeriodic
Definition: UefiSpec.h:535
@ AllocateAnyPages
Definition: UefiSpec.h:33
EFI_STATUS TransactionStatus
Definition: BlockIo2.h:39
EFI_PCI_IO_PROTOCOL_IO_MEM Write
Definition: PciIo.h:197
Definition: Nvme.h:901
Definition: Nvme.h:865