]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeMdeModulePkg/NvmExpressDxe: Add NVM Express support.
authorFeng Tian <feng.tian@intel.com>
Mon, 12 Aug 2013 06:13:54 +0000 (06:13 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Mon, 12 Aug 2013 06:13:54 +0000 (06:13 +0000)
Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14545 6f19259b-4bc3-4df7-8a09-765794883524

13 files changed:
MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..60849ae
--- /dev/null
@@ -0,0 +1,233 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.c
new file mode 100644 (file)
index 0000000..b6729ce
--- /dev/null
@@ -0,0 +1,1057 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpress.h
new file mode 100644 (file)
index 0000000..d39b62e
--- /dev/null
@@ -0,0 +1,614 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.c
new file mode 100644 (file)
index 0000000..458afd2
--- /dev/null
@@ -0,0 +1,559 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressBlockIo.h
new file mode 100644 (file)
index 0000000..5f896fe
--- /dev/null
@@ -0,0 +1,111 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.c
new file mode 100644 (file)
index 0000000..66af190
--- /dev/null
@@ -0,0 +1,162 @@
+/** @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;
+}
+
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDiskInfo.h
new file mode 100644 (file)
index 0000000..7db3dff
--- /dev/null
@@ -0,0 +1,129 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf
new file mode 100644 (file)
index 0000000..3ed185a
--- /dev/null
@@ -0,0 +1,68 @@
+## @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.c
new file mode 100644 (file)
index 0000000..157e101
--- /dev/null
@@ -0,0 +1,926 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressHci.h
new file mode 100644 (file)
index 0000000..406cef4
--- /dev/null
@@ -0,0 +1,790 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
new file mode 100644 (file)
index 0000000..d1231ac
--- /dev/null
@@ -0,0 +1,884 @@
+/** @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
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.h b/MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.h
new file mode 100644 (file)
index 0000000..cf05bff
--- /dev/null
@@ -0,0 +1,299 @@
+/** @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
index 7895834c245fc90b10bfa47427bb8b63c78d5cce..2ff9dc5fae30f93cc09fbef89d5f0c2fe6de63a3 100644 (file)
 \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