2 NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
3 NVM Express specification.
5 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "NvmExpress.h"
19 // NVM Express Driver Binding Protocol Instance
21 EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding
= {
22 NvmExpressDriverBindingSupported
,
23 NvmExpressDriverBindingStart
,
24 NvmExpressDriverBindingStop
,
31 // NVM Express EFI Driver Supported EFI Version Protocol Instance
33 EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion
= {
34 sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL
), // Size of Protocol structure.
35 0 // Version number to be filled at start up.
39 // Template for NVM Express Pass Thru Mode data structure.
41 GLOBAL_REMOVE_IF_UNREFERENCED EFI_NVM_EXPRESS_PASS_THRU_MODE gEfiNvmExpressPassThruMode
= {
42 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL
|
43 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL
|
44 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_NONBLOCKIO
|
45 EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVM
,
51 Check if the specified Nvm Express device namespace is active, and create child handles
52 for them with BlockIo and DiskInfo protocol instances.
54 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
55 @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be
56 allocated and built. Caller must set the NamespaceId to zero if the
57 device path node will contain a valid UUID.
59 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
60 @return Others Some error occurs when enumerating the namespaces.
64 EnumerateNvmeDevNamespace (
65 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
,
69 NVME_ADMIN_NAMESPACE_DATA
*NamespaceData
;
70 EFI_DEVICE_PATH_PROTOCOL
*NewDevicePathNode
;
71 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
72 EFI_HANDLE DeviceHandle
;
73 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
74 EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
;
75 NVME_DEVICE_PRIVATE_DATA
*Device
;
84 NewDevicePathNode
= NULL
;
89 // Allocate a buffer for Identify Namespace data
91 NamespaceData
= AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA
));
92 if(NamespaceData
== NULL
) {
93 return EFI_OUT_OF_RESOURCES
;
96 ParentDevicePath
= Private
->ParentDevicePath
;
100 Status
= NvmeIdentifyNamespace (
103 (VOID
*)NamespaceData
105 if (EFI_ERROR(Status
)) {
109 // Validate Namespace
111 if (NamespaceData
->Ncap
== 0) {
112 Status
= EFI_DEVICE_ERROR
;
115 // allocate device private data for each discovered namespace
117 Device
= AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA
));
118 if (Device
== NULL
) {
119 Status
= EFI_OUT_OF_RESOURCES
;
124 // Initialize SSD namespace instance data
126 Device
->Signature
= NVME_DEVICE_PRIVATE_DATA_SIGNATURE
;
127 Device
->NamespaceId
= NamespaceId
;
128 Device
->NamespaceUuid
= NamespaceData
->Eui64
;
130 Device
->ControllerHandle
= Private
->ControllerHandle
;
131 Device
->DriverBindingHandle
= Private
->DriverBindingHandle
;
132 Device
->Controller
= Private
;
135 // Build BlockIo media structure
137 Device
->Media
.MediaId
= 0;
138 Device
->Media
.RemovableMedia
= FALSE
;
139 Device
->Media
.MediaPresent
= TRUE
;
140 Device
->Media
.LogicalPartition
= FALSE
;
141 Device
->Media
.ReadOnly
= FALSE
;
142 Device
->Media
.WriteCaching
= FALSE
;
143 Device
->Media
.IoAlign
= Private
->PassThruMode
.IoAlign
;
145 Flbas
= NamespaceData
->Flbas
;
146 LbaFmtIdx
= Flbas
& 0xF;
147 Lbads
= NamespaceData
->LbaFormat
[LbaFmtIdx
].Lbads
;
148 Device
->Media
.BlockSize
= (UINT32
)1 << Lbads
;
150 Device
->Media
.LastBlock
= NamespaceData
->Nsze
- 1;
151 Device
->Media
.LogicalBlocksPerPhysicalBlock
= 1;
152 Device
->Media
.LowestAlignedLba
= 1;
155 // Create BlockIo Protocol instance
157 Device
->BlockIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
158 Device
->BlockIo
.Media
= &Device
->Media
;
159 Device
->BlockIo
.Reset
= NvmeBlockIoReset
;
160 Device
->BlockIo
.ReadBlocks
= NvmeBlockIoReadBlocks
;
161 Device
->BlockIo
.WriteBlocks
= NvmeBlockIoWriteBlocks
;
162 Device
->BlockIo
.FlushBlocks
= NvmeBlockIoFlushBlocks
;
165 // Create BlockIo2 Protocol instance
167 Device
->BlockIo2
.Media
= &Device
->Media
;
168 Device
->BlockIo2
.Reset
= NvmeBlockIoResetEx
;
169 Device
->BlockIo2
.ReadBlocksEx
= NvmeBlockIoReadBlocksEx
;
170 Device
->BlockIo2
.WriteBlocksEx
= NvmeBlockIoWriteBlocksEx
;
171 Device
->BlockIo2
.FlushBlocksEx
= NvmeBlockIoFlushBlocksEx
;
172 InitializeListHead (&Device
->AsyncQueue
);
175 // Create StorageSecurityProtocol Instance
177 Device
->StorageSecurity
.ReceiveData
= NvmeStorageSecurityReceiveData
;
178 Device
->StorageSecurity
.SendData
= NvmeStorageSecuritySendData
;
181 // Create DiskInfo Protocol instance
183 CopyMem (&Device
->NamespaceData
, NamespaceData
, sizeof (NVME_ADMIN_NAMESPACE_DATA
));
184 InitializeDiskInfo (Device
);
187 // Create a Nvm Express Namespace Device Path Node
189 Status
= Private
->Passthru
.BuildDevicePath (
195 if (EFI_ERROR(Status
)) {
200 // Append the SSD node to the controller's device path
202 DevicePath
= AppendDevicePathNode (ParentDevicePath
, NewDevicePathNode
);
203 if (DevicePath
== NULL
) {
204 Status
= EFI_OUT_OF_RESOURCES
;
209 RemainingDevicePath
= DevicePath
;
210 Status
= gBS
->LocateDevicePath (&gEfiDevicePathProtocolGuid
, &RemainingDevicePath
, &DeviceHandle
);
211 if (!EFI_ERROR (Status
) && (DeviceHandle
!= NULL
) && IsDevicePathEnd(RemainingDevicePath
)) {
212 Status
= EFI_ALREADY_STARTED
;
213 FreePool (DevicePath
);
217 Device
->DevicePath
= DevicePath
;
220 // Make sure the handle is NULL so we create a new handle
222 Device
->DeviceHandle
= NULL
;
224 Status
= gBS
->InstallMultipleProtocolInterfaces (
225 &Device
->DeviceHandle
,
226 &gEfiDevicePathProtocolGuid
,
228 &gEfiBlockIoProtocolGuid
,
230 &gEfiBlockIo2ProtocolGuid
,
232 &gEfiDiskInfoProtocolGuid
,
237 if(EFI_ERROR(Status
)) {
242 // Check if the NVMe controller supports the Security Send and Security Receive commands
244 if ((Private
->ControllerData
->Oacs
& SECURITY_SEND_RECEIVE_SUPPORTED
) != 0) {
245 Status
= gBS
->InstallProtocolInterface (
246 &Device
->DeviceHandle
,
247 &gEfiStorageSecurityCommandProtocolGuid
,
248 EFI_NATIVE_INTERFACE
,
249 &Device
->StorageSecurity
251 if(EFI_ERROR(Status
)) {
252 gBS
->UninstallMultipleProtocolInterfaces (
253 &Device
->DeviceHandle
,
254 &gEfiDevicePathProtocolGuid
,
256 &gEfiBlockIoProtocolGuid
,
258 &gEfiBlockIo2ProtocolGuid
,
260 &gEfiDiskInfoProtocolGuid
,
269 Private
->ControllerHandle
,
270 &gEfiNvmExpressPassThruProtocolGuid
,
271 (VOID
**) &DummyInterface
,
272 Private
->DriverBindingHandle
,
273 Device
->DeviceHandle
,
274 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
278 // Dump NvmExpress Identify Namespace Data
280 DEBUG ((EFI_D_INFO
, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId
));
281 DEBUG ((EFI_D_INFO
, " NSZE : 0x%x\n", NamespaceData
->Nsze
));
282 DEBUG ((EFI_D_INFO
, " NCAP : 0x%x\n", NamespaceData
->Ncap
));
283 DEBUG ((EFI_D_INFO
, " NUSE : 0x%x\n", NamespaceData
->Nuse
));
284 DEBUG ((EFI_D_INFO
, " LBAF0.LBADS : 0x%x\n", (NamespaceData
->LbaFormat
[0].Lbads
)));
287 // Build controller name for Component Name (2) protocol.
289 CopyMem (Sn
, Private
->ControllerData
->Sn
, sizeof (Private
->ControllerData
->Sn
));
291 CopyMem (Mn
, Private
->ControllerData
->Mn
, sizeof (Private
->ControllerData
->Mn
));
293 UnicodeSPrintAsciiFormat (Device
->ModelName
, sizeof (Device
->ModelName
), "%a-%a-%x", Sn
, Mn
, NamespaceData
->Eui64
);
297 gNvmExpressComponentName
.SupportedLanguages
,
298 &Device
->ControllerNameTable
,
305 gNvmExpressComponentName2
.SupportedLanguages
,
306 &Device
->ControllerNameTable
,
313 if(NamespaceData
!= NULL
) {
314 FreePool (NamespaceData
);
317 if (NewDevicePathNode
!= NULL
) {
318 FreePool (NewDevicePathNode
);
321 if(EFI_ERROR(Status
) && (Device
!= NULL
) && (Device
->DevicePath
!= NULL
)) {
322 FreePool (Device
->DevicePath
);
324 if(EFI_ERROR(Status
) && (Device
!= NULL
)) {
331 Discover all Nvm Express device namespaces, and create child handles for them with BlockIo
332 and DiskInfo protocol instances.
334 @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
336 @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.
337 @return Others Some error occurs when enumerating the namespaces.
341 DiscoverAllNamespaces (
342 IN NVME_CONTROLLER_PRIVATE_DATA
*Private
347 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*Passthru
;
349 NamespaceId
= 0xFFFFFFFF;
350 Passthru
= &Private
->Passthru
;
353 Status
= Passthru
->GetNextNamespace (
355 (UINT32
*)&NamespaceId
358 if (EFI_ERROR (Status
)) {
362 Status
= EnumerateNvmeDevNamespace (
367 if (EFI_ERROR(Status
)) {
376 Unregisters a Nvm Express device namespace.
378 This function removes the protocols installed on the controller handle and
379 frees the resources allocated for the namespace.
381 @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.
382 @param Controller The controller handle of the namespace.
383 @param Handle The child handle.
385 @retval EFI_SUCCESS The namespace is successfully unregistered.
386 @return Others Some error occurs when unregistering the namespace.
390 UnregisterNvmeNamespace (
391 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
392 IN EFI_HANDLE Controller
,
397 EFI_BLOCK_IO_PROTOCOL
*BlockIo
;
398 NVME_DEVICE_PRIVATE_DATA
*Device
;
399 EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
*StorageSecurity
;
402 VOID
*DummyInterface
;
406 Status
= gBS
->OpenProtocol (
408 &gEfiBlockIoProtocolGuid
,
410 This
->DriverBindingHandle
,
412 EFI_OPEN_PROTOCOL_GET_PROTOCOL
414 if (EFI_ERROR (Status
)) {
418 Device
= NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo
);
421 // Wait for the device's asynchronous I/O queue to become empty.
424 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
425 IsEmpty
= IsListEmpty (&Device
->AsyncQueue
);
426 gBS
->RestoreTPL (OldTpl
);
436 // Close the child handle
440 &gEfiNvmExpressPassThruProtocolGuid
,
441 This
->DriverBindingHandle
,
446 // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().
447 // Here should uninstall both of them.
449 Status
= gBS
->UninstallMultipleProtocolInterfaces (
451 &gEfiDevicePathProtocolGuid
,
453 &gEfiBlockIoProtocolGuid
,
455 &gEfiBlockIo2ProtocolGuid
,
457 &gEfiDiskInfoProtocolGuid
,
462 if (EFI_ERROR (Status
)) {
465 &gEfiNvmExpressPassThruProtocolGuid
,
466 (VOID
**) &DummyInterface
,
467 This
->DriverBindingHandle
,
469 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
475 // If Storage Security Command Protocol is installed, then uninstall this protocol.
477 Status
= gBS
->OpenProtocol (
479 &gEfiStorageSecurityCommandProtocolGuid
,
480 (VOID
**) &StorageSecurity
,
481 This
->DriverBindingHandle
,
483 EFI_OPEN_PROTOCOL_GET_PROTOCOL
486 if (!EFI_ERROR (Status
)) {
487 Status
= gBS
->UninstallProtocolInterface (
489 &gEfiStorageSecurityCommandProtocolGuid
,
490 &Device
->StorageSecurity
492 if (EFI_ERROR (Status
)) {
495 &gEfiNvmExpressPassThruProtocolGuid
,
496 (VOID
**) &DummyInterface
,
497 This
->DriverBindingHandle
,
499 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
505 if(Device
->DevicePath
!= NULL
) {
506 FreePool (Device
->DevicePath
);
509 if (Device
->ControllerNameTable
!= NULL
) {
510 FreeUnicodeStringTable (Device
->ControllerNameTable
);
519 Call back function when the timer event is signaled.
521 @param[in] Event The Event this notify function registered to.
522 @param[in] Context Pointer to the context data registered to the
528 ProcessAsyncTaskList (
533 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
534 EFI_PCI_IO_PROTOCOL
*PciIo
;
539 LIST_ENTRY
*NextLink
;
540 NVME_PASS_THRU_ASYNC_REQ
*AsyncRequest
;
541 NVME_BLKIO2_SUBTASK
*Subtask
;
542 NVME_BLKIO2_REQUEST
*BlkIo2Request
;
543 EFI_BLOCK_IO2_TOKEN
*Token
;
547 Private
= (NVME_CONTROLLER_PRIVATE_DATA
*)Context
;
549 Cq
= Private
->CqBuffer
[QueueId
] + Private
->CqHdbl
[QueueId
].Cqh
;
551 PciIo
= Private
->PciIo
;
554 // Submit asynchronous subtasks to the NVMe Submission Queue
556 for (Link
= GetFirstNode (&Private
->UnsubmittedSubtasks
);
557 !IsNull (&Private
->UnsubmittedSubtasks
, Link
);
559 NextLink
= GetNextNode (&Private
->UnsubmittedSubtasks
, Link
);
560 Subtask
= NVME_BLKIO2_SUBTASK_FROM_LINK (Link
);
561 BlkIo2Request
= Subtask
->BlockIo2Request
;
562 Token
= BlkIo2Request
->Token
;
563 RemoveEntryList (Link
);
564 BlkIo2Request
->UnsubmittedSubtaskNum
--;
567 // If any previous subtask fails, do not process subsequent ones.
569 if (Token
->TransactionStatus
!= EFI_SUCCESS
) {
570 if (IsListEmpty (&BlkIo2Request
->SubtasksQueue
) &&
571 BlkIo2Request
->LastSubtaskSubmitted
&&
572 (BlkIo2Request
->UnsubmittedSubtaskNum
== 0)) {
574 // Remove the BlockIo2 request from the device asynchronous queue.
576 RemoveEntryList (&BlkIo2Request
->Link
);
577 FreePool (BlkIo2Request
);
578 gBS
->SignalEvent (Token
->Event
);
581 FreePool (Subtask
->CommandPacket
->NvmeCmd
);
582 FreePool (Subtask
->CommandPacket
->NvmeCompletion
);
583 FreePool (Subtask
->CommandPacket
);
589 Status
= Private
->Passthru
.PassThru (
591 Subtask
->NamespaceId
,
592 Subtask
->CommandPacket
,
595 if (Status
== EFI_NOT_READY
) {
596 InsertHeadList (&Private
->UnsubmittedSubtasks
, Link
);
597 BlkIo2Request
->UnsubmittedSubtaskNum
++;
599 } else if (EFI_ERROR (Status
)) {
600 Token
->TransactionStatus
= EFI_DEVICE_ERROR
;
602 if (IsListEmpty (&BlkIo2Request
->SubtasksQueue
) &&
605 // Remove the BlockIo2 request from the device asynchronous queue.
607 RemoveEntryList (&BlkIo2Request
->Link
);
608 FreePool (BlkIo2Request
);
609 gBS
->SignalEvent (Token
->Event
);
612 FreePool (Subtask
->CommandPacket
->NvmeCmd
);
613 FreePool (Subtask
->CommandPacket
->NvmeCompletion
);
614 FreePool (Subtask
->CommandPacket
);
617 InsertTailList (&BlkIo2Request
->SubtasksQueue
, Link
);
618 if (Subtask
->IsLast
) {
619 BlkIo2Request
->LastSubtaskSubmitted
= TRUE
;
624 while (Cq
->Pt
!= Private
->Pt
[QueueId
]) {
625 ASSERT (Cq
->Sqid
== QueueId
);
630 // Find the command with given Command Id.
632 for (Link
= GetFirstNode (&Private
->AsyncPassThruQueue
);
633 !IsNull (&Private
->AsyncPassThruQueue
, Link
);
635 NextLink
= GetNextNode (&Private
->AsyncPassThruQueue
, Link
);
636 AsyncRequest
= NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link
);
637 if (AsyncRequest
->CommandId
== Cq
->Cid
) {
639 // Copy the Respose Queue entry for this command to the callers
643 AsyncRequest
->Packet
->NvmeCompletion
,
645 sizeof(EFI_NVM_EXPRESS_COMPLETION
)
649 // Free the resources allocated before cmd submission
651 if (AsyncRequest
->MapData
!= NULL
) {
652 PciIo
->Unmap (PciIo
, AsyncRequest
->MapData
);
654 if (AsyncRequest
->MapMeta
!= NULL
) {
655 PciIo
->Unmap (PciIo
, AsyncRequest
->MapMeta
);
657 if (AsyncRequest
->MapPrpList
!= NULL
) {
658 PciIo
->Unmap (PciIo
, AsyncRequest
->MapPrpList
);
660 if (AsyncRequest
->PrpListHost
!= NULL
) {
663 AsyncRequest
->PrpListNo
,
664 AsyncRequest
->PrpListHost
668 RemoveEntryList (Link
);
669 gBS
->SignalEvent (AsyncRequest
->CallerEvent
);
670 FreePool (AsyncRequest
);
673 // Update submission queue head.
675 Private
->AsyncSqHead
= Cq
->Sqhd
;
680 Private
->CqHdbl
[QueueId
].Cqh
++;
681 if (Private
->CqHdbl
[QueueId
].Cqh
> NVME_ASYNC_CCQ_SIZE
) {
682 Private
->CqHdbl
[QueueId
].Cqh
= 0;
683 Private
->Pt
[QueueId
] ^= 1;
686 Cq
= Private
->CqBuffer
[QueueId
] + Private
->CqHdbl
[QueueId
].Cqh
;
690 Data
= ReadUnaligned32 ((UINT32
*)&Private
->CqHdbl
[QueueId
]);
695 NVME_CQHDBL_OFFSET(QueueId
, Private
->Cap
.Dstrd
),
703 Tests to see if this driver supports a given controller. If a child device is provided,
704 it further tests to see if this driver supports creating a handle for the specified child device.
706 This function checks to see if the driver specified by This supports the device specified by
707 ControllerHandle. Drivers will typically use the device path attached to
708 ControllerHandle and/or the services from the bus I/O abstraction attached to
709 ControllerHandle to determine if the driver supports ControllerHandle. This function
710 may be called many times during platform initialization. In order to reduce boot times, the tests
711 performed by this function must be very small, and take as little time as possible to execute. This
712 function must not change the state of any hardware devices, and this function must be aware that the
713 device specified by ControllerHandle may already be managed by the same driver or a
714 different driver. This function must match its calls to AllocatePages() with FreePages(),
715 AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
716 Since ControllerHandle may have been previously started by the same driver, if a protocol is
717 already in the opened state, then it must not be closed with CloseProtocol(). This is required
718 to guarantee the state of ControllerHandle is not modified by this function.
720 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
721 @param[in] ControllerHandle The handle of the controller to test. This handle
722 must support a protocol interface that supplies
723 an I/O abstraction to the driver.
724 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
725 parameter is ignored by device drivers, and is optional for bus
726 drivers. For bus drivers, if this parameter is not NULL, then
727 the bus driver must determine if the bus controller specified
728 by ControllerHandle and the child controller specified
729 by RemainingDevicePath are both supported by this
732 @retval EFI_SUCCESS The device specified by ControllerHandle and
733 RemainingDevicePath is supported by the driver specified by This.
734 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
735 RemainingDevicePath is already being managed by the driver
737 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
738 RemainingDevicePath is already being managed by a different
739 driver or an application that requires exclusive access.
740 Currently not implemented.
741 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
742 RemainingDevicePath is not supported by the driver specified by This.
746 NvmExpressDriverBindingSupported (
747 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
748 IN EFI_HANDLE Controller
,
749 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
753 EFI_DEV_PATH_PTR DevicePathNode
;
754 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
755 EFI_PCI_IO_PROTOCOL
*PciIo
;
759 // Check whether device path is valid
761 if (RemainingDevicePath
!= NULL
) {
763 // Check if RemainingDevicePath is the End of Device Path Node,
764 // if yes, go on checking other conditions
766 if (!IsDevicePathEnd (RemainingDevicePath
)) {
768 // If RemainingDevicePath isn't the End of Device Path Node,
769 // check its validation
771 DevicePathNode
.DevPath
= RemainingDevicePath
;
773 if ((DevicePathNode
.DevPath
->Type
!= MESSAGING_DEVICE_PATH
) ||
774 (DevicePathNode
.DevPath
->SubType
!= MSG_NVME_NAMESPACE_DP
) ||
775 (DevicePathNodeLength(DevicePathNode
.DevPath
) != sizeof(NVME_NAMESPACE_DEVICE_PATH
))) {
776 return EFI_UNSUPPORTED
;
782 // Open the EFI Device Path protocol needed to perform the supported test
784 Status
= gBS
->OpenProtocol (
786 &gEfiDevicePathProtocolGuid
,
787 (VOID
**) &ParentDevicePath
,
788 This
->DriverBindingHandle
,
790 EFI_OPEN_PROTOCOL_BY_DRIVER
792 if (Status
== EFI_ALREADY_STARTED
) {
796 if (EFI_ERROR (Status
)) {
801 // Close protocol, don't use device path protocol in the Support() function
805 &gEfiDevicePathProtocolGuid
,
806 This
->DriverBindingHandle
,
811 // Attempt to Open PCI I/O Protocol
813 Status
= gBS
->OpenProtocol (
815 &gEfiPciIoProtocolGuid
,
817 This
->DriverBindingHandle
,
819 EFI_OPEN_PROTOCOL_BY_DRIVER
821 if (Status
== EFI_ALREADY_STARTED
) {
825 if (EFI_ERROR (Status
)) {
830 // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).
831 // This controller should be a Nvm Express controller.
833 Status
= PciIo
->Pci
.Read (
836 PCI_CLASSCODE_OFFSET
,
840 if (EFI_ERROR (Status
)) {
845 // Examine Nvm Express controller PCI Configuration table fields
847 if ((ClassCode
[0] != PCI_IF_NVMHCI
) || (ClassCode
[1] != PCI_CLASS_MASS_STORAGE_NVM
) || (ClassCode
[2] != PCI_CLASS_MASS_STORAGE
)) {
848 Status
= EFI_UNSUPPORTED
;
854 &gEfiPciIoProtocolGuid
,
855 This
->DriverBindingHandle
,
864 Starts a device controller or a bus controller.
866 The Start() function is designed to be invoked from the EFI boot service ConnectController().
867 As a result, much of the error checking on the parameters to Start() has been moved into this
868 common boot service. It is legal to call Start() from other locations,
869 but the following calling restrictions must be followed or the system behavior will not be deterministic.
870 1. ControllerHandle must be a valid EFI_HANDLE.
871 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
872 EFI_DEVICE_PATH_PROTOCOL.
873 3. Prior to calling Start(), the Supported() function for the driver specified by This must
874 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
876 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
877 @param[in] ControllerHandle The handle of the controller to start. This handle
878 must support a protocol interface that supplies
879 an I/O abstraction to the driver.
880 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
881 parameter is ignored by device drivers, and is optional for bus
882 drivers. For a bus driver, if this parameter is NULL, then handles
883 for all the children of Controller are created by this driver.
884 If this parameter is not NULL and the first Device Path Node is
885 not the End of Device Path Node, then only the handle for the
886 child device specified by the first Device Path Node of
887 RemainingDevicePath is created by this driver.
888 If the first Device Path Node of RemainingDevicePath is
889 the End of Device Path Node, no child handle is created by this
892 @retval EFI_SUCCESS The device was started.
893 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
894 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
895 @retval Others The driver failded to start the device.
900 NvmExpressDriverBindingStart (
901 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
902 IN EFI_HANDLE Controller
,
903 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
907 EFI_PCI_IO_PROTOCOL
*PciIo
;
908 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
909 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
911 EFI_PHYSICAL_ADDRESS MappedAddr
;
913 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*Passthru
;
915 DEBUG ((EFI_D_INFO
, "NvmExpressDriverBindingStart: start\n"));
919 ParentDevicePath
= NULL
;
921 Status
= gBS
->OpenProtocol (
923 &gEfiDevicePathProtocolGuid
,
924 (VOID
**) &ParentDevicePath
,
925 This
->DriverBindingHandle
,
927 EFI_OPEN_PROTOCOL_BY_DRIVER
929 if ((EFI_ERROR (Status
)) && (Status
!= EFI_ALREADY_STARTED
)) {
933 Status
= gBS
->OpenProtocol (
935 &gEfiPciIoProtocolGuid
,
937 This
->DriverBindingHandle
,
939 EFI_OPEN_PROTOCOL_BY_DRIVER
942 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
947 // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.
949 if (Status
!= EFI_ALREADY_STARTED
) {
950 Private
= AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA
));
952 if (Private
== NULL
) {
953 DEBUG ((EFI_D_ERROR
, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));
954 Status
= EFI_OUT_OF_RESOURCES
;
959 // 6 x 4kB aligned buffers will be carved out of this buffer.
960 // 1st 4kB boundary is the start of the admin submission queue.
961 // 2nd 4kB boundary is the start of the admin completion queue.
962 // 3rd 4kB boundary is the start of I/O submission queue #1.
963 // 4th 4kB boundary is the start of I/O completion queue #1.
964 // 5th 4kB boundary is the start of I/O submission queue #2.
965 // 6th 4kB boundary is the start of I/O completion queue #2.
967 // Allocate 6 pages of memory, then map it for bus master read and write.
969 Status
= PciIo
->AllocateBuffer (
974 (VOID
**)&Private
->Buffer
,
977 if (EFI_ERROR (Status
)) {
981 Bytes
= EFI_PAGES_TO_SIZE (6);
982 Status
= PciIo
->Map (
984 EfiPciIoOperationBusMasterCommonBuffer
,
991 if (EFI_ERROR (Status
) || (Bytes
!= EFI_PAGES_TO_SIZE (6))) {
995 Private
->BufferPciAddr
= (UINT8
*)(UINTN
)MappedAddr
;
997 Private
->Signature
= NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE
;
998 Private
->ControllerHandle
= Controller
;
999 Private
->ImageHandle
= This
->DriverBindingHandle
;
1000 Private
->DriverBindingHandle
= This
->DriverBindingHandle
;
1001 Private
->PciIo
= PciIo
;
1002 Private
->ParentDevicePath
= ParentDevicePath
;
1003 Private
->Passthru
.Mode
= &Private
->PassThruMode
;
1004 Private
->Passthru
.PassThru
= NvmExpressPassThru
;
1005 Private
->Passthru
.GetNextNamespace
= NvmExpressGetNextNamespace
;
1006 Private
->Passthru
.BuildDevicePath
= NvmExpressBuildDevicePath
;
1007 Private
->Passthru
.GetNamespace
= NvmExpressGetNamespace
;
1008 CopyMem (&Private
->PassThruMode
, &gEfiNvmExpressPassThruMode
, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE
));
1009 InitializeListHead (&Private
->AsyncPassThruQueue
);
1010 InitializeListHead (&Private
->UnsubmittedSubtasks
);
1012 Status
= NvmeControllerInit (Private
);
1013 if (EFI_ERROR(Status
)) {
1018 // Start the asynchronous I/O completion monitor
1020 Status
= gBS
->CreateEvent (
1021 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
1023 ProcessAsyncTaskList
,
1025 &Private
->TimerEvent
1027 if (EFI_ERROR (Status
)) {
1031 Status
= gBS
->SetTimer (
1032 Private
->TimerEvent
,
1036 if (EFI_ERROR (Status
)) {
1040 Status
= gBS
->InstallMultipleProtocolInterfaces (
1042 &gEfiNvmExpressPassThruProtocolGuid
,
1046 if (EFI_ERROR (Status
)) {
1050 Status
= gBS
->OpenProtocol (
1052 &gEfiNvmExpressPassThruProtocolGuid
,
1053 (VOID
**) &Passthru
,
1054 This
->DriverBindingHandle
,
1056 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1058 if (EFI_ERROR (Status
)) {
1062 Private
= NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (Passthru
);
1065 if (RemainingDevicePath
== NULL
) {
1067 // Enumerate all NVME namespaces in the controller
1069 Status
= DiscoverAllNamespaces (
1073 } else if (!IsDevicePathEnd (RemainingDevicePath
)) {
1075 // Enumerate the specified NVME namespace
1077 Status
= Private
->Passthru
.GetNamespace (
1079 RemainingDevicePath
,
1083 if (!EFI_ERROR (Status
)) {
1084 Status
= EnumerateNvmeDevNamespace (
1091 DEBUG ((EFI_D_INFO
, "NvmExpressDriverBindingStart: end successfully\n"));
1095 if ((Private
!= NULL
) && (Private
->Mapping
!= NULL
)) {
1096 PciIo
->Unmap (PciIo
, Private
->Mapping
);
1099 if ((Private
!= NULL
) && (Private
->Buffer
!= NULL
)) {
1100 PciIo
->FreeBuffer (PciIo
, 6, Private
->Buffer
);
1103 if ((Private
!= NULL
) && (Private
->ControllerData
!= NULL
)) {
1104 FreePool (Private
->ControllerData
);
1107 if (Private
!= NULL
) {
1108 if (Private
->TimerEvent
!= NULL
) {
1109 gBS
->CloseEvent (Private
->TimerEvent
);
1115 gBS
->CloseProtocol (
1117 &gEfiPciIoProtocolGuid
,
1118 This
->DriverBindingHandle
,
1122 gBS
->CloseProtocol (
1124 &gEfiDevicePathProtocolGuid
,
1125 This
->DriverBindingHandle
,
1129 DEBUG ((EFI_D_INFO
, "NvmExpressDriverBindingStart: end with %r\n", Status
));
1136 Stops a device controller or a bus controller.
1138 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
1139 As a result, much of the error checking on the parameters to Stop() has been moved
1140 into this common boot service. It is legal to call Stop() from other locations,
1141 but the following calling restrictions must be followed or the system behavior will not be deterministic.
1142 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
1143 same driver's Start() function.
1144 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
1145 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
1146 Start() function, and the Start() function must have called OpenProtocol() on
1147 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
1149 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
1150 @param[in] ControllerHandle A handle to the device being stopped. The handle must
1151 support a bus specific I/O protocol for the driver
1152 to use to stop the device.
1153 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
1154 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
1155 if NumberOfChildren is 0.
1157 @retval EFI_SUCCESS The device was stopped.
1158 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
1163 NvmExpressDriverBindingStop (
1164 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
1165 IN EFI_HANDLE Controller
,
1166 IN UINTN NumberOfChildren
,
1167 IN EFI_HANDLE
*ChildHandleBuffer
1171 BOOLEAN AllChildrenStopped
;
1173 NVME_CONTROLLER_PRIVATE_DATA
*Private
;
1174 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL
*PassThru
;
1178 if (NumberOfChildren
== 0) {
1179 Status
= gBS
->OpenProtocol (
1181 &gEfiNvmExpressPassThruProtocolGuid
,
1182 (VOID
**) &PassThru
,
1183 This
->DriverBindingHandle
,
1185 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1188 if (!EFI_ERROR (Status
)) {
1189 Private
= NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru
);
1192 // Wait for the asynchronous PassThru queue to become empty.
1195 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
1196 IsEmpty
= IsListEmpty (&Private
->AsyncPassThruQueue
) &&
1197 IsListEmpty (&Private
->UnsubmittedSubtasks
);
1198 gBS
->RestoreTPL (OldTpl
);
1207 gBS
->UninstallMultipleProtocolInterfaces (
1209 &gEfiNvmExpressPassThruProtocolGuid
,
1214 if (Private
->TimerEvent
!= NULL
) {
1215 gBS
->CloseEvent (Private
->TimerEvent
);
1218 if (Private
->Mapping
!= NULL
) {
1219 Private
->PciIo
->Unmap (Private
->PciIo
, Private
->Mapping
);
1222 if (Private
->Buffer
!= NULL
) {
1223 Private
->PciIo
->FreeBuffer (Private
->PciIo
, 6, Private
->Buffer
);
1226 FreePool (Private
->ControllerData
);
1230 gBS
->CloseProtocol (
1232 &gEfiPciIoProtocolGuid
,
1233 This
->DriverBindingHandle
,
1236 gBS
->CloseProtocol (
1238 &gEfiDevicePathProtocolGuid
,
1239 This
->DriverBindingHandle
,
1245 AllChildrenStopped
= TRUE
;
1247 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
1248 Status
= UnregisterNvmeNamespace (This
, Controller
, ChildHandleBuffer
[Index
]);
1249 if (EFI_ERROR (Status
)) {
1250 AllChildrenStopped
= FALSE
;
1254 if (!AllChildrenStopped
) {
1255 return EFI_DEVICE_ERROR
;
1262 This is the unload handle for the NVM Express driver.
1264 Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.
1265 Uninstall all the protocols installed in the driver.
1267 @param[in] ImageHandle The drivers' driver image.
1269 @retval EFI_SUCCESS The image is unloaded.
1270 @retval Others Failed to unload the image.
1276 IN EFI_HANDLE ImageHandle
1280 EFI_HANDLE
*DeviceHandleBuffer
;
1281 UINTN DeviceHandleCount
;
1283 EFI_COMPONENT_NAME_PROTOCOL
*ComponentName
;
1284 EFI_COMPONENT_NAME2_PROTOCOL
*ComponentName2
;
1287 // Get the list of the device handles managed by this driver.
1288 // If there is an error getting the list, then means the driver
1289 // doesn't manage any device. At this way, we would only close
1290 // those protocols installed at image handle.
1292 DeviceHandleBuffer
= NULL
;
1293 Status
= gBS
->LocateHandleBuffer (
1295 &gEfiNvmExpressPassThruProtocolGuid
,
1301 if (!EFI_ERROR (Status
)) {
1303 // Disconnect the driver specified by ImageHandle from all
1304 // the devices in the handle database.
1306 for (Index
= 0; Index
< DeviceHandleCount
; Index
++) {
1307 Status
= gBS
->DisconnectController (
1308 DeviceHandleBuffer
[Index
],
1312 if (EFI_ERROR (Status
)) {
1319 // Uninstall all the protocols installed in the driver entry point
1321 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1323 &gEfiDriverBindingProtocolGuid
,
1324 &gNvmExpressDriverBinding
,
1325 &gEfiDriverSupportedEfiVersionProtocolGuid
,
1326 &gNvmExpressDriverSupportedEfiVersion
,
1330 if (EFI_ERROR (Status
)) {
1335 // Note we have to one by one uninstall the following protocols.
1336 // It's because some of them are optionally installed based on
1337 // the following PCD settings.
1338 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable
1339 // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable
1340 // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable
1341 // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable
1343 Status
= gBS
->HandleProtocol (
1345 &gEfiComponentNameProtocolGuid
,
1346 (VOID
**) &ComponentName
1348 if (!EFI_ERROR (Status
)) {
1349 gBS
->UninstallProtocolInterface (
1351 &gEfiComponentNameProtocolGuid
,
1356 Status
= gBS
->HandleProtocol (
1358 &gEfiComponentName2ProtocolGuid
,
1359 (VOID
**) &ComponentName2
1361 if (!EFI_ERROR (Status
)) {
1362 gBS
->UninstallProtocolInterface (
1364 &gEfiComponentName2ProtocolGuid
,
1369 Status
= EFI_SUCCESS
;
1373 // Free the buffer containing the list of handles from the handle database
1375 if (DeviceHandleBuffer
!= NULL
) {
1376 gBS
->FreePool (DeviceHandleBuffer
);
1382 The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.
1384 @param ImageHandle The firmware allocated handle for this driver image.
1385 @param SystemTable Pointer to the EFI system table.
1387 @retval EFI_SUCCESS Driver loaded.
1388 @retval other Driver not loaded.
1393 NvmExpressDriverEntry (
1394 IN EFI_HANDLE ImageHandle
,
1395 IN EFI_SYSTEM_TABLE
*SystemTable
1400 Status
= EfiLibInstallDriverBindingComponentName2 (
1403 &gNvmExpressDriverBinding
,
1405 &gNvmExpressComponentName
,
1406 &gNvmExpressComponentName2
1408 ASSERT_EFI_ERROR (Status
);
1411 // Install EFI Driver Supported EFI Version Protocol required for
1412 // EFI drivers that are on PCI and other plug in cards.
1414 gNvmExpressDriverSupportedEfiVersion
.FirmwareVersion
= 0x00020028;
1415 Status
= gBS
->InstallMultipleProtocolInterfaces (
1417 &gEfiDriverSupportedEfiVersionProtocolGuid
,
1418 &gNvmExpressDriverSupportedEfiVersion
,
1421 ASSERT_EFI_ERROR (Status
);