2 The NvmExpressPei driver is used to manage non-volatile memory subsystem
3 which follows NVM Express specification at PEI phase.
5 Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "NvmExpressPei.h"
14 Create PRP lists for Data transfer which is larger than 2 memory pages.
16 @param[in] Private The pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA data structure.
17 @param[in] PhysicalAddr The physical base address of Data Buffer.
18 @param[in] Pages The number of pages to be transfered.
20 @retval The pointer Value to the first PRP List of the PRP lists.
25 IN PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
26 IN EFI_PHYSICAL_ADDRESS PhysicalAddr
,
37 EFI_PHYSICAL_ADDRESS PrpListPhyAddr
;
40 EFI_PHYSICAL_ADDRESS NewPhyAddr
;
43 // The number of Prp Entry in a memory page.
45 PrpEntryNo
= EFI_PAGE_SIZE
/ sizeof (UINT64
);
48 // Calculate total PrpList number.
50 PrpListNo
= (UINTN
) DivU64x64Remainder ((UINT64
)Pages
, (UINT64
)PrpEntryNo
, &Remainder
);
55 if (PrpListNo
> NVME_PRP_SIZE
) {
58 "%a: The implementation only supports PrpList number up to 4."
59 " But %d are needed here.\n",
65 PrpListHost
= (VOID
*)(UINTN
) NVME_PRP_BASE (Private
);
67 Bytes
= EFI_PAGES_TO_SIZE (PrpListNo
);
68 PrpListPhyAddr
= (UINT64
)(UINTN
)(PrpListHost
);
71 // Fill all PRP lists except of last one.
73 ZeroMem (PrpListHost
, Bytes
);
74 for (PrpListIndex
= 0; PrpListIndex
< PrpListNo
- 1; ++PrpListIndex
) {
75 PrpListBase
= (UINTN
)PrpListHost
+ PrpListIndex
* EFI_PAGE_SIZE
;
77 for (PrpEntryIndex
= 0; PrpEntryIndex
< PrpEntryNo
; ++PrpEntryIndex
) {
78 PrpEntry
= (UINT8
*)(UINTN
) (PrpListBase
+ PrpEntryIndex
* sizeof(UINT64
));
79 if (PrpEntryIndex
!= PrpEntryNo
- 1) {
81 // Fill all PRP entries except of last one.
83 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&PhysicalAddr
), sizeof (UINT64
));
84 PhysicalAddr
+= EFI_PAGE_SIZE
;
87 // Fill last PRP entries with next PRP List pointer.
89 NewPhyAddr
= (PrpListPhyAddr
+ (PrpListIndex
+ 1) * EFI_PAGE_SIZE
);
90 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&NewPhyAddr
), sizeof (UINT64
));
96 // Fill last PRP list.
98 PrpListBase
= (UINTN
)PrpListHost
+ PrpListIndex
* EFI_PAGE_SIZE
;
99 for (PrpEntryIndex
= 0; PrpEntryIndex
< ((Remainder
!= 0) ? Remainder
: PrpEntryNo
); ++PrpEntryIndex
) {
100 PrpEntry
= (UINT8
*)(UINTN
) (PrpListBase
+ PrpEntryIndex
* sizeof(UINT64
));
101 CopyMem (PrpEntry
, (VOID
*)(UINTN
) (&PhysicalAddr
), sizeof (UINT64
));
103 PhysicalAddr
+= EFI_PAGE_SIZE
;
106 return PrpListPhyAddr
;
110 Check the execution status from a given completion queue entry.
112 @param[in] Cq A pointer to the NVME_CQ item.
120 if (Cq
->Sct
== 0x0 && Cq
->Sc
== 0x0) {
124 DEBUG ((DEBUG_INFO
, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN
)Cq
));
127 " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n",
132 DEBUG ((DEBUG_INFO
, " Status Code Type : [0x%x], Status Code : [0x%x]\n", Cq
->Sct
, Cq
->Sc
));
133 DEBUG ((DEBUG_INFO
, " NVMe Cmd Execution Result - "));
139 DEBUG ((DEBUG_INFO
, "Successful Completion\n"));
142 DEBUG ((DEBUG_INFO
, "Invalid Command Opcode\n"));
145 DEBUG ((DEBUG_INFO
, "Invalid Field in Command\n"));
148 DEBUG ((DEBUG_INFO
, "Command ID Conflict\n"));
151 DEBUG ((DEBUG_INFO
, "Data Transfer Error\n"));
154 DEBUG ((DEBUG_INFO
, "Commands Aborted due to Power Loss Notification\n"));
157 DEBUG ((DEBUG_INFO
, "Internal Device Error\n"));
160 DEBUG ((DEBUG_INFO
, "Command Abort Requested\n"));
163 DEBUG ((DEBUG_INFO
, "Command Aborted due to SQ Deletion\n"));
166 DEBUG ((DEBUG_INFO
, "Command Aborted due to Failed Fused Command\n"));
169 DEBUG ((DEBUG_INFO
, "Command Aborted due to Missing Fused Command\n"));
172 DEBUG ((DEBUG_INFO
, "Invalid Namespace or Format\n"));
175 DEBUG ((DEBUG_INFO
, "Command Sequence Error\n"));
178 DEBUG ((DEBUG_INFO
, "Invalid SGL Last Segment Descriptor\n"));
181 DEBUG ((DEBUG_INFO
, "Invalid Number of SGL Descriptors\n"));
184 DEBUG ((DEBUG_INFO
, "Data SGL Length Invalid\n"));
187 DEBUG ((DEBUG_INFO
, "Metadata SGL Length Invalid\n"));
190 DEBUG ((DEBUG_INFO
, "SGL Descriptor Type Invalid\n"));
193 DEBUG ((DEBUG_INFO
, "LBA Out of Range\n"));
196 DEBUG ((DEBUG_INFO
, "Capacity Exceeded\n"));
199 DEBUG ((DEBUG_INFO
, "Namespace Not Ready\n"));
202 DEBUG ((DEBUG_INFO
, "Reservation Conflict\n"));
210 DEBUG ((DEBUG_INFO
, "Completion Queue Invalid\n"));
213 DEBUG ((DEBUG_INFO
, "Invalid Queue Identifier\n"));
216 DEBUG ((DEBUG_INFO
, "Maximum Queue Size Exceeded\n"));
219 DEBUG ((DEBUG_INFO
, "Abort Command Limit Exceeded\n"));
222 DEBUG ((DEBUG_INFO
, "Asynchronous Event Request Limit Exceeded\n"));
225 DEBUG ((DEBUG_INFO
, "Invalid Firmware Slot\n"));
228 DEBUG ((DEBUG_INFO
, "Invalid Firmware Image\n"));
231 DEBUG ((DEBUG_INFO
, "Invalid Interrupt Vector\n"));
234 DEBUG ((DEBUG_INFO
, "Invalid Log Page\n"));
237 DEBUG ((DEBUG_INFO
, "Invalid Format\n"));
240 DEBUG ((DEBUG_INFO
, "Firmware Application Requires Conventional Reset\n"));
243 DEBUG ((DEBUG_INFO
, "Invalid Queue Deletion\n"));
246 DEBUG ((DEBUG_INFO
, "Feature Identifier Not Saveable\n"));
249 DEBUG ((DEBUG_INFO
, "Feature Not Changeable\n"));
252 DEBUG ((DEBUG_INFO
, "Feature Not Namespace Specific\n"));
255 DEBUG ((DEBUG_INFO
, "Firmware Application Requires NVM Subsystem Reset\n"));
258 DEBUG ((DEBUG_INFO
, "Conflicting Attributes\n"));
261 DEBUG ((DEBUG_INFO
, "Invalid Protection Information\n"));
264 DEBUG ((DEBUG_INFO
, "Attempted Write to Read Only Range\n"));
272 DEBUG ((DEBUG_INFO
, "Write Fault\n"));
275 DEBUG ((DEBUG_INFO
, "Unrecovered Read Error\n"));
278 DEBUG ((DEBUG_INFO
, "End-to-end Guard Check Error\n"));
281 DEBUG ((DEBUG_INFO
, "End-to-end Application Tag Check Error\n"));
284 DEBUG ((DEBUG_INFO
, "End-to-end Reference Tag Check Error\n"));
287 DEBUG ((DEBUG_INFO
, "Compare Failure\n"));
290 DEBUG ((DEBUG_INFO
, "Access Denied\n"));
296 DEBUG ((DEBUG_INFO
, "Unknown error\n"));
300 return EFI_DEVICE_ERROR
;
304 Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
305 supports blocking execution of the command.
307 @param[in] Private The pointer to the NVME_CONTEXT Data structure.
308 @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will
310 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
311 the namespace ID specifies that the command packet should be sent to all
313 @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
314 to the NVMe namespace specified by NamespaceId.
316 @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
317 TransferLength bytes were transferred to, or from DataBuffer.
318 @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
319 the controller is not ready. The caller may retry again later.
320 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
321 Express Command Packet.
322 @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
324 The EDKII PEI NVM Express Command Packet was not sent, so no
325 additional status information is available.
326 @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
327 is not supported by the host adapter.
328 The EDKII PEI NVM Express Command Packet was not sent, so no
329 additional status information is available.
330 @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
335 NvmePassThruExecute (
336 IN PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
,
337 IN UINT32 NamespaceId
,
338 IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
*Packet
347 EDKII_IOMMU_OPERATION MapOp
;
349 EFI_PHYSICAL_ADDRESS PhyAddr
;
358 // Check the data fields in Packet parameter
360 if (Packet
== NULL
) {
363 "%a, Invalid parameter: Packet(%lx)\n",
367 return EFI_INVALID_PARAMETER
;
370 if ((Packet
->NvmeCmd
== NULL
) || (Packet
->NvmeCompletion
== NULL
)) {
373 "%a, Invalid parameter: NvmeCmd (%lx)/NvmeCompletion(%lx)\n",
375 (UINTN
)Packet
->NvmeCmd
,
376 (UINTN
)Packet
->NvmeCompletion
378 return EFI_INVALID_PARAMETER
;
381 if (Packet
->QueueType
!= NVME_ADMIN_QUEUE
&& Packet
->QueueType
!= NVME_IO_QUEUE
) {
384 "%a, Invalid parameter: QueueId(%lx)\n",
386 (UINTN
)Packet
->QueueType
388 return EFI_INVALID_PARAMETER
;
391 QueueId
= Packet
->QueueType
;
392 Sq
= Private
->SqBuffer
[QueueId
] + Private
->SqTdbl
[QueueId
].Sqt
;
393 Cq
= Private
->CqBuffer
[QueueId
] + Private
->CqHdbl
[QueueId
].Cqh
;
394 if (QueueId
== NVME_ADMIN_QUEUE
) {
395 SqSize
= NVME_ASQ_SIZE
+ 1;
396 CqSize
= NVME_ACQ_SIZE
+ 1;
398 SqSize
= NVME_CSQ_SIZE
+ 1;
399 CqSize
= NVME_CCQ_SIZE
+ 1;
402 if (Packet
->NvmeCmd
->Nsid
!= NamespaceId
) {
405 "%a: Nsid mismatch (%x, %x)\n",
407 Packet
->NvmeCmd
->Nsid
,
410 return EFI_INVALID_PARAMETER
;
413 ZeroMem (Sq
, sizeof (NVME_SQ
));
414 Sq
->Opc
= (UINT8
)Packet
->NvmeCmd
->Cdw0
.Opcode
;
415 Sq
->Fuse
= (UINT8
)Packet
->NvmeCmd
->Cdw0
.FusedOperation
;
416 Sq
->Cid
= Private
->Cid
[QueueId
]++;;
417 Sq
->Nsid
= Packet
->NvmeCmd
->Nsid
;
420 // Currently we only support PRP for data transfer, SGL is NOT supported
422 ASSERT (Sq
->Psdt
== 0);
424 DEBUG ((DEBUG_ERROR
, "%a: Does not support SGL mechanism.\n", __FUNCTION__
));
425 return EFI_UNSUPPORTED
;
428 Sq
->Prp
[0] = (UINT64
)(UINTN
)Packet
->TransferBuffer
;
432 Status
= EFI_SUCCESS
;
434 // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller
435 // specific addresses.
437 if ((Sq
->Opc
& (BIT0
| BIT1
)) != 0) {
438 if (((Packet
->TransferLength
!= 0) && (Packet
->TransferBuffer
== NULL
)) ||
439 ((Packet
->TransferLength
== 0) && (Packet
->TransferBuffer
!= NULL
))) {
440 return EFI_INVALID_PARAMETER
;
444 // Currently, we only support creating IO submission/completion queues that are
445 // allocated internally by the driver.
447 if ((Packet
->QueueType
== NVME_ADMIN_QUEUE
) &&
448 ((Sq
->Opc
== NVME_ADMIN_CRIOCQ_CMD
) || (Sq
->Opc
== NVME_ADMIN_CRIOSQ_CMD
))) {
449 if ((Packet
->TransferBuffer
!= Private
->SqBuffer
[NVME_IO_QUEUE
]) &&
450 (Packet
->TransferBuffer
!= Private
->CqBuffer
[NVME_IO_QUEUE
])) {
453 "%a: Does not support external IO queues creation request.\n",
456 return EFI_UNSUPPORTED
;
459 if ((Sq
->Opc
& BIT0
) != 0) {
460 MapOp
= EdkiiIoMmuOperationBusMasterRead
;
462 MapOp
= EdkiiIoMmuOperationBusMasterWrite
;
465 if ((Packet
->TransferLength
!= 0) && (Packet
->TransferBuffer
!= NULL
)) {
466 MapLength
= Packet
->TransferLength
;
469 Packet
->TransferBuffer
,
474 if (EFI_ERROR (Status
) || (MapLength
!= Packet
->TransferLength
)) {
475 Status
= EFI_OUT_OF_RESOURCES
;
476 DEBUG ((DEBUG_ERROR
, "%a: Fail to map data buffer.\n", __FUNCTION__
));
480 Sq
->Prp
[0] = PhyAddr
;
483 if((Packet
->MetadataLength
!= 0) && (Packet
->MetadataBuffer
!= NULL
)) {
484 MapLength
= Packet
->MetadataLength
;
487 Packet
->MetadataBuffer
,
492 if (EFI_ERROR (Status
) || (MapLength
!= Packet
->MetadataLength
)) {
493 Status
= EFI_OUT_OF_RESOURCES
;
494 DEBUG ((DEBUG_ERROR
, "%a: Fail to map meta data buffer.\n", __FUNCTION__
));
503 // If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
504 // then build a PRP list in the second PRP submission queue entry.
506 Offset
= ((UINT32
)Sq
->Prp
[0]) & (EFI_PAGE_SIZE
- 1);
507 Bytes
= Packet
->TransferLength
;
509 if ((Offset
+ Bytes
) > (EFI_PAGE_SIZE
* 2)) {
511 // Create PrpList for remaining Data Buffer.
513 PhyAddr
= (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
514 Sq
->Prp
[1] = NvmeCreatePrpList (
517 EFI_SIZE_TO_PAGES(Offset
+ Bytes
) - 1
519 if (Sq
->Prp
[1] == 0) {
520 Status
= EFI_OUT_OF_RESOURCES
;
521 DEBUG ((DEBUG_ERROR
, "%a: Create PRP list fail, Status - %r\n", __FUNCTION__
, Status
));
525 } else if ((Offset
+ Bytes
) > EFI_PAGE_SIZE
) {
526 Sq
->Prp
[1] = (Sq
->Prp
[0] + EFI_PAGE_SIZE
) & ~(EFI_PAGE_SIZE
- 1);
529 if (Packet
->NvmeCmd
->Flags
& CDW10_VALID
) {
530 Sq
->Payload
.Raw
.Cdw10
= Packet
->NvmeCmd
->Cdw10
;
532 if (Packet
->NvmeCmd
->Flags
& CDW11_VALID
) {
533 Sq
->Payload
.Raw
.Cdw11
= Packet
->NvmeCmd
->Cdw11
;
535 if (Packet
->NvmeCmd
->Flags
& CDW12_VALID
) {
536 Sq
->Payload
.Raw
.Cdw12
= Packet
->NvmeCmd
->Cdw12
;
538 if (Packet
->NvmeCmd
->Flags
& CDW13_VALID
) {
539 Sq
->Payload
.Raw
.Cdw13
= Packet
->NvmeCmd
->Cdw13
;
541 if (Packet
->NvmeCmd
->Flags
& CDW14_VALID
) {
542 Sq
->Payload
.Raw
.Cdw14
= Packet
->NvmeCmd
->Cdw14
;
544 if (Packet
->NvmeCmd
->Flags
& CDW15_VALID
) {
545 Sq
->Payload
.Raw
.Cdw15
= Packet
->NvmeCmd
->Cdw15
;
549 // Ring the submission queue doorbell.
551 Private
->SqTdbl
[QueueId
].Sqt
++;
552 if (Private
->SqTdbl
[QueueId
].Sqt
== SqSize
) {
553 Private
->SqTdbl
[QueueId
].Sqt
= 0;
555 Data32
= ReadUnaligned32 ((UINT32
*)&Private
->SqTdbl
[QueueId
]);
556 Status
= NVME_SET_SQTDBL (Private
, QueueId
, &Data32
);
557 if (EFI_ERROR (Status
)) {
558 DEBUG ((DEBUG_ERROR
, "%a: NVME_SET_SQTDBL fail, Status - %r\n", __FUNCTION__
, Status
));
563 // Wait for completion queue to get filled in.
565 Status
= EFI_TIMEOUT
;
567 while (Timer
< Packet
->CommandTimeout
) {
568 if (Cq
->Pt
!= Private
->Pt
[QueueId
]) {
569 Status
= EFI_SUCCESS
;
573 MicroSecondDelay (NVME_POLL_INTERVAL
);
574 Timer
+= NVME_POLL_INTERVAL
;
577 if (Status
== EFI_TIMEOUT
) {
579 // Timeout occurs for an NVMe command, reset the controller to abort the outstanding command
581 DEBUG ((DEBUG_ERROR
, "%a: Timeout occurs for the PassThru command.\n", __FUNCTION__
));
582 Status
= NvmeControllerInit (Private
);
583 if (EFI_ERROR (Status
)) {
584 Status
= EFI_DEVICE_ERROR
;
587 // Return EFI_TIMEOUT to indicate a timeout occurs for PassThru command
589 Status
= EFI_TIMEOUT
;
595 // Move forward the Completion Queue head
597 Private
->CqHdbl
[QueueId
].Cqh
++;
598 if (Private
->CqHdbl
[QueueId
].Cqh
== CqSize
) {
599 Private
->CqHdbl
[QueueId
].Cqh
= 0;
600 Private
->Pt
[QueueId
] ^= 1;
604 // Copy the Respose Queue entry for this command to the callers response buffer
606 CopyMem (Packet
->NvmeCompletion
, Cq
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
609 // Check the NVMe cmd execution result
611 Status
= NvmeCheckCqStatus (Cq
);
612 NVME_SET_CQHDBL (Private
, QueueId
, &Private
->CqHdbl
[QueueId
]);
615 if (MapMeta
!= NULL
) {
616 IoMmuUnmap (MapMeta
);
619 if (MapData
!= NULL
) {
620 IoMmuUnmap (MapData
);
627 Gets the device path information of the underlying NVM Express host controller.
629 @param[in] This The PPI instance pointer.
630 @param[out] DevicePathLength The length of the device path in bytes specified
632 @param[out] DevicePath The device path of the underlying NVM Express
634 This field re-uses EFI Device Path Protocol as
635 defined by Section 10.2 EFI Device Path Protocol
636 of UEFI 2.7 Specification.
638 @retval EFI_SUCCESS The operation succeeds.
639 @retval EFI_INVALID_PARAMETER DevicePathLength or DevicePath is NULL.
640 @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources.
645 NvmePassThruGetDevicePath (
646 IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI
*This
,
647 OUT UINTN
*DevicePathLength
,
648 OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
651 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
653 if (This
== NULL
|| DevicePathLength
== NULL
|| DevicePath
== NULL
) {
654 return EFI_INVALID_PARAMETER
;
657 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This
);
659 *DevicePathLength
= Private
->DevicePathLength
;
660 *DevicePath
= AllocateCopyPool (Private
->DevicePathLength
, Private
->DevicePath
);
661 if (*DevicePath
== NULL
) {
662 *DevicePathLength
= 0;
663 return EFI_OUT_OF_RESOURCES
;
670 Used to retrieve the next namespace ID for this NVM Express controller.
672 If on input the value pointed to by NamespaceId is 0xFFFFFFFF, then the first
673 valid namespace ID defined on the NVM Express controller is returned in the
674 location pointed to by NamespaceId and a status of EFI_SUCCESS is returned.
676 If on input the value pointed to by NamespaceId is an invalid namespace ID
677 other than 0xFFFFFFFF, then EFI_INVALID_PARAMETER is returned.
679 If on input the value pointed to by NamespaceId is a valid namespace ID, then
680 the next valid namespace ID on the NVM Express controller is returned in the
681 location pointed to by NamespaceId, and EFI_SUCCESS is returned.
683 If the value pointed to by NamespaceId is the namespace ID of the last
684 namespace on the NVM Express controller, then EFI_NOT_FOUND is returned.
686 @param[in] This The PPI instance pointer.
687 @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId
688 for an NVM Express namespace present on the
689 NVM Express controller. On output, a pointer
690 to the next NamespaceId of an NVM Express
691 namespace on an NVM Express controller. An
692 input value of 0xFFFFFFFF retrieves the
693 first NamespaceId for an NVM Express
694 namespace present on an NVM Express
697 @retval EFI_SUCCESS The Namespace ID of the next Namespace was
699 @retval EFI_NOT_FOUND There are no more namespaces defined on this
701 @retval EFI_INVALID_PARAMETER NamespaceId is an invalid value other than
707 NvmePassThruGetNextNameSpace (
708 IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI
*This
,
709 IN OUT UINT32
*NamespaceId
712 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
716 if (This
== NULL
|| NamespaceId
== NULL
) {
717 return EFI_INVALID_PARAMETER
;
720 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This
);
722 Status
= EFI_NOT_FOUND
;
725 // If active namespace number is 0, then valid namespace ID is unavailable
727 if (Private
->ActiveNamespaceNum
== 0) {
728 return EFI_NOT_FOUND
;
732 // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID
734 if (*NamespaceId
== 0xFFFFFFFF) {
736 // Start with the first namespace ID
738 *NamespaceId
= Private
->NamespaceInfo
[0].NamespaceId
;
739 Status
= EFI_SUCCESS
;
741 if (*NamespaceId
> Private
->ControllerData
->Nn
) {
742 return EFI_INVALID_PARAMETER
;
745 if ((*NamespaceId
+ 1) > Private
->ControllerData
->Nn
) {
746 return EFI_NOT_FOUND
;
749 for (DeviceIndex
= 0; DeviceIndex
< Private
->ActiveNamespaceNum
; DeviceIndex
++) {
750 if (*NamespaceId
== Private
->NamespaceInfo
[DeviceIndex
].NamespaceId
) {
751 if ((DeviceIndex
+ 1) < Private
->ActiveNamespaceNum
) {
752 *NamespaceId
= Private
->NamespaceInfo
[DeviceIndex
+ 1].NamespaceId
;
753 Status
= EFI_SUCCESS
;
765 Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function only
766 supports blocking execution of the command.
768 @param[in] This The PPI instance pointer.
769 @param[in] NamespaceId Is a 32 bit Namespace ID to which the Nvm Express command packet will
771 A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in
772 the namespace ID specifies that the command packet should be sent to all
774 @param[in,out] Packet A pointer to the EDKII PEI NVM Express PassThru Command Packet to send
775 to the NVMe namespace specified by NamespaceId.
777 @retval EFI_SUCCESS The EDKII PEI NVM Express Command Packet was sent by the host.
778 TransferLength bytes were transferred to, or from DataBuffer.
779 @retval EFI_NOT_READY The EDKII PEI NVM Express Command Packet could not be sent because
780 the controller is not ready. The caller may retry again later.
781 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the EDKII PEI NVM
782 Express Command Packet.
783 @retval EFI_INVALID_PARAMETER Namespace, or the contents of EDKII_PEI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
785 The EDKII PEI NVM Express Command Packet was not sent, so no
786 additional status information is available.
787 @retval EFI_UNSUPPORTED The command described by the EDKII PEI NVM Express Command Packet
788 is not supported by the host adapter.
789 The EDKII PEI NVM Express Command Packet was not sent, so no
790 additional status information is available.
791 @retval EFI_TIMEOUT A timeout occurred while waiting for the EDKII PEI NVM Express Command
798 IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI
*This
,
799 IN UINT32 NamespaceId
,
800 IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
*Packet
803 PEI_NVME_CONTROLLER_PRIVATE_DATA
*Private
;
806 if (This
== NULL
|| Packet
== NULL
) {
807 return EFI_INVALID_PARAMETER
;
810 Private
= GET_NVME_PEIM_HC_PRIVATE_DATA_FROM_THIS_NVME_PASSTHRU (This
);
812 // Check NamespaceId is valid or not.
814 if ((NamespaceId
> Private
->ControllerData
->Nn
) &&
815 (NamespaceId
!= (UINT32
) -1)) {
816 return EFI_INVALID_PARAMETER
;
819 Status
= NvmePassThruExecute (