13#define NVME_SHUTDOWN_PROCESS_TIMEOUT 45
19UINTN mNvmeControllerNumber = 0;
41 PciIo = Private->PciIo;
42 Status = PciIo->Mem.
Read (
51 if (EFI_ERROR (Status)) {
79 PciIo = Private->PciIo;
80 Status = PciIo->Mem.
Read (
89 if (EFI_ERROR (Status)) {
117 PciIo = Private->PciIo;
119 Status = PciIo->Mem.
Write (
128 if (EFI_ERROR (Status)) {
132 DEBUG ((DEBUG_INFO,
"Cc.En: %d\n", Cc->En));
133 DEBUG ((DEBUG_INFO,
"Cc.Css: %d\n", Cc->Css));
134 DEBUG ((DEBUG_INFO,
"Cc.Mps: %d\n", Cc->Mps));
135 DEBUG ((DEBUG_INFO,
"Cc.Ams: %d\n", Cc->Ams));
136 DEBUG ((DEBUG_INFO,
"Cc.Shn: %d\n", Cc->Shn));
137 DEBUG ((DEBUG_INFO,
"Cc.Iosqes: %d\n", Cc->Iosqes));
138 DEBUG ((DEBUG_INFO,
"Cc.Iocqes: %d\n", Cc->Iocqes));
163 PciIo = Private->PciIo;
164 Status = PciIo->Mem.
Read (
173 if (EFI_ERROR (Status)) {
201 PciIo = Private->PciIo;
203 Status = PciIo->Mem.
Write (
212 if (EFI_ERROR (Status)) {
216 DEBUG ((DEBUG_INFO,
"Aqa.Asqs: %d\n", Aqa->Asqs));
217 DEBUG ((DEBUG_INFO,
"Aqa.Acqs: %d\n", Aqa->Acqs));
242 PciIo = Private->PciIo;
245 Status = PciIo->Mem.
Write (
254 if (EFI_ERROR (Status)) {
258 DEBUG ((DEBUG_INFO,
"Asq: %lx\n", *Asq));
283 PciIo = Private->PciIo;
286 Status = PciIo->Mem.
Write (
295 if (EFI_ERROR (Status)) {
299 DEBUG ((DEBUG_INFO,
"Acq: %lxh\n", *Acq));
328 if (EFI_ERROR (Status)) {
339 if (EFI_ERROR (Status)) {
347 if (Private->Cap.To == 0) {
350 Timeout = Private->Cap.To;
353 for (Index = (Timeout * 500); Index != 0; --Index) {
361 if (EFI_ERROR (Status)) {
371 Status = EFI_DEVICE_ERROR;
373 (EFI_ERROR_CODE | EFI_ERROR_MAJOR),
374 (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR)
378 DEBUG ((DEBUG_INFO,
"NVMe controller is disabled with status [%r].\n", Status));
415 if (EFI_ERROR (Status)) {
423 if (Private->Cap.To == 0) {
426 Timeout = Private->Cap.To;
429 for (Index = (Timeout * 500); Index != 0; --Index) {
437 if (EFI_ERROR (Status)) {
447 Status = EFI_TIMEOUT;
449 (EFI_ERROR_CODE | EFI_ERROR_MAJOR),
450 (EFI_IO_BUS_SCSI | EFI_IOB_EC_INTERFACE_ERROR)
454 DEBUG ((DEBUG_INFO,
"NVMe controller is enabled with status [%r].\n", Status));
486 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
493 CommandPacket.NvmeCmd = &Command;
494 CommandPacket.NvmeCompletion = &Completion;
495 CommandPacket.TransferBuffer = Buffer;
497 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
498 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
503 Command.Flags = CDW10_VALID;
505 Status = Private->Passthru.PassThru (
529 IN UINT32 NamespaceId,
542 CommandPacket.NvmeCmd = &Command;
543 CommandPacket.NvmeCompletion = &Completion;
545 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
546 Command.Nsid = NamespaceId;
547 CommandPacket.TransferBuffer = Buffer;
549 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
550 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
554 CommandPacket.NvmeCmd->Cdw10 = 0;
555 CommandPacket.NvmeCmd->Flags = CDW10_VALID;
557 Status = Private->Passthru.PassThru (
590 Private->CreateIoQueue =
TRUE;
592 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
598 CommandPacket.NvmeCmd = &Command;
599 CommandPacket.NvmeCompletion = &Completion;
601 Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
602 CommandPacket.TransferBuffer = Private->CqBufferPciAddr[Index];
603 CommandPacket.TransferLength = EFI_PAGE_SIZE;
604 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
605 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
608 QueueSize = NVME_CCQ_SIZE;
610 if (Private->Cap.Mqes > NVME_ASYNC_CCQ_SIZE) {
611 QueueSize = NVME_ASYNC_CCQ_SIZE;
613 QueueSize = Private->Cap.Mqes;
618 CrIoCq.Qsize = QueueSize;
621 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
623 Status = Private->Passthru.PassThru (
629 if (EFI_ERROR (Status)) {
634 Private->CreateIoQueue =
FALSE;
662 Private->CreateIoQueue =
TRUE;
664 for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
670 CommandPacket.NvmeCmd = &Command;
671 CommandPacket.NvmeCompletion = &Completion;
673 Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
674 CommandPacket.TransferBuffer = Private->SqBufferPciAddr[Index];
675 CommandPacket.TransferLength = EFI_PAGE_SIZE;
676 CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
677 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
680 QueueSize = NVME_CSQ_SIZE;
682 if (Private->Cap.Mqes > NVME_ASYNC_CSQ_SIZE) {
683 QueueSize = NVME_ASYNC_CSQ_SIZE;
685 QueueSize = Private->Cap.Mqes;
690 CrIoSq.Qsize = QueueSize;
695 CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
697 Status = Private->Passthru.PassThru (
703 if (EFI_ERROR (Status)) {
708 Private->CreateIoQueue =
FALSE;
739 PciIo = Private->PciIo;
740 Status = PciIo->Attributes (
747 if (!EFI_ERROR (Status)) {
748 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
749 Status = PciIo->Attributes (
757 if (EFI_ERROR (Status)) {
758 DEBUG ((DEBUG_INFO,
"NvmeControllerInit: failed to enable controller\n"));
766 if (EFI_ERROR (Status)) {
770 if ((Private->Cap.Css & BIT0) == 0) {
771 DEBUG ((DEBUG_INFO,
"NvmeControllerInit: the controller doesn't support NVMe command set\n"));
772 return EFI_UNSUPPORTED;
778 ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);
786 Private->SqTdbl[0].Sqt = 0;
787 Private->SqTdbl[1].Sqt = 0;
788 Private->SqTdbl[2].Sqt = 0;
789 Private->CqHdbl[0].Cqh = 0;
790 Private->CqHdbl[1].Cqh = 0;
791 Private->CqHdbl[2].Cqh = 0;
792 Private->AsyncSqHead = 0;
796 if (EFI_ERROR (Status)) {
803 Aqa.Asqs = NVME_ASQ_SIZE;
805 Aqa.Acqs = NVME_ACQ_SIZE;
811 Asq = (UINT64)(
UINTN)(Private->BufferPciAddr) & ~0xFFF;
816 Acq = (UINT64)(
UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) & ~0xFFF;
822 Private->SqBuffer[0] = (
NVME_SQ *)(
UINTN)(Private->Buffer);
823 Private->SqBufferPciAddr[0] = (
NVME_SQ *)(
UINTN)(Private->BufferPciAddr);
824 Private->CqBuffer[0] = (
NVME_CQ *)(
UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);
825 Private->CqBufferPciAddr[0] = (
NVME_CQ *)(
UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);
826 Private->SqBuffer[1] = (
NVME_SQ *)(
UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);
827 Private->SqBufferPciAddr[1] = (
NVME_SQ *)(
UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);
828 Private->CqBuffer[1] = (
NVME_CQ *)(
UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);
829 Private->CqBufferPciAddr[1] = (
NVME_CQ *)(
UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);
830 Private->SqBuffer[2] = (
NVME_SQ *)(
UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);
831 Private->SqBufferPciAddr[2] = (
NVME_SQ *)(
UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);
832 Private->CqBuffer[2] = (
NVME_CQ *)(
UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);
833 Private->CqBufferPciAddr[2] = (
NVME_CQ *)(
UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);
835 DEBUG ((DEBUG_INFO,
"Private->Buffer = [%016X]\n", (UINT64)(
UINTN)Private->Buffer));
836 DEBUG ((DEBUG_INFO,
"Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
837 DEBUG ((DEBUG_INFO,
"Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
838 DEBUG ((DEBUG_INFO,
"Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));
839 DEBUG ((DEBUG_INFO,
"Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));
840 DEBUG ((DEBUG_INFO,
"Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));
841 DEBUG ((DEBUG_INFO,
"Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));
842 DEBUG ((DEBUG_INFO,
"Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));
843 DEBUG ((DEBUG_INFO,
"Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));
850 if (EFI_ERROR (Status)) {
859 if (EFI_ERROR (Status)) {
868 if (EFI_ERROR (Status)) {
873 if (EFI_ERROR (Status)) {
880 if (Private->ControllerData ==
NULL) {
883 if (Private->ControllerData ==
NULL) {
884 return EFI_OUT_OF_RESOURCES;
893 if (EFI_ERROR (Status)) {
895 Private->ControllerData =
NULL;
896 return EFI_NOT_FOUND;
902 CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));
904 CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));
906 DEBUG ((DEBUG_INFO,
" == NVME IDENTIFY CONTROLLER DATA ==\n"));
907 DEBUG ((DEBUG_INFO,
" PCI VID : 0x%x\n", Private->ControllerData->Vid));
908 DEBUG ((DEBUG_INFO,
" PCI SSVID : 0x%x\n", Private->ControllerData->Ssvid));
909 DEBUG ((DEBUG_INFO,
" SN : %a\n", Sn));
910 DEBUG ((DEBUG_INFO,
" MN : %a\n", Mn));
911 DEBUG ((DEBUG_INFO,
" FR : 0x%x\n", *((UINT64 *)Private->ControllerData->Fr)));
912 DEBUG ((DEBUG_INFO,
" TNVMCAP (high 8-byte) : 0x%lx\n", *((UINT64 *)(Private->ControllerData->Tnvmcap + 8))));
913 DEBUG ((DEBUG_INFO,
" TNVMCAP (low 8-byte) : 0x%lx\n", *((UINT64 *)Private->ControllerData->Tnvmcap)));
914 DEBUG ((DEBUG_INFO,
" RAB : 0x%x\n", Private->ControllerData->Rab));
915 DEBUG ((DEBUG_INFO,
" IEEE : 0x%x\n", *(UINT32 *)Private->ControllerData->Ieee_oui));
916 DEBUG ((DEBUG_INFO,
" AERL : 0x%x\n", Private->ControllerData->Aerl));
917 DEBUG ((DEBUG_INFO,
" SQES : 0x%x\n", Private->ControllerData->Sqes));
918 DEBUG ((DEBUG_INFO,
" CQES : 0x%x\n", Private->ControllerData->Cqes));
919 DEBUG ((DEBUG_INFO,
" NN : 0x%x\n", Private->ControllerData->Nn));
926 if (EFI_ERROR (Status)) {
960 IN VOID *ResetData OPTIONAL
976 Status =
gBS->LocateHandleBuffer (
978 &gEfiPciIoProtocolGuid,
983 if (EFI_ERROR (Status)) {
987 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
988 Status =
gBS->OpenProtocolInformation (
989 Handles[HandleIndex],
990 &gEfiPciIoProtocolGuid,
994 if (EFI_ERROR (Status)) {
998 for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
1003 if (((OpenInfos[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) &&
1004 (OpenInfos[OpenInfoIndex].AgentHandle ==
gImageHandle))
1006 Status =
gBS->OpenProtocol (
1007 OpenInfos[OpenInfoIndex].ControllerHandle,
1008 &gEfiNvmExpressPassThruProtocolGuid,
1012 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1014 if (EFI_ERROR (Status)) {
1018 Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (
NvmePassThru);
1024 if (EFI_ERROR (Status)) {
1032 Cc.Shn = NVME_CC_SHN_NORMAL_SHUTDOWN;
1034 if (EFI_ERROR (Status)) {
1043 for (Index = 0; Index < NVME_SHUTDOWN_PROCESS_TIMEOUT * 100; Index++) {
1045 if (!EFI_ERROR (Status) && (Csts.Shst == NVME_CSTS_SHST_SHUTDOWN_COMPLETED)) {
1046 DEBUG ((DEBUG_INFO,
"NvmeShutdownController: shutdown processing is completed after %dms.\n", Index * 10));
1053 gBS->Stall (10 * 1000);
1056 if (Index == NVME_SHUTDOWN_PROCESS_TIMEOUT * 100) {
1057 DEBUG ((DEBUG_ERROR,
"NvmeShutdownController: shutdown processing is timed out\n"));
1077 mNvmeControllerNumber++;
1078 if (mNvmeControllerNumber == 1) {
1079 Status =
gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid,
NULL, (VOID **)&ResetNotify);
1080 if (!EFI_ERROR (Status)) {
1084 DEBUG ((DEBUG_WARN,
"NVME: ResetNotification absent! Shutdown notification cannot be performed!\n"));
1102 mNvmeControllerNumber--;
1103 if (mNvmeControllerNumber == 0) {
1104 Status =
gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid,
NULL, (VOID **)&ResetNotify);
1105 if (!EFI_ERROR (Status)) {
UINT64 EFIAPI ReadUnaligned64(IN CONST UINT64 *Buffer)
UINT32 EFIAPI WriteUnaligned32(OUT UINT32 *Buffer, IN UINT32 Value)
UINT64 EFIAPI WriteUnaligned64(OUT UINT64 *Buffer, IN UINT64 Value)
UINT32 EFIAPI ReadUnaligned32(IN CONST UINT32 *Buffer)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define ASSERT_EFI_ERROR(StatusParameter)
#define DEBUG(Expression)
#define REPORT_STATUS_CODE(Type, Value)
@ EfiPciIoAttributeOperationEnable
@ EfiPciIoAttributeOperationSupported
EFI_STATUS WriteNvmeAdminQueueAttributes(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_AQA *Aqa)
EFI_STATUS ReadNvmeControllerConfiguration(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_CC *Cc)
EFI_STATUS WriteNvmeControllerConfiguration(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_CC *Cc)
EFI_STATUS NvmeDisableController(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
EFI_STATUS NvmeEnableController(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
EFI_STATUS ReadNvmeControllerCapabilities(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_CAP *Cap)
EFI_STATUS NvmeIdentifyNamespace(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN UINT32 NamespaceId, IN VOID *Buffer)
VOID NvmeRegisterShutdownNotification(VOID)
EFI_STATUS NvmeCreateIoSubmissionQueue(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
VOID EFIAPI NvmeShutdownAllControllers(IN EFI_RESET_TYPE ResetType, IN EFI_STATUS ResetStatus, IN UINTN DataSize, IN VOID *ResetData OPTIONAL)
EFI_STATUS NvmeCreateIoCompletionQueue(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
EFI_STATUS NvmeIdentifyController(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN VOID *Buffer)
EFI_STATUS WriteNvmeAdminSubmissionQueueBaseAddress(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_ASQ *Asq)
EFI_STATUS ReadNvmeControllerStatus(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_CSTS *Csts)
VOID NvmeUnregisterShutdownNotification(VOID)
EFI_STATUS WriteNvmeAdminCompletionQueueBaseAddress(IN NVME_CONTROLLER_PRIVATE_DATA *Private, IN NVME_ACQ *Acq)
EFI_STATUS NvmeControllerInit(IN NVME_CONTROLLER_PRIVATE_DATA *Private)
EFI_STATUS EFIAPI NvmePassThru(IN EDKII_PEI_NVM_EXPRESS_PASS_THRU_PPI *This, IN UINT32 NamespaceId, IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet)
#define EFI_PAGES_TO_SIZE(Pages)
EFI_STATUS EFIAPI EfiEventGroupSignal(IN CONST EFI_GUID *EventGroup)
EFI_PCI_IO_PROTOCOL_IO_MEM Write
EFI_PCI_IO_PROTOCOL_IO_MEM Read