2 NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
3 NVM Express specification.
5 Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "NvmExpress.h"
12 #define NVME_SHUTDOWN_PROCESS_TIMEOUT 45
15 // The number of NVME controllers managed by this driver, used by
16 // NvmeRegisterShutdownNotification() and NvmeUnregisterShutdownNotification().
18 UINTN mNvmeControllerNumber
= 0;
21 Read Nvm Express controller capability register.
23 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
24 @param Cap The buffer used to store capability register content.
26 @return EFI_SUCCESS Successfully read the controller capability register content.
27 @return EFI_DEVICE_ERROR Fail to read the controller capability register.
31 ReadNvmeControllerCapabilities (
32 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
36 EFI_PCI_IO_PROTOCOL
*PciIo
;
40 PciIo
= Private
->PciIo
;
41 Status
= PciIo
->Mem
.Read (
50 if (EFI_ERROR (Status
)) {
54 WriteUnaligned64 ((UINT64
*)Cap
, Data
);
59 Read Nvm Express controller configuration register.
61 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
62 @param Cc The buffer used to store configuration register content.
64 @return EFI_SUCCESS Successfully read the controller configuration register content.
65 @return EFI_DEVICE_ERROR Fail to read the controller configuration register.
69 ReadNvmeControllerConfiguration (
70 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
74 EFI_PCI_IO_PROTOCOL
*PciIo
;
78 PciIo
= Private
->PciIo
;
79 Status
= PciIo
->Mem
.Read (
88 if (EFI_ERROR (Status
)) {
92 WriteUnaligned32 ((UINT32
*)Cc
, Data
);
97 Write Nvm Express controller configuration register.
99 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
100 @param Cc The buffer used to store the content to be written into configuration register.
102 @return EFI_SUCCESS Successfully write data into the controller configuration register.
103 @return EFI_DEVICE_ERROR Fail to write data into the controller configuration register.
107 WriteNvmeControllerConfiguration (
108 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
112 EFI_PCI_IO_PROTOCOL
*PciIo
;
116 PciIo
= Private
->PciIo
;
117 Data
= ReadUnaligned32 ((UINT32
*)Cc
);
118 Status
= PciIo
->Mem
.Write (
127 if (EFI_ERROR (Status
)) {
131 DEBUG ((DEBUG_INFO
, "Cc.En: %d\n", Cc
->En
));
132 DEBUG ((DEBUG_INFO
, "Cc.Css: %d\n", Cc
->Css
));
133 DEBUG ((DEBUG_INFO
, "Cc.Mps: %d\n", Cc
->Mps
));
134 DEBUG ((DEBUG_INFO
, "Cc.Ams: %d\n", Cc
->Ams
));
135 DEBUG ((DEBUG_INFO
, "Cc.Shn: %d\n", Cc
->Shn
));
136 DEBUG ((DEBUG_INFO
, "Cc.Iosqes: %d\n", Cc
->Iosqes
));
137 DEBUG ((DEBUG_INFO
, "Cc.Iocqes: %d\n", Cc
->Iocqes
));
143 Read Nvm Express controller status register.
145 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
146 @param Csts The buffer used to store status register content.
148 @return EFI_SUCCESS Successfully read the controller status register content.
149 @return EFI_DEVICE_ERROR Fail to read the controller status register.
153 ReadNvmeControllerStatus (
154 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
158 EFI_PCI_IO_PROTOCOL
*PciIo
;
162 PciIo
= Private
->PciIo
;
163 Status
= PciIo
->Mem
.Read (
172 if (EFI_ERROR (Status
)) {
176 WriteUnaligned32 ((UINT32
*)Csts
, Data
);
181 Write Nvm Express admin queue attributes register.
183 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
184 @param Aqa The buffer used to store the content to be written into admin queue attributes register.
186 @return EFI_SUCCESS Successfully write data into the admin queue attributes register.
187 @return EFI_DEVICE_ERROR Fail to write data into the admin queue attributes register.
191 WriteNvmeAdminQueueAttributes (
192 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
196 EFI_PCI_IO_PROTOCOL
*PciIo
;
200 PciIo
= Private
->PciIo
;
201 Data
= ReadUnaligned32 ((UINT32
*)Aqa
);
202 Status
= PciIo
->Mem
.Write (
211 if (EFI_ERROR (Status
)) {
215 DEBUG ((DEBUG_INFO
, "Aqa.Asqs: %d\n", Aqa
->Asqs
));
216 DEBUG ((DEBUG_INFO
, "Aqa.Acqs: %d\n", Aqa
->Acqs
));
222 Write Nvm Express admin submission queue base address register.
224 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
225 @param Asq The buffer used to store the content to be written into admin submission queue base address register.
227 @return EFI_SUCCESS Successfully write data into the admin submission queue base address register.
228 @return EFI_DEVICE_ERROR Fail to write data into the admin submission queue base address register.
232 WriteNvmeAdminSubmissionQueueBaseAddress (
233 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
237 EFI_PCI_IO_PROTOCOL
*PciIo
;
241 PciIo
= Private
->PciIo
;
242 Data
= ReadUnaligned64 ((UINT64
*)Asq
);
244 Status
= PciIo
->Mem
.Write (
253 if (EFI_ERROR (Status
)) {
257 DEBUG ((DEBUG_INFO
, "Asq: %lx\n", *Asq
));
263 Write Nvm Express admin completion queue base address register.
265 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
266 @param Acq The buffer used to store the content to be written into admin completion queue base address register.
268 @return EFI_SUCCESS Successfully write data into the admin completion queue base address register.
269 @return EFI_DEVICE_ERROR Fail to write data into the admin completion queue base address register.
273 WriteNvmeAdminCompletionQueueBaseAddress (
274 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
278 EFI_PCI_IO_PROTOCOL
*PciIo
;
282 PciIo
= Private
->PciIo
;
283 Data
= ReadUnaligned64 ((UINT64
*)Acq
);
285 Status
= PciIo
->Mem
.Write (
294 if (EFI_ERROR (Status
)) {
298 DEBUG ((DEBUG_INFO
, "Acq: %lxh\n", *Acq
));
304 Disable the Nvm Express controller.
306 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
308 @return EFI_SUCCESS Successfully disable the controller.
309 @return EFI_DEVICE_ERROR Fail to disable the controller.
313 NvmeDisableController (
314 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
324 // Read Controller Configuration Register.
326 Status
= ReadNvmeControllerConfiguration (Private
, &Cc
);
327 if (EFI_ERROR (Status
)) {
334 // Disable the controller.
336 Status
= WriteNvmeControllerConfiguration (Private
, &Cc
);
338 if (EFI_ERROR (Status
)) {
343 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to transition from 1 to 0 after
344 // Cc.Enable transition from 1 to 0. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
346 if (Private
->Cap
.To
== 0) {
349 Timeout
= Private
->Cap
.To
;
352 for (Index
= (Timeout
* 500); Index
!= 0; --Index
) {
356 // Check if the controller is initialized
358 Status
= ReadNvmeControllerStatus (Private
, &Csts
);
360 if (EFI_ERROR (Status
)) {
370 Status
= EFI_DEVICE_ERROR
;
372 (EFI_ERROR_CODE
| EFI_ERROR_MAJOR
),
373 (EFI_IO_BUS_SCSI
| EFI_IOB_EC_INTERFACE_ERROR
)
377 DEBUG ((DEBUG_INFO
, "NVMe controller is disabled with status [%r].\n", Status
));
382 Enable the Nvm Express controller.
384 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
386 @return EFI_SUCCESS Successfully enable the controller.
387 @return EFI_DEVICE_ERROR Fail to enable the controller.
388 @return EFI_TIMEOUT Fail to enable the controller in given time slot.
392 NvmeEnableController (
393 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
403 // Enable the controller.
404 // CC.AMS, CC.MPS and CC.CSS are all set to 0.
406 ZeroMem (&Cc
, sizeof (NVME_CC
));
411 Status
= WriteNvmeControllerConfiguration (Private
, &Cc
);
412 if (EFI_ERROR (Status
)) {
417 // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
418 // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
420 if (Private
->Cap
.To
== 0) {
423 Timeout
= Private
->Cap
.To
;
426 for (Index
= (Timeout
* 500); Index
!= 0; --Index
) {
430 // Check if the controller is initialized
432 Status
= ReadNvmeControllerStatus (Private
, &Csts
);
434 if (EFI_ERROR (Status
)) {
444 Status
= EFI_TIMEOUT
;
446 (EFI_ERROR_CODE
| EFI_ERROR_MAJOR
),
447 (EFI_IO_BUS_SCSI
| EFI_IOB_EC_INTERFACE_ERROR
)
451 DEBUG ((DEBUG_INFO
, "NVMe controller is enabled with status [%r].\n", Status
));
456 Get identify controller data.
458 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
459 @param Buffer The buffer used to store the identify controller data.
461 @return EFI_SUCCESS Successfully get the identify controller data.
462 @return EFI_DEVICE_ERROR Fail to get the identify controller data.
466 NvmeIdentifyController (
467 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
471 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
472 EFI_NVM_EXPRESS_COMMAND Command
;
473 EFI_NVM_EXPRESS_COMPLETION Completion
;
476 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
477 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
478 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
480 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
482 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
483 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
487 CommandPacket
.NvmeCmd
= &Command
;
488 CommandPacket
.NvmeCompletion
= &Completion
;
489 CommandPacket
.TransferBuffer
= Buffer
;
490 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_CONTROLLER_DATA
);
491 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
492 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
494 // Set bit 0 (Cns bit) to 1 to identify a controller
497 Command
.Flags
= CDW10_VALID
;
499 Status
= Private
->Passthru
.PassThru (
510 Get specified identify namespace data.
512 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
513 @param NamespaceId The specified namespace identifier.
514 @param Buffer The buffer used to store the identify namespace data.
516 @return EFI_SUCCESS Successfully get the identify namespace data.
517 @return EFI_DEVICE_ERROR Fail to get the identify namespace data.
521 NvmeIdentifyNamespace (
522 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
523 IN UINT32 NamespaceId
,
527 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
528 EFI_NVM_EXPRESS_COMMAND Command
;
529 EFI_NVM_EXPRESS_COMPLETION Completion
;
532 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
533 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
534 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
536 CommandPacket
.NvmeCmd
= &Command
;
537 CommandPacket
.NvmeCompletion
= &Completion
;
539 Command
.Cdw0
.Opcode
= NVME_ADMIN_IDENTIFY_CMD
;
540 Command
.Nsid
= NamespaceId
;
541 CommandPacket
.TransferBuffer
= Buffer
;
542 CommandPacket
.TransferLength
= sizeof (NVME_ADMIN_NAMESPACE_DATA
);
543 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
544 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
546 // Set bit 0 (Cns bit) to 1 to identify a namespace
548 CommandPacket
.NvmeCmd
->Cdw10
= 0;
549 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
;
551 Status
= Private
->Passthru
.PassThru (
562 Create io completion queue.
564 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
566 @return EFI_SUCCESS Successfully create io completion queue.
567 @return EFI_DEVICE_ERROR Fail to create io completion queue.
571 NvmeCreateIoCompletionQueue (
572 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
575 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
576 EFI_NVM_EXPRESS_COMMAND Command
;
577 EFI_NVM_EXPRESS_COMPLETION Completion
;
579 NVME_ADMIN_CRIOCQ CrIoCq
;
583 Status
= EFI_SUCCESS
;
584 Private
->CreateIoQueue
= TRUE
;
586 for (Index
= 1; Index
< NVME_MAX_QUEUES
; Index
++) {
587 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
588 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
589 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
590 ZeroMem (&CrIoCq
, sizeof (NVME_ADMIN_CRIOCQ
));
592 CommandPacket
.NvmeCmd
= &Command
;
593 CommandPacket
.NvmeCompletion
= &Completion
;
595 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOCQ_CMD
;
596 CommandPacket
.TransferBuffer
= Private
->CqBufferPciAddr
[Index
];
597 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
598 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
599 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
602 QueueSize
= NVME_CCQ_SIZE
;
604 if (Private
->Cap
.Mqes
> NVME_ASYNC_CCQ_SIZE
) {
605 QueueSize
= NVME_ASYNC_CCQ_SIZE
;
607 QueueSize
= Private
->Cap
.Mqes
;
612 CrIoCq
.Qsize
= QueueSize
;
614 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoCq
, sizeof (NVME_ADMIN_CRIOCQ
));
615 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
617 Status
= Private
->Passthru
.PassThru (
623 if (EFI_ERROR (Status
)) {
628 Private
->CreateIoQueue
= FALSE
;
634 Create io submission queue.
636 @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
638 @return EFI_SUCCESS Successfully create io submission queue.
639 @return EFI_DEVICE_ERROR Fail to create io submission queue.
643 NvmeCreateIoSubmissionQueue (
644 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
647 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket
;
648 EFI_NVM_EXPRESS_COMMAND Command
;
649 EFI_NVM_EXPRESS_COMPLETION Completion
;
651 NVME_ADMIN_CRIOSQ CrIoSq
;
655 Status
= EFI_SUCCESS
;
656 Private
->CreateIoQueue
= TRUE
;
658 for (Index
= 1; Index
< NVME_MAX_QUEUES
; Index
++) {
659 ZeroMem (&CommandPacket
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET
));
660 ZeroMem (&Command
, sizeof (EFI_NVM_EXPRESS_COMMAND
));
661 ZeroMem (&Completion
, sizeof (EFI_NVM_EXPRESS_COMPLETION
));
662 ZeroMem (&CrIoSq
, sizeof (NVME_ADMIN_CRIOSQ
));
664 CommandPacket
.NvmeCmd
= &Command
;
665 CommandPacket
.NvmeCompletion
= &Completion
;
667 Command
.Cdw0
.Opcode
= NVME_ADMIN_CRIOSQ_CMD
;
668 CommandPacket
.TransferBuffer
= Private
->SqBufferPciAddr
[Index
];
669 CommandPacket
.TransferLength
= EFI_PAGE_SIZE
;
670 CommandPacket
.CommandTimeout
= NVME_GENERIC_TIMEOUT
;
671 CommandPacket
.QueueType
= NVME_ADMIN_QUEUE
;
674 QueueSize
= NVME_CSQ_SIZE
;
676 if (Private
->Cap
.Mqes
> NVME_ASYNC_CSQ_SIZE
) {
677 QueueSize
= NVME_ASYNC_CSQ_SIZE
;
679 QueueSize
= Private
->Cap
.Mqes
;
684 CrIoSq
.Qsize
= QueueSize
;
688 CopyMem (&CommandPacket
.NvmeCmd
->Cdw10
, &CrIoSq
, sizeof (NVME_ADMIN_CRIOSQ
));
689 CommandPacket
.NvmeCmd
->Flags
= CDW10_VALID
| CDW11_VALID
;
691 Status
= Private
->Passthru
.PassThru (
697 if (EFI_ERROR (Status
)) {
702 Private
->CreateIoQueue
= FALSE
;
708 Initialize the Nvm Express controller.
710 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
712 @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.
713 @retval Others A device error occurred while initializing the controller.
718 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
722 EFI_PCI_IO_PROTOCOL
*PciIo
;
731 // Enable this controller.
733 PciIo
= Private
->PciIo
;
734 Status
= PciIo
->Attributes (
736 EfiPciIoAttributeOperationSupported
,
741 if (!EFI_ERROR (Status
)) {
742 Supports
&= (UINT64
)EFI_PCI_DEVICE_ENABLE
;
743 Status
= PciIo
->Attributes (
745 EfiPciIoAttributeOperationEnable
,
751 if (EFI_ERROR (Status
)) {
752 DEBUG ((DEBUG_INFO
, "NvmeControllerInit: failed to enable controller\n"));
757 // Read the Controller Capabilities register and verify that the NVM command set is supported
759 Status
= ReadNvmeControllerCapabilities (Private
, &Private
->Cap
);
760 if (EFI_ERROR (Status
)) {
764 if ((Private
->Cap
.Css
& BIT0
) == 0) {
765 DEBUG ((DEBUG_INFO
, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));
766 return EFI_UNSUPPORTED
;
770 // Currently the driver only supports 4k page size.
772 ASSERT ((Private
->Cap
.Mpsmin
+ 12) <= EFI_PAGE_SHIFT
);
780 Private
->SqTdbl
[0].Sqt
= 0;
781 Private
->SqTdbl
[1].Sqt
= 0;
782 Private
->SqTdbl
[2].Sqt
= 0;
783 Private
->CqHdbl
[0].Cqh
= 0;
784 Private
->CqHdbl
[1].Cqh
= 0;
785 Private
->CqHdbl
[2].Cqh
= 0;
786 Private
->AsyncSqHead
= 0;
788 Status
= NvmeDisableController (Private
);
790 if (EFI_ERROR (Status
)) {
795 // set number of entries admin submission & completion queues.
797 Aqa
.Asqs
= NVME_ASQ_SIZE
;
799 Aqa
.Acqs
= NVME_ACQ_SIZE
;
803 // Address of admin submission queue.
805 Asq
= (UINT64
)(UINTN
)(Private
->BufferPciAddr
) & ~0xFFF;
808 // Address of admin completion queue.
810 Acq
= (UINT64
)(UINTN
)(Private
->BufferPciAddr
+ EFI_PAGE_SIZE
) & ~0xFFF;
813 // Address of I/O submission & completion queue.
815 ZeroMem (Private
->Buffer
, EFI_PAGES_TO_SIZE (6));
816 Private
->SqBuffer
[0] = (NVME_SQ
*)(UINTN
)(Private
->Buffer
);
817 Private
->SqBufferPciAddr
[0] = (NVME_SQ
*)(UINTN
)(Private
->BufferPciAddr
);
818 Private
->CqBuffer
[0] = (NVME_CQ
*)(UINTN
)(Private
->Buffer
+ 1 * EFI_PAGE_SIZE
);
819 Private
->CqBufferPciAddr
[0] = (NVME_CQ
*)(UINTN
)(Private
->BufferPciAddr
+ 1 * EFI_PAGE_SIZE
);
820 Private
->SqBuffer
[1] = (NVME_SQ
*)(UINTN
)(Private
->Buffer
+ 2 * EFI_PAGE_SIZE
);
821 Private
->SqBufferPciAddr
[1] = (NVME_SQ
*)(UINTN
)(Private
->BufferPciAddr
+ 2 * EFI_PAGE_SIZE
);
822 Private
->CqBuffer
[1] = (NVME_CQ
*)(UINTN
)(Private
->Buffer
+ 3 * EFI_PAGE_SIZE
);
823 Private
->CqBufferPciAddr
[1] = (NVME_CQ
*)(UINTN
)(Private
->BufferPciAddr
+ 3 * EFI_PAGE_SIZE
);
824 Private
->SqBuffer
[2] = (NVME_SQ
*)(UINTN
)(Private
->Buffer
+ 4 * EFI_PAGE_SIZE
);
825 Private
->SqBufferPciAddr
[2] = (NVME_SQ
*)(UINTN
)(Private
->BufferPciAddr
+ 4 * EFI_PAGE_SIZE
);
826 Private
->CqBuffer
[2] = (NVME_CQ
*)(UINTN
)(Private
->Buffer
+ 5 * EFI_PAGE_SIZE
);
827 Private
->CqBufferPciAddr
[2] = (NVME_CQ
*)(UINTN
)(Private
->BufferPciAddr
+ 5 * EFI_PAGE_SIZE
);
829 DEBUG ((DEBUG_INFO
, "Private->Buffer = [%016X]\n", (UINT64
)(UINTN
)Private
->Buffer
));
830 DEBUG ((DEBUG_INFO
, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa
.Asqs
));
831 DEBUG ((DEBUG_INFO
, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa
.Acqs
));
832 DEBUG ((DEBUG_INFO
, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private
->SqBuffer
[0]));
833 DEBUG ((DEBUG_INFO
, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private
->CqBuffer
[0]));
834 DEBUG ((DEBUG_INFO
, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private
->SqBuffer
[1]));
835 DEBUG ((DEBUG_INFO
, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private
->CqBuffer
[1]));
836 DEBUG ((DEBUG_INFO
, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private
->SqBuffer
[2]));
837 DEBUG ((DEBUG_INFO
, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private
->CqBuffer
[2]));
840 // Program admin queue attributes.
842 Status
= WriteNvmeAdminQueueAttributes (Private
, &Aqa
);
844 if (EFI_ERROR (Status
)) {
849 // Program admin submission queue address.
851 Status
= WriteNvmeAdminSubmissionQueueBaseAddress (Private
, &Asq
);
853 if (EFI_ERROR (Status
)) {
858 // Program admin completion queue address.
860 Status
= WriteNvmeAdminCompletionQueueBaseAddress (Private
, &Acq
);
862 if (EFI_ERROR (Status
)) {
866 Status
= NvmeEnableController (Private
);
867 if (EFI_ERROR (Status
)) {
872 // Allocate buffer for Identify Controller data
874 if (Private
->ControllerData
== NULL
) {
875 Private
->ControllerData
= (NVME_ADMIN_CONTROLLER_DATA
*)AllocateZeroPool (sizeof (NVME_ADMIN_CONTROLLER_DATA
));
877 if (Private
->ControllerData
== NULL
) {
878 return EFI_OUT_OF_RESOURCES
;
883 // Get current Identify Controller Data
885 Status
= NvmeIdentifyController (Private
, Private
->ControllerData
);
887 if (EFI_ERROR (Status
)) {
888 FreePool (Private
->ControllerData
);
889 Private
->ControllerData
= NULL
;
890 return EFI_NOT_FOUND
;
894 // Dump NvmExpress Identify Controller Data
896 CopyMem (Sn
, Private
->ControllerData
->Sn
, sizeof (Private
->ControllerData
->Sn
));
898 CopyMem (Mn
, Private
->ControllerData
->Mn
, sizeof (Private
->ControllerData
->Mn
));
900 DEBUG ((DEBUG_INFO
, " == NVME IDENTIFY CONTROLLER DATA ==\n"));
901 DEBUG ((DEBUG_INFO
, " PCI VID : 0x%x\n", Private
->ControllerData
->Vid
));
902 DEBUG ((DEBUG_INFO
, " PCI SSVID : 0x%x\n", Private
->ControllerData
->Ssvid
));
903 DEBUG ((DEBUG_INFO
, " SN : %a\n", Sn
));
904 DEBUG ((DEBUG_INFO
, " MN : %a\n", Mn
));
905 DEBUG ((DEBUG_INFO
, " FR : 0x%x\n", *((UINT64
*)Private
->ControllerData
->Fr
)));
906 DEBUG ((DEBUG_INFO
, " TNVMCAP (high 8-byte) : 0x%lx\n", *((UINT64
*)(Private
->ControllerData
->Tnvmcap
+ 8))));
907 DEBUG ((DEBUG_INFO
, " TNVMCAP (low 8-byte) : 0x%lx\n", *((UINT64
*)Private
->ControllerData
->Tnvmcap
)));
908 DEBUG ((DEBUG_INFO
, " RAB : 0x%x\n", Private
->ControllerData
->Rab
));
909 DEBUG ((DEBUG_INFO
, " IEEE : 0x%x\n", *(UINT32
*)Private
->ControllerData
->Ieee_oui
));
910 DEBUG ((DEBUG_INFO
, " AERL : 0x%x\n", Private
->ControllerData
->Aerl
));
911 DEBUG ((DEBUG_INFO
, " SQES : 0x%x\n", Private
->ControllerData
->Sqes
));
912 DEBUG ((DEBUG_INFO
, " CQES : 0x%x\n", Private
->ControllerData
->Cqes
));
913 DEBUG ((DEBUG_INFO
, " NN : 0x%x\n", Private
->ControllerData
->Nn
));
916 // Create two I/O completion queues.
917 // One for blocking I/O, one for non-blocking I/O.
919 Status
= NvmeCreateIoCompletionQueue (Private
);
920 if (EFI_ERROR (Status
)) {
925 // Create two I/O Submission queues.
926 // One for blocking I/O, one for non-blocking I/O.
928 Status
= NvmeCreateIoSubmissionQueue (Private
);
934 This routine is called to properly shutdown the Nvm Express controller per NVMe spec.
936 @param[in] ResetType The type of reset to perform.
937 @param[in] ResetStatus The status code for the reset.
938 @param[in] DataSize The size, in bytes, of ResetData.
939 @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or
940 EfiResetShutdown the data buffer starts with a Null-terminated
941 string, optionally followed by additional binary data.
942 The string is a description that the caller may use to further
943 indicate the reason for the system reset.
944 For a ResetType of EfiResetPlatformSpecific the data buffer
945 also starts with a Null-terminated string that is followed
946 by an EFI_GUID that describes the specific type of reset to perform.
950 NvmeShutdownAllControllers (
951 IN EFI_RESET_TYPE ResetType
,
952 IN EFI_STATUS ResetStatus
,
954 IN VOID
*ResetData OPTIONAL
961 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfos
;
964 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*NvmePassThru
;
968 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
970 Status
= gBS
->LocateHandleBuffer (
972 &gEfiPciIoProtocolGuid
,
977 if (EFI_ERROR (Status
)) {
981 for (HandleIndex
= 0; HandleIndex
< HandleCount
; HandleIndex
++) {
982 Status
= gBS
->OpenProtocolInformation (
983 Handles
[HandleIndex
],
984 &gEfiPciIoProtocolGuid
,
988 if (EFI_ERROR (Status
)) {
992 for (OpenInfoIndex
= 0; OpenInfoIndex
< OpenInfoCount
; OpenInfoIndex
++) {
994 // Find all the NVME controller managed by this driver.
995 // gImageHandle equals to DriverBinding handle for this driver.
997 if (((OpenInfos
[OpenInfoIndex
].Attributes
& EFI_OPEN_PROTOCOL_BY_DRIVER
) != 0) &&
998 (OpenInfos
[OpenInfoIndex
].AgentHandle
== gImageHandle
))
1000 Status
= gBS
->OpenProtocol (
1001 OpenInfos
[OpenInfoIndex
].ControllerHandle
,
1002 &gEfiNvmExpressPassThruProtocolGuid
,
1003 (VOID
**)&NvmePassThru
,
1006 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1008 if (EFI_ERROR (Status
)) {
1012 Private
= NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (NvmePassThru
);
1015 // Read Controller Configuration Register.
1017 Status
= ReadNvmeControllerConfiguration (Private
, &Cc
);
1018 if (EFI_ERROR (Status
)) {
1023 // The host should set the Shutdown Notification (CC.SHN) field to 01b
1024 // to indicate a normal shutdown operation.
1026 Cc
.Shn
= NVME_CC_SHN_NORMAL_SHUTDOWN
;
1027 Status
= WriteNvmeControllerConfiguration (Private
, &Cc
);
1028 if (EFI_ERROR (Status
)) {
1033 // The controller indicates when shutdown processing is completed by updating the
1034 // Shutdown Status (CSTS.SHST) field to 10b.
1035 // Wait up to 45 seconds (break down to 4500 x 10ms) for the shutdown to complete.
1037 for (Index
= 0; Index
< NVME_SHUTDOWN_PROCESS_TIMEOUT
* 100; Index
++) {
1038 Status
= ReadNvmeControllerStatus (Private
, &Csts
);
1039 if (!EFI_ERROR (Status
) && (Csts
.Shst
== NVME_CSTS_SHST_SHUTDOWN_COMPLETED
)) {
1040 DEBUG ((DEBUG_INFO
, "NvmeShutdownController: shutdown processing is completed after %dms.\n", Index
* 10));
1047 gBS
->Stall (10 * 1000);
1050 if (Index
== NVME_SHUTDOWN_PROCESS_TIMEOUT
* 100) {
1051 DEBUG ((DEBUG_ERROR
, "NvmeShutdownController: shutdown processing is timed out\n"));
1059 Register the shutdown notification through the ResetNotification protocol.
1061 Register the shutdown notification when mNvmeControllerNumber increased from 0 to 1.
1064 NvmeRegisterShutdownNotification (
1069 EFI_RESET_NOTIFICATION_PROTOCOL
*ResetNotify
;
1071 mNvmeControllerNumber
++;
1072 if (mNvmeControllerNumber
== 1) {
1073 Status
= gBS
->LocateProtocol (&gEfiResetNotificationProtocolGuid
, NULL
, (VOID
**)&ResetNotify
);
1074 if (!EFI_ERROR (Status
)) {
1075 Status
= ResetNotify
->RegisterResetNotify (ResetNotify
, NvmeShutdownAllControllers
);
1076 ASSERT_EFI_ERROR (Status
);
1078 DEBUG ((DEBUG_WARN
, "NVME: ResetNotification absent! Shutdown notification cannot be performed!\n"));
1084 Unregister the shutdown notification through the ResetNotification protocol.
1086 Unregister the shutdown notification when mNvmeControllerNumber decreased from 1 to 0.
1089 NvmeUnregisterShutdownNotification (
1094 EFI_RESET_NOTIFICATION_PROTOCOL
*ResetNotify
;
1096 mNvmeControllerNumber
--;
1097 if (mNvmeControllerNumber
== 0) {
1098 Status
= gBS
->LocateProtocol (&gEfiResetNotificationProtocolGuid
, NULL
, (VOID
**)&ResetNotify
);
1099 if (!EFI_ERROR (Status
)) {
1100 Status
= ResetNotify
->UnregisterResetNotify (ResetNotify
, NvmeShutdownAllControllers
);
1101 ASSERT_EFI_ERROR (Status
);