2 Provide functions to initialize NVME controller and perform NVME commands
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "OpalPasswordPei.h"
18 #define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) + 1)
21 /// NVME Host controller registers operation
23 #define NVME_GET_CAP(Nvme, Cap) NvmeMmioRead (Cap, Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP))
24 #define NVME_GET_CC(Nvme, Cc) NvmeMmioRead (Cc, Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC))
25 #define NVME_SET_CC(Nvme, Cc) NvmeMmioWrite (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))
26 #define NVME_GET_CSTS(Nvme, Csts) NvmeMmioRead (Csts, Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))
27 #define NVME_GET_AQA(Nvme, Aqa) NvmeMmioRead (Aqa, Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA))
28 #define NVME_SET_AQA(Nvme, Aqa) NvmeMmioWrite (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))
29 #define NVME_GET_ASQ(Nvme, Asq) NvmeMmioRead (Asq, Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))
30 #define NVME_SET_ASQ(Nvme, Asq) NvmeMmioWrite (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))
31 #define NVME_GET_ACQ(Nvme, Acq) NvmeMmioRead (Acq, Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))
32 #define NVME_SET_ACQ(Nvme, Acq) NvmeMmioWrite (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))
33 #define NVME_GET_VER(Nvme, Ver) NvmeMmioRead (Ver, Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER))
34 #define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl) NvmeMmioWrite (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL))
35 #define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl) NvmeMmioWrite (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL))
38 /// Base memory address
41 BASEMEM_CONTROLLER_DATA
,
42 BASEMEM_IDENTIFY_DATA
,
53 /// All of base memories are 4K(0x1000) alignment
55 #define NVME_MEM_BASE(Nvme) ((UINTN)(Nvme->BaseMem))
56 #define NVME_CONTROL_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CONTROLLER_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
57 #define NVME_NAMESPACE_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_IDENTIFY_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
58 #define NVME_ASQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
59 #define NVME_ACQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
60 #define NVME_SQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
61 #define NVME_CQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
62 #define NVME_PRP_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) + ((index)*NVME_PRP_SIZE)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
63 #define NVME_SEC_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
66 Transfer MMIO Data to memory.
68 @param[in,out] MemBuffer - Destination: Memory address
69 @param[in] MmioAddr - Source: MMIO address
70 @param[in] Size - Size for read
72 @retval EFI_SUCCESS - MMIO read sucessfully
76 IN OUT VOID
*MemBuffer
,
85 // priority has adjusted
88 *((UINT32
*)MemBuffer
) = MmioRead32 (MmioAddr
);
92 *((UINT64
*)MemBuffer
) = MmioRead64 (MmioAddr
);
96 *((UINT16
*)MemBuffer
) = MmioRead16 (MmioAddr
);
100 *((UINT8
*)MemBuffer
) = MmioRead8 (MmioAddr
);
104 Ptr
= (UINT8
*)MemBuffer
;
105 for (Offset
= 0; Offset
< Size
; Offset
+= 1) {
106 Data
= MmioRead8 (MmioAddr
+ Offset
);
116 Transfer memory data to MMIO.
118 @param[in,out] MmioAddr - Destination: MMIO address
119 @param[in] MemBuffer - Source: Memory address
120 @param[in] Size - Size for write
122 @retval EFI_SUCCESS - MMIO write sucessfully
126 IN OUT UINTN MmioAddr
,
135 // priority has adjusted
138 MmioWrite32 (MmioAddr
, *((UINT32
*)MemBuffer
));
142 MmioWrite64 (MmioAddr
, *((UINT64
*)MemBuffer
));
146 MmioWrite16 (MmioAddr
, *((UINT16
*)MemBuffer
));
150 MmioWrite8 (MmioAddr
, *((UINT8
*)MemBuffer
));
154 Ptr
= (UINT8
*)MemBuffer
;
155 for (Offset
= 0; Offset
< Size
; Offset
+= 1) {
157 MmioWrite8 (MmioAddr
+ Offset
, Data
);
166 Transfer MMIO data to memory.
168 @param[in,out] MemBuffer - Destination: Memory address
169 @param[in] MmioAddr - Source: MMIO address
170 @param[in] Size - Size for read
172 @retval EFI_SUCCESS - MMIO read sucessfully
176 IN OUT VOID
*MemBuffer
,
185 // priority has adjusted
188 *((UINT32
*)MemBuffer
) = PciRead32 (MmioAddr
);
192 *((UINT16
*)MemBuffer
) = PciRead16 (MmioAddr
);
196 *((UINT8
*)MemBuffer
) = PciRead8 (MmioAddr
);
200 Ptr
= (UINT8
*)MemBuffer
;
201 for (Offset
= 0; Offset
< Size
; Offset
+= 1) {
202 Data
= PciRead8 (MmioAddr
+ Offset
);
212 Transfer memory data to MMIO.
214 @param[in,out] MmioAddr - Destination: MMIO address
215 @param[in] MemBuffer - Source: Memory address
216 @param[in] Size - Size for write
218 @retval EFI_SUCCESS - MMIO write sucessfully
222 IN OUT UINTN MmioAddr
,
231 // priority has adjusted
234 PciWrite32 (MmioAddr
, *((UINT32
*)MemBuffer
));
238 PciWrite16 (MmioAddr
, *((UINT16
*)MemBuffer
));
242 PciWrite8 (MmioAddr
, *((UINT8
*)MemBuffer
));
246 Ptr
= (UINT8
*)MemBuffer
;
247 for (Offset
= 0; Offset
< Size
; Offset
+= 1) {
249 PciWrite8 (MmioAddr
+ Offset
, Data
);
258 Get total pages for specific NVME based memory.
260 @param[in] BaseMemIndex - The Index of BaseMem (0-based).
262 @retval - The page count for specific BaseMem Index
266 NvmeGetBaseMemPages (
267 IN UINTN BaseMemIndex
272 UINT32 PageSizeList
[8];
274 PageSizeList
[0] = 1; /* Controller Data */
275 PageSizeList
[1] = 1; /* Identify Data */
276 PageSizeList
[2] = 1; /* ASQ */
277 PageSizeList
[3] = 1; /* ACQ */
278 PageSizeList
[4] = 1; /* SQs */
279 PageSizeList
[5] = 1; /* CQs */
280 PageSizeList
[6] = NVME_PRP_SIZE
* NVME_CSQ_DEPTH
; /* PRPs */
281 PageSizeList
[7] = 1; /* Security Commands */
283 if (BaseMemIndex
> MAX_BASEMEM_COUNT
) {
289 for (Index
= 0; Index
< BaseMemIndex
; Index
++) {
290 Pages
+= PageSizeList
[Index
];
297 Wait for NVME controller status to be ready or not.
299 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
300 @param[in] WaitReady - Flag for waitting status ready or not
302 @return EFI_SUCCESS - Successfully to wait specific status.
303 @return others - Fail to wait for specific controller status.
309 IN NVME_CONTEXT
*Nvme
,
319 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
320 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
322 if (Nvme
->Cap
.To
== 0) {
325 Timeout
= Nvme
->Cap
.To
;
328 Status
= EFI_SUCCESS
;
329 for(Index
= (Timeout
* 500); Index
!= 0; --Index
) {
330 MicroSecondDelay (1000);
333 // Check if the controller is initialized
335 Status
= NVME_GET_CSTS (Nvme
, &Csts
);
336 if (EFI_ERROR(Status
)) {
337 DEBUG ((DEBUG_ERROR
, "NVME_GET_CSTS fail, Status = %r\n", Status
));
341 if ((BOOLEAN
) Csts
.Rdy
== WaitReady
) {
347 Status
= EFI_TIMEOUT
;
354 Disable the Nvm Express controller.
356 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
358 @return EFI_SUCCESS - Successfully disable the controller.
359 @return others - Fail to disable the controller.
364 NvmeDisableController (
365 IN NVME_CONTEXT
*Nvme
372 Status
= NVME_GET_CSTS (Nvme
, &Csts
);
375 /// Read Controller Configuration Register.
377 Status
= NVME_GET_CC (Nvme
, &Cc
);
378 if (EFI_ERROR(Status
)) {
379 DEBUG ((DEBUG_ERROR
, "NVME_GET_CC fail, Status = %r\n", Status
));
386 /// Disable the controller.
388 Status
= NVME_SET_CC (Nvme
, &Cc
);
389 if (EFI_ERROR(Status
)) {
390 DEBUG ((DEBUG_ERROR
, "NVME_SET_CC fail, Status = %r\n", Status
));
395 Status
= NvmeWaitController (Nvme
, FALSE
);
396 if (EFI_ERROR(Status
)) {
397 DEBUG ((DEBUG_ERROR
, "NvmeWaitController fail, Status = %r\n", Status
));
404 DEBUG ((DEBUG_INFO
, "NvmeDisableController fail, Status: %r\n", Status
));
409 Enable the Nvm Express controller.
411 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
413 @return EFI_SUCCESS - Successfully enable the controller.
414 @return EFI_DEVICE_ERROR - Fail to enable the controller.
415 @return EFI_TIMEOUT - Fail to enable the controller in given time slot.
420 NvmeEnableController (
421 IN NVME_CONTEXT
*Nvme
428 // Enable the controller
430 ZeroMem (&Cc
, sizeof (NVME_CC
));
434 Status
= NVME_SET_CC (Nvme
, &Cc
);
435 if (EFI_ERROR(Status
)) {
436 DEBUG ((DEBUG_ERROR
, "NVME_SET_CC fail, Status = %r\n", Status
));
440 Status
= NvmeWaitController (Nvme
, TRUE
);
441 if (EFI_ERROR(Status
)) {
442 DEBUG ((DEBUG_ERROR
, "NvmeWaitController fail, Status = %r\n", Status
));
449 DEBUG ((DEBUG_INFO
, "NvmeEnableController fail, Status: %r\n", Status
));
454 Shutdown the Nvm Express controller.
456 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
458 @return EFI_SUCCESS - Successfully shutdown the controller.
459 @return EFI_DEVICE_ERROR - Fail to shutdown the controller.
460 @return EFI_TIMEOUT - Fail to shutdown the controller in given time slot.
465 NvmeShutdownController (
466 IN NVME_CONTEXT
*Nvme
475 Status
= NVME_GET_CC (Nvme
, &Cc
);
476 if (EFI_ERROR(Status
)) {
477 DEBUG ((DEBUG_ERROR
, "NVME_GET_CC fail, Status = %r\n", Status
));
481 Cc
.Shn
= 1; // Normal shutdown
483 Status
= NVME_SET_CC (Nvme
, &Cc
);
484 if (EFI_ERROR(Status
)) {
485 DEBUG ((DEBUG_ERROR
, "NVME_SET_CC fail, Status = %r\n", Status
));
489 Timeout
= NVME_GENERIC_TIMEOUT
/1000; // ms
490 for(Index
= (UINT32
)(Timeout
); Index
!= 0; --Index
) {
491 MicroSecondDelay (1000);
493 Status
= NVME_GET_CSTS (Nvme
, &Csts
);
494 if (EFI_ERROR(Status
)) {
495 DEBUG ((DEBUG_ERROR
, "NVME_GET_CSTS fail, Status = %r\n", Status
));
499 if (Csts
.Shst
== 2) { // Shutdown processing complete
505 Status
= EFI_TIMEOUT
;
512 Check the execution status from a given completion queue entry.
514 @param[in] Cq - A pointer to the NVME_CQ item.
522 if (Cq
->Sct
== 0x0 && Cq
->Sc
== 0x0) {
526 DEBUG ((DEBUG_INFO
, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN
)Cq
));
527 DEBUG ((DEBUG_INFO
, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq
->Sqid
, Cq
->Pt
, Cq
->Cid
));
528 DEBUG ((DEBUG_INFO
, " NVMe Cmd Execution Result - "));
534 DEBUG ((DEBUG_INFO
, "Successful Completion\n"));
537 DEBUG ((DEBUG_INFO
, "Invalid Command Opcode\n"));
540 DEBUG ((DEBUG_INFO
, "Invalid Field in Command\n"));
543 DEBUG ((DEBUG_INFO
, "Command ID Conflict\n"));
546 DEBUG ((DEBUG_INFO
, "Data Transfer Error\n"));
549 DEBUG ((DEBUG_INFO
, "Commands Aborted due to Power Loss Notification\n"));
552 DEBUG ((DEBUG_INFO
, "Internal Device Error\n"));
555 DEBUG ((DEBUG_INFO
, "Command Abort Requested\n"));
558 DEBUG ((DEBUG_INFO
, "Command Aborted due to SQ Deletion\n"));
561 DEBUG ((DEBUG_INFO
, "Command Aborted due to Failed Fused Command\n"));
564 DEBUG ((DEBUG_INFO
, "Command Aborted due to Missing Fused Command\n"));
567 DEBUG ((DEBUG_INFO
, "Invalid Namespace or Format\n"));
570 DEBUG ((DEBUG_INFO
, "Command Sequence Error\n"));
573 DEBUG ((DEBUG_INFO
, "Invalid SGL Last Segment Descriptor\n"));
576 DEBUG ((DEBUG_INFO
, "Invalid Number of SGL Descriptors\n"));
579 DEBUG ((DEBUG_INFO
, "Data SGL Length Invalid\n"));
582 DEBUG ((DEBUG_INFO
, "Metadata SGL Length Invalid\n"));
585 DEBUG ((DEBUG_INFO
, "SGL Descriptor Type Invalid\n"));
588 DEBUG ((DEBUG_INFO
, "LBA Out of Range\n"));
591 DEBUG ((DEBUG_INFO
, "Capacity Exceeded\n"));
594 DEBUG ((DEBUG_INFO
, "Namespace Not Ready\n"));
597 DEBUG ((DEBUG_INFO
, "Reservation Conflict\n"));
605 DEBUG ((DEBUG_INFO
, "Completion Queue Invalid\n"));
608 DEBUG ((DEBUG_INFO
, "Invalid Queue Identifier\n"));
611 DEBUG ((DEBUG_INFO
, "Maximum Queue Size Exceeded\n"));
614 DEBUG ((DEBUG_INFO
, "Abort Command Limit Exceeded\n"));
617 DEBUG ((DEBUG_INFO
, "Asynchronous Event Request Limit Exceeded\n"));
620 DEBUG ((DEBUG_INFO
, "Invalid Firmware Slot\n"));
623 DEBUG ((DEBUG_INFO
, "Invalid Firmware Image\n"));
626 DEBUG ((DEBUG_INFO
, "Invalid Interrupt Vector\n"));
629 DEBUG ((DEBUG_INFO
, "Invalid Log Page\n"));
632 DEBUG ((DEBUG_INFO
, "Invalid Format\n"));
635 DEBUG ((DEBUG_INFO
, "Firmware Application Requires Conventional Reset\n"));
638 DEBUG ((DEBUG_INFO
, "Invalid Queue Deletion\n"));
641 DEBUG ((DEBUG_INFO
, "Feature Identifier Not Saveable\n"));
644 DEBUG ((DEBUG_INFO
, "Feature Not Changeable\n"));
647 DEBUG ((DEBUG_INFO
, "Feature Not Namespace Specific\n"));
650 DEBUG ((DEBUG_INFO
, "Firmware Application Requires NVM Subsystem Reset\n"));
653 DEBUG ((DEBUG_INFO
, "Conflicting Attributes\n"));
656 DEBUG ((DEBUG_INFO
, "Invalid Protection Information\n"));
659 DEBUG ((DEBUG_INFO
, "Attempted Write to Read Only Range\n"));
667 DEBUG ((DEBUG_INFO
, "Write Fault\n"));
670 DEBUG ((DEBUG_INFO
, "Unrecovered Read Error\n"));
673 DEBUG ((DEBUG_INFO
, "End-to-end Guard Check Error\n"));
676 DEBUG ((DEBUG_INFO
, "End-to-end Application Tag Check Error\n"));
679 DEBUG ((DEBUG_INFO
, "End-to-end Reference Tag Check Error\n"));
682 DEBUG ((DEBUG_INFO
, "Compare Failure\n"));
685 DEBUG ((DEBUG_INFO
, "Access Denied\n"));
691 DEBUG ((DEBUG_INFO
, "Unknown error\n"));
695 return EFI_DEVICE_ERROR
;
699 Create PRP lists for Data transfer which is larger than 2 memory pages.
700 Note here we calcuate the number of required PRP lists and allocate them at one time.
702 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
703 @param[in] SqId - The SQ index for this PRP
704 @param[in] PhysicalAddr - The physical base address of Data Buffer.
705 @param[in] Pages - The number of pages to be transfered.
706 @param[out] PrpListHost - The host base address of PRP lists.
707 @param[in,out] PrpListNo - The number of PRP List.
709 @retval The pointer Value to the first PRP List of the PRP lists.
715 IN NVME_CONTEXT
*Nvme
,
717 IN EFI_PHYSICAL_ADDRESS PhysicalAddr
,
719 OUT VOID
**PrpListHost
,
720 IN OUT UINTN
*PrpListNo
728 EFI_PHYSICAL_ADDRESS PrpListPhyAddr
;
731 EFI_PHYSICAL_ADDRESS NewPhyAddr
;
734 /// The number of Prp Entry in a memory page.
736 PrpEntryNo
= EFI_PAGE_SIZE
/ sizeof (UINT64
);
739 /// Calculate total PrpList number.
741 *PrpListNo
= (UINTN
) DivU64x64Remainder ((UINT64
)Pages
, (UINT64
)PrpEntryNo
, &Remainder
);
742 if (Remainder
!= 0) {
746 if (*PrpListNo
> NVME_PRP_SIZE
) {
747 DEBUG ((DEBUG_INFO
, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x) PrpEntryNo: %x\n",
748 PhysicalAddr
, Pages
, PrpEntryNo
));
749 DEBUG ((DEBUG_INFO
, "*PrpListNo: %x, Remainder: %lx", *PrpListNo
, Remainder
));
752 *PrpListHost
= (VOID
*)(UINTN
) NVME_PRP_BASE (Nvme
, SqId
);
754 Bytes
= EFI_PAGES_TO_SIZE (*PrpListNo
);
755 PrpListPhyAddr
= (UINT64
)(UINTN
)(*PrpListHost
);
758 /// Fill all PRP lists except of last one.
760 ZeroMem (*PrpListHost
, Bytes
);
761 for (PrpListIndex
= 0; PrpListIndex
< *PrpListNo
- 1; ++PrpListIndex
) {
762 PrpListBase
= *(UINT64
*)PrpListHost
+ PrpListIndex
* EFI_PAGE_SIZE
;
764 for (PrpEntryIndex
= 0; PrpEntryIndex
< PrpEntryNo
; ++PrpEntryIndex
) {
765 PrpEntry
= (UINT8
*)(UINTN
) (PrpListBase
+ PrpEntryIndex
* sizeof(UINT64
));
766 if (PrpEntryIndex
!= PrpEntryNo
- 1) {
768 /// Fill all PRP entries except of last one.
770 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&PhysicalAddr
), sizeof (UINT64
));
771 PhysicalAddr
+= EFI_PAGE_SIZE
;
774 /// Fill last PRP entries with next PRP List pointer.
776 NewPhyAddr
= (PrpListPhyAddr
+ (PrpListIndex
+ 1) * EFI_PAGE_SIZE
);
777 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&NewPhyAddr
), sizeof (UINT64
));
783 /// Fill last PRP list.
785 PrpListBase
= *(UINT64
*)PrpListHost
+ PrpListIndex
* EFI_PAGE_SIZE
;
786 for (PrpEntryIndex
= 0; PrpEntryIndex
< ((Remainder
!= 0) ? Remainder
: PrpEntryNo
); ++PrpEntryIndex
) {
787 PrpEntry
= (UINT8
*)(UINTN
) (PrpListBase
+ PrpEntryIndex
* sizeof(UINT64
));
788 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&PhysicalAddr
), sizeof (UINT64
));
790 PhysicalAddr
+= EFI_PAGE_SIZE
;
793 return PrpListPhyAddr
;
797 Waits until all NVME commands completed.
799 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
800 @param[in] Qid - Queue index
802 @retval EFI_SUCCESS - All NVME commands have completed
803 @retval EFI_TIMEOUT - Timeout occured
804 @retval EFI_NOT_READY - Not all NVME commands have completed
805 @retval others - Error occurred on device side.
808 NvmeWaitAllComplete (
809 IN NVME_CONTEXT
*Nvme
,
817 Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
818 both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
819 I/O functionality is optional.
821 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
822 @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
823 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
824 ID specifies that the command packet should be sent to all valid namespaces.
825 @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
826 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
827 UUID specifies that the command packet should be sent to all valid namespaces.
828 @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
831 @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
832 to, or from DataBuffer.
833 @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
834 may retry again later.
835 @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.
836 @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
837 Express Command Packet was not sent, so no additional status information is available.
838 @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.
839 The NVM Express Command Packet was not sent, so no additional status information is available.
840 @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.
845 IN NVME_CONTEXT
*Nvme
,
846 IN UINT32 NamespaceId
,
847 IN UINT64 NamespaceUuid
,
848 IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
*Packet
857 EFI_PHYSICAL_ADDRESS PhyAddr
;
865 /// check the Data fields in Packet parameter.
867 if ((Nvme
== NULL
) || (Packet
== NULL
)) {
868 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n",
869 (UINTN
)Nvme
, (UINTN
)Packet
));
870 return EFI_INVALID_PARAMETER
;
873 if ((Packet
->NvmeCmd
== NULL
) || (Packet
->NvmeResponse
== NULL
)) {
874 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n",
875 (UINTN
)Packet
->NvmeCmd
, (UINTN
)Packet
->NvmeResponse
));
876 return EFI_INVALID_PARAMETER
;
879 if (Packet
->QueueId
!= NVME_ADMIN_QUEUE
&& Packet
->QueueId
!= NVME_IO_QUEUE
) {
880 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: QueueId(%x)\n",
882 return EFI_INVALID_PARAMETER
;
887 Status
= EFI_SUCCESS
;
889 Qid
= Packet
->QueueId
;
890 Sq
= Nvme
->SqBuffer
[Qid
] + Nvme
->SqTdbl
[Qid
].Sqt
;
891 Cq
= Nvme
->CqBuffer
[Qid
] + Nvme
->CqHdbl
[Qid
].Cqh
;
892 if (Qid
== NVME_ADMIN_QUEUE
) {
893 SqSize
= NVME_ASQ_SIZE
+ 1;
894 CqSize
= NVME_ACQ_SIZE
+ 1;
896 SqSize
= NVME_CSQ_DEPTH
;
897 CqSize
= NVME_CCQ_DEPTH
;
900 if (Packet
->NvmeCmd
->Nsid
!= NamespaceId
) {
901 DEBUG ((DEBUG_ERROR
, "NvmePassThru: Nsid mismatch (%x, %x)\n",
902 Packet
->NvmeCmd
->Nsid
, NamespaceId
));
903 return EFI_INVALID_PARAMETER
;
906 ZeroMem (Sq
, sizeof (NVME_SQ
));
907 Sq
->Opc
= Packet
->NvmeCmd
->Cdw0
.Opcode
;
908 Sq
->Fuse
= Packet
->NvmeCmd
->Cdw0
.FusedOperation
;
909 Sq
->Cid
= Packet
->NvmeCmd
->Cdw0
.Cid
;
910 Sq
->Nsid
= Packet
->NvmeCmd
->Nsid
;
913 /// Currently we only support PRP for Data transfer, SGL is NOT supported.
915 ASSERT (Sq
->Psdt
== 0);
917 DEBUG ((DEBUG_ERROR
, "NvmePassThru: doesn't support SGL mechanism\n"));
918 return EFI_UNSUPPORTED
;
921 Sq
->Prp
[0] = Packet
->TransferBuffer
;
924 if(Packet
->MetadataBuffer
!= (UINT64
)(UINTN
)NULL
) {
925 Sq
->Mptr
= Packet
->MetadataBuffer
;
929 /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
930 /// then build a PRP list in the second PRP submission queue entry.
932 Offset
= ((UINT32
)Sq
->Prp
[0]) & (EFI_PAGE_SIZE
- 1);
933 Bytes
= Packet
->TransferLength
;
935 if ((Offset
+ Bytes
) > (EFI_PAGE_SIZE
* 2)) {
937 /// Create PrpList for remaining Data Buffer.
939 PhyAddr
= (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
940 Sq
->Prp
[1] = NvmeCreatePrpList (Nvme
, Nvme
->SqTdbl
[Qid
].Sqt
, PhyAddr
, EFI_SIZE_TO_PAGES(Offset
+ Bytes
) - 1, &PrpListHost
, &PrpListNo
);
941 if (Sq
->Prp
[1] == 0) {
942 Status
= EFI_OUT_OF_RESOURCES
;
943 DEBUG ((DEBUG_ERROR
, "NvmeCreatePrpList fail, Status: %r\n", Status
));
947 } else if ((Offset
+ Bytes
) > EFI_PAGE_SIZE
) {
948 Sq
->Prp
[1] = (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
951 if(Packet
->NvmeCmd
->Flags
& CDW10_VALID
) {
952 Sq
->Payload
.Raw
.Cdw10
= Packet
->NvmeCmd
->Cdw10
;
954 if(Packet
->NvmeCmd
->Flags
& CDW11_VALID
) {
955 Sq
->Payload
.Raw
.Cdw11
= Packet
->NvmeCmd
->Cdw11
;
957 if(Packet
->NvmeCmd
->Flags
& CDW12_VALID
) {
958 Sq
->Payload
.Raw
.Cdw12
= Packet
->NvmeCmd
->Cdw12
;
960 if(Packet
->NvmeCmd
->Flags
& CDW13_VALID
) {
961 Sq
->Payload
.Raw
.Cdw13
= Packet
->NvmeCmd
->Cdw13
;
963 if(Packet
->NvmeCmd
->Flags
& CDW14_VALID
) {
964 Sq
->Payload
.Raw
.Cdw14
= Packet
->NvmeCmd
->Cdw14
;
966 if(Packet
->NvmeCmd
->Flags
& CDW15_VALID
) {
967 Sq
->Payload
.Raw
.Cdw15
= Packet
->NvmeCmd
->Cdw15
;
971 /// Ring the submission queue doorbell.
973 Nvme
->SqTdbl
[Qid
].Sqt
++;
974 if(Nvme
->SqTdbl
[Qid
].Sqt
== SqSize
) {
975 Nvme
->SqTdbl
[Qid
].Sqt
= 0;
977 Status
= NVME_SET_SQTDBL (Nvme
, Qid
, &Nvme
->SqTdbl
[Qid
]);
978 if (EFI_ERROR(Status
)) {
979 DEBUG ((DEBUG_ERROR
, "NVME_SET_SQTDBL fail, Status: %r\n", Status
));
984 /// Wait for completion queue to get filled in.
986 Status
= EFI_TIMEOUT
;
988 while (Timer
< NVME_CMD_TIMEOUT
) {
989 //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));
990 //DumpMem (Cq, sizeof (NVME_CQ));
991 if (Cq
->Pt
!= Nvme
->Pt
[Qid
]) {
992 Status
= EFI_SUCCESS
;
996 MicroSecondDelay (NVME_CMD_WAIT
);
997 Timer
+= NVME_CMD_WAIT
;
1000 Nvme
->CqHdbl
[Qid
].Cqh
++;
1001 if (Nvme
->CqHdbl
[Qid
].Cqh
== CqSize
) {
1002 Nvme
->CqHdbl
[Qid
].Cqh
= 0;
1007 /// Copy the Respose Queue entry for this command to the callers response Buffer
1009 CopyMem (Packet
->NvmeResponse
, Cq
, sizeof(NVM_EXPRESS_RESPONSE
));
1011 if (!EFI_ERROR(Status
)) { // We still need to check CQ status if no timeout error occured
1012 Status
= NvmeCheckCqStatus (Cq
);
1014 NVME_SET_CQHDBL (Nvme
, Qid
, &Nvme
->CqHdbl
[Qid
]);
1021 Get identify controller Data.
1023 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1024 @param[in] Buffer - The Buffer used to store the identify controller Data.
1026 @return EFI_SUCCESS - Successfully get the identify controller Data.
1027 @return others - Fail to get the identify controller Data.
1032 NvmeIdentifyController (
1033 IN NVME_CONTEXT
*Nvme
,
1037 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1038 NVM_EXPRESS_COMMAND Command
;
1039 NVM_EXPRESS_RESPONSE Response
;
1042 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1043 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1044 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1046 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_OPC
;
1047 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1049 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
1050 // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
1054 CommandPacket
.NvmeCmd
= &Command
;
1055 CommandPacket
.NvmeResponse
= &Response
;
1056 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Buffer
;
1057 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_CONTROLLER_DATA
);
1058 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1059 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1061 // Set bit 0 (Cns bit) to 1 to identify a controller
1064 Command
.Flags
= CDW10_VALID
;
1066 Status
= NvmePassThru (
1072 if (!EFI_ERROR (Status
)) {
1073 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1080 Get specified identify namespace Data.
1082 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1083 @param[in] NamespaceId - The specified namespace identifier.
1084 @param[in] Buffer - The Buffer used to store the identify namespace Data.
1086 @return EFI_SUCCESS - Successfully get the identify namespace Data.
1087 @return others - Fail to get the identify namespace Data.
1092 NvmeIdentifyNamespace (
1093 IN NVME_CONTEXT
*Nvme
,
1094 IN UINT32 NamespaceId
,
1098 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1099 NVM_EXPRESS_COMMAND Command
;
1100 NVM_EXPRESS_RESPONSE Response
;
1103 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1104 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1105 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1107 CommandPacket
.NvmeCmd
= &Command
;
1108 CommandPacket
.NvmeResponse
= &Response
;
1110 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_OPC
;
1111 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1112 Command
.Nsid
= NamespaceId
;
1113 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Buffer
;
1114 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_NAMESPACE_DATA
);
1115 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1116 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1118 // Set bit 0 (Cns bit) to 1 to identify a namespace
1120 CommandPacket
.NvmeCmd
->Cdw10
= 0;
1121 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
;
1123 Status
= NvmePassThru (
1129 if (!EFI_ERROR (Status
)) {
1130 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1137 Get Block Size for specific namespace of NVME.
1139 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1141 @return - Block Size in bytes
1147 IN NVME_CONTEXT
*Nvme
1155 Flbas
= Nvme
->NamespaceData
->Flbas
;
1156 LbaFmtIdx
= Flbas
& 3;
1157 Lbads
= Nvme
->NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
1159 BlockSize
= (UINT32
)1 << Lbads
;
1164 Get last LBA for specific namespace of NVME.
1166 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1168 @return - Last LBA address
1174 IN NVME_CONTEXT
*Nvme
1178 LastBlock
= Nvme
->NamespaceData
->Nsze
- 1;
1183 Create io completion queue.
1185 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1187 @return EFI_SUCCESS - Successfully create io completion queue.
1188 @return others - Fail to create io completion queue.
1193 NvmeCreateIoCompletionQueue (
1194 IN NVME_CONTEXT
*Nvme
1197 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1198 NVM_EXPRESS_COMMAND Command
;
1199 NVM_EXPRESS_RESPONSE Response
;
1201 NVME_ADMIN_CRIOCQ CrIoCq
;
1203 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1204 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1205 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1206 ZeroMem (&CrIoCq
, sizeof(NVME_ADMIN_CRIOCQ
));
1208 CommandPacket
.NvmeCmd
= &Command
;
1209 CommandPacket
.NvmeResponse
= &Response
;
1211 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOCQ_OPC
;
1212 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1213 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->CqBuffer
[NVME_IO_QUEUE
];
1214 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1215 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1216 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1218 CrIoCq
.Qid
= NVME_IO_QUEUE
;
1219 CrIoCq
.Qsize
= NVME_CCQ_SIZE
;
1221 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoCq
, sizeof (NVME_ADMIN_CRIOCQ
));
1222 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1224 Status
= NvmePassThru (
1230 if (!EFI_ERROR (Status
)) {
1231 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1238 Create io submission queue.
1240 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1242 @return EFI_SUCCESS - Successfully create io submission queue.
1243 @return others - Fail to create io submission queue.
1248 NvmeCreateIoSubmissionQueue (
1249 IN NVME_CONTEXT
*Nvme
1252 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1253 NVM_EXPRESS_COMMAND Command
;
1254 NVM_EXPRESS_RESPONSE Response
;
1256 NVME_ADMIN_CRIOSQ CrIoSq
;
1258 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1259 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1260 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1261 ZeroMem (&CrIoSq
, sizeof(NVME_ADMIN_CRIOSQ
));
1263 CommandPacket
.NvmeCmd
= &Command
;
1264 CommandPacket
.NvmeResponse
= &Response
;
1266 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOSQ_OPC
;
1267 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1268 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->SqBuffer
[NVME_IO_QUEUE
];
1269 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1270 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1271 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1273 CrIoSq
.Qid
= NVME_IO_QUEUE
;
1274 CrIoSq
.Qsize
= NVME_CSQ_SIZE
;
1276 CrIoSq
.Cqid
= NVME_IO_QUEUE
;
1278 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoSq
, sizeof (NVME_ADMIN_CRIOSQ
));
1279 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1281 Status
= NvmePassThru (
1287 if (!EFI_ERROR (Status
)) {
1288 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1295 Security send and receive commands.
1297 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1298 @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
1299 @param[in] SecurityProtocol - Security Protocol
1300 @param[in] SpSpecific - Security Protocol Specific
1301 @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512
1302 @param[in,out] TransferBuffer - Address of Data to transfer
1304 @return EFI_SUCCESS - Successfully create io submission queue.
1305 @return others - Fail to send/receive commands.
1309 NvmeSecuritySendReceive (
1310 IN NVME_CONTEXT
*Nvme
,
1311 IN BOOLEAN SendCommand
,
1312 IN UINT8 SecurityProtocol
,
1313 IN UINT16 SpSpecific
,
1314 IN UINTN TransferLength
,
1315 IN OUT VOID
*TransferBuffer
1318 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1319 NVM_EXPRESS_COMMAND Command
;
1320 NVM_EXPRESS_RESPONSE Response
;
1322 NVME_ADMIN_SECSEND SecSend
;
1327 Oacs
= (OACS
*)&Nvme
->ControllerData
->Oacs
;
1330 // Verify security bit for Security Send/Receive commands
1332 if (Oacs
->Security
== 0) {
1333 DEBUG ((DEBUG_ERROR
, "Security command doesn't support.\n"));
1334 return EFI_NOT_READY
;
1337 SecBuff
= (VOID
*)(UINTN
) NVME_SEC_BASE (Nvme
);
1340 // Actions for sending security command
1343 CopyMem (SecBuff
, TransferBuffer
, TransferLength
);
1346 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1347 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1348 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1349 ZeroMem (&SecSend
, sizeof(NVME_ADMIN_SECSEND
));
1351 CommandPacket
.NvmeCmd
= &Command
;
1352 CommandPacket
.NvmeResponse
= &Response
;
1354 Opcode
= (UINT8
)(SendCommand
? NVME_ADMIN_SECURITY_SEND_OPC
: NVME_ADMIN_SECURITY_RECV_OPC
);
1355 Command
.Cdw0
.Opcode
= Opcode
;
1356 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1357 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)SecBuff
;
1358 CommandPacket
.TransferLength
= (UINT32
)TransferLength
;
1359 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1360 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1362 SecSend
.Spsp
= SpSpecific
;
1363 SecSend
.Secp
= SecurityProtocol
;
1364 SecSend
.Tl
= (UINT32
)TransferLength
;
1366 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &SecSend
, sizeof (NVME_ADMIN_SECSEND
));
1367 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1369 Status
= NvmePassThru (
1375 if (!EFI_ERROR (Status
)) {
1376 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1380 // Actions for receiving security command
1383 CopyMem (TransferBuffer
, SecBuff
, TransferLength
);
1390 Destroy io completion queue.
1392 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1394 @return EFI_SUCCESS - Successfully destroy io completion queue.
1395 @return others - Fail to destroy io completion queue.
1400 NvmeDestroyIoCompletionQueue (
1401 IN NVME_CONTEXT
*Nvme
1404 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1405 NVM_EXPRESS_COMMAND Command
;
1406 NVM_EXPRESS_RESPONSE Response
;
1408 NVME_ADMIN_DEIOCQ DelIoCq
;
1410 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1411 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1412 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1413 ZeroMem (&DelIoCq
, sizeof(NVME_ADMIN_DEIOCQ
));
1415 CommandPacket
.NvmeCmd
= &Command
;
1416 CommandPacket
.NvmeResponse
= &Response
;
1418 Command
.Cdw0
.Opcode
= NVME_ADMIN_DELIOCQ_OPC
;
1419 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1420 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->CqBuffer
[NVME_IO_QUEUE
];
1421 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1422 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1423 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1425 DelIoCq
.Qid
= NVME_IO_QUEUE
;
1426 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &DelIoCq
, sizeof (NVME_ADMIN_DEIOCQ
));
1427 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1429 Status
= NvmePassThru (
1435 if (!EFI_ERROR (Status
)) {
1436 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1443 Destroy io submission queue.
1445 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1447 @return EFI_SUCCESS - Successfully destroy io submission queue.
1448 @return others - Fail to destroy io submission queue.
1453 NvmeDestroyIoSubmissionQueue (
1454 IN NVME_CONTEXT
*Nvme
1457 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1458 NVM_EXPRESS_COMMAND Command
;
1459 NVM_EXPRESS_RESPONSE Response
;
1461 NVME_ADMIN_DEIOSQ DelIoSq
;
1463 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1464 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1465 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1466 ZeroMem (&DelIoSq
, sizeof(NVME_ADMIN_DEIOSQ
));
1468 CommandPacket
.NvmeCmd
= &Command
;
1469 CommandPacket
.NvmeResponse
= &Response
;
1471 Command
.Cdw0
.Opcode
= NVME_ADMIN_DELIOSQ_OPC
;
1472 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1473 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->SqBuffer
[NVME_IO_QUEUE
];
1474 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1475 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1476 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1478 DelIoSq
.Qid
= NVME_IO_QUEUE
;
1479 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &DelIoSq
, sizeof (NVME_ADMIN_DEIOSQ
));
1480 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1482 Status
= NvmePassThru (
1488 if (!EFI_ERROR (Status
)) {
1489 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1496 Allocate transfer-related Data struct which is used at Nvme.
1498 @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.
1500 @retval EFI_OUT_OF_RESOURCE No enough resource.
1501 @retval EFI_SUCCESS Successful to allocate resource.
1506 NvmeAllocateResource (
1507 IN OUT NVME_CONTEXT
*Nvme
1511 EFI_PHYSICAL_ADDRESS DeviceAddress
;
1516 // Allocate resources for DMA.
1518 Status
= IoMmuAllocateBuffer (
1519 EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE
),
1524 if (EFI_ERROR (Status
)) {
1525 return EFI_OUT_OF_RESOURCES
;
1527 ASSERT (DeviceAddress
== ((EFI_PHYSICAL_ADDRESS
) (UINTN
) Base
));
1528 Nvme
->BaseMemMapping
= Mapping
;
1529 Nvme
->BaseMem
= Base
;
1530 ZeroMem (Nvme
->BaseMem
, EFI_PAGE_SIZE
* EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE
));
1534 "%a() NvmeContext 0x%x\n",
1543 Free allocated transfer-related Data struct which is used at NVMe.
1545 @param[in, out] Nvme The pointer to the NVME_CONTEXT Data structure.
1551 IN OUT NVME_CONTEXT
*Nvme
1554 if (Nvme
->BaseMem
!= NULL
) {
1556 EFI_SIZE_TO_PAGES (NVME_MEM_MAX_SIZE
),
1558 Nvme
->BaseMemMapping
1560 Nvme
->BaseMem
= NULL
;
1565 Initialize the Nvm Express controller.
1567 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1569 @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.
1570 @retval Others - A device error occurred while initializing the controller.
1574 NvmeControllerInit (
1575 IN NVME_CONTEXT
*Nvme
1588 /// Update PCIE BAR0/1 for NVME device
1592 PciWrite32 (Nvme
->PciBase
+ 0x10, MlBAR
); // MLBAR (BAR0)
1593 PciWrite32 (Nvme
->PciBase
+ 0x14, MuBAR
); // MUBAR (BAR1)
1596 /// Enable PCIE decode
1598 PciWrite8 (Nvme
->PciBase
+ NVME_PCIE_PCICMD
, 0x6);
1601 NVME_GET_VER (Nvme
, &Ver
);
1602 if (!(Ver
.Mjr
== 0x0001) && (Ver
.Mnr
== 0x0000)) {
1603 DEBUG ((DEBUG_INFO
, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n"));
1607 /// Read the Controller Capabilities register and verify that the NVM command set is supported
1609 Status
= NVME_GET_CAP (Nvme
, &Nvme
->Cap
);
1610 if (EFI_ERROR (Status
)) {
1611 DEBUG ((DEBUG_ERROR
, "NVME_GET_CAP fail, Status: %r\n", Status
));
1615 if (Nvme
->Cap
.Css
!= 0x01) {
1616 DEBUG ((DEBUG_ERROR
, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n"));
1617 Status
= EFI_UNSUPPORTED
;
1622 /// Currently the driver only supports 4k page Size.
1624 if ((Nvme
->Cap
.Mpsmin
+ 12) > EFI_PAGE_SHIFT
) {
1625 DEBUG ((DEBUG_ERROR
, "NvmeControllerInit fail: only supports 4k page Size\n"));
1627 Status
= EFI_UNSUPPORTED
;
1637 ZeroMem ((VOID
*)(UINTN
)(&(Nvme
->SqTdbl
[0])), sizeof (NVME_SQTDBL
) * NVME_MAX_IO_QUEUES
);
1638 ZeroMem ((VOID
*)(UINTN
)(&(Nvme
->CqHdbl
[0])), sizeof (NVME_CQHDBL
) * NVME_MAX_IO_QUEUES
);
1640 ZeroMem (Nvme
->BaseMem
, NVME_MEM_MAX_SIZE
);
1642 Status
= NvmeDisableController (Nvme
);
1643 if (EFI_ERROR(Status
)) {
1644 DEBUG ((DEBUG_ERROR
, "NvmeDisableController fail, Status: %r\n", Status
));
1649 /// set number of entries admin submission & completion queues.
1651 Aqa
.Asqs
= NVME_ASQ_SIZE
;
1653 Aqa
.Acqs
= NVME_ACQ_SIZE
;
1657 /// Address of admin submission queue.
1659 Asq
= (UINT64
)(UINTN
)(NVME_ASQ_BASE (Nvme
) & ~0xFFF);
1662 /// Address of admin completion queue.
1664 Acq
= (UINT64
)(UINTN
)(NVME_ACQ_BASE (Nvme
) & ~0xFFF);
1667 /// Address of I/O submission & completion queue.
1669 Nvme
->SqBuffer
[0] = (NVME_SQ
*)(UINTN
)NVME_ASQ_BASE (Nvme
); // NVME_ADMIN_QUEUE
1670 Nvme
->CqBuffer
[0] = (NVME_CQ
*)(UINTN
)NVME_ACQ_BASE (Nvme
); // NVME_ADMIN_QUEUE
1671 Nvme
->SqBuffer
[1] = (NVME_SQ
*)(UINTN
)NVME_SQ_BASE (Nvme
, 0); // NVME_IO_QUEUE
1672 Nvme
->CqBuffer
[1] = (NVME_CQ
*)(UINTN
)NVME_CQ_BASE (Nvme
, 0); // NVME_IO_QUEUE
1674 DEBUG ((DEBUG_INFO
, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa
.Asqs
));
1675 DEBUG ((DEBUG_INFO
, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa
.Acqs
));
1676 DEBUG ((DEBUG_INFO
, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Nvme
->SqBuffer
[0]));
1677 DEBUG ((DEBUG_INFO
, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Nvme
->CqBuffer
[0]));
1678 DEBUG ((DEBUG_INFO
, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Nvme
->SqBuffer
[1]));
1679 DEBUG ((DEBUG_INFO
, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Nvme
->CqBuffer
[1]));
1682 /// Program admin queue attributes.
1684 Status
= NVME_SET_AQA (Nvme
, &Aqa
);
1685 if (EFI_ERROR(Status
)) {
1690 /// Program admin submission queue address.
1692 Status
= NVME_SET_ASQ (Nvme
, &Asq
);
1693 if (EFI_ERROR(Status
)) {
1698 /// Program admin completion queue address.
1700 Status
= NVME_SET_ACQ (Nvme
, &Acq
);
1701 if (EFI_ERROR(Status
)) {
1705 Status
= NvmeEnableController (Nvme
);
1706 if (EFI_ERROR(Status
)) {
1711 /// Create one I/O completion queue.
1713 Status
= NvmeCreateIoCompletionQueue (Nvme
);
1714 if (EFI_ERROR(Status
)) {
1719 /// Create one I/O Submission queue.
1721 Status
= NvmeCreateIoSubmissionQueue (Nvme
);
1722 if (EFI_ERROR(Status
)) {
1727 /// Get current Identify Controller Data
1729 Nvme
->ControllerData
= (NVME_ADMIN_CONTROLLER_DATA
*)(UINTN
) NVME_CONTROL_DATA_BASE (Nvme
);
1730 Status
= NvmeIdentifyController (Nvme
, Nvme
->ControllerData
);
1731 if (EFI_ERROR(Status
)) {
1736 /// Dump NvmExpress Identify Controller Data
1738 Nvme
->ControllerData
->Sn
[19] = 0;
1739 Nvme
->ControllerData
->Mn
[39] = 0;
1740 //NvmeDumpIdentifyController (Nvme->ControllerData);
1743 /// Get current Identify Namespace Data
1745 Nvme
->NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*)NVME_NAMESPACE_DATA_BASE (Nvme
);
1746 Status
= NvmeIdentifyNamespace (Nvme
, Nvme
->Nsid
, Nvme
->NamespaceData
);
1747 if (EFI_ERROR(Status
)) {
1748 DEBUG ((DEBUG_ERROR
, "NvmeIdentifyNamespace fail, Status = %r\n", Status
));
1753 /// Dump NvmExpress Identify Namespace Data
1755 if (Nvme
->NamespaceData
->Ncap
== 0) {
1756 DEBUG ((DEBUG_ERROR
, "Invalid Namespace, Ncap: %lx\n", Nvme
->NamespaceData
->Ncap
));
1757 Status
= EFI_DEVICE_ERROR
;
1761 Nvme
->BlockSize
= NvmeGetBlockSize (Nvme
);
1762 Nvme
->LastBlock
= NvmeGetLastLba (Nvme
);
1764 Nvme
->State
= NvmeStatusInit
;
1773 Un-initialize the Nvm Express controller.
1775 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1777 @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.
1778 @retval Others - A device error occurred while un-initializing the controller.
1782 NvmeControllerExit (
1783 IN NVME_CONTEXT
*Nvme
1788 Status
= EFI_SUCCESS
;
1789 if (Nvme
->State
== NvmeStatusInit
|| Nvme
->State
== NvmeStatusMax
) {
1791 /// Destroy I/O Submission queue.
1793 Status
= NvmeDestroyIoSubmissionQueue (Nvme
);
1794 if (EFI_ERROR(Status
)) {
1795 DEBUG ((DEBUG_ERROR
, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status
));
1800 /// Destroy I/O completion queue.
1802 Status
= NvmeDestroyIoCompletionQueue (Nvme
);
1803 if (EFI_ERROR(Status
)) {
1804 DEBUG ((DEBUG_ERROR
, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status
));
1808 Status
= NvmeShutdownController (Nvme
);
1809 if (EFI_ERROR(Status
)) {
1810 DEBUG ((DEBUG_ERROR
, "NvmeShutdownController fail, Status: %r\n", Status
));
1815 /// Disable PCIE decode
1817 PciWrite8 (Nvme
->PciBase
+ NVME_PCIE_PCICMD
, 0x0);
1818 PciWrite32 (Nvme
->PciBase
+ 0x10, 0); // MLBAR (BAR0)
1819 PciWrite32 (Nvme
->PciBase
+ 0x14, 0); // MUBAR (BAR1)
1821 Nvme
->State
= NvmeStatusUnknown
;