2 Provide functions to initialize NVME controller and perform NVME commands
4 Copyright (c) 2016 - 2017, 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 "OpalPasswordSmm.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 Check whether there are available command slots.
799 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
800 @param[in] Qid - Queue index
802 @retval EFI_SUCCESS - Available command slot is found
803 @retval EFI_NOT_READY - No available command slot is found
804 @retval EFI_DEVICE_ERROR - Error occurred on device side.
809 IN NVME_CONTEXT
*Nvme
,
817 Check whether all command slots are clean.
819 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
820 @param[in] Qid - Queue index
822 @retval EFI_SUCCESS - All command slots are clean
823 @retval EFI_NOT_READY - Not all command slots are clean
824 @retval EFI_DEVICE_ERROR - Error occurred on device side.
828 NvmeIsAllCmdSlotClean (
829 IN NVME_CONTEXT
*Nvme
,
837 Waits until all NVME commands completed.
839 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
840 @param[in] Qid - Queue index
842 @retval EFI_SUCCESS - All NVME commands have completed
843 @retval EFI_TIMEOUT - Timeout occured
844 @retval EFI_NOT_READY - Not all NVME commands have completed
845 @retval others - Error occurred on device side.
848 NvmeWaitAllComplete (
849 IN NVME_CONTEXT
*Nvme
,
857 Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
858 both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
859 I/O functionality is optional.
861 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
862 @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
863 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
864 ID specifies that the command packet should be sent to all valid namespaces.
865 @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
866 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
867 UUID specifies that the command packet should be sent to all valid namespaces.
868 @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
871 @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
872 to, or from DataBuffer.
873 @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
874 may retry again later.
875 @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.
876 @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
877 Express Command Packet was not sent, so no additional status information is available.
878 @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.
879 The NVM Express Command Packet was not sent, so no additional status information is available.
880 @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.
885 IN NVME_CONTEXT
*Nvme
,
886 IN UINT32 NamespaceId
,
887 IN UINT64 NamespaceUuid
,
888 IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
*Packet
897 EFI_PHYSICAL_ADDRESS PhyAddr
;
905 /// check the Data fields in Packet parameter.
907 if ((Nvme
== NULL
) || (Packet
== NULL
)) {
908 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n",
909 (UINTN
)Nvme
, (UINTN
)Packet
));
910 return EFI_INVALID_PARAMETER
;
913 if ((Packet
->NvmeCmd
== NULL
) || (Packet
->NvmeResponse
== NULL
)) {
914 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n",
915 (UINTN
)Packet
->NvmeCmd
, (UINTN
)Packet
->NvmeResponse
));
916 return EFI_INVALID_PARAMETER
;
919 if (Packet
->QueueId
!= NVME_ADMIN_QUEUE
&& Packet
->QueueId
!= NVME_IO_QUEUE
) {
920 DEBUG ((DEBUG_ERROR
, "NvmePassThru, invalid parameter: QueueId(%x)\n",
922 return EFI_INVALID_PARAMETER
;
927 Status
= EFI_SUCCESS
;
929 Qid
= Packet
->QueueId
;
930 Sq
= Nvme
->SqBuffer
[Qid
] + Nvme
->SqTdbl
[Qid
].Sqt
;
931 Cq
= Nvme
->CqBuffer
[Qid
] + Nvme
->CqHdbl
[Qid
].Cqh
;
932 if (Qid
== NVME_ADMIN_QUEUE
) {
933 SqSize
= NVME_ASQ_SIZE
+ 1;
934 CqSize
= NVME_ACQ_SIZE
+ 1;
936 SqSize
= NVME_CSQ_DEPTH
;
937 CqSize
= NVME_CCQ_DEPTH
;
940 if (Packet
->NvmeCmd
->Nsid
!= NamespaceId
) {
941 DEBUG ((DEBUG_ERROR
, "NvmePassThru: Nsid mismatch (%x, %x)\n",
942 Packet
->NvmeCmd
->Nsid
, NamespaceId
));
943 return EFI_INVALID_PARAMETER
;
946 ZeroMem (Sq
, sizeof (NVME_SQ
));
947 Sq
->Opc
= Packet
->NvmeCmd
->Cdw0
.Opcode
;
948 Sq
->Fuse
= Packet
->NvmeCmd
->Cdw0
.FusedOperation
;
949 Sq
->Cid
= Packet
->NvmeCmd
->Cdw0
.Cid
;
950 Sq
->Nsid
= Packet
->NvmeCmd
->Nsid
;
953 /// Currently we only support PRP for Data transfer, SGL is NOT supported.
955 ASSERT (Sq
->Psdt
== 0);
957 DEBUG ((DEBUG_ERROR
, "NvmePassThru: doesn't support SGL mechanism\n"));
958 return EFI_UNSUPPORTED
;
961 Sq
->Prp
[0] = Packet
->TransferBuffer
;
964 if(Packet
->MetadataBuffer
!= (UINT64
)(UINTN
)NULL
) {
965 Sq
->Mptr
= Packet
->MetadataBuffer
;
969 /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
970 /// then build a PRP list in the second PRP submission queue entry.
972 Offset
= ((UINT32
)Sq
->Prp
[0]) & (EFI_PAGE_SIZE
- 1);
973 Bytes
= Packet
->TransferLength
;
975 if ((Offset
+ Bytes
) > (EFI_PAGE_SIZE
* 2)) {
977 /// Create PrpList for remaining Data Buffer.
979 PhyAddr
= (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
980 Sq
->Prp
[1] = NvmeCreatePrpList (Nvme
, Nvme
->SqTdbl
[Qid
].Sqt
, PhyAddr
, EFI_SIZE_TO_PAGES(Offset
+ Bytes
) - 1, &PrpListHost
, &PrpListNo
);
981 if (Sq
->Prp
[1] == 0) {
982 Status
= EFI_OUT_OF_RESOURCES
;
983 DEBUG ((DEBUG_ERROR
, "NvmeCreatePrpList fail, Status: %r\n", Status
));
987 } else if ((Offset
+ Bytes
) > EFI_PAGE_SIZE
) {
988 Sq
->Prp
[1] = (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
991 if(Packet
->NvmeCmd
->Flags
& CDW10_VALID
) {
992 Sq
->Payload
.Raw
.Cdw10
= Packet
->NvmeCmd
->Cdw10
;
994 if(Packet
->NvmeCmd
->Flags
& CDW11_VALID
) {
995 Sq
->Payload
.Raw
.Cdw11
= Packet
->NvmeCmd
->Cdw11
;
997 if(Packet
->NvmeCmd
->Flags
& CDW12_VALID
) {
998 Sq
->Payload
.Raw
.Cdw12
= Packet
->NvmeCmd
->Cdw12
;
1000 if(Packet
->NvmeCmd
->Flags
& CDW13_VALID
) {
1001 Sq
->Payload
.Raw
.Cdw13
= Packet
->NvmeCmd
->Cdw13
;
1003 if(Packet
->NvmeCmd
->Flags
& CDW14_VALID
) {
1004 Sq
->Payload
.Raw
.Cdw14
= Packet
->NvmeCmd
->Cdw14
;
1006 if(Packet
->NvmeCmd
->Flags
& CDW15_VALID
) {
1007 Sq
->Payload
.Raw
.Cdw15
= Packet
->NvmeCmd
->Cdw15
;
1011 /// Ring the submission queue doorbell.
1013 Nvme
->SqTdbl
[Qid
].Sqt
++;
1014 if(Nvme
->SqTdbl
[Qid
].Sqt
== SqSize
) {
1015 Nvme
->SqTdbl
[Qid
].Sqt
= 0;
1017 Status
= NVME_SET_SQTDBL (Nvme
, Qid
, &Nvme
->SqTdbl
[Qid
]);
1018 if (EFI_ERROR(Status
)) {
1019 DEBUG ((DEBUG_ERROR
, "NVME_SET_SQTDBL fail, Status: %r\n", Status
));
1024 /// Wait for completion queue to get filled in.
1026 Status
= EFI_TIMEOUT
;
1028 while (Timer
< NVME_CMD_TIMEOUT
) {
1029 //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));
1030 //DumpMem (Cq, sizeof (NVME_CQ));
1031 if (Cq
->Pt
!= Nvme
->Pt
[Qid
]) {
1032 Status
= EFI_SUCCESS
;
1036 MicroSecondDelay (NVME_CMD_WAIT
);
1037 Timer
+= NVME_CMD_WAIT
;
1040 Nvme
->CqHdbl
[Qid
].Cqh
++;
1041 if (Nvme
->CqHdbl
[Qid
].Cqh
== CqSize
) {
1042 Nvme
->CqHdbl
[Qid
].Cqh
= 0;
1047 /// Copy the Respose Queue entry for this command to the callers response Buffer
1049 CopyMem (Packet
->NvmeResponse
, Cq
, sizeof(NVM_EXPRESS_RESPONSE
));
1051 if (!EFI_ERROR(Status
)) { // We still need to check CQ status if no timeout error occured
1052 Status
= NvmeCheckCqStatus (Cq
);
1054 NVME_SET_CQHDBL (Nvme
, Qid
, &Nvme
->CqHdbl
[Qid
]);
1061 Get identify controller Data.
1063 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1064 @param[in] Buffer - The Buffer used to store the identify controller Data.
1066 @return EFI_SUCCESS - Successfully get the identify controller Data.
1067 @return others - Fail to get the identify controller Data.
1072 NvmeIdentifyController (
1073 IN NVME_CONTEXT
*Nvme
,
1077 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1078 NVM_EXPRESS_COMMAND Command
;
1079 NVM_EXPRESS_RESPONSE Response
;
1082 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1083 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1084 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1086 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_OPC
;
1087 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1089 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
1090 // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
1094 CommandPacket
.NvmeCmd
= &Command
;
1095 CommandPacket
.NvmeResponse
= &Response
;
1096 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Buffer
;
1097 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_CONTROLLER_DATA
);
1098 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1099 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1101 // Set bit 0 (Cns bit) to 1 to identify a controller
1104 Command
.Flags
= CDW10_VALID
;
1106 Status
= NvmePassThru (
1112 if (!EFI_ERROR (Status
)) {
1113 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1120 Get specified identify namespace Data.
1122 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1123 @param[in] NamespaceId - The specified namespace identifier.
1124 @param[in] Buffer - The Buffer used to store the identify namespace Data.
1126 @return EFI_SUCCESS - Successfully get the identify namespace Data.
1127 @return others - Fail to get the identify namespace Data.
1132 NvmeIdentifyNamespace (
1133 IN NVME_CONTEXT
*Nvme
,
1134 IN UINT32 NamespaceId
,
1138 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1139 NVM_EXPRESS_COMMAND Command
;
1140 NVM_EXPRESS_RESPONSE Response
;
1143 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1144 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1145 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1147 CommandPacket
.NvmeCmd
= &Command
;
1148 CommandPacket
.NvmeResponse
= &Response
;
1150 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_OPC
;
1151 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1152 Command
.Nsid
= NamespaceId
;
1153 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Buffer
;
1154 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_NAMESPACE_DATA
);
1155 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1156 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1158 // Set bit 0 (Cns bit) to 1 to identify a namespace
1160 CommandPacket
.NvmeCmd
->Cdw10
= 0;
1161 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
;
1163 Status
= NvmePassThru (
1169 if (!EFI_ERROR (Status
)) {
1170 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1177 Get Block Size for specific namespace of NVME.
1179 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1181 @return - Block Size in bytes
1187 IN NVME_CONTEXT
*Nvme
1195 Flbas
= Nvme
->NamespaceData
->Flbas
;
1196 LbaFmtIdx
= Flbas
& 3;
1197 Lbads
= Nvme
->NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
1199 BlockSize
= (UINT32
)1 << Lbads
;
1204 Get last LBA for specific namespace of NVME.
1206 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1208 @return - Last LBA address
1214 IN NVME_CONTEXT
*Nvme
1218 LastBlock
= Nvme
->NamespaceData
->Nsze
- 1;
1223 Create io completion queue.
1225 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1227 @return EFI_SUCCESS - Successfully create io completion queue.
1228 @return others - Fail to create io completion queue.
1233 NvmeCreateIoCompletionQueue (
1234 IN NVME_CONTEXT
*Nvme
1237 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1238 NVM_EXPRESS_COMMAND Command
;
1239 NVM_EXPRESS_RESPONSE Response
;
1241 NVME_ADMIN_CRIOCQ CrIoCq
;
1243 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1244 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1245 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1246 ZeroMem (&CrIoCq
, sizeof(NVME_ADMIN_CRIOCQ
));
1248 CommandPacket
.NvmeCmd
= &Command
;
1249 CommandPacket
.NvmeResponse
= &Response
;
1251 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOCQ_OPC
;
1252 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1253 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->CqBuffer
[NVME_IO_QUEUE
];
1254 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1255 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1256 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1258 CrIoCq
.Qid
= NVME_IO_QUEUE
;
1259 CrIoCq
.Qsize
= NVME_CCQ_SIZE
;
1261 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoCq
, sizeof (NVME_ADMIN_CRIOCQ
));
1262 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1264 Status
= NvmePassThru (
1270 if (!EFI_ERROR (Status
)) {
1271 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1278 Create io submission queue.
1280 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1282 @return EFI_SUCCESS - Successfully create io submission queue.
1283 @return others - Fail to create io submission queue.
1288 NvmeCreateIoSubmissionQueue (
1289 IN NVME_CONTEXT
*Nvme
1292 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1293 NVM_EXPRESS_COMMAND Command
;
1294 NVM_EXPRESS_RESPONSE Response
;
1296 NVME_ADMIN_CRIOSQ CrIoSq
;
1298 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1299 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1300 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1301 ZeroMem (&CrIoSq
, sizeof(NVME_ADMIN_CRIOSQ
));
1303 CommandPacket
.NvmeCmd
= &Command
;
1304 CommandPacket
.NvmeResponse
= &Response
;
1306 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOSQ_OPC
;
1307 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1308 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->SqBuffer
[NVME_IO_QUEUE
];
1309 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1310 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1311 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1313 CrIoSq
.Qid
= NVME_IO_QUEUE
;
1314 CrIoSq
.Qsize
= NVME_CSQ_SIZE
;
1316 CrIoSq
.Cqid
= NVME_IO_QUEUE
;
1318 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoSq
, sizeof (NVME_ADMIN_CRIOSQ
));
1319 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1321 Status
= NvmePassThru (
1327 if (!EFI_ERROR (Status
)) {
1328 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1335 Security send and receive commands.
1337 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1338 @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
1339 @param[in] SecurityProtocol - Security Protocol
1340 @param[in] SpSpecific - Security Protocol Specific
1341 @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512
1342 @param[in,out] TransferBuffer - Address of Data to transfer
1344 @return EFI_SUCCESS - Successfully create io submission queue.
1345 @return others - Fail to send/receive commands.
1349 NvmeSecuritySendReceive (
1350 IN NVME_CONTEXT
*Nvme
,
1351 IN BOOLEAN SendCommand
,
1352 IN UINT8 SecurityProtocol
,
1353 IN UINT16 SpSpecific
,
1354 IN UINTN TransferLength
,
1355 IN OUT VOID
*TransferBuffer
1358 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1359 NVM_EXPRESS_COMMAND Command
;
1360 NVM_EXPRESS_RESPONSE Response
;
1362 NVME_ADMIN_SECSEND SecSend
;
1367 Oacs
= (OACS
*)&Nvme
->ControllerData
->Oacs
;
1370 // Verify security bit for Security Send/Receive commands
1372 if (Oacs
->Security
== 0) {
1373 DEBUG ((DEBUG_ERROR
, "Security command doesn't support.\n"));
1374 return EFI_NOT_READY
;
1377 SecBuff
= (VOID
*)(UINTN
) NVME_SEC_BASE (Nvme
);
1380 // Actions for sending security command
1383 CopyMem (SecBuff
, TransferBuffer
, TransferLength
);
1386 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1387 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1388 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1389 ZeroMem (&SecSend
, sizeof(NVME_ADMIN_SECSEND
));
1391 CommandPacket
.NvmeCmd
= &Command
;
1392 CommandPacket
.NvmeResponse
= &Response
;
1394 Opcode
= (UINT8
)(SendCommand
? NVME_ADMIN_SECURITY_SEND_OPC
: NVME_ADMIN_SECURITY_RECV_OPC
);
1395 Command
.Cdw0
.Opcode
= Opcode
;
1396 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1397 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)SecBuff
;
1398 CommandPacket
.TransferLength
= (UINT32
)TransferLength
;
1399 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1400 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1402 SecSend
.Spsp
= SpSpecific
;
1403 SecSend
.Secp
= SecurityProtocol
;
1404 SecSend
.Tl
= (UINT32
)TransferLength
;
1406 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &SecSend
, sizeof (NVME_ADMIN_SECSEND
));
1407 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1409 Status
= NvmePassThru (
1415 if (!EFI_ERROR (Status
)) {
1416 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1420 // Actions for receiving security command
1423 CopyMem (TransferBuffer
, SecBuff
, TransferLength
);
1430 Destroy io completion queue.
1432 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1434 @return EFI_SUCCESS - Successfully destroy io completion queue.
1435 @return others - Fail to destroy io completion queue.
1440 NvmeDestroyIoCompletionQueue (
1441 IN NVME_CONTEXT
*Nvme
1444 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1445 NVM_EXPRESS_COMMAND Command
;
1446 NVM_EXPRESS_RESPONSE Response
;
1448 NVME_ADMIN_DEIOCQ DelIoCq
;
1450 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1451 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1452 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1453 ZeroMem (&DelIoCq
, sizeof(NVME_ADMIN_DEIOCQ
));
1455 CommandPacket
.NvmeCmd
= &Command
;
1456 CommandPacket
.NvmeResponse
= &Response
;
1458 Command
.Cdw0
.Opcode
= NVME_ADMIN_DELIOCQ_OPC
;
1459 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1460 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->CqBuffer
[NVME_IO_QUEUE
];
1461 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1462 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1463 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1465 DelIoCq
.Qid
= NVME_IO_QUEUE
;
1466 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &DelIoCq
, sizeof (NVME_ADMIN_DEIOCQ
));
1467 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1469 Status
= NvmePassThru (
1475 if (!EFI_ERROR (Status
)) {
1476 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1483 Destroy io submission queue.
1485 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1487 @return EFI_SUCCESS - Successfully destroy io submission queue.
1488 @return others - Fail to destroy io submission queue.
1493 NvmeDestroyIoSubmissionQueue (
1494 IN NVME_CONTEXT
*Nvme
1497 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1498 NVM_EXPRESS_COMMAND Command
;
1499 NVM_EXPRESS_RESPONSE Response
;
1501 NVME_ADMIN_DEIOSQ DelIoSq
;
1503 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1504 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1505 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1506 ZeroMem (&DelIoSq
, sizeof(NVME_ADMIN_DEIOSQ
));
1508 CommandPacket
.NvmeCmd
= &Command
;
1509 CommandPacket
.NvmeResponse
= &Response
;
1511 Command
.Cdw0
.Opcode
= NVME_ADMIN_DELIOSQ_OPC
;
1512 Command
.Cdw0
.Cid
= Nvme
->Cid
[NVME_ADMIN_QUEUE
]++;
1513 CommandPacket
.TransferBuffer
= (UINT64
)(UINTN
)Nvme
->SqBuffer
[NVME_IO_QUEUE
];
1514 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
1515 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1516 CommandPacket
.QueueId
= NVME_ADMIN_QUEUE
;
1518 DelIoSq
.Qid
= NVME_IO_QUEUE
;
1519 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &DelIoSq
, sizeof (NVME_ADMIN_DEIOSQ
));
1520 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
1522 Status
= NvmePassThru (
1528 if (!EFI_ERROR (Status
)) {
1529 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
1536 Allocate transfer-related Data struct which is used at Nvme.
1538 @param[in] ImageHandle Image handle for this driver image
1539 @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
1541 @retval EFI_OUT_OF_RESOURCE The allocation is failure.
1542 @retval EFI_SUCCESS Successful to allocate memory.
1547 NvmeAllocateResource (
1548 IN EFI_HANDLE ImageHandle
,
1549 IN NVME_CONTEXT
*Nvme
1553 EFI_PHYSICAL_ADDRESS Addr
;
1557 // Allocate resources required by NVMe host controller.
1562 Status
= gDS
->AllocateMemorySpace (
1563 EfiGcdAllocateMaxAddressSearchBottomUp
,
1564 EfiGcdMemoryTypeMemoryMappedIo
,
1565 15, // 2^15: 32K Alignment
1571 if (EFI_ERROR (Status
)) {
1572 return EFI_OUT_OF_RESOURCES
;
1574 Nvme
->Nbar
= (UINT32
) Addr
;
1577 Size
= NVME_MEM_MAX_SIZE
;
1579 Status
= gBS
->AllocatePages (
1582 EFI_SIZE_TO_PAGES (Size
),
1583 (EFI_PHYSICAL_ADDRESS
*)&Addr
1585 if (EFI_ERROR (Status
)) {
1586 return EFI_OUT_OF_RESOURCES
;
1588 Nvme
->BaseMem
= (UINT32
) Addr
;
1590 // Clean up DMA Buffer before using
1591 ZeroMem ((VOID
*)(UINTN
)Addr
, NVME_MEM_MAX_SIZE
);
1597 Free allocated transfer-related Data struct which is used at NVMe.
1599 @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
1605 IN NVME_CONTEXT
*Nvme
1611 if (Nvme
->BaseMem
!= 0) {
1613 gDS
->FreeMemorySpace (Nvme
->Nbar
, Size
);
1617 if (Nvme
->Nbar
!= 0) {
1618 Size
= NVME_MEM_MAX_SIZE
;
1619 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
) Nvme
->Nbar
, EFI_SIZE_TO_PAGES (Size
));
1625 Initialize the Nvm Express controller.
1627 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1629 @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.
1630 @retval Others - A device error occurred while initializing the controller.
1634 NvmeControllerInit (
1635 IN NVME_CONTEXT
*Nvme
1648 /// Update PCIE BAR0/1 for NVME device
1652 PciWrite32 (Nvme
->PciBase
+ 0x10, MlBAR
); // MLBAR (BAR0)
1653 PciWrite32 (Nvme
->PciBase
+ 0x14, MuBAR
); // MUBAR (BAR1)
1656 /// Enable PCIE decode
1658 PciWrite8 (Nvme
->PciBase
+ NVME_PCIE_PCICMD
, 0x6);
1661 NVME_GET_VER (Nvme
, &Ver
);
1662 if (!(Ver
.Mjr
== 0x0001) && (Ver
.Mnr
== 0x0000)) {
1663 DEBUG ((DEBUG_INFO
, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n"));
1667 /// Read the Controller Capabilities register and verify that the NVM command set is supported
1669 Status
= NVME_GET_CAP (Nvme
, &Nvme
->Cap
);
1670 if (EFI_ERROR (Status
)) {
1671 DEBUG ((DEBUG_ERROR
, "NVME_GET_CAP fail, Status: %r\n", Status
));
1675 if (Nvme
->Cap
.Css
!= 0x01) {
1676 DEBUG ((DEBUG_ERROR
, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n"));
1677 Status
= EFI_UNSUPPORTED
;
1682 /// Currently the driver only supports 4k page Size.
1684 if ((Nvme
->Cap
.Mpsmin
+ 12) > EFI_PAGE_SHIFT
) {
1685 DEBUG ((DEBUG_ERROR
, "NvmeControllerInit fail: only supports 4k page Size\n"));
1687 Status
= EFI_UNSUPPORTED
;
1697 ZeroMem ((VOID
*)(UINTN
)(&(Nvme
->SqTdbl
[0])), sizeof (NVME_SQTDBL
) * NVME_MAX_IO_QUEUES
);
1698 ZeroMem ((VOID
*)(UINTN
)(&(Nvme
->CqHdbl
[0])), sizeof (NVME_CQHDBL
) * NVME_MAX_IO_QUEUES
);
1700 ZeroMem ((VOID
*)(UINTN
)Nvme
->BaseMem
, NVME_MEM_MAX_SIZE
);
1702 Status
= NvmeDisableController (Nvme
);
1703 if (EFI_ERROR(Status
)) {
1704 DEBUG ((DEBUG_ERROR
, "NvmeDisableController fail, Status: %r\n", Status
));
1709 /// set number of entries admin submission & completion queues.
1711 Aqa
.Asqs
= NVME_ASQ_SIZE
;
1713 Aqa
.Acqs
= NVME_ACQ_SIZE
;
1717 /// Address of admin submission queue.
1719 Asq
= (UINT64
)(UINTN
)(NVME_ASQ_BASE (Nvme
) & ~0xFFF);
1722 /// Address of admin completion queue.
1724 Acq
= (UINT64
)(UINTN
)(NVME_ACQ_BASE (Nvme
) & ~0xFFF);
1727 /// Address of I/O submission & completion queue.
1729 Nvme
->SqBuffer
[0] = (NVME_SQ
*)(UINTN
)NVME_ASQ_BASE (Nvme
); // NVME_ADMIN_QUEUE
1730 Nvme
->CqBuffer
[0] = (NVME_CQ
*)(UINTN
)NVME_ACQ_BASE (Nvme
); // NVME_ADMIN_QUEUE
1731 Nvme
->SqBuffer
[1] = (NVME_SQ
*)(UINTN
)NVME_SQ_BASE (Nvme
, 0); // NVME_IO_QUEUE
1732 Nvme
->CqBuffer
[1] = (NVME_CQ
*)(UINTN
)NVME_CQ_BASE (Nvme
, 0); // NVME_IO_QUEUE
1734 DEBUG ((DEBUG_INFO
, "BaseMem = [%08X]\n", Nvme
->BaseMem
));
1735 DEBUG ((DEBUG_INFO
, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa
.Asqs
));
1736 DEBUG ((DEBUG_INFO
, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa
.Acqs
));
1737 DEBUG ((DEBUG_INFO
, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Nvme
->SqBuffer
[0]));
1738 DEBUG ((DEBUG_INFO
, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Nvme
->CqBuffer
[0]));
1739 DEBUG ((DEBUG_INFO
, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Nvme
->SqBuffer
[1]));
1740 DEBUG ((DEBUG_INFO
, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Nvme
->CqBuffer
[1]));
1743 /// Program admin queue attributes.
1745 Status
= NVME_SET_AQA (Nvme
, &Aqa
);
1746 if (EFI_ERROR(Status
)) {
1751 /// Program admin submission queue address.
1753 Status
= NVME_SET_ASQ (Nvme
, &Asq
);
1754 if (EFI_ERROR(Status
)) {
1759 /// Program admin completion queue address.
1761 Status
= NVME_SET_ACQ (Nvme
, &Acq
);
1762 if (EFI_ERROR(Status
)) {
1766 Status
= NvmeEnableController (Nvme
);
1767 if (EFI_ERROR(Status
)) {
1772 /// Create one I/O completion queue.
1774 Status
= NvmeCreateIoCompletionQueue (Nvme
);
1775 if (EFI_ERROR(Status
)) {
1780 /// Create one I/O Submission queue.
1782 Status
= NvmeCreateIoSubmissionQueue (Nvme
);
1783 if (EFI_ERROR(Status
)) {
1788 /// Get current Identify Controller Data
1790 Nvme
->ControllerData
= (NVME_ADMIN_CONTROLLER_DATA
*)(UINTN
) NVME_CONTROL_DATA_BASE (Nvme
);
1791 Status
= NvmeIdentifyController (Nvme
, Nvme
->ControllerData
);
1792 if (EFI_ERROR(Status
)) {
1797 /// Dump NvmExpress Identify Controller Data
1799 Nvme
->ControllerData
->Sn
[19] = 0;
1800 Nvme
->ControllerData
->Mn
[39] = 0;
1801 //NvmeDumpIdentifyController (Nvme->ControllerData);
1804 /// Get current Identify Namespace Data
1806 Nvme
->NamespaceData
= (NVME_ADMIN_NAMESPACE_DATA
*)NVME_NAMESPACE_DATA_BASE (Nvme
);
1807 Status
= NvmeIdentifyNamespace (Nvme
, Nvme
->Nsid
, Nvme
->NamespaceData
);
1808 if (EFI_ERROR(Status
)) {
1809 DEBUG ((DEBUG_ERROR
, "NvmeIdentifyNamespace fail, Status = %r\n", Status
));
1814 /// Dump NvmExpress Identify Namespace Data
1816 if (Nvme
->NamespaceData
->Ncap
== 0) {
1817 DEBUG ((DEBUG_ERROR
, "Invalid Namespace, Ncap: %lx\n", Nvme
->NamespaceData
->Ncap
));
1818 Status
= EFI_DEVICE_ERROR
;
1822 Nvme
->BlockSize
= NvmeGetBlockSize (Nvme
);
1823 Nvme
->LastBlock
= NvmeGetLastLba (Nvme
);
1825 Nvme
->State
= NvmeStatusInit
;
1834 Un-initialize the Nvm Express controller.
1836 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1838 @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.
1839 @retval Others - A device error occurred while un-initializing the controller.
1843 NvmeControllerExit (
1844 IN NVME_CONTEXT
*Nvme
1849 Status
= EFI_SUCCESS
;
1850 if (Nvme
->State
== NvmeStatusInit
|| Nvme
->State
== NvmeStatusMax
) {
1852 /// Destroy I/O Submission queue.
1854 Status
= NvmeDestroyIoSubmissionQueue (Nvme
);
1855 if (EFI_ERROR(Status
)) {
1856 DEBUG ((DEBUG_ERROR
, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status
));
1861 /// Destroy I/O completion queue.
1863 Status
= NvmeDestroyIoCompletionQueue (Nvme
);
1864 if (EFI_ERROR(Status
)) {
1865 DEBUG ((DEBUG_ERROR
, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status
));
1869 Status
= NvmeShutdownController (Nvme
);
1870 if (EFI_ERROR(Status
)) {
1871 DEBUG ((DEBUG_ERROR
, "NvmeShutdownController fail, Status: %r\n", Status
));
1876 /// Disable PCIE decode
1878 PciWrite8 (Nvme
->PciBase
+ NVME_PCIE_PCICMD
, 0x0);
1879 PciWrite32 (Nvme
->PciBase
+ 0x10, 0); // MLBAR (BAR0)
1880 PciWrite32 (Nvme
->PciBase
+ 0x14, 0); // MUBAR (BAR1)
1882 Nvme
->State
= NvmeStatusUnknown
;
1887 Read sector Data from the NVMe device.
1889 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1890 @param[in,out] Buffer - The Buffer used to store the Data read from the device.
1891 @param[in] Lba - The start block number.
1892 @param[in] Blocks - Total block number to be read.
1894 @retval EFI_SUCCESS - Datum are read from the device.
1895 @retval Others - Fail to read all the datum.
1900 IN NVME_CONTEXT
*Nvme
,
1901 IN OUT UINT64 Buffer
,
1907 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1908 NVM_EXPRESS_COMMAND Command
;
1909 NVM_EXPRESS_RESPONSE Response
;
1913 BlockSize
= Nvme
->BlockSize
;
1914 Bytes
= Blocks
* BlockSize
;
1916 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1917 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1918 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1920 CommandPacket
.NvmeCmd
= &Command
;
1921 CommandPacket
.NvmeResponse
= &Response
;
1923 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_READ_OPC
;
1924 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Nvme
->Cid
[NVME_IO_QUEUE
]++;
1925 CommandPacket
.NvmeCmd
->Nsid
= Nvme
->Nsid
;
1926 CommandPacket
.TransferBuffer
= Buffer
;
1928 CommandPacket
.TransferLength
= Bytes
;
1929 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1930 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
1932 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
1933 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(RShiftU64 (Lba
, 32));
1934 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
1936 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
1938 Status
= NvmePassThru (
1949 Write sector Data to the NVMe device.
1951 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
1952 @param[in] Buffer - The Buffer to be written into the device.
1953 @param[in] Lba - The start block number.
1954 @param[in] Blocks - Total block number to be written.
1956 @retval EFI_SUCCESS - Datum are written into the Buffer.
1957 @retval Others - Fail to write all the datum.
1962 IN NVME_CONTEXT
*Nvme
,
1968 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
1969 NVM_EXPRESS_COMMAND Command
;
1970 NVM_EXPRESS_RESPONSE Response
;
1975 BlockSize
= Nvme
->BlockSize
;
1976 Bytes
= Blocks
* BlockSize
;
1978 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
1979 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
1980 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
1982 CommandPacket
.NvmeCmd
= &Command
;
1983 CommandPacket
.NvmeResponse
= &Response
;
1985 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_WRITE_OPC
;
1986 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Nvme
->Cid
[NVME_IO_QUEUE
]++;
1987 CommandPacket
.NvmeCmd
->Nsid
= Nvme
->Nsid
;
1988 CommandPacket
.TransferBuffer
= Buffer
;
1990 CommandPacket
.TransferLength
= Bytes
;
1991 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
1992 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
1994 CommandPacket
.NvmeCmd
->Cdw10
= (UINT32
)Lba
;
1995 CommandPacket
.NvmeCmd
->Cdw11
= (UINT32
)(RShiftU64 (Lba
, 32));
1996 CommandPacket
.NvmeCmd
->Cdw12
= (Blocks
- 1) & 0xFFFF;
1998 CommandPacket
.MetadataBuffer
= (UINT64
)(UINTN
)NULL
;
1999 CommandPacket
.MetadataLength
= 0;
2001 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
| CDW12_VALID
;
2003 Status
= NvmePassThru (
2014 Flushes all modified Data to the device.
2016 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
2018 @retval EFI_SUCCESS - Datum are written into the Buffer.
2019 @retval Others - Fail to write all the datum.
2024 IN NVME_CONTEXT
*Nvme
2027 NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
2028 NVM_EXPRESS_COMMAND Command
;
2029 NVM_EXPRESS_RESPONSE Response
;
2032 ZeroMem (&CommandPacket
, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
2033 ZeroMem (&Command
, sizeof(NVM_EXPRESS_COMMAND
));
2034 ZeroMem (&Response
, sizeof(NVM_EXPRESS_RESPONSE
));
2036 CommandPacket
.NvmeCmd
= &Command
;
2037 CommandPacket
.NvmeResponse
= &Response
;
2039 CommandPacket
.NvmeCmd
->Cdw0
.Opcode
= NVME_IO_FLUSH_OPC
;
2040 CommandPacket
.NvmeCmd
->Cdw0
.Cid
= Nvme
->Cid
[NVME_IO_QUEUE
]++;
2041 CommandPacket
.NvmeCmd
->Nsid
= Nvme
->Nsid
;
2042 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
2043 CommandPacket
.QueueId
= NVME_IO_QUEUE
;
2045 Status
= NvmePassThru (
2051 if (!EFI_ERROR (Status
)) {
2052 Status
= NvmeWaitAllComplete (Nvme
, CommandPacket
.QueueId
);
2059 Read some blocks from the device.
2061 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
2062 @param[out] Buffer - The Buffer used to store the Data read from the device.
2063 @param[in] Lba - The start block number.
2064 @param[in] Blocks - Total block number to be read.
2066 @retval EFI_SUCCESS - Datum are read from the device.
2067 @retval Others - Fail to read all the datum.
2072 IN NVME_CONTEXT
*Nvme
,
2080 UINT32 MaxTransferBlocks
;
2082 ASSERT (Blocks
<= NVME_MAX_SECTORS
);
2083 Status
= EFI_SUCCESS
;
2084 BlockSize
= Nvme
->BlockSize
;
2085 if (Nvme
->ControllerData
->Mdts
!= 0) {
2086 MaxTransferBlocks
= (1 << (Nvme
->ControllerData
->Mdts
)) * (1 << (Nvme
->Cap
.Mpsmin
+ 12)) / BlockSize
;
2088 MaxTransferBlocks
= 1024;
2091 while (Blocks
> 0) {
2092 if (Blocks
> MaxTransferBlocks
) {
2093 Status
= NvmeReadSectors (Nvme
, Buffer
, Lba
, MaxTransferBlocks
);
2095 Blocks
-= MaxTransferBlocks
;
2096 Buffer
+= (MaxTransferBlocks
* BlockSize
);
2097 Lba
+= MaxTransferBlocks
;
2099 Status
= NvmeReadSectors (Nvme
, Buffer
, Lba
, (UINT32
) Blocks
);
2103 if (EFI_ERROR(Status
)) {
2104 DEBUG ((DEBUG_ERROR
, "NvmeRead fail, Status = %r\n", Status
));
2113 Write some blocks to the device.
2115 @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
2116 @param[in] Buffer - The Buffer to be written into the device.
2117 @param[in] Lba - The start block number.
2118 @param[in] Blocks - Total block number to be written.
2120 @retval EFI_SUCCESS - Datum are written into the Buffer.
2121 @retval Others - Fail to write all the datum.
2126 IN NVME_CONTEXT
*Nvme
,
2134 UINT32 MaxTransferBlocks
;
2136 ASSERT (Blocks
<= NVME_MAX_SECTORS
);
2137 Status
= EFI_SUCCESS
;
2138 BlockSize
= Nvme
->BlockSize
;
2140 if (Nvme
->ControllerData
->Mdts
!= 0) {
2141 MaxTransferBlocks
= (1 << (Nvme
->ControllerData
->Mdts
)) * (1 << (Nvme
->Cap
.Mpsmin
+ 12)) / BlockSize
;
2143 MaxTransferBlocks
= 1024;
2146 while (Blocks
> 0) {
2147 if (Blocks
> MaxTransferBlocks
) {
2148 Status
= NvmeWriteSectors (Nvme
, Buffer
, Lba
, MaxTransferBlocks
);
2150 Blocks
-= MaxTransferBlocks
;
2151 Buffer
+= (MaxTransferBlocks
* BlockSize
);
2152 Lba
+= MaxTransferBlocks
;
2154 Status
= NvmeWriteSectors (Nvme
, Buffer
, Lba
, (UINT32
) Blocks
);
2158 if (EFI_ERROR(Status
)) {
2159 DEBUG ((DEBUG_ERROR
, "NvmeWrite fail, Status = %r\n", Status
));