--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpress.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gNvmExpressComponentName = {\r
+ NvmExpressComponentNameGetDriverName,\r
+ NvmExpressComponentNameGetControllerName,\r
+ "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gNvmExpressComponentName2 = {\r
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) NvmExpressComponentNameGetDriverName,\r
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) NvmExpressComponentNameGetControllerName,\r
+ "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mNvmExpressDriverNameTable[] = {\r
+ { "eng;en", L"NVM Express Driver" },\r
+ { NULL, NULL }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mNvmExpressControllerNameTable[] = {\r
+ { "eng;en", L"NVM Express Controller" },\r
+ { NULL, NULL }\r
+};\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ )\r
+{\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ mNvmExpressDriverNameTable,\r
+ DriverName,\r
+ (BOOLEAN)(This == &gNvmExpressComponentName)\r
+ );\r
+}\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+\r
+ //\r
+ // Make sure this driver is currently managing ControllHandle\r
+ //\r
+ Status = EfiTestManagedDevice (\r
+ ControllerHandle,\r
+ gNvmExpressDriverBinding.DriverBindingHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ ControllerNameTable = mNvmExpressControllerNameTable;\r
+ if (ChildHandle != NULL) {\r
+ Status = EfiTestChildHandle (\r
+ ControllerHandle,\r
+ ChildHandle,\r
+ &gEfiPciIoProtocolGuid\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Get the child context\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ gNvmExpressDriverBinding.DriverBindingHandle,\r
+ ChildHandle,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
+ ControllerNameTable = Device->ControllerNameTable;\r
+ }\r
+\r
+ return LookupUnicodeString2 (\r
+ Language,\r
+ This->SupportedLanguages,\r
+ ControllerNameTable,\r
+ ControllerName,\r
+ (BOOLEAN)(This == &gNvmExpressComponentName)\r
+ );\r
+\r
+}\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpress.h"\r
+\r
+//\r
+// NVM Express Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding = {\r
+ NvmExpressDriverBindingSupported,\r
+ NvmExpressDriverBindingStart,\r
+ NvmExpressDriverBindingStop,\r
+ 0x10,\r
+ NULL,\r
+ NULL\r
+};\r
+\r
+//\r
+// NVM Express EFI Driver Supported EFI Version Protocol Instance\r
+//\r
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion = {\r
+ sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.\r
+ 0 // Version number to be filled at start up.\r
+};\r
+\r
+/**\r
+ Check if the specified Nvm Express device namespace is active, and create child handles\r
+ for them with BlockIo and DiskInfo protocol instances.\r
+\r
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
+ allocated and built. Caller must set the NamespaceId to zero if the\r
+ device path node will contain a valid UUID.\r
+ @param[in] NamespaceUuid The NVM Express namespace UUID for which a device path node is to be\r
+ allocated and built. UUID will only be valid of the Namespace ID is zero.\r
+\r
+ @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
+ @return Others Some error occurs when enumerating the namespaces.\r
+\r
+**/\r
+EFI_STATUS\r
+EnumerateNvmeDevNamespace (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ UINT32 NamespaceId,\r
+ UINT64 NamespaceUuid\r
+ )\r
+{\r
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ UINT32 Lbads;\r
+ UINT32 Flbas;\r
+ UINT32 LbaFmtIdx;\r
+\r
+ NewDevicePathNode = NULL;\r
+ DevicePath = NULL;\r
+ Device = NULL;\r
+\r
+ //\r
+ // Allocate a buffer for Identify Namespace data\r
+ //\r
+ NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
+ if(NamespaceData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ ParentDevicePath = Private->ParentDevicePath;\r
+ //\r
+ // Identify Namespace\r
+ //\r
+ Status = NvmeIdentifyNamespace (\r
+ Private,\r
+ NamespaceId,\r
+ (VOID *)NamespaceData\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+ //\r
+ // Validate Namespace\r
+ //\r
+ if (NamespaceData->Ncap == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // allocate device private data for each discovered namespace\r
+ //\r
+ Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));\r
+ if (Device == NULL) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Initialize SSD namespace instance data\r
+ //\r
+ Device->Signature = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;\r
+ Device->NamespaceId = NamespaceId;\r
+ Device->NamespaceUuid = NamespaceData->Eui64;\r
+\r
+ Device->ControllerHandle = Private->ControllerHandle;\r
+ Device->DriverBindingHandle = Private->DriverBindingHandle;\r
+ Device->Controller = Private;\r
+\r
+ //\r
+ // Build BlockIo media structure\r
+ //\r
+ Device->Media.MediaId = 0;\r
+ Device->Media.RemovableMedia = FALSE;\r
+ Device->Media.MediaPresent = TRUE;\r
+ Device->Media.LogicalPartition = FALSE;\r
+ Device->Media.ReadOnly = FALSE;\r
+ Device->Media.WriteCaching = FALSE;\r
+\r
+ Flbas = NamespaceData->Flbas;\r
+ LbaFmtIdx = Flbas & 3;\r
+ Lbads = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;\r
+ Device->Media.BlockSize = (UINT32)1 << Lbads;\r
+\r
+ Device->Media.LastBlock = NamespaceData->Nsze - 1;\r
+ Device->Media.LogicalBlocksPerPhysicalBlock = 1;\r
+ Device->Media.LowestAlignedLba = 1;\r
+\r
+ //\r
+ // Create BlockIo Protocol instance\r
+ //\r
+ Device->BlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
+ Device->BlockIo.Media = &Device->Media;\r
+ Device->BlockIo.Reset = NvmeBlockIoReset;\r
+ Device->BlockIo.ReadBlocks = NvmeBlockIoReadBlocks;\r
+ Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;\r
+ Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;\r
+\r
+ //\r
+ // Create DiskInfo Protocol instance\r
+ //\r
+ InitializeDiskInfo (Device);\r
+\r
+ //\r
+ // Create a Nvm Express Namespace Device Path Node\r
+ //\r
+ Status = Private->Passthru.BuildDevicePath (\r
+ &Private->Passthru,\r
+ Device->NamespaceId,\r
+ Device->NamespaceUuid,\r
+ &NewDevicePathNode\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Append the SSD node to the controller's device path\r
+ //\r
+ DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);\r
+ if (DevicePath == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit;\r
+ }\r
+\r
+ DeviceHandle = NULL;\r
+ RemainingDevicePath = DevicePath;\r
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+ if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+ Status = EFI_ALREADY_STARTED;\r
+ FreePool (DevicePath);\r
+ goto Exit;\r
+ }\r
+\r
+ Device->DevicePath = DevicePath;\r
+\r
+ //\r
+ // Make sure the handle is NULL so we create a new handle\r
+ //\r
+ Device->DeviceHandle = NULL;\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Device->DeviceHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Device->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Device->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &Device->DiskInfo,\r
+ NULL\r
+ );\r
+\r
+ if(EFI_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+ gBS->OpenProtocol (\r
+ Private->ControllerHandle,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &Private->PciIo,\r
+ Private->DriverBindingHandle,\r
+ Device->DeviceHandle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+\r
+ //\r
+ // Build controller name for Component Name (2) protocol.\r
+ //\r
+ UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Private->ControllerData->Sn, Private->ControllerData->Mn, NamespaceData->Eui64);\r
+\r
+ AddUnicodeString2 (\r
+ "eng",\r
+ gNvmExpressComponentName.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ TRUE\r
+ );\r
+\r
+ AddUnicodeString2 (\r
+ "en",\r
+ gNvmExpressComponentName2.SupportedLanguages,\r
+ &Device->ControllerNameTable,\r
+ Device->ModelName,\r
+ FALSE\r
+ );\r
+ }\r
+\r
+Exit:\r
+ if(NamespaceData != NULL) {\r
+ FreePool (NamespaceData);\r
+ }\r
+\r
+ if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {\r
+ FreePool (Device->DevicePath);\r
+ }\r
+ if(EFI_ERROR(Status) && (Device != NULL)) {\r
+ FreePool (Device);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Discover all Nvm Express device namespaces, and create child handles for them with BlockIo\r
+ and DiskInfo protocol instances.\r
+\r
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @retval EFI_SUCCESS All the namespaces in the device are successfully enumerated.\r
+ @return Others Some error occurs when enumerating the namespaces.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverAllNamespaces (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 NamespaceId;\r
+ UINT64 NamespaceUuid;\r
+ NVM_EXPRESS_PASS_THRU_PROTOCOL *Passthru;\r
+\r
+ NamespaceId = 0xFFFFFFFF;\r
+ NamespaceUuid = 0;\r
+ Passthru = &Private->Passthru;\r
+\r
+ while (TRUE) {\r
+ Status = Passthru->GetNextNamespace (\r
+ Passthru,\r
+ (UINT32 *)&NamespaceId,\r
+ (UINT64 *)&NamespaceUuid\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+\r
+ Status = EnumerateNvmeDevNamespace (\r
+ Private,\r
+ NamespaceId,\r
+ NamespaceUuid\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Unregisters a Nvm Express device namespace.\r
+\r
+ This function removes the protocols installed on the controller handle and\r
+ frees the resources allocated for the namespace.\r
+\r
+ @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param Controller The controller handle of the namespace.\r
+ @param Handle The child handle.\r
+\r
+ @retval EFI_SUCCESS The namespace is successfully unregistered.\r
+ @return Others Some error occurs when unregistering the namespace.\r
+\r
+**/\r
+EFI_STATUS\r
+UnregisterNvmeNamespace (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_HANDLE Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+\r
+ BlockIo = NULL;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ (VOID **) &BlockIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);\r
+\r
+ //\r
+ // Close the child handle\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Handle\r
+ );\r
+\r
+ //\r
+ // The Nvm Express driver installs the BlockIo and DiskInfo in the DriverBindingStart().\r
+ // Here should uninstall both of them.\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ Device->DevicePath,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &Device->BlockIo,\r
+ &gEfiDiskInfoProtocolGuid,\r
+ &Device->DiskInfo,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ if(Device->DevicePath != NULL) {\r
+ FreePool (Device->DevicePath);\r
+ }\r
+\r
+ if (Device->ControllerNameTable != NULL) {\r
+ FreeUnicodeStringTable (Device->ControllerNameTable);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEV_PATH_PTR DevicePathNode;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 ClassCode[3];\r
+\r
+ //\r
+ // Check whether device path is valid\r
+ //\r
+ if (RemainingDevicePath != NULL) {\r
+ //\r
+ // Check if RemainingDevicePath is the End of Device Path Node,\r
+ // if yes, go on checking other conditions\r
+ //\r
+ if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // If RemainingDevicePath isn't the End of Device Path Node,\r
+ // check its validation\r
+ //\r
+ DevicePathNode.DevPath = RemainingDevicePath;\r
+\r
+ if ((DevicePathNode.DevPath->Type != MESSAGING_DEVICE_PATH) ||\r
+ (DevicePathNode.DevPath->SubType != MSG_NVME_NAMESPACE_DP) ||\r
+ DevicePathNodeLength(DevicePathNode.DevPath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Open the EFI Device Path protocol needed to perform the supported test\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Close protocol, don't use device path protocol in the Support() function\r
+ //\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ //\r
+ // Attempt to Open PCI I/O Protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (Status == EFI_ALREADY_STARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Now further check the PCI header: Base class (offset 0x0B) and Sub Class (offset 0x0A).\r
+ // This controller should be a Nvm Express controller.\r
+ //\r
+ Status = PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint8,\r
+ PCI_CLASSCODE_OFFSET,\r
+ sizeof (ClassCode),\r
+ ClassCode\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Examine Nvm Express controller PCI Configuration table fields\r
+ //\r
+ if ((ClassCode[0] != PCI_IF_NVMHCI) || (ClassCode[1] != PCI_CLASS_MASS_STORAGE_NVM) || (ClassCode[2] != PCI_CLASS_MASS_STORAGE)) {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+Done:\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+ UINT32 NamespaceId;\r
+ UINT64 NamespaceUuid;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
+ UINTN Bytes;\r
+\r
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: start\n"));\r
+\r
+ Private = NULL;\r
+ ParentDevicePath = NULL;\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &ParentDevicePath,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ (VOID **) &PciIo,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check EFI_ALREADY_STARTED to reuse the original NVME_CONTROLLER_PRIVATE_DATA.\r
+ //\r
+ if (Status != EFI_ALREADY_STARTED) {\r
+ Private = AllocateZeroPool (sizeof (NVME_CONTROLLER_PRIVATE_DATA));\r
+\r
+ if (Private == NULL) {\r
+ DEBUG ((EFI_D_ERROR, "NvmExpressDriverBindingStart: allocating pool for Nvme Private Data failed!\n"));\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Exit2;\r
+ }\r
+\r
+ //\r
+ // 4 x 4kB aligned buffers will be carved out of this buffer.\r
+ // 1st 4kB boundary is the start of the admin submission queue.\r
+ // 2nd 4kB boundary is the start of the admin completion queue.\r
+ // 3rd 4kB boundary is the start of I/O submission queue #1.\r
+ // 4th 4kB boundary is the start of I/O completion queue #1.\r
+ //\r
+ // Allocate 4 pages of memory, then map it for bus master read and write.\r
+ //\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ 6,\r
+ (VOID**)&Private->Buffer,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit2;\r
+ }\r
+\r
+ Bytes = EFI_PAGES_TO_SIZE (4);\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ Private->Buffer,\r
+ &Bytes,\r
+ &MappedAddr,\r
+ &Private->Mapping\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (4))) {\r
+ goto Exit2;\r
+ }\r
+\r
+ Private->BufferPciAddr = (UINT8 *)(UINTN)MappedAddr;\r
+ ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (4));\r
+\r
+ Private->Signature = NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
+ Private->ControllerHandle = Controller;\r
+ Private->ImageHandle = This->DriverBindingHandle;\r
+ Private->DriverBindingHandle = This->DriverBindingHandle;\r
+ Private->PciIo = PciIo;\r
+ Private->ParentDevicePath = ParentDevicePath;\r
+ Private->Passthru.Mode = &Private->PassThruMode;\r
+ Private->Passthru.PassThru = NvmExpressPassThru;\r
+ Private->Passthru.GetNextNamespace = NvmExpressGetNextNamespace;\r
+ Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;\r
+ Private->Passthru.GetNamespace = NvmExpressGetNamespace;\r
+ Private->PassThruMode.Attributes = NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL;\r
+\r
+ Status = NvmeControllerInit (Private);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ goto Exit2;\r
+ }\r
+\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit2;\r
+ }\r
+ } else {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ Private = NULL;\r
+ goto Exit1;\r
+ }\r
+ }\r
+\r
+ if (RemainingDevicePath == NULL) {\r
+ //\r
+ // Enumerate all NVME namespaces in the controller\r
+ //\r
+ Status = DiscoverAllNamespaces (\r
+ Private\r
+ );\r
+\r
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+ //\r
+ // Enumerate the specified NVME namespace\r
+ //\r
+ Status = Private->Passthru.GetNamespace (\r
+ &Private->Passthru,\r
+ RemainingDevicePath,\r
+ &NamespaceId,\r
+ &NamespaceUuid\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = EnumerateNvmeDevNamespace (\r
+ Private,\r
+ NamespaceId,\r
+ NamespaceUuid\r
+ );\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end successfully\n"));\r
+ return EFI_SUCCESS;\r
+\r
+Exit1:\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private,\r
+ NULL\r
+ );\r
+Exit2:\r
+ if ((Private != NULL) && (Private->Mapping != NULL)) {\r
+ PciIo->Unmap (PciIo, Private->Mapping);\r
+ }\r
+\r
+ if ((Private != NULL) && (Private->Buffer != NULL)) {\r
+ PciIo->FreeBuffer (PciIo, 4, Private->Buffer);\r
+ }\r
+\r
+ if (Private != NULL) {\r
+ FreePool (Private);\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+\r
+ DEBUG ((EFI_D_INFO, "NvmExpressDriverBindingStart: end with %r\n", Status));\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN AllChildrenStopped;\r
+ UINTN Index;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+\r
+ if (NumberOfChildren == 0) {\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ (VOID **) &Private,\r
+ This->DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Controller,\r
+ &gEfiCallerIdGuid,\r
+ Private,\r
+ NULL\r
+ );\r
+\r
+ if (Private->Mapping != NULL) {\r
+ Private->PciIo->Unmap (Private->PciIo, Private->Mapping);\r
+ }\r
+\r
+ if (Private->Buffer != NULL) {\r
+ Private->PciIo->FreeBuffer (Private->PciIo, 4, Private->Buffer);\r
+ }\r
+\r
+ FreePool (Private->ControllerData);\r
+ FreePool (Private);\r
+ }\r
+\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiPciIoProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ gBS->CloseProtocol (\r
+ Controller,\r
+ &gEfiDevicePathProtocolGuid,\r
+ This->DriverBindingHandle,\r
+ Controller\r
+ );\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ AllChildrenStopped = TRUE;\r
+\r
+ for (Index = 0; Index < NumberOfChildren; Index++) {\r
+ Status = UnregisterNvmeNamespace (This, Controller, ChildHandleBuffer[Index]);\r
+ if (EFI_ERROR (Status)) {\r
+ AllChildrenStopped = FALSE;\r
+ }\r
+ }\r
+\r
+ if (!AllChildrenStopped) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This is the unload handle for the NVM Express driver.\r
+\r
+ Disconnect the driver specified by ImageHandle from the NVMe device in the handle database.\r
+ Uninstall all the protocols installed in the driver.\r
+\r
+ @param[in] ImageHandle The drivers' driver image.\r
+\r
+ @retval EFI_SUCCESS The image is unloaded.\r
+ @retval Others Failed to unload the image.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressUnload (\r
+ IN EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *DeviceHandleBuffer;\r
+ UINTN DeviceHandleCount;\r
+ UINTN Index;\r
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;\r
+ EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
+\r
+ //\r
+ // Get the list of all the handles in the handle database.\r
+ // If there is an error getting the list, then the unload\r
+ // operation fails.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ AllHandles,\r
+ NULL,\r
+ NULL,\r
+ &DeviceHandleCount,\r
+ &DeviceHandleBuffer\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Disconnect the driver specified by ImageHandle from all\r
+ // the devices in the handle database.\r
+ //\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = gBS->DisconnectController (\r
+ DeviceHandleBuffer[Index],\r
+ ImageHandle,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ //\r
+ // Uninstall all the protocols installed in the driver entry point\r
+ //\r
+ for (Index = 0; Index < DeviceHandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiDriverBindingProtocolGuid,\r
+ (VOID **) &DriverBinding\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (DriverBinding->ImageHandle != ImageHandle) {\r
+ continue;\r
+ }\r
+\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiDriverBindingProtocolGuid,\r
+ DriverBinding\r
+ );\r
+\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiComponentNameProtocolGuid,\r
+ (VOID **) &ComponentName\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiComponentNameProtocolGuid,\r
+ ComponentName\r
+ );\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ DeviceHandleBuffer[Index],\r
+ &gEfiComponentName2ProtocolGuid,\r
+ (VOID **) &ComponentName2\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ gBS->UninstallProtocolInterface (\r
+ ImageHandle,\r
+ &gEfiComponentName2ProtocolGuid,\r
+ ComponentName2\r
+ );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free the buffer containing the list of handles from the handle database\r
+ //\r
+ if (DeviceHandleBuffer != NULL) {\r
+ gBS->FreePool (DeviceHandleBuffer);\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The entry point for Nvm Express driver, used to install Nvm Express driver on the ImageHandle.\r
+\r
+ @param ImageHandle The firmware allocated handle for this driver image.\r
+ @param SystemTable Pointer to the EFI system table.\r
+\r
+ @retval EFI_SUCCESS Driver loaded.\r
+ @retval other Driver not loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverEntry (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = EfiLibInstallDriverBindingComponentName2 (\r
+ ImageHandle,\r
+ SystemTable,\r
+ &gNvmExpressDriverBinding,\r
+ ImageHandle,\r
+ &gNvmExpressComponentName,\r
+ &gNvmExpressComponentName2\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Install EFI Driver Supported EFI Version Protocol required for\r
+ // EFI drivers that are on PCI and other plug in cards.\r
+ //\r
+ gNvmExpressDriverSupportedEfiVersion.FirmwareVersion = 0x00020028;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &ImageHandle,\r
+ &gEfiDriverSupportedEfiVersionProtocolGuid,\r
+ &gNvmExpressDriverSupportedEfiVersion,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_NVM_EXPRESS_H_\r
+#define _EFI_NVM_EXPRESS_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/LoadedImage.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DiskInfo.h>\r
+#include <Protocol/DriverSupportedEfiVersion.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+\r
+typedef struct _NVME_CONTROLLER_PRIVATE_DATA NVME_CONTROLLER_PRIVATE_DATA;\r
+typedef struct _NVME_DEVICE_PRIVATE_DATA NVME_DEVICE_PRIVATE_DATA;\r
+\r
+#include "NvmExpressPassthru.h"\r
+#include "NvmExpressBlockIo.h"\r
+#include "NvmExpressDiskInfo.h"\r
+#include "NvmExpressHci.h"\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL gNvmExpressDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL gNvmExpressComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gNvmExpressComponentName2;\r
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiVersion;\r
+\r
+#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass storage sub-class non-volatile memory.\r
+#define PCI_IF_NVMHCI 0x02 // mass storage programming interface NVMHCI.\r
+\r
+#define NVME_ASQ_SIZE 2 // Number of admin submission queue entries\r
+#define NVME_ACQ_SIZE 2 // Number of admin completion queue entries\r
+\r
+#define NVME_CSQ_SIZE 2 // Number of I/O submission queue entries\r
+#define NVME_CCQ_SIZE 2 // Number of I/O completion queue entries\r
+\r
+#define NVME_MAX_IO_QUEUES 2 // Number of I/O queues supported by the driver\r
+\r
+#define NVME_CONTROLLER_ID 0\r
+\r
+//\r
+// Time out value for Nvme transaction execution\r
+//\r
+#define NVME_GENERIC_TIMEOUT EFI_TIMER_PERIOD_SECONDS (5)\r
+\r
+//\r
+// Unique signature for private data structure.\r
+//\r
+#define NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('N','V','M','E')\r
+\r
+//\r
+// Nvme private data structure.\r
+//\r
+struct _NVME_CONTROLLER_PRIVATE_DATA {\r
+ UINT32 Signature;\r
+\r
+ EFI_HANDLE ControllerHandle;\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_HANDLE DriverBindingHandle;\r
+\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 PciAttributes;\r
+\r
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
+\r
+ NVM_EXPRESS_PASS_THRU_MODE PassThruMode;\r
+ NVM_EXPRESS_PASS_THRU_PROTOCOL Passthru;\r
+\r
+ //\r
+ // pointer to identify controller data\r
+ //\r
+ NVME_ADMIN_CONTROLLER_DATA *ControllerData;\r
+\r
+ //\r
+ // 6 x 4kB aligned buffers will be carved out of this buffer.\r
+ // 1st 4kB boundary is the start of the admin submission queue.\r
+ // 2nd 4kB boundary is the start of submission queue #1.\r
+ // 3rd 4kB boundary is the start of the admin completion queue.\r
+ // 4th 4kB boundary is the start of completion queue #1.\r
+ // 5th 4kB boundary is the start of the first PRP list page.\r
+ // 6th 4kB boundary is the start of the second PRP list page.\r
+ //\r
+ UINT8 *Buffer;\r
+ UINT8 *BufferPciAddr;\r
+\r
+ //\r
+ // Pointers to 4kB aligned submission & completion queues.\r
+ //\r
+ NVME_SQ *SqBuffer[NVME_MAX_IO_QUEUES];\r
+ NVME_CQ *CqBuffer[NVME_MAX_IO_QUEUES];\r
+ NVME_SQ *SqBufferPciAddr[NVME_MAX_IO_QUEUES];\r
+ NVME_CQ *CqBufferPciAddr[NVME_MAX_IO_QUEUES];\r
+\r
+ //\r
+ // Submission and completion queue indices.\r
+ //\r
+ NVME_SQTDBL SqTdbl[NVME_MAX_IO_QUEUES];\r
+ NVME_CQHDBL CqHdbl[NVME_MAX_IO_QUEUES];\r
+\r
+ UINT8 Pt[2];\r
+ UINT16 Cid[2];\r
+\r
+ //\r
+ // Nvme controller capabilities\r
+ //\r
+ NVME_CAP Cap;\r
+\r
+ VOID *Mapping;\r
+};\r
+\r
+#define NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU(a) \\r
+ CR (a, \\r
+ NVME_CONTROLLER_PRIVATE_DATA, \\r
+ Passthru, \\r
+ NVME_CONTROLLER_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+//\r
+// Unique signature for private data structure.\r
+//\r
+#define NVME_DEVICE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('X','S','S','D')\r
+\r
+//\r
+// Nvme device private data structure\r
+//\r
+struct _NVME_DEVICE_PRIVATE_DATA {\r
+ UINT32 Signature;\r
+\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_HANDLE ControllerHandle;\r
+ EFI_HANDLE DriverBindingHandle;\r
+\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+\r
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;\r
+\r
+ UINT32 NamespaceId;\r
+ UINT64 NamespaceUuid;\r
+\r
+ EFI_BLOCK_IO_MEDIA Media;\r
+ EFI_BLOCK_IO_PROTOCOL BlockIo;\r
+ EFI_DISK_INFO_PROTOCOL DiskInfo;\r
+\r
+ EFI_LBA NumBlocks;\r
+\r
+ CHAR16 ModelName[80];\r
+ NVME_ADMIN_NAMESPACE_DATA NamespaceData;\r
+\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+\r
+};\r
+\r
+//\r
+// Statments to retrieve the private data from produced protocols.\r
+//\r
+#define NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO(a) \\r
+ CR (a, \\r
+ NVME_DEVICE_PRIVATE_DATA, \\r
+ BlockIo, \\r
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+#define NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO(a) \\r
+ CR (a, \\r
+ NVME_DEVICE_PRIVATE_DATA, \\r
+ DiskInfo, \\r
+ NVME_DEVICE_PRIVATE_DATA_SIGNATURE \\r
+ )\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+ This function retrieves the user readable name of a driver in the form of a\r
+ Unicode string. If the driver specified by This has a user readable name in\r
+ the language specified by Language, then a pointer to the driver name is\r
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+ by This does not support the language specified by Language,\r
+ then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified\r
+ in RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param DriverName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ driver specified by This in the language\r
+ specified by Language.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by\r
+ This and the language specified by Language was\r
+ returned in DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressComponentNameGetDriverName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **DriverName\r
+ );\r
+\r
+/**\r
+ Retrieves a Unicode string that is the user readable name of the controller\r
+ that is being managed by a driver.\r
+\r
+ This function retrieves the user readable name of the controller specified by\r
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+ driver specified by This has a user readable name in the language specified by\r
+ Language, then a pointer to the controller name is returned in ControllerName,\r
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently\r
+ managing the controller specified by ControllerHandle and ChildHandle,\r
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not\r
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+ EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+ @param ControllerHandle[in] The handle of a controller that the driver\r
+ specified by This is managing. This handle\r
+ specifies the controller whose name is to be\r
+ returned.\r
+\r
+ @param ChildHandle[in] The handle of the child controller to retrieve\r
+ the name of. This is an optional parameter that\r
+ may be NULL. It will be NULL for device\r
+ drivers. It will also be NULL for a bus drivers\r
+ that wish to retrieve the name of the bus\r
+ controller. It will not be NULL for a bus\r
+ driver that wishes to retrieve the name of a\r
+ child controller.\r
+\r
+ @param Language[in] A pointer to a Null-terminated ASCII string\r
+ array indicating the language. This is the\r
+ language of the driver name that the caller is\r
+ requesting, and it must match one of the\r
+ languages specified in SupportedLanguages. The\r
+ number of languages supported by a driver is up\r
+ to the driver writer. Language is specified in\r
+ RFC 4646 or ISO 639-2 language code format.\r
+\r
+ @param ControllerName[out] A pointer to the Unicode string to return.\r
+ This Unicode string is the name of the\r
+ controller specified by ControllerHandle and\r
+ ChildHandle in the language specified by\r
+ Language from the point of view of the driver\r
+ specified by This.\r
+\r
+ @retval EFI_SUCCESS The Unicode string for the user readable name in\r
+ the language specified by Language for the\r
+ driver specified by This was returned in\r
+ DriverName.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+ EFI_HANDLE.\r
+\r
+ @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently\r
+ managing the controller specified by\r
+ ControllerHandle and ChildHandle.\r
+\r
+ @retval EFI_UNSUPPORTED The driver specified by This does not support\r
+ the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressComponentNameGetControllerName (\r
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_HANDLE ChildHandle OPTIONAL,\r
+ IN CHAR8 *Language,\r
+ OUT CHAR16 **ControllerName\r
+ );\r
+\r
+/**\r
+ Tests to see if this driver supports a given controller. If a child device is provided,\r
+ it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+ This function checks to see if the driver specified by This supports the device specified by\r
+ ControllerHandle. Drivers will typically use the device path attached to\r
+ ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+ ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+ may be called many times during platform initialization. In order to reduce boot times, the tests\r
+ performed by this function must be very small, and take as little time as possible to execute. This\r
+ function must not change the state of any hardware devices, and this function must be aware that the\r
+ device specified by ControllerHandle may already be managed by the same driver or a\r
+ different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+ AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+ Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+ already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+ to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to test. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For bus drivers, if this parameter is not NULL, then\r
+ the bus driver must determine if the bus controller specified\r
+ by ControllerHandle and the child controller specified\r
+ by RemainingDevicePath are both supported by this\r
+ bus driver.\r
+\r
+ @retval EFI_SUCCESS The device specified by ControllerHandle and\r
+ RemainingDevicePath is supported by the driver specified by This.\r
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by the driver\r
+ specified by This.\r
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
+ RemainingDevicePath is already being managed by a different\r
+ driver or an application that requires exclusive access.\r
+ Currently not implemented.\r
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
+ RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingSupported (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Starts a device controller or a bus controller.\r
+\r
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+ As a result, much of the error checking on the parameters to Start() has been moved into this\r
+ common boot service. It is legal to call Start() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE.\r
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+ EFI_DEVICE_PATH_PROTOCOL.\r
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle The handle of the controller to start. This handle\r
+ must support a protocol interface that supplies\r
+ an I/O abstraction to the driver.\r
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
+ parameter is ignored by device drivers, and is optional for bus\r
+ drivers. For a bus driver, if this parameter is NULL, then handles\r
+ for all the children of Controller are created by this driver.\r
+ If this parameter is not NULL and the first Device Path Node is\r
+ not the End of Device Path Node, then only the handle for the\r
+ child device specified by the first Device Path Node of\r
+ RemainingDevicePath is created by this driver.\r
+ If the first Device Path Node of RemainingDevicePath is\r
+ the End of Device Path Node, no child handle is created by this\r
+ driver.\r
+\r
+ @retval EFI_SUCCESS The device was started.\r
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval Others The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingStart (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
+ );\r
+\r
+/**\r
+ Stops a device controller or a bus controller.\r
+\r
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+ As a result, much of the error checking on the parameters to Stop() has been moved\r
+ into this common boot service. It is legal to call Stop() from other locations,\r
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+ same driver's Start() function.\r
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+ Start() function, and the Start() function must have called OpenProtocol() on\r
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
+ support a bus specific I/O protocol for the driver\r
+ to use to stop the device.\r
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+ if NumberOfChildren is 0.\r
+\r
+ @retval EFI_SUCCESS The device was stopped.\r
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressDriverBindingStop (\r
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+ IN EFI_HANDLE Controller,\r
+ IN UINTN NumberOfChildren,\r
+ IN EFI_HANDLE *ChildHandleBuffer\r
+ );\r
+\r
+/**\r
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking\r
+ I/O functionality is optional.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ ID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in] NamespaceUuid Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ UUID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in,out] Packet A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified\r
+ by NamespaceId.\r
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking I/O is performed.\r
+ If Event is NULL, then blocking I/O is performed. If Event is not NULL and non blocking I/O\r
+ is supported, then nonblocking I/O is performed, and Event will be signaled when the NVM\r
+ Express Command Packet completes.\r
+\r
+ @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
+ to, or from DataBuffer.\r
+ @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred\r
+ is returned in TransferLength.\r
+ @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
+ may retry again later.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.\r
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
+ Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the host adapter.\r
+ The NVM Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressPassThru (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to retrieve the list of namespaces defined on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves a list of namespaces\r
+ defined on an NVM Express controller. If on input a NamespaceID is specified by all 0xFF in the\r
+ namespace buffer, then the first namespace defined on the NVM Express controller is returned in\r
+ NamespaceID, and a status of EFI_SUCCESS is returned.\r
+\r
+ If NamespaceId is a Namespace value that was returned on a previous call to GetNextNamespace(),\r
+ then the next valid NamespaceId for an NVM Express SSD namespace on the NVM Express controller\r
+ is returned in NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ If Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned on a previous call to\r
+ GetNextNamespace(), then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If NamespaceId is the NamespaceId of the last SSD namespace on the NVM Express controller, then\r
+ EFI_NOT_FOUND is returned\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express\r
+ namespace present on the NVM Express controller. On output, a\r
+ pointer to the next NamespaceId of an NVM Express namespace on\r
+ an NVM Express controller. An input value of 0xFFFFFFFF retrieves\r
+ the first NamespaceId for an NVM Express namespace present on an\r
+ NVM Express controller.\r
+ @param[out] NamespaceUuid On output, the UUID associated with the next namespace, if a UUID\r
+ is defined for that NamespaceId, otherwise, zero is returned in\r
+ this parameter. If the caller does not require a UUID, then a NULL\r
+ pointer may be passed.\r
+\r
+ @retval EFI_SUCCESS The NamespaceId of the next Namespace was returned.\r
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.\r
+ @retval EFI_INVALID_PARAMETER Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned\r
+ on a previous call to GetNextNamespace().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressGetNextNamespace (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to translate a device path node to a Target ID and LUN.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamwspace() function determines the Namespace ID and Namespace UUID\r
+ associated with the NVM Express SSD namespace described by DevicePath. If DevicePath is a device path node type\r
+ that the NVM Express Pass Thru driver supports, then the NVM Express Pass Thru driver will attempt to translate\r
+ the contents DevicePath into a Namespace ID and UUID. If this translation is successful, then that Namespace ID\r
+ and UUID are returned in NamespaceID and NamespaceUUID, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on\r
+ the NVM Express controller.\r
+ @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.\r
+ @param[out] NamespaceUuid The NVM Express namespace contained in the device path node.\r
+\r
+ @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId and NamespaceUuid.\r
+ @retval EFI_INVALID_PARAMETER If DevicePath, NamespaceId, or NamespaceUuid are NULL, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+ @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver\r
+ supports, then EFI_UNSUPPORTED is returned.\r
+ @retval EFI_NOT_FOUND If DevicePath is a device path node type that the Nvm Express Pass Thru driver\r
+ supports, but there is not a valid translation from DevicePath to a NamespaceID\r
+ and NamespaceUuid, then EFI_NOT_FOUND is returned.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressGetNamespace (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid\r
+ );\r
+\r
+/**\r
+ Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device\r
+ path node for the NVM Express namespace specified by NamespaceId.\r
+\r
+ If the namespace device specified by NamespaceId is not valid , then EFI_NOT_FOUND is returned.\r
+\r
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
+\r
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are\r
+ initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
+ allocated and built. Caller must set the NamespaceId to zero if the\r
+ device path node will contain a valid UUID.\r
+ @param[in] NamespaceUuid The NVM Express namespace UUID for which a device path node is to be\r
+ allocated and built. UUID will only be valid of the Namespace ID is zero.\r
+ @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express\r
+ namespace specified by NamespaceId. This function is responsible for\r
+ allocating the buffer DevicePath with the boot service AllocatePool().\r
+ It is the caller's responsibility to free DevicePath when the caller\r
+ is finished with DevicePath.\r
+ @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified\r
+ by NamespaceId was allocated and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The NVM Express namespace specified by NamespaceId does not exist on the\r
+ NVM Express controller.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressBuildDevicePath (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpress.h"\r
+\r
+/**\r
+ Read some sectors from the device.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer used to store the data read from the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS Datum are read from the device.\r
+ @retval Others Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadSectors (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+ UINT32 Bytes;\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+\r
+ Controller = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r
+ CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;\r
+\r
+ CommandPacket.TransferLength = Bytes;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(Lba >> 32);\r
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r
+\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ Status = Controller->Passthru.PassThru (\r
+ &Controller->Passthru,\r
+ Device->NamespaceId,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write some sectors to the device.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer to be written into the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS Datum are written into the buffer.\r
+ @retval Others Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteSectors (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ UINT32 Bytes;\r
+ UINT32 BlockSize;\r
+\r
+ Controller = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r
+ CommandPacket.TransferBuffer = (VOID *)(UINTN)Buffer;\r
+\r
+ CommandPacket.TransferLength = Bytes;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(Lba >> 32);\r
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r
+\r
+ CommandPacket.MetadataBuffer = NULL;\r
+ CommandPacket.MetadataLength = 0;\r
+\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ Status = Controller->Passthru.PassThru (\r
+ &Controller->Passthru,\r
+ Device->NamespaceId,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read some blocks from the device.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer used to store the data read from the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be read.\r
+\r
+ @retval EFI_SUCCESS Datum are read from the device.\r
+ @retval Others Fail to read all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeRead (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ OUT VOID *Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+ UINT32 MaxTransferBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Controller = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+\r
+ if (Controller->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Controller->ControllerData->Mdts)) * (1 << (Controller->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = ReadSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "NvmeRead() Lba = %8d, Blocks = %8d, BlockSize = %d Status = %r\n", Lba, Blocks, BlockSize, Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write some blocks to the device.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer to be written into the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be written.\r
+\r
+ @retval EFI_SUCCESS Datum are written into the buffer.\r
+ @retval Others Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeWrite (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN VOID *Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+ UINT32 MaxTransferBlocks;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Controller = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+\r
+ if (Controller->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Controller->ControllerData->Mdts)) * (1 << (Controller->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, MaxTransferBlocks);\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = WriteSectors (Device, (UINT64)(UINTN)Buffer, Lba, (UINT32)Blocks);\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "NvmeWrite() Lba = %8d, Blocks = %8d, BlockSize = %d Status = %r\n", Lba, Blocks, BlockSize, Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flushes all modified data to the device.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data structure.\r
+\r
+ @retval EFI_SUCCESS Datum are written into the buffer.\r
+ @retval Others Fail to write all the datum.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeFlush (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Controller;\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ Controller = Device->Controller;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;\r
+ CommandPacket.NvmeCmd->Cdw0.Cid = Controller->Cid[1]++;\r
+ CommandPacket.NvmeCmd->Nsid = Device->NamespaceId;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_IO_QUEUE;\r
+\r
+ Status = Controller->Passthru.PassThru (\r
+ &Controller->Passthru,\r
+ Device->NamespaceId,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // For Nvm Express subsystem, reset block device means reset controller.\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r
+\r
+ Private = Device->Controller;\r
+\r
+ Status = NvmeControllerInit (Private);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ UINTN IoAlign;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Media = This->Media;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r
+\r
+ Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ UINTN IoAlign;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Media = This->Media;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r
+\r
+ Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (This);\r
+\r
+ Status = NvmeFlush (Device);\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Header file for EFI_BLOCK_IO_PROTOCOL interface.\r
+\r
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EFI_NVME_BLOCKIO_H_\r
+#define _EFI_NVME_BLOCKIO_H_\r
+\r
+/**\r
+ Reset the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoReset (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ );\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId Id of the media, changes every time the media is replaced.\r
+ @param Lba The starting Logical Block Address to read from\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the destination buffer for the data. The caller is\r
+ responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The data was read correctly from the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoReadBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param MediaId The media ID that the write request is for.\r
+ @param Lba The starting logical block address to be written. The caller is\r
+ responsible for writing to only legitimate locations.\r
+ @param BufferSize Size of Buffer, must be a multiple of device block size.\r
+ @param Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The data was written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+ or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoWriteBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the data\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoFlushBlocks (\r
+ IN EFI_BLOCK_IO_PROTOCOL *This\r
+ );\r
+\r
+#endif\r
--- /dev/null
+/** @file
+ This file is used to implement the EFI_DISK_INFO_PROTOCOL interface..
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "NvmExpress.h"
+
+EFI_DISK_INFO_PROTOCOL gNvmExpressDiskInfoProtocolTemplate = {
+ EFI_DISK_INFO_NVME_INTERFACE_GUID,
+ NvmExpressDiskInfoInquiry,
+ NvmExpressDiskInfoIdentify,
+ NvmExpressDiskInfoSenseData,
+ NvmExpressDiskInfoWhichIde
+};
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with NVME interface GUID.
+
+ @param[in] Device The pointer of NVME_DEVICE_PRIVATE_DATA.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN NVME_DEVICE_PRIVATE_DATA *Device
+ )
+{
+ CopyMem (&Device->DiskInfo, &gNvmExpressDiskInfoProtocolTemplate, sizeof (EFI_DISK_INFO_PROTOCOL));
+}
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ EFI_STATUS Status;
+ NVME_DEVICE_PRIVATE_DATA *Device;
+
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO (This);
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ if (*IdentifyDataSize >= sizeof (Device->NamespaceData)) {
+ Status = EFI_SUCCESS;
+ CopyMem (IdentifyData, &Device->NamespaceData, sizeof (Device->NamespaceData));
+ }
+ *IdentifyDataSize = sizeof (Device->NamespaceData);
+ return Status;
+}
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
--- /dev/null
+/** @file
+ Header file for EFI_DISK_INFO_PROTOCOL interface.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _NVME_DISKINFO_H_
+#define _NVME_DISKINFO_H_
+
+/**
+ Initialize the installation of DiskInfo protocol.
+
+ This function prepares for the installation of DiskInfo protocol on the child handle.
+ By default, it installs DiskInfo protocol with NVME interface GUID.
+
+ @param[in] Device The pointer of NVME_DEVICE_PRIVATE_DATA.
+
+**/
+VOID
+InitializeDiskInfo (
+ IN NVME_DEVICE_PRIVATE_DATA *Device
+ );
+
+
+/**
+ Provides inquiry information for the controller type.
+
+ This function is used to get inquiry data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] InquiryData Pointer to a buffer for the inquiry data.
+ @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ Provides identify information for the controller type.
+
+ This function is used to get identify data. Data format
+ of Identify data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL
+ instance.
+ @param[in, out] IdentifyData Pointer to a buffer for the identify data.
+ @param[in, out] IdentifyDataSize Pointer to the value for the identify data
+ size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ Provides sense data information for the controller type.
+
+ This function is used to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[in, out] SenseData Pointer to the SenseData.
+ @param[in, out] SenseDataSize Size of SenseData in bytes.
+ @param[out] SenseDataNumber Pointer to the value for the sense data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class.
+ @retval EFI_DEVICE_ERROR Error reading SenseData from device.
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+
+/**
+ This function is used to get controller information.
+
+ @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.
+ @retval EFI_UNSUPPORTED This is not an IDE device.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmExpressDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+
+#endif
--- /dev/null
+## @file\r
+# Component Description File For NVM Express Host Controller Module.\r
+#\r
+# NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+# NVM Express specification.\r
+#\r
+# Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php.\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = NvmExpressDxe\r
+ FILE_GUID = 5BE3BDF4-53CF-46a3-A6A9-73C34A6E5EE3\r
+ MODULE_TYPE = UEFI_DRIVER\r
+ VERSION_STRING = 1.0\r
+ ENTRY_POINT = NvmExpressDriverEntry\r
+ UNLOAD_IMAGE = NvmExpressUnload\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+# DRIVER_BINDING = gNvmExpressDriverBinding\r
+# COMPONENT_NAME = gNvmExpressComponentName\r
+# COMPONENT_NAME2 = gNvmExpressComponentName2\r
+\r
+[Sources]\r
+ NvmExpressBlockIo.c\r
+ NvmExpressBlockIo.h\r
+ ComponentName.c\r
+ NvmExpress.c\r
+ NvmExpress.h\r
+ NvmExpressDiskInfo.c\r
+ NvmExpressDiskInfo.h\r
+ NvmExpressHci.c\r
+ NvmExpressHci.h\r
+ NvmExpressPassthru.c\r
+ NvmExpressPassthru.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+ BaseMemoryLib\r
+ BaseLib\r
+ DebugLib\r
+ DevicePathLib\r
+ MemoryAllocationLib\r
+ UefiDriverEntryPoint\r
+ UefiBootServicesTableLib\r
+ UefiLib\r
+ PrintLib\r
+\r
+[Protocols]\r
+ gEfiPciIoProtocolGuid ## TO_START\r
+ gEfiDevicePathProtocolGuid ## TO_START\r
+ gEfiBlockIoProtocolGuid ## BY_START\r
+ gEfiDiskInfoProtocolGuid ## BY_START\r
+ gEfiDriverSupportedEfiVersionProtocolGuid ## BY_START
\ No newline at end of file
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpress.h"\r
+\r
+/**\r
+ Read Nvm Express controller capability register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Cap The buffer used to store capability register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the controller capability register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the controller capability register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeControllerCapabilities (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_CAP *Cap\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint64,\r
+ NVME_BAR,\r
+ NVME_CAP_OFFSET,\r
+ 1,\r
+ Cap\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Nvm Express controller configuration register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Cc The buffer used to store configuration register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the controller configuration register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the controller configuration register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeControllerConfiguration (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_CC *Cc\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_CC_OFFSET,\r
+ 1,\r
+ Cc\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write Nvm Express controller configuration register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Cc The buffer used to store the content to be written into configuration register.\r
+\r
+ @return EFI_SUCCESS Successfully write data into the controller configuration register.\r
+ @return EFI_DEVICE_ERROR Fail to write data into the controller configuration register.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteNvmeControllerConfiguration (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_CC *Cc\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_CC_OFFSET,\r
+ 1,\r
+ Cc\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Cc.En: %d\n", Cc->En));\r
+ DEBUG ((EFI_D_INFO, "Cc.Css: %d\n", Cc->Css));\r
+ DEBUG ((EFI_D_INFO, "Cc.Mps: %d\n", Cc->Mps));\r
+ DEBUG ((EFI_D_INFO, "Cc.Ams: %d\n", Cc->Ams));\r
+ DEBUG ((EFI_D_INFO, "Cc.Shn: %d\n", Cc->Shn));\r
+ DEBUG ((EFI_D_INFO, "Cc.Iosqes: %d\n", Cc->Iosqes));\r
+ DEBUG ((EFI_D_INFO, "Cc.Iocqes: %d\n", Cc->Iocqes));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Nvm Express controller status register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Csts The buffer used to store status register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the controller status register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the controller status register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeControllerStatus (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_CSTS *Csts\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_CSTS_OFFSET,\r
+ 1,\r
+ Csts\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Nvm Express admin queue attributes register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Aqa The buffer used to store admin queue attributes register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the admin queue attributes register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the admin queue attributes register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeAdminQueueAttributes (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_AQA *Aqa\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_AQA_OFFSET,\r
+ 1,\r
+ Aqa\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write Nvm Express admin queue attributes register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Aqa The buffer used to store the content to be written into admin queue attributes register.\r
+\r
+ @return EFI_SUCCESS Successfully write data into the admin queue attributes register.\r
+ @return EFI_DEVICE_ERROR Fail to write data into the admin queue attributes register.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteNvmeAdminQueueAttributes (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_AQA *Aqa\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_AQA_OFFSET,\r
+ 1,\r
+ Aqa\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Aqa.Asqs: %d\n", Aqa->Asqs));\r
+ DEBUG ((EFI_D_INFO, "Aqa.Acqs: %d\n", Aqa->Acqs));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Nvm Express admin submission queue base address register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Asq The buffer used to store admin submission queue base address register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the admin submission queue base address register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the admin submission queue base address register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeAdminSubmissionQueueBaseAddress (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_ASQ *Asq\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint64,\r
+ NVME_BAR,\r
+ NVME_ASQ_OFFSET,\r
+ 1,\r
+ Asq\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write Nvm Express admin submission queue base address register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Asq The buffer used to store the content to be written into admin submission queue base address register.\r
+\r
+ @return EFI_SUCCESS Successfully write data into the admin submission queue base address register.\r
+ @return EFI_DEVICE_ERROR Fail to write data into the admin submission queue base address register.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteNvmeAdminSubmissionQueueBaseAddress (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_ASQ *Asq\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint64,\r
+ NVME_BAR,\r
+ NVME_ASQ_OFFSET,\r
+ 1,\r
+ Asq\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Asq.Asqb: %lx\n", Asq->Asqb));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Nvm Express admin completion queue base address register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Acq The buffer used to store admin completion queue base address register content.\r
+\r
+ @return EFI_SUCCESS Successfully read the admin completion queue base address register content.\r
+ @return EFI_DEVICE_ERROR Fail to read the admin completion queue base address register.\r
+\r
+**/\r
+EFI_STATUS\r
+ReadNvmeAdminCompletionQueueBaseAddress (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_ACQ *Acq\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint64,\r
+ NVME_BAR,\r
+ NVME_ACQ_OFFSET,\r
+ 1,\r
+ Acq\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Write Nvm Express admin completion queue base address register.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Acq The buffer used to store the content to be written into admin completion queue base address register.\r
+\r
+ @return EFI_SUCCESS Successfully write data into the admin completion queue base address register.\r
+ @return EFI_DEVICE_ERROR Fail to write data into the admin completion queue base address register.\r
+\r
+**/\r
+EFI_STATUS\r
+WriteNvmeAdminCompletionQueueBaseAddress (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN NVME_ACQ *Acq\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint64,\r
+ NVME_BAR,\r
+ NVME_ACQ_OFFSET,\r
+ 1,\r
+ Acq\r
+ );\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "Acq.Acqb: %lxh\n", Acq->Acqb));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Disable the Nvm Express controller.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @return EFI_SUCCESS Successfully disable the controller.\r
+ @return EFI_DEVICE_ERROR Fail to disable the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeDisableController (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ NVME_CC Cc;\r
+ NVME_CSTS Csts;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Read Controller Configuration Register.\r
+ //\r
+ Status = ReadNvmeControllerConfiguration (Private, &Cc);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Cc.En = 0;\r
+\r
+ //\r
+ // Disable the controller.\r
+ //\r
+ Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ gBS->Stall(10000);\r
+\r
+ //\r
+ // Check if the controller is reset\r
+ //\r
+ Status = ReadNvmeControllerStatus (Private, &Csts);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Csts.Rdy != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "NVMe controller is disabled with status [%r].\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Enable the Nvm Express controller.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @return EFI_SUCCESS Successfully enable the controller.\r
+ @return EFI_DEVICE_ERROR Fail to enable the controller.\r
+ @return EFI_TIMEOUT Fail to enable the controller in given time slot.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeEnableController (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ NVME_CC Cc;\r
+ NVME_CSTS Csts;\r
+ EFI_STATUS Status;\r
+ UINT32 Index;\r
+ UINT8 Timeout;\r
+\r
+ //\r
+ // Enable the controller\r
+ //\r
+ ZeroMem (&Cc, sizeof (NVME_CC));\r
+ Cc.En = 1;\r
+ Cc.Iosqes = 6;\r
+ Cc.Iocqes = 4;\r
+ Status = WriteNvmeControllerConfiguration (Private, &Cc);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after\r
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.\r
+ //\r
+ if (Private->Cap.To == 0) {\r
+ Timeout = 1;\r
+ } else {\r
+ Timeout = Private->Cap.To;\r
+ }\r
+\r
+ for(Index = (Timeout * 500); Index != 0; --Index) {\r
+ gBS->Stall(1000);\r
+\r
+ //\r
+ // Check if the controller is initialized\r
+ //\r
+ Status = ReadNvmeControllerStatus (Private, &Csts);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Csts.Rdy) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+\r
+ DEBUG ((EFI_D_INFO, "NVMe controller is enabled with status [%r].\n", Status));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get identify controller data.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer used to store the identify controller data.\r
+\r
+ @return EFI_SUCCESS Successfully get the identify controller data.\r
+ @return EFI_DEVICE_ERROR Fail to get the identify controller data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIdentifyController (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
+ Command.Cdw0.Cid = Private->Cid[0]++;\r
+ //\r
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.\r
+ // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.\r
+ //\r
+ Command.Nsid = 0;\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+ CommandPacket.TransferBuffer = Buffer;\r
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+ //\r
+ // Set bit 0 (Cns bit) to 1 to identify a controller\r
+ //\r
+ Command.Cdw10 = 1;\r
+ Command.Flags = CDW10_VALID;\r
+\r
+ Status = Private->Passthru.PassThru (\r
+ &Private->Passthru,\r
+ NVME_CONTROLLER_ID,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get specified identify namespace data.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param NamespaceId The specified namespace identifier.\r
+ @param Buffer The buffer used to store the identify namespace data.\r
+\r
+ @return EFI_SUCCESS Successfully get the identify namespace data.\r
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIdentifyNamespace (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN UINT32 NamespaceId,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;\r
+ Command.Cdw0.Cid = Private->Cid[0]++;\r
+ Command.Nsid = NamespaceId;\r
+ CommandPacket.TransferBuffer = Buffer;\r
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+ //\r
+ // Set bit 0 (Cns bit) to 1 to identify a namespace\r
+ //\r
+ CommandPacket.NvmeCmd->Cdw10 = 0;\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;\r
+\r
+ Status = Private->Passthru.PassThru (\r
+ &Private->Passthru,\r
+ NamespaceId,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create io completion queue.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @return EFI_SUCCESS Successfully create io completion queue.\r
+ @return EFI_DEVICE_ERROR Fail to create io completion queue.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeCreateIoCompletionQueue (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_CRIOCQ CrIoCq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;\r
+ Command.Cdw0.Cid = Private->Cid[0]++;\r
+ CommandPacket.TransferBuffer = Private->CqBufferPciAddr[1];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ CrIoCq.Qid = NVME_IO_QUEUE;\r
+ CrIoCq.Qsize = NVME_CCQ_SIZE;\r
+ CrIoCq.Pc = 1;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = Private->Passthru.PassThru (\r
+ &Private->Passthru,\r
+ 0,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Create io submission queue.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @return EFI_SUCCESS Successfully create io submission queue.\r
+ @return EFI_DEVICE_ERROR Fail to create io submission queue.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeCreateIoSubmissionQueue (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;\r
+ NVM_EXPRESS_COMMAND Command;\r
+ NVM_EXPRESS_RESPONSE Response;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_CRIOSQ CrIoSq;\r
+\r
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));\r
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));\r
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));\r
+\r
+ CommandPacket.NvmeCmd = &Command;\r
+ CommandPacket.NvmeResponse = &Response;\r
+\r
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;\r
+ Command.Cdw0.Cid = Private->Cid[0]++;\r
+ CommandPacket.TransferBuffer = Private->SqBufferPciAddr[1];\r
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;\r
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;\r
+\r
+ CrIoSq.Qid = NVME_IO_QUEUE;\r
+ CrIoSq.Qsize = NVME_CSQ_SIZE;\r
+ CrIoSq.Pc = 1;\r
+ CrIoSq.Cqid = NVME_IO_QUEUE;\r
+ CrIoSq.Qprio = 0;\r
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));\r
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;\r
+\r
+ Status = Private->Passthru.PassThru (\r
+ &Private->Passthru,\r
+ 0,\r
+ 0,\r
+ &CommandPacket,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize the Nvm Express controller.\r
+\r
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
+ @retval Others A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerInit (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT64 Supports;\r
+ NVME_AQA Aqa;\r
+ NVME_ASQ Asq;\r
+ NVME_ACQ Acq;\r
+\r
+ //\r
+ // Save original PCI attributes and enable this controller.\r
+ //\r
+ PciIo = Private->PciIo;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationGet,\r
+ 0,\r
+ &Private->PciAttributes\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationSupported,\r
+ 0,\r
+ &Supports\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Supports &= EFI_PCI_DEVICE_ENABLE;\r
+ Status = PciIo->Attributes (\r
+ PciIo,\r
+ EfiPciIoAttributeOperationEnable,\r
+ Supports,\r
+ NULL\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "NvmeControllerInit: failed to enable controller\n"));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Read the Controller Capabilities register and verify that the NVM command set is supported\r
+ //\r
+ Status = ReadNvmeControllerCapabilities (Private, &Private->Cap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Private->Cap.Css != 0x01) {\r
+ DEBUG ((EFI_D_INFO, "NvmeControllerInit: the controller doesn't support NVMe command set\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Currently the driver only supports 4k page size.\r
+ //\r
+ ASSERT ((Private->Cap.Mpsmin + 12) <= EFI_PAGE_SHIFT);\r
+\r
+ Private->Cid[0] = 0;\r
+ Private->Cid[1] = 0;\r
+\r
+ Status = NvmeDisableController (Private);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // set number of entries admin submission & completion queues.\r
+ //\r
+ Aqa.Asqs = NVME_ASQ_SIZE;\r
+ Aqa.Acqs = NVME_ACQ_SIZE;\r
+\r
+ //\r
+ // Address of admin submission queue.\r
+ //\r
+ Asq.Rsvd1 = 0;\r
+ Asq.Asqb = (UINT64)(UINTN)(Private->BufferPciAddr) >> 12;\r
+\r
+ //\r
+ // Address of admin completion queue.\r
+ //\r
+ Acq.Rsvd1 = 0;\r
+ Acq.Acqb = (UINT64)(UINTN)(Private->BufferPciAddr + EFI_PAGE_SIZE) >> 12;\r
+\r
+ //\r
+ // Address of I/O submission & completion queue.\r
+ //\r
+ Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);\r
+ Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);\r
+ Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);\r
+ Private->CqBufferPciAddr[0] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 1 * EFI_PAGE_SIZE);\r
+ Private->SqBuffer[1] = (NVME_SQ *)(UINTN)(Private->Buffer + 2 * EFI_PAGE_SIZE);\r
+ Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);\r
+ Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);\r
+ Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);\r
+\r
+ DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));\r
+ DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));\r
+ DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));\r
+ DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));\r
+ DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));\r
+ DEBUG ((EFI_D_INFO, "I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));\r
+ DEBUG ((EFI_D_INFO, "I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));\r
+\r
+ //\r
+ // Program admin queue attributes.\r
+ //\r
+ Status = WriteNvmeAdminQueueAttributes (Private, &Aqa);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Program admin submission queue address.\r
+ //\r
+ Status = WriteNvmeAdminSubmissionQueueBaseAddress (Private, &Asq);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Program admin completion queue address.\r
+ //\r
+ Status = WriteNvmeAdminCompletionQueueBaseAddress (Private, &Acq);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = NvmeEnableController (Private);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create one I/O completion queue.\r
+ //\r
+ Status = NvmeCreateIoCompletionQueue (Private);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create one I/O Submission queue.\r
+ //\r
+ Status = NvmeCreateIoSubmissionQueue (Private);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate buffer for Identify Controller data\r
+ //\r
+ Private->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)AllocateZeroPool (sizeof(NVME_ADMIN_CONTROLLER_DATA));\r
+\r
+ if (Private->ControllerData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Get current Identify Controller Data\r
+ //\r
+ Status = NvmeIdentifyController (Private, Private->ControllerData);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(Private->ControllerData);\r
+ Private->ControllerData = NULL;\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ return Status;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _NVME_HCI_H_\r
+#define _NVME_HCI_H_\r
+\r
+#define NVME_BAR 0\r
+\r
+//\r
+// controller register offsets\r
+//\r
+#define NVME_CAP_OFFSET 0x0000 // Controller Capabilities\r
+#define NVME_VER_OFFSET 0x0008 // Version\r
+#define NVME_INTMS_OFFSET 0x000c // Interrupt Mask Set\r
+#define NVME_INTMC_OFFSET 0x0010 // Interrupt Mask Clear\r
+#define NVME_CC_OFFSET 0x0014 // Controller Configuration\r
+#define NVME_CSTS_OFFSET 0x001c // Controller Status\r
+#define NVME_AQA_OFFSET 0x0024 // Admin Queue Attributes\r
+#define NVME_ASQ_OFFSET 0x0028 // Admin Submission Queue Base Address\r
+#define NVME_ACQ_OFFSET 0x0030 // Admin Completion Queue Base Address\r
+#define NVME_SQ0_OFFSET 0x1000 // Submission Queue 0 (admin) Tail Doorbell\r
+#define NVME_CQ0_OFFSET 0x1004 // Completion Queue 0 (admin) Head Doorbell\r
+\r
+//\r
+// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD))\r
+// Get the doorbell stride bit shift value from the controller capabilities.\r
+//\r
+#define NVME_SQTDBL_OFFSET(QID, DSTRD) 0x1000 + ((2 * (QID)) * (4 << (DSTRD))) // Submission Queue y (NVM) Tail Doorbell\r
+#define NVME_CQHDBL_OFFSET(QID, DSTRD) 0x1000 + (((2 * (QID)) + 1) * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell\r
+\r
+\r
+#pragma pack(1)\r
+\r
+//\r
+// 3.1.1 Offset 00h: CAP - Controller Capabilities\r
+//\r
+typedef struct {\r
+ UINT16 Mqes; // Maximum Queue Entries Supported\r
+ UINT8 Cqr:1; // Contiguous Queues Required\r
+ UINT8 Ams:2; // Arbitration Mechanism Supported\r
+ UINT8 Rsvd1:5;\r
+ UINT8 To; // Timeout\r
+ UINT16 Dstrd:4;\r
+ UINT16 Rsvd2:1;\r
+ UINT16 Css:4; // Command Sets Supported\r
+ UINT16 Rsvd3:7;\r
+ UINT8 Mpsmin:4;\r
+ UINT8 Mpsmax:4;\r
+ UINT8 Rsvd4;\r
+} NVME_CAP;\r
+\r
+//\r
+// 3.1.2 Offset 08h: VS - Version\r
+//\r
+typedef struct {\r
+ UINT16 Mnr; // Minor version number\r
+ UINT16 Mjr; // Major version number\r
+} NVME_VER;\r
+\r
+//\r
+// 3.1.5 Offset 14h: CC - Controller Configuration\r
+//\r
+typedef struct {\r
+ UINT16 En:1; // Enable\r
+ UINT16 Rsvd1:3;\r
+ UINT16 Css:3; // Command Set Selected\r
+ UINT16 Mps:4; // Memory Page Size\r
+ UINT16 Ams:3; // Arbitration Mechanism Selected\r
+ UINT16 Shn:2; // Shutdown Notification\r
+ UINT8 Iosqes:4; // I/O Submission Queue Entry Size\r
+ UINT8 Iocqes:4; // I/O Completion Queue Entry Size\r
+ UINT8 Rsvd2;\r
+} NVME_CC;\r
+\r
+//\r
+// 3.1.6 Offset 1Ch: CSTS - Controller Status\r
+//\r
+typedef struct {\r
+ UINT32 Rdy:1; // Ready\r
+ UINT32 Cfs:1; // Controller Fatal Status\r
+ UINT32 Shst:2; // Shutdown Status\r
+ UINT32 Nssro:1; // NVM Subsystem Reset Occurred\r
+ UINT32 Rsvd1:27;\r
+} NVME_CSTS;\r
+\r
+//\r
+// 3.1.8 Offset 24h: AQA - Admin Queue Attributes\r
+//\r
+typedef struct {\r
+ UINT16 Asqs:12; // Submission Queue Size\r
+ UINT16 Rsvd1:4;\r
+ UINT16 Acqs:12; // Completion Queue Size\r
+ UINT16 Rsvd2:4;\r
+} NVME_AQA;\r
+\r
+//\r
+// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address\r
+//\r
+typedef struct {\r
+ UINT64 Rsvd1:12;\r
+ UINT64 Asqb:52; // Admin Submission Queue Base Address\r
+} NVME_ASQ;\r
+\r
+//\r
+// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address\r
+//\r
+typedef struct {\r
+ UINT64 Rsvd1:12;\r
+ UINT64 Acqb:52; // Admin Completion Queue Base Address\r
+} NVME_ACQ;\r
+\r
+//\r
+// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission Queue y Tail Doorbell\r
+//\r
+typedef struct {\r
+ UINT16 Sqt;\r
+ UINT16 Rsvd1;\r
+} NVME_SQTDBL;\r
+\r
+//\r
+// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL - Completion Queue y Head Doorbell\r
+//\r
+typedef struct {\r
+ UINT16 Cqh;\r
+ UINT16 Rsvd1;\r
+} NVME_CQHDBL;\r
+\r
+//\r
+// NVM command set structures\r
+//\r
+// Read Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting Sector Address */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Sectors */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Af:4; /* Access Frequency */\r
+ UINT32 Al:2; /* Access Latency */\r
+ UINT32 Sr:1; /* Sequential Request */\r
+ UINT32 In:1; /* Incompressible */\r
+ UINT32 Rsvd2:24;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Elbat; /* Expected Logical Block Application Tag */\r
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */\r
+} NVME_READ;\r
+\r
+//\r
+// Write Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting Sector Address */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Sectors */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Af:4; /* Access Frequency */\r
+ UINT32 Al:2; /* Access Latency */\r
+ UINT32 Sr:1; /* Sequential Request */\r
+ UINT32 In:1; /* Incompressible */\r
+ UINT32 Rsvd2:24;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Lbat; /* Logical Block Application Tag */\r
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */\r
+} NVME_WRITE;\r
+\r
+//\r
+// Flush\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Flush; /* Flush */\r
+} NVME_FLUSH;\r
+\r
+//\r
+// Write Uncorrectable command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT32 Nlb:16; /* Number of Logical Blocks */\r
+ UINT32 Rsvd1:16;\r
+} NVME_WRITE_UNCORRECTABLE;\r
+\r
+//\r
+// Write Zeroes command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Logical Blocks */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Rsvd2;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Lbat; /* Logical Block Application Tag */\r
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */\r
+} NVME_WRITE_ZEROES;\r
+\r
+//\r
+// Compare command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10, 11\r
+ //\r
+ UINT64 Slba; /* Starting LBA */\r
+ //\r
+ // CDW 12\r
+ //\r
+ UINT16 Nlb; /* Number of Logical Blocks */\r
+ UINT16 Rsvd1:10;\r
+ UINT16 Prinfo:4; /* Protection Info Check */\r
+ UINT16 Fua:1; /* Force Unit Access */\r
+ UINT16 Lr:1; /* Limited Retry */\r
+ //\r
+ // CDW 13\r
+ //\r
+ UINT32 Rsvd2;\r
+ //\r
+ // CDW 14\r
+ //\r
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */\r
+ //\r
+ // CDW 15\r
+ //\r
+ UINT16 Elbat; /* Expected Logical Block Application Tag */\r
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */\r
+} NVME_COMPARE;\r
+\r
+typedef union {\r
+ NVME_READ Read;\r
+ NVME_WRITE Write;\r
+ NVME_FLUSH Flush;\r
+ NVME_WRITE_UNCORRECTABLE WriteUncorrectable;\r
+ NVME_WRITE_ZEROES WriteZeros;\r
+ NVME_COMPARE Compare;\r
+} NVME_CMD;\r
+\r
+typedef struct {\r
+ UINT16 Mp; /* Maximum Power */\r
+ UINT8 Rsvd1; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Mps:1; /* Max Power Scale */\r
+ UINT8 Nops:1; /* Non-Operational State */\r
+ UINT8 Rsvd2:6; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Enlat; /* Entry Latency */\r
+ UINT32 Exlat; /* Exit Latency */\r
+ UINT8 Rrt:5; /* Relative Read Throughput */\r
+ UINT8 Rsvd3:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rrl:5; /* Relative Read Leatency */\r
+ UINT8 Rsvd4:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rwt:5; /* Relative Write Throughput */\r
+ UINT8 Rsvd5:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rwl:5; /* Relative Write Leatency */\r
+ UINT8 Rsvd6:3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 Rsvd7[16]; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_PSDESCRIPTOR;\r
+\r
+//\r
+// Identify Controller Data\r
+//\r
+typedef struct {\r
+ //\r
+ // Controller Capabilities and Features 0-255\r
+ //\r
+ UINT16 Vid; /* PCI Vendor ID */\r
+ UINT16 Ssvid; /* PCI sub-system vendor ID */\r
+ UINT8 Sn[20]; /* Produce serial number */\r
+\r
+ UINT8 Mn[40]; /* Proeduct model number */\r
+ UINT8 Fr[8]; /* Firmware Revision */\r
+ UINT8 Rab; /* Recommended Arbitration Burst */\r
+ UINT8 Ieee_oiu[3]; /* Organization Unique Identifier */\r
+ UINT8 Cmic; /* Multi-interface Capabilities */\r
+ UINT8 Mdts; /* Maximum Data Transfer Size */\r
+ UINT8 Cntlid[2]; /* Controller ID */\r
+ UINT8 Rsvd1[176]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // Admin Command Set Attributes\r
+ //\r
+ UINT16 Oacs; /* Optional Admin Command Support */\r
+ UINT8 Acl; /* Abort Command Limit */\r
+ UINT8 Aerl; /* Async Event Request Limit */\r
+ UINT8 Frmw; /* Firmware updates */\r
+ UINT8 Lpa; /* Log Page Attributes */\r
+ UINT8 Elpe; /* Error Log Page Entries */\r
+ UINT8 Npss; /* Number of Power States Support */\r
+ UINT8 Avscc; /* Admin Vendor Specific Command Configuration */\r
+ UINT8 Apsta; /* Autonomous Power State Transition Attributes */\r
+ UINT8 Rsvd2[246]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // NVM Command Set Attributes\r
+ //\r
+ UINT8 Sqes; /* Submission Queue Entry Size */\r
+ UINT8 Cqes; /* Completion Queue Entry Size */\r
+ UINT16 Rsvd3; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Nn; /* Number of Namespaces */\r
+ UINT16 Oncs; /* Optional NVM Command Support */\r
+ UINT16 Fuses; /* Fused Operation Support */\r
+ UINT8 Fna; /* Format NVM Attributes */\r
+ UINT8 Vwc; /* Volatile Write Cache */\r
+ UINT16 Awun; /* Atomic Write Unit Normal */\r
+ UINT16 Awupf; /* Atomic Write Unit Power Fail */\r
+ UINT8 Nvscc; /* NVM Vendor Specific Command Configuration */\r
+ UINT8 Rsvd4; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT16 Acwu; /* Atomic Compare & Write Unit */\r
+ UINT16 Rsvd5; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Sgls; /* SGL Support */\r
+ UINT8 Rsvd6[164]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // I/O Command set Attributes\r
+ //\r
+ UINT8 Rsvd7[1344]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ //\r
+ // Power State Descriptors\r
+ //\r
+ NVME_PSDESCRIPTOR PsDescriptor[32];\r
+\r
+ UINT8 VendorData[1024]; /* Vendor specific data */\r
+} NVME_ADMIN_CONTROLLER_DATA;\r
+\r
+typedef struct {\r
+ UINT16 Ms; /* Metadata Size */\r
+ UINT8 Lbads; /* LBA Data Size */\r
+ UINT8 Rp:2; /* Relative Performance */\r
+ #define LBAF_RP_BEST 00b\r
+ #define LBAF_RP_BETTER 01b\r
+ #define LBAF_RP_GOOD 10b\r
+ #define LBAF_RP_DEGRADED 11b\r
+ UINT8 Rsvd1:6; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_LBAFORMAT;\r
+\r
+//\r
+// Identify Namespace Data\r
+//\r
+typedef struct {\r
+ //\r
+ // NVM Command Set Specific\r
+ //\r
+ UINT64 Nsze; /* Namespace Size (total number of blocks in formatted namespace) */\r
+ UINT64 Ncap; /* Namespace Capacity (max number of logical blocks) */\r
+ UINT64 Nuse; /* Namespace Utilization */\r
+ UINT8 Nsfeat; /* Namespace Features */\r
+ UINT8 Nlbaf; /* Number of LBA Formats */\r
+ UINT8 Flbas; /* Formatted LBA size */\r
+ UINT8 Mc; /* Metadata Capabilities */\r
+ UINT8 Dpc; /* End-to-end Data Protection capabilities */\r
+ UINT8 Dps; /* End-to-end Data Protection Type Settings */\r
+ UINT8 Nmic; /* Namespace Multi-path I/O and Namespace Sharing Capabilities */\r
+ UINT8 Rescap; /* Reservation Capabilities */\r
+ UINT8 Rsvd1[88]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT64 Eui64; /* IEEE Extended Unique Identifier */\r
+ //\r
+ // LBA Format\r
+ //\r
+ NVME_LBAFORMAT LbaFormat[16];\r
+\r
+ UINT8 Rsvd2[192]; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT8 VendorData[3712]; /* Vendor specific data */\r
+} NVME_ADMIN_NAMESPACE_DATA;\r
+\r
+//\r
+// NvmExpress Admin Identify Cmd\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Cns:2;\r
+ UINT32 Rsvd1:30;\r
+} NVME_ADMIN_IDENTIFY;\r
+\r
+//\r
+// NvmExpress Admin Create I/O Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Qid:16; /* Queue Identifier */\r
+ UINT32 Qsize:16; /* Queue Size */\r
+\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Pc:1; /* Physically Contiguous */\r
+ UINT32 Ien:1; /* Interrupts Enabled */\r
+ UINT32 Rsvd1:14; /* reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Iv:16; /* Interrupt Vector */\r
+} NVME_ADMIN_CRIOCQ;\r
+\r
+//\r
+// NvmExpress Admin Create I/O Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Qid:16; /* Queue Identifier */\r
+ UINT32 Qsize:16; /* Queue Size */\r
+\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Pc:1; /* Physically Contiguous */\r
+ UINT32 Qprio:2; /* Queue Priority */\r
+ UINT32 Rsvd1:13; /* Reserved as of Nvm Express 1.1 Spec */\r
+ UINT32 Cqid:16; /* Completion Queue ID */\r
+} NVME_ADMIN_CRIOSQ;\r
+\r
+//\r
+// NvmExpress Admin Delete I/O Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT16 Qid;\r
+ UINT16 Rsvd1;\r
+} NVME_ADMIN_DEIOCQ;\r
+\r
+//\r
+// NvmExpress Admin Delete I/O Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT16 Qid;\r
+ UINT16 Rsvd1;\r
+} NVME_ADMIN_DEIOSQ;\r
+\r
+//\r
+// NvmExpress Admin Abort Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Sqid:16; /* Submission Queue identifier */\r
+ UINT32 Cid:16; /* Command Identifier */\r
+} NVME_ADMIN_ABORT;\r
+\r
+//\r
+// NvmExpress Admin Firmware Activate Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fs:3; /* Submission Queue identifier */\r
+ UINT32 Aa:2; /* Command Identifier */\r
+ UINT32 Rsvd1:27;\r
+} NVME_ADMIN_FIRMWARE_ACTIVATE;\r
+\r
+//\r
+// NvmExpress Admin Firmware Image Download Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Numd; /* Number of Dwords */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Ofst; /* Offset */\r
+} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD;\r
+\r
+//\r
+// NvmExpress Admin Get Features Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fid:8; /* Feature Identifier */\r
+ UINT32 Sel:3; /* Select */\r
+ UINT32 Rsvd1:21;\r
+} NVME_ADMIN_GET_FEATURES;\r
+\r
+//\r
+// NvmExpress Admin Get Log Page Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Lid:8; /* Log Page Identifier */\r
+ #define LID_ERROR_INFO\r
+ #define LID_SMART_INFO\r
+ #define LID_FW_SLOT_INFO\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Numd:12; /* Number of Dwords */\r
+ UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */\r
+} NVME_ADMIN_GET_LOG_PAGE;\r
+\r
+//\r
+// NvmExpress Admin Set Features Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Fid:8; /* Feature Identifier */\r
+ UINT32 Rsvd1:23;\r
+ UINT32 Sv:1; /* Save */\r
+} NVME_ADMIN_SET_FEATURES;\r
+\r
+//\r
+// NvmExpress Admin Format NVM Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Lbaf:4; /* LBA Format */\r
+ UINT32 Ms:1; /* Metadata Settings */\r
+ UINT32 Pi:3; /* Protection Information */\r
+ UINT32 Pil:1; /* Protection Information Location */\r
+ UINT32 Ses:3; /* Secure Erase Settings */\r
+ UINT32 Rsvd1:20;\r
+} NVME_ADMIN_FORMAT_NVM;\r
+\r
+//\r
+// NvmExpress Admin Security Receive Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Spsp:16; /* SP Specific */\r
+ UINT32 Secp:8; /* Security Protocol */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Al; /* Allocation Length */\r
+} NVME_ADMIN_SECURITY_RECEIVE;\r
+\r
+//\r
+// NvmExpress Admin Security Send Command\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 10\r
+ //\r
+ UINT32 Rsvd1:8;\r
+ UINT32 Spsp:16; /* SP Specific */\r
+ UINT32 Secp:8; /* Security Protocol */\r
+ //\r
+ // CDW 11\r
+ //\r
+ UINT32 Tl; /* Transfer Length */\r
+} NVME_ADMIN_SECURITY_SEND;\r
+\r
+typedef union {\r
+ NVME_ADMIN_IDENTIFY Identify;\r
+ NVME_ADMIN_CRIOCQ CrIoCq;\r
+ NVME_ADMIN_CRIOSQ CrIoSq;\r
+ NVME_ADMIN_DEIOCQ DeIoCq;\r
+ NVME_ADMIN_DEIOSQ DeIoSq;\r
+ NVME_ADMIN_ABORT Abort;\r
+ NVME_ADMIN_FIRMWARE_ACTIVATE Activate;\r
+ NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD FirmwareImageDownload;\r
+ NVME_ADMIN_GET_FEATURES GetFeatures;\r
+ NVME_ADMIN_GET_LOG_PAGE GetLogPage;\r
+ NVME_ADMIN_SET_FEATURES SetFeatures;\r
+ NVME_ADMIN_FORMAT_NVM FormatNvm;\r
+ NVME_ADMIN_SECURITY_RECEIVE SecurityReceive;\r
+ NVME_ADMIN_SECURITY_SEND SecuritySend;\r
+} NVME_ADMIN_CMD;\r
+\r
+typedef struct {\r
+ UINT32 Cdw10;\r
+ UINT32 Cdw11;\r
+ UINT32 Cdw12;\r
+ UINT32 Cdw13;\r
+ UINT32 Cdw14;\r
+ UINT32 Cdw15;\r
+} NVME_RAW;\r
+\r
+typedef union {\r
+ NVME_ADMIN_CMD Admin; // Union of Admin commands\r
+ NVME_CMD Nvm; // Union of Nvm commands\r
+ NVME_RAW Raw;\r
+} NVME_PAYLOAD;\r
+\r
+//\r
+// Submission Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 0, Common to all comnmands\r
+ //\r
+ UINT8 Opc; // Opcode\r
+ UINT8 Fuse:2; // Fused Operation\r
+ UINT8 Rsvd1:5;\r
+ UINT8 Psdt:1; // PRP or SGL for Data Transfer\r
+ UINT16 Cid; // Command Identifier\r
+\r
+ //\r
+ // CDW 1\r
+ //\r
+ UINT32 Nsid; // Namespace Identifier\r
+\r
+ //\r
+ // CDW 2,3\r
+ //\r
+ UINT64 Rsvd2;\r
+\r
+ //\r
+ // CDW 4,5\r
+ //\r
+ UINT64 Mptr; // Metadata Pointer\r
+\r
+ //\r
+ // CDW 6-9\r
+ //\r
+ UINT64 Prp[2]; // First and second PRP entries\r
+\r
+ NVME_PAYLOAD Payload;\r
+\r
+} NVME_SQ;\r
+\r
+//\r
+// Completion Queue\r
+//\r
+typedef struct {\r
+ //\r
+ // CDW 0\r
+ //\r
+ UINT32 Dword0;\r
+ //\r
+ // CDW 1\r
+ //\r
+ UINT32 Rsvd1;\r
+ //\r
+ // CDW 2\r
+ //\r
+ UINT16 Sqhd; // Submission Queue Head Pointer\r
+ UINT16 Sqid; // Submission Queue Identifier\r
+ //\r
+ // CDW 3\r
+ //\r
+ UINT16 Cid; // Command Identifier\r
+ UINT16 Pt:1; // Phase Tag\r
+ UINT16 Sc:8; // Status Code\r
+ UINT16 Sct:3; // Status Code Type\r
+ UINT16 Rsvd2:2;\r
+ UINT16 Mo:1; // More\r
+ UINT16 Dnr:1; // Retry\r
+} NVME_CQ;\r
+\r
+//\r
+// Nvm Express Admin cmd opcodes\r
+//\r
+#define NVME_ADMIN_CRIOSQ_OPC 1\r
+#define NVME_ADMIN_CRIOCQ_OPC 5\r
+#define NVME_ADMIN_IDENTIFY_OPC 6\r
+\r
+#define NVME_IO_FLUSH_OPC 0\r
+#define NVME_IO_WRITE_OPC 1\r
+#define NVME_IO_READ_OPC 2\r
+\r
+//\r
+// Offset from the beginning of private data queue buffer\r
+//\r
+#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE\r
+\r
+/**\r
+ Initialize the Nvm Express controller.\r
+\r
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+\r
+ @retval EFI_SUCCESS The NVM Express Controller is initialized successfully.\r
+ @retval Others A device error occurred while initializing the controller.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeControllerInit (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ );\r
+\r
+/**\r
+ Get identify controller data.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param Buffer The buffer used to store the identify controller data.\r
+\r
+ @return EFI_SUCCESS Successfully get the identify controller data.\r
+ @return EFI_DEVICE_ERROR Fail to get the identify controller data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIdentifyController (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Get specified identify namespace data.\r
+\r
+ @param Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.\r
+ @param NamespaceId The specified namespace identifier.\r
+ @param Buffer The buffer used to store the identify namespace data.\r
+\r
+ @return EFI_SUCCESS Successfully get the identify namespace data.\r
+ @return EFI_DEVICE_ERROR Fail to get the identify namespace data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIdentifyNamespace (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private,\r
+ IN UINT32 NamespaceId,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+#pragma pack()\r
+\r
+#endif\r
+\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpress.h"\r
+\r
+//\r
+// Page size should be set in the Controller Configuration register\r
+// during controller init, and the controller configuration save in\r
+// the controller's private data. The Max and Min supported page sizes\r
+// for the controller are specified in the Controller Capabilities register.\r
+//\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED NVM_EXPRESS_PASS_THRU_MODE gNvmExpressPassThruMode = {\r
+ 0,\r
+ NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL | NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVME,\r
+ sizeof (UINTN),\r
+ 0x10000,\r
+ 0,\r
+ 0\r
+};\r
+\r
+\r
+/**\r
+ Dump the execution status from a given completion queue entry.\r
+\r
+ @param[in] Cq A pointer to the NVME_CQ item.\r
+\r
+**/\r
+VOID\r
+NvmeDumpStatus (\r
+ IN NVME_CQ *Cq\r
+ )\r
+{\r
+ DEBUG ((EFI_D_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));\r
+\r
+ DEBUG ((EFI_D_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));\r
+\r
+ DEBUG ((EFI_D_VERBOSE, " NVMe Cmd Execution Result - "));\r
+\r
+ switch (Cq->Sct) {\r
+ case 0x0:\r
+ switch (Cq->Sc) {\r
+ case 0x0:\r
+ DEBUG ((EFI_D_VERBOSE, "Successful Completion\n"));\r
+ break;\r
+ case 0x1:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Command Opcode\n"));\r
+ break;\r
+ case 0x2:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Field in Command\n"));\r
+ break;\r
+ case 0x3:\r
+ DEBUG ((EFI_D_VERBOSE, "Command ID Conflict\n"));\r
+ break;\r
+ case 0x4:\r
+ DEBUG ((EFI_D_VERBOSE, "Data Transfer Error\n"));\r
+ break;\r
+ case 0x5:\r
+ DEBUG ((EFI_D_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));\r
+ break;\r
+ case 0x6:\r
+ DEBUG ((EFI_D_VERBOSE, "Internal Device Error\n"));\r
+ break;\r
+ case 0x7:\r
+ DEBUG ((EFI_D_VERBOSE, "Command Abort Requested\n"));\r
+ break;\r
+ case 0x8:\r
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to SQ Deletion\n"));\r
+ break;\r
+ case 0x9:\r
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Failed Fused Command\n"));\r
+ break;\r
+ case 0xA:\r
+ DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Missing Fused Command\n"));\r
+ break;\r
+ case 0xB:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Namespace or Format\n"));\r
+ break;\r
+ case 0xC:\r
+ DEBUG ((EFI_D_VERBOSE, "Command Sequence Error\n"));\r
+ break;\r
+ case 0xD:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));\r
+ break;\r
+ case 0xE:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Number of SGL Descriptors\n"));\r
+ break;\r
+ case 0xF:\r
+ DEBUG ((EFI_D_VERBOSE, "Data SGL Length Invalid\n"));\r
+ break;\r
+ case 0x10:\r
+ DEBUG ((EFI_D_VERBOSE, "Metadata SGL Length Invalid\n"));\r
+ break;\r
+ case 0x11:\r
+ DEBUG ((EFI_D_VERBOSE, "SGL Descriptor Type Invalid\n"));\r
+ break;\r
+ case 0x80:\r
+ DEBUG ((EFI_D_VERBOSE, "LBA Out of Range\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((EFI_D_VERBOSE, "Capacity Exceeded\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((EFI_D_VERBOSE, "Namespace Not Ready\n"));\r
+ break;\r
+ case 0x83:\r
+ DEBUG ((EFI_D_VERBOSE, "Reservation Conflict\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case 0x1:\r
+ switch (Cq->Sc) {\r
+ case 0x0:\r
+ DEBUG ((EFI_D_VERBOSE, "Completion Queue Invalid\n"));\r
+ break;\r
+ case 0x1:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Queue Identifier\n"));\r
+ break;\r
+ case 0x2:\r
+ DEBUG ((EFI_D_VERBOSE, "Maximum Queue Size Exceeded\n"));\r
+ break;\r
+ case 0x3:\r
+ DEBUG ((EFI_D_VERBOSE, "Abort Command Limit Exceeded\n"));\r
+ break;\r
+ case 0x5:\r
+ DEBUG ((EFI_D_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));\r
+ break;\r
+ case 0x6:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Slot\n"));\r
+ break;\r
+ case 0x7:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Image\n"));\r
+ break;\r
+ case 0x8:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Interrupt Vector\n"));\r
+ break;\r
+ case 0x9:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Log Page\n"));\r
+ break;\r
+ case 0xA:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Format\n"));\r
+ break;\r
+ case 0xB:\r
+ DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires Conventional Reset\n"));\r
+ break;\r
+ case 0xC:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Queue Deletion\n"));\r
+ break;\r
+ case 0xD:\r
+ DEBUG ((EFI_D_VERBOSE, "Feature Identifier Not Saveable\n"));\r
+ break;\r
+ case 0xE:\r
+ DEBUG ((EFI_D_VERBOSE, "Feature Not Changeable\n"));\r
+ break;\r
+ case 0xF:\r
+ DEBUG ((EFI_D_VERBOSE, "Feature Not Namespace Specific\n"));\r
+ break;\r
+ case 0x10:\r
+ DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));\r
+ break;\r
+ case 0x80:\r
+ DEBUG ((EFI_D_VERBOSE, "Conflicting Attributes\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((EFI_D_VERBOSE, "Invalid Protection Information\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((EFI_D_VERBOSE, "Attempted Write to Read Only Range\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case 0x2:\r
+ switch (Cq->Sc) {\r
+ case 0x80:\r
+ DEBUG ((EFI_D_VERBOSE, "Write Fault\n"));\r
+ break;\r
+ case 0x81:\r
+ DEBUG ((EFI_D_VERBOSE, "Unrecovered Read Error\n"));\r
+ break;\r
+ case 0x82:\r
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Guard Check Error\n"));\r
+ break;\r
+ case 0x83:\r
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Application Tag Check Error\n"));\r
+ break;\r
+ case 0x84:\r
+ DEBUG ((EFI_D_VERBOSE, "End-to-end Reference Tag Check Error\n"));\r
+ break;\r
+ case 0x85:\r
+ DEBUG ((EFI_D_VERBOSE, "Compare Failure\n"));\r
+ break;\r
+ case 0x86:\r
+ DEBUG ((EFI_D_VERBOSE, "Access Denied\n"));\r
+ break;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+/**\r
+ Create PRP lists for data transfer which is larger than 2 memory pages.\r
+ Note here we calcuate the number of required PRP lists and allocate them at one time.\r
+\r
+ @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param[in] PhysicalAddr The physical base address of data buffer.\r
+ @param[in] Pages The number of pages to be transfered.\r
+ @param[out] PrpListHost The host base address of PRP lists.\r
+ @param[in,out] PrpListNo The number of PRP List.\r
+ @param[out] Mapping The mapping value returned from PciIo.Map().\r
+\r
+ @retval The pointer to the first PRP List of the PRP lists.\r
+\r
+**/\r
+VOID*\r
+NvmeCreatePrpList (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,\r
+ IN UINTN Pages,\r
+ OUT VOID **PrpListHost,\r
+ IN OUT UINTN *PrpListNo,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ UINTN PrpEntryNo;\r
+ UINT64 PrpListBase;\r
+ UINTN PrpListIndex;\r
+ UINTN PrpEntryIndex;\r
+ UINT64 Remainder;\r
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;\r
+ UINTN Bytes;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // The number of Prp Entry in a memory page.\r
+ //\r
+ PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);\r
+\r
+ //\r
+ // Calculate total PrpList number.\r
+ //\r
+ *PrpListNo = (UINTN)DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder);\r
+ if (Remainder != 0) {\r
+ *PrpListNo += 1;\r
+ }\r
+\r
+ Status = PciIo->AllocateBuffer (\r
+ PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ *PrpListNo,\r
+ PrpListHost,\r
+ 0\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ EfiPciIoOperationBusMasterCommonBuffer,\r
+ *PrpListHost,\r
+ &Bytes,\r
+ &PrpListPhyAddr,\r
+ Mapping\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (*PrpListNo))) {\r
+ DEBUG ((EFI_D_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));\r
+ goto EXIT;\r
+ }\r
+ //\r
+ // Fill all PRP lists except of last one.\r
+ //\r
+ ZeroMem (*PrpListHost, Bytes);\r
+ for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {\r
+ PrpListBase = *(UINT8*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+\r
+ for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {\r
+ if (PrpEntryIndex != PrpEntryNo - 1) {\r
+ //\r
+ // Fill all PRP entries except of last one.\r
+ //\r
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
+ } else {\r
+ //\r
+ // Fill last PRP entries with next PRP List pointer.\r
+ //\r
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Fill last PRP list.\r
+ //\r
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+ for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) {\r
+ *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
+ }\r
+\r
+ return (VOID*)(UINTN)PrpListPhyAddr;\r
+\r
+EXIT:\r
+ PciIo->FreeBuffer (PciIo, *PrpListNo, *PrpListHost);\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking\r
+ I/O functionality is optional.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ ID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in] NamespaceUuid Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ UUID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in,out] Packet A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified\r
+ by NamespaceId.\r
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking I/O is performed.\r
+ If Event is NULL, then blocking I/O is performed. If Event is not NULL and non blocking I/O\r
+ is supported, then nonblocking I/O is performed, and Event will be signaled when the NVM\r
+ Express Command Packet completes.\r
+\r
+ @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
+ to, or from DataBuffer.\r
+ @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred\r
+ is returned in TransferLength.\r
+ @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
+ may retry again later.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.\r
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
+ Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the host adapter.\r
+ The NVM Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressPassThru (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ NVME_SQ *Sq;\r
+ NVME_CQ *Cq;\r
+ UINT8 Qid;\r
+ UINT32 Bytes;\r
+ UINT16 Offset;\r
+ EFI_EVENT TimerEvent;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *MapData;\r
+ VOID *MapMeta;\r
+ VOID *MapPrpList;\r
+ UINTN MapLength;\r
+ UINT64 *Prp;\r
+ VOID *PrpListHost;\r
+ UINTN PrpListNo;\r
+\r
+ //\r
+ // check the data fields in Packet parameter.\r
+ //\r
+ if ((This == NULL) || (Packet == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId != NVME_IO_QUEUE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
+ PciIo = Private->PciIo;\r
+ MapData = NULL;\r
+ MapMeta = NULL;\r
+ MapPrpList = NULL;\r
+ PrpListHost = NULL;\r
+ PrpListNo = 0;\r
+ Prp = NULL;\r
+ TimerEvent = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ Qid = Packet->QueueId;\r
+ Sq = Private->SqBuffer[Qid] + Private->SqTdbl[Qid].Sqt;\r
+ Cq = Private->CqBuffer[Qid] + Private->CqHdbl[Qid].Cqh;\r
+\r
+ if (Packet->NvmeCmd->Nsid != NamespaceId) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ZeroMem (Sq, sizeof (NVME_SQ));\r
+ Sq->Opc = Packet->NvmeCmd->Cdw0.Opcode;\r
+ Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation;\r
+ Sq->Cid = Packet->NvmeCmd->Cdw0.Cid;\r
+ Sq->Nsid = Packet->NvmeCmd->Nsid;\r
+\r
+ //\r
+ // Currently we only support PRP for data transfer, SGL is NOT supported.\r
+ //\r
+ ASSERT ((Sq->Opc & BIT15) == 0);\r
+ if ((Sq->Opc & BIT15) != 0) {\r
+ DEBUG ((EFI_D_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;\r
+ //\r
+ // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.\r
+ // Note here we don't handle data buffer for CreateIOSubmitionQueue and CreateIOCompletionQueue cmds because\r
+ // these two cmds are special which requires their data buffer must support simultaneous access by both the\r
+ // processor and a PCI Bus Master. It's caller's responsbility to ensure this.\r
+ //\r
+ if (((Sq->Opc & (BIT0 | BIT1)) != 0) && (Sq->Opc != NVME_ADMIN_CRIOCQ_OPC) && (Sq->Opc != NVME_ADMIN_CRIOSQ_OPC)) {\r
+ if ((Sq->Opc & BIT0) != 0) {\r
+ Flag = EfiPciIoOperationBusMasterRead;\r
+ } else {\r
+ Flag = EfiPciIoOperationBusMasterWrite;\r
+ }\r
+\r
+ MapLength = Packet->TransferLength;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ Flag,\r
+ Packet->TransferBuffer,\r
+ &MapLength,\r
+ &PhyAddr,\r
+ &MapData\r
+ );\r
+ if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Sq->Prp[0] = PhyAddr;\r
+ Sq->Prp[1] = 0;\r
+\r
+ MapLength = Packet->MetadataLength;\r
+ if(Packet->MetadataBuffer != NULL) {\r
+ MapLength = Packet->MetadataLength;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ Flag,\r
+ Packet->MetadataBuffer,\r
+ &MapLength,\r
+ &PhyAddr,\r
+ &MapMeta\r
+ );\r
+ if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ MapData\r
+ );\r
+\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Sq->Mptr = PhyAddr;\r
+ }\r
+ }\r
+ //\r
+ // If the buffer size spans more than two memory pages (page size as defined in CC.Mps),\r
+ // then build a PRP list in the second PRP submission queue entry.\r
+ //\r
+ Offset = ((UINT16)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);\r
+ Bytes = Packet->TransferLength;\r
+\r
+ if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {\r
+ //\r
+ // Create PrpList for remaining data buffer.\r
+ //\r
+ PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
+ Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);\r
+ if (Prp == NULL) {\r
+ goto EXIT;\r
+ }\r
+\r
+ Sq->Prp[1] = (UINT64)(UINTN)Prp;\r
+ } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {\r
+ Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
+ }\r
+\r
+ if(Packet->NvmeCmd->Flags & CDW10_VALID) {\r
+ Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW11_VALID) {\r
+ Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW12_VALID) {\r
+ Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW13_VALID) {\r
+ Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW14_VALID) {\r
+ Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;\r
+ }\r
+ if(Packet->NvmeCmd->Flags & CDW15_VALID) {\r
+ Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;\r
+ }\r
+\r
+ //\r
+ // Ring the submission queue doorbell.\r
+ //\r
+ Private->SqTdbl[Qid].Sqt ^= 1;\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_SQTDBL_OFFSET(Qid, Private->Cap.Dstrd),\r
+ 1,\r
+ &Private->SqTdbl[Qid]\r
+ );\r
+\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &TimerEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ Status = gBS->SetTimer(TimerEvent, TimerRelative, Packet->CommandTimeout);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ Packet->ControllerStatus = NVM_EXPRESS_STATUS_CONTROLLER_DEVICE_ERROR;\r
+ goto EXIT;\r
+ }\r
+\r
+ //\r
+ // Wait for completion queue to get filled in.\r
+ //\r
+ Status = EFI_TIMEOUT;\r
+ Packet->ControllerStatus = NVM_EXPRESS_STATUS_CONTROLLER_TIMEOUT_COMMAND;\r
+ while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {\r
+ if (Cq->Pt != Private->Pt[Qid]) {\r
+ Status = EFI_SUCCESS;\r
+ Packet->ControllerStatus = NVM_EXPRESS_STATUS_CONTROLLER_READY;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if ((Private->CqHdbl[Qid].Cqh ^= 1) == 0) {\r
+ Private->Pt[Qid] ^= 1;\r
+ }\r
+\r
+ //\r
+ // Copy the Respose Queue entry for this command to the callers response buffer\r
+ //\r
+ CopyMem(Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE));\r
+\r
+ //\r
+ // Dump every completion entry status for debugging.\r
+ //\r
+ DEBUG_CODE_BEGIN();\r
+ NvmeDumpStatus(Cq);\r
+ DEBUG_CODE_END();\r
+\r
+ PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_CQHDBL_OFFSET(Qid, Private->Cap.Dstrd),\r
+ 1,\r
+ &Private->CqHdbl[Qid]\r
+ );\r
+\r
+EXIT:\r
+ if (MapData != NULL) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ MapData\r
+ );\r
+ }\r
+\r
+ if (MapMeta != NULL) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ MapMeta\r
+ );\r
+ }\r
+\r
+ if (MapPrpList != NULL) {\r
+ PciIo->Unmap (\r
+ PciIo,\r
+ MapPrpList\r
+ );\r
+ }\r
+\r
+ if (Prp != NULL) {\r
+ PciIo->FreeBuffer (PciIo, PrpListNo, PrpListHost);\r
+ }\r
+\r
+ if (TimerEvent != NULL) {\r
+ gBS->CloseEvent (TimerEvent);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Used to retrieve the list of namespaces defined on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves a list of namespaces\r
+ defined on an NVM Express controller. If on input a NamespaceID is specified by all 0xFF in the\r
+ namespace buffer, then the first namespace defined on the NVM Express controller is returned in\r
+ NamespaceID, and a status of EFI_SUCCESS is returned.\r
+\r
+ If NamespaceId is a Namespace value that was returned on a previous call to GetNextNamespace(),\r
+ then the next valid NamespaceId for an NVM Express SSD namespace on the NVM Express controller\r
+ is returned in NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ If Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned on a previous call to\r
+ GetNextNamespace(), then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If NamespaceId is the NamespaceId of the last SSD namespace on the NVM Express controller, then\r
+ EFI_NOT_FOUND is returned\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express\r
+ namespace present on the NVM Express controller. On output, a\r
+ pointer to the next NamespaceId of an NVM Express namespace on\r
+ an NVM Express controller. An input value of 0xFFFFFFFF retrieves\r
+ the first NamespaceId for an NVM Express namespace present on an\r
+ NVM Express controller.\r
+ @param[out] NamespaceUuid On output, the UUID associated with the next namespace, if a UUID\r
+ is defined for that NamespaceId, otherwise, zero is returned in\r
+ this parameter. If the caller does not require a UUID, then a NULL\r
+ pointer may be passed.\r
+\r
+ @retval EFI_SUCCESS The NamespaceId of the next Namespace was returned.\r
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.\r
+ @retval EFI_INVALID_PARAMETER Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned\r
+ on a previous call to GetNextNamespace().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressGetNextNamespace (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid OPTIONAL\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
+ UINT32 NextNamespaceId;\r
+ EFI_STATUS Status;\r
+\r
+ if ((This == NULL) || (NamespaceId == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NamespaceData = NULL;\r
+ Status = EFI_NOT_FOUND;\r
+\r
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
+ //\r
+ // If the NamespaceId input value is 0xFFFFFFFF, then get the first valid namespace ID\r
+ //\r
+ if (*NamespaceId == 0xFFFFFFFF) {\r
+ //\r
+ // Start with the first namespace ID\r
+ //\r
+ NextNamespaceId = 1;\r
+ //\r
+ // Allocate buffer for Identify Namespace data.\r
+ //\r
+ NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
+\r
+ if (NamespaceData == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ *NamespaceId = NextNamespaceId;\r
+ if (NamespaceUuid != NULL) {\r
+ *NamespaceUuid = NamespaceData->Eui64;\r
+ }\r
+ } else {\r
+ if (*NamespaceId >= Private->ControllerData->Nn) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ NextNamespaceId = *NamespaceId + 1;\r
+ //\r
+ // Allocate buffer for Identify Namespace data.\r
+ //\r
+ NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
+ if (NamespaceData == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ *NamespaceId = NextNamespaceId;\r
+ if (NamespaceUuid != NULL) {\r
+ *NamespaceUuid = NamespaceData->Eui64;\r
+ }\r
+ }\r
+\r
+Done:\r
+ if (NamespaceData != NULL) {\r
+ FreePool(NamespaceData);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Used to translate a device path node to a Namespace ID and Namespace UUID.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamwspace() function determines the Namespace ID and Namespace UUID\r
+ associated with the NVM Express SSD namespace described by DevicePath. If DevicePath is a device path node type\r
+ that the NVM Express Pass Thru driver supports, then the NVM Express Pass Thru driver will attempt to translate\r
+ the contents DevicePath into a Namespace ID and UUID. If this translation is successful, then that Namespace ID\r
+ and UUID are returned in NamespaceID and NamespaceUUID, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on\r
+ the NVM Express controller.\r
+ @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.\r
+ @param[out] NamespaceUuid The NVM Express namespace contained in the device path node.\r
+\r
+ @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId and NamespaceUuid.\r
+ @retval EFI_INVALID_PARAMETER If DevicePath, NamespaceId, or NamespaceUuid are NULL, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+ @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver\r
+ supports, then EFI_UNSUPPORTED is returned.\r
+ @retval EFI_NOT_FOUND If DevicePath is a device path node type that the Nvm Express Pass Thru driver\r
+ supports, but there is not a valid translation from DevicePath to a NamespaceID\r
+ and NamespaceUuid, then EFI_NOT_FOUND is returned.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressGetNamespace (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid\r
+ )\r
+{\r
+ NVME_NAMESPACE_DEVICE_PATH *Node;\r
+\r
+ if ((This == NULL) || (DevicePath == NULL) || (NamespaceId == NULL) || (NamespaceUuid == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DevicePath->Type != MESSAGING_DEVICE_PATH) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Node = (NVME_NAMESPACE_DEVICE_PATH *)DevicePath;\r
+\r
+ if (DevicePath->SubType == MSG_NVME_NAMESPACE_DP) {\r
+ if (DevicePathNodeLength(DevicePath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *NamespaceId = Node->NamespaceId;\r
+ *NamespaceUuid = Node->NamespaceUuid;\r
+\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+}\r
+\r
+/**\r
+ Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device\r
+ path node for the NVM Express namespace specified by NamespaceId.\r
+\r
+ If the namespace device specified by NamespaceId is not valid , then EFI_NOT_FOUND is returned.\r
+\r
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
+\r
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are\r
+ initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
+ allocated and built. Caller must set the NamespaceId to zero if the\r
+ device path node will contain a valid UUID.\r
+ @param[in] NamespaceUuid The NVM Express namespace UUID for which a device path node is to be\r
+ allocated and built. UUID will only be valid of the Namespace ID is zero.\r
+ @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express\r
+ namespace specified by NamespaceId. This function is responsible for\r
+ allocating the buffer DevicePath with the boot service AllocatePool().\r
+ It is the caller's responsibility to free DevicePath when the caller\r
+ is finished with DevicePath.\r
+ @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified\r
+ by NamespaceId was allocated and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The NVM Express namespace specified by NamespaceId does not exist on the\r
+ NVM Express controller.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmExpressBuildDevicePath (\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_NAMESPACE_DEVICE_PATH *Node;\r
+\r
+ //\r
+ // Validate parameters\r
+ //\r
+ if ((This == NULL) || (DevicePath == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
+\r
+ if (NamespaceId == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Node = (NVME_NAMESPACE_DEVICE_PATH *)AllocateZeroPool (sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
+\r
+ if (Node == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Node->Header.Type = MESSAGING_DEVICE_PATH;\r
+ Node->Header.SubType = MSG_NVME_NAMESPACE_DP;\r
+ SetDevicePathNodeLength (&Node->Header, sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
+ Node->NamespaceId = NamespaceId;\r
+ Node->NamespaceUuid = NamespaceUuid;\r
+\r
+ *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
--- /dev/null
+/** @file\r
+ NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows\r
+ NVM Express specification.\r
+\r
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _NVM_EXPRESS_PASS_THRU_H_\r
+#define _NVM_EXPRESS_PASS_THRU_H_\r
+\r
+#define NVM_EXPRESS_PASS_THRU_PROTOCOL_GUID \\r
+ { \\r
+ 0xec51ef5c, 0x2cf3, 0x4a55, {0xbf, 0x85, 0xb6, 0x3c, 0xa3, 0xb1, 0x3f, 0x44 } \\r
+ }\r
+\r
+typedef struct _NVM_EXPRESS_PASS_THRU_PROTOCOL NVM_EXPRESS_PASS_THRU_PROTOCOL;\r
+\r
+typedef struct {\r
+ UINT32 AdapterId;\r
+ UINT32 Attributes;\r
+ UINT32 IoAlign;\r
+ UINT32 HciVersion;\r
+ UINT64 Timeout;\r
+ UINT32 MaxNamespace;\r
+} NVM_EXPRESS_PASS_THRU_MODE;\r
+\r
+//\r
+// If this bit is set, then the NVM_EXPRESS_PASS_THRU_PROTOCOL interface is for directly addressable namespaces.\r
+//\r
+#define NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL 0x0001\r
+//\r
+// If this bit is set, then the NVM_EXPRESS_PASS_THRU_PROTOCOL interface is for a single volume logical namespace\r
+// comprised of multiple namespaces.\r
+//\r
+#define NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL 0x0002\r
+//\r
+// If this bit is set, then the NVM_EXPRESS_PASS_THRU_PROTOCOL interface supports non blocking I/O.\r
+//\r
+#define NVM_EXPRESS_PASS_THRU_ATTRIBUTES_NONBLOCKIO 0x0004\r
+//\r
+// If this bit is set, then the NVM_EXPRESS_PASS_THRU_PROTOCOL interface supports NVM command set commands.\r
+//\r
+#define NVM_EXPRESS_PASS_THRU_ATTRIBUTES_CMD_SET_NVME 0x0008\r
+\r
+//\r
+// QueueId\r
+//\r
+#define NVME_ADMIN_QUEUE 0x00\r
+#define NVME_IO_QUEUE 0x01\r
+\r
+//\r
+// ControllerStatus\r
+//\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_READY 0x00\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_CMD_ERROR 0x01\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_FATAL 0x02\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_CMD_DATA_ERROR 0x04\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_CMD_ABORT 0x05\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_DEVICE_ERROR 0x06\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_TIMEOUT_COMMAND 0x09\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_INVALID_NAMESPACE 0x0B\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_NOT_READY 0x0C\r
+#define NVM_EXPRESS_STATUS_CONTROLLER_OTHER 0x7F\r
+\r
+typedef struct {\r
+ UINT8 Opcode;\r
+ UINT8 FusedOperation;\r
+ #define NORMAL_CMD 0x00\r
+ #define FUSED_FIRST_CMD 0x01\r
+ #define FUSED_SECOND_CMD 0x02\r
+ UINT16 Cid;\r
+} NVME_CDW0;\r
+\r
+typedef struct {\r
+ NVME_CDW0 Cdw0;\r
+ UINT8 Flags;\r
+ #define CDW10_VALID 0x01\r
+ #define CDW11_VALID 0x02\r
+ #define CDW12_VALID 0x04\r
+ #define CDW13_VALID 0x08\r
+ #define CDW14_VALID 0x10\r
+ #define CDW15_VALID 0x20\r
+ UINT32 Nsid;\r
+ UINT32 Cdw10;\r
+ UINT32 Cdw11;\r
+ UINT32 Cdw12;\r
+ UINT32 Cdw13;\r
+ UINT32 Cdw14;\r
+ UINT32 Cdw15;\r
+} NVM_EXPRESS_COMMAND;\r
+\r
+typedef struct {\r
+ UINT32 Cdw0;\r
+ UINT32 Cdw1;\r
+ UINT32 Cdw2;\r
+ UINT32 Cdw3;\r
+} NVM_EXPRESS_RESPONSE;\r
+\r
+typedef struct {\r
+ UINT64 CommandTimeout;\r
+ VOID *TransferBuffer;\r
+ UINT32 TransferLength;\r
+ VOID *MetadataBuffer;\r
+ UINT32 MetadataLength;\r
+ UINT8 QueueId;\r
+ NVM_EXPRESS_COMMAND *NvmeCmd;\r
+ NVM_EXPRESS_RESPONSE *NvmeResponse;\r
+ UINT8 ControllerStatus;\r
+} NVM_EXPRESS_PASS_THRU_COMMAND_PACKET;\r
+\r
+//\r
+// Protocol funtion prototypes\r
+//\r
+/**\r
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking\r
+ I/O functionality is optional.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ ID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in] NamespaceUuid Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.\r
+ A value of 0 denotes the NVM Express controller, a value of all 0FFh in the namespace\r
+ UUID specifies that the command packet should be sent to all valid namespaces.\r
+ @param[in,out] Packet A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified\r
+ by NamespaceId.\r
+ @param[in] Event If nonblocking I/O is not supported then Event is ignored, and blocking I/O is performed.\r
+ If Event is NULL, then blocking I/O is performed. If Event is not NULL and non blocking I/O\r
+ is supported, then nonblocking I/O is performed, and Event will be signaled when the NVM\r
+ Express Command Packet completes.\r
+\r
+ @retval EFI_SUCCESS The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred\r
+ to, or from DataBuffer.\r
+ @retval EFI_BAD_BUFFER_SIZE The NVM Express Command Packet was not executed. The number of bytes that could be transferred\r
+ is returned in TransferLength.\r
+ @retval EFI_NOT_READY The NVM Express Command Packet could not be sent because the controller is not ready. The caller\r
+ may retry again later.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to send the NVM Express Command Packet.\r
+ @retval EFI_INVALID_PARAMETER Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM\r
+ Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_UNSUPPORTED The command described by the NVM Express Command Packet is not supported by the host adapter.\r
+ The NVM Express Command Packet was not sent, so no additional status information is available.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the NVM Express Command Packet to execute.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *NVM_EXPRESS_PASS_THRU_PASSTHRU)(\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to retrieve the list of namespaces defined on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNextNamespace() function retrieves a list of namespaces\r
+ defined on an NVM Express controller. If on input a NamespaceID is specified by all 0xFF in the\r
+ namespace buffer, then the first namespace defined on the NVM Express controller is returned in\r
+ NamespaceID, and a status of EFI_SUCCESS is returned.\r
+\r
+ If NamespaceId is a Namespace value that was returned on a previous call to GetNextNamespace(),\r
+ then the next valid NamespaceId for an NVM Express SSD namespace on the NVM Express controller\r
+ is returned in NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ If Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned on a previous call to\r
+ GetNextNamespace(), then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If NamespaceId is the NamespaceId of the last SSD namespace on the NVM Express controller, then\r
+ EFI_NOT_FOUND is returned\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in,out] NamespaceId On input, a pointer to a legal NamespaceId for an NVM Express\r
+ namespace present on the NVM Express controller. On output, a\r
+ pointer to the next NamespaceId of an NVM Express namespace on\r
+ an NVM Express controller. An input value of 0xFFFFFFFF retrieves\r
+ the first NamespaceId for an NVM Express namespace present on an\r
+ NVM Express controller.\r
+ @param[out] NamespaceUuid On output, the UUID associated with the next namespace, if a UUID\r
+ is defined for that NamespaceId, otherwise, zero is returned in\r
+ this parameter. If the caller does not require a UUID, then a NULL\r
+ pointer may be passed.\r
+\r
+ @retval EFI_SUCCESS The NamespaceId of the next Namespace was returned.\r
+ @retval EFI_NOT_FOUND There are no more namespaces defined on this controller.\r
+ @retval EFI_INVALID_PARAMETER Namespace array is not a 0xFFFFFFFF and NamespaceId was not returned\r
+ on a previous call to GetNextNamespace().\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *NVM_EXPRESS_PASS_THRU_GET_NEXT_NAMESPACE)(\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid OPTIONAL\r
+ );\r
+\r
+/**\r
+ Used to allocate and build a device path node for an NVM Express namespace on an NVM Express controller.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.BuildDevicePath() function allocates and builds a single device\r
+ path node for the NVM Express namespace specified by NamespaceId.\r
+\r
+ If the namespace device specified by NamespaceId is not valid , then EFI_NOT_FOUND is returned.\r
+\r
+ If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+ If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
+\r
+ Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of DevicePath are\r
+ initialized to describe the NVM Express namespace specified by NamespaceId, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] NamespaceId The NVM Express namespace ID for which a device path node is to be\r
+ allocated and built. Caller must set the NamespaceId to zero if the\r
+ device path node will contain a valid UUID.\r
+ @param[in] NamespaceUuid The NVM Express namespace UUID for which a device path node is to be\r
+ allocated and built. UUID will only be valid of the Namespace ID is zero.\r
+ @param[in,out] DevicePath A pointer to a single device path node that describes the NVM Express\r
+ namespace specified by NamespaceId. This function is responsible for\r
+ allocating the buffer DevicePath with the boot service AllocatePool().\r
+ It is the caller's responsibility to free DevicePath when the caller\r
+ is finished with DevicePath.\r
+ @retval EFI_SUCCESS The device path node that describes the NVM Express namespace specified\r
+ by NamespaceId was allocated and returned in DevicePath.\r
+ @retval EFI_NOT_FOUND The NVM Express namespace specified by NamespaceId does not exist on the\r
+ NVM Express controller.\r
+ @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate the DevicePath node.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *NVM_EXPRESS_PASS_THRU_BUILD_DEVICE_PATH)(\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN UINT64 NamespaceUuid,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ );\r
+\r
+/**\r
+ Used to translate a device path node to a Namespace ID and Namespace UUID.\r
+\r
+ The NVM_EXPRESS_PASS_THRU_PROTOCOL.GetNamwspace() function determines the Namespace ID and Namespace UUID\r
+ associated with the NVM Express SSD namespace described by DevicePath. If DevicePath is a device path node type\r
+ that the NVM Express Pass Thru driver supports, then the NVM Express Pass Thru driver will attempt to translate\r
+ the contents DevicePath into a Namespace ID and UUID. If this translation is successful, then that Namespace ID\r
+ and UUID are returned in NamespaceID and NamespaceUUID, and EFI_SUCCESS is returned.\r
+\r
+ @param[in] This A pointer to the NVM_EXPRESS_PASS_THRU_PROTOCOL instance.\r
+ @param[in] DevicePath A pointer to the device path node that describes an NVM Express namespace on\r
+ the NVM Express controller.\r
+ @param[out] NamespaceId The NVM Express namespace ID contained in the device path node.\r
+ @param[out] NamespaceUuid The NVM Express namespace contained in the device path node.\r
+\r
+ @retval EFI_SUCCESS DevicePath was successfully translated to NamespaceId and NamespaceUuid.\r
+ @retval EFI_INVALID_PARAMETER If DevicePath, NamespaceId, or NamespaceUuid are NULL, then EFI_INVALID_PARAMETER\r
+ is returned.\r
+ @retval EFI_UNSUPPORTED If DevicePath is not a device path node type that the NVM Express Pass Thru driver\r
+ supports, then EFI_UNSUPPORTED is returned.\r
+ @retval EFI_NOT_FOUND If DevicePath is a device path node type that the Nvm Express Pass Thru driver\r
+ supports, but there is not a valid translation from DevicePath to a NamespaceID\r
+ and NamespaceUuid, then EFI_NOT_FOUND is returned.\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *NVM_EXPRESS_PASS_THRU_GET_NAMESPACE)(\r
+ IN NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT32 *NamespaceId,\r
+ OUT UINT64 *NamespaceUuid\r
+ );\r
+\r
+//\r
+// Protocol Interface Structure\r
+//\r
+struct _NVM_EXPRESS_PASS_THRU_PROTOCOL {\r
+ NVM_EXPRESS_PASS_THRU_MODE *Mode;\r
+ NVM_EXPRESS_PASS_THRU_PASSTHRU PassThru;\r
+ NVM_EXPRESS_PASS_THRU_GET_NEXT_NAMESPACE GetNextNamespace;\r
+ NVM_EXPRESS_PASS_THRU_BUILD_DEVICE_PATH BuildDevicePath;\r
+ NVM_EXPRESS_PASS_THRU_GET_NAMESPACE GetNamespace;\r
+};\r
+\r
+//extern EFI_GUID gNvmExpressPassThruProtocolGuid;\r
+\r
+#endif\r
+\r
\r
MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
+ MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r
MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf\r
MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf\r
MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf\r