From: Darbin Reyes <darbin.emm.re...@hpe.com>

Adds a library for functions that facilitate the execution of NVMe
commands using the passthru protocol. These functions are intended
for use with NVMe controllers that are compliant with version 1.1
of the NVMe spec. The initial implementation of the library
contains functions for:

1. Executing a Get Log command.
2. Executing an Identify command.
3. Executing a firmware download and activate command.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Darbin Reyes <darbin.emm.re...@hpe.com>
Reviewed-by: Samer El-Haj-Mahmoud <samer.el-haj-mahm...@hpe.com>
---
 MdeModulePkg/Include/Library/NvmExpressLib.h       | 279 +++++++++
 .../Library/DxeNvmExpressLib/DxeNvmExpressLib.c    | 635 +++++++++++++++++++++
 .../Library/DxeNvmExpressLib/DxeNvmExpressLib.inf  |  41 ++
 MdeModulePkg/MdeModulePkg.dec                      |   4 +
 4 files changed, 959 insertions(+)
 create mode 100644 MdeModulePkg/Include/Library/NvmExpressLib.h
 create mode 100644 MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.c
 create mode 100644 MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.inf

diff --git a/MdeModulePkg/Include/Library/NvmExpressLib.h 
b/MdeModulePkg/Include/Library/NvmExpressLib.h
new file mode 100644
index 0000000..d1e06a9
--- /dev/null
+++ b/MdeModulePkg/Include/Library/NvmExpressLib.h
@@ -0,0 +1,279 @@
+/** @file
+  Functions for sending NVMe commands to an NVMe controller that supports
+  the NVMe Specification version 1.1.
+
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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.
+
+  @par Specification Reference:
+  NVMe Specification 1.1
+
+**/
+
+#ifndef __NVM_E_LIB__
+#define __NVM_E_LIB__
+
+
+
+#include <IndustryStandard/Nvme.h>
+
+#include <Library/UefiLib.h>
+
+#include <Protocol/NvmExpressPassthru.h>
+
+//
+// Time out value for Nvme transaction execution
+//
+#define NVME_GENERIC_TIMEOUT                      EFI_TIMER_PERIOD_SECONDS (5)
+
+/**
+
+  Executes a Get Log Page command.
+  (ref. spec. v1.1 5.10).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  LogId                 Log Page Identifier.
+  @param[in]  LogSize               Size in bytes of LogBuffer.
+  @param[out] LogBuffer             Pointer to buffer in which to return the 
log.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, LogBuffer, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  IN  NVME_LOG_ID                        LogId,
+  IN  UINT32                             LogSize,
+  OUT VOID                               *LogBuffer,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  );
+
+/**
+
+  Gets the NVMe firmware slot information log.
+  (ref. spec. v1.1 5.10.1.3).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[out] FwSlotInfoLog         Pointer to an NVMe firmware info. log 
struct.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, FwSlotInfoLog, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFwSlotInfoLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  OUT NVME_FW_SLOT_INFO_LOG              *FwSlotInfoLog,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  );
+
+/**
+
+  Gets the NVMe smart health information log.
+  (ref. spec. v1.1 5.10.1.2).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[out] SmartHealthInfoLog    Pointer to an NVMe smart health log struct.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, SmartHealthInfoLog, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSmartHealthInfoLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  OUT NVME_SMART_HEALTH_INFO_LOG                  *SmartHealthInfoLog,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  );
+
+/**
+
+  Executes a firmware image download command.
+  (ref. spec. v1.1 5.8).
+
+  Note: This command is optional in the NVMe spec. so it may not be supported.
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  Image                 Points to the new image.
+  @param[in]  NumDwords             Size of the Image in dwords.
+  @param[in]  DwordOffset           Dword offset from start of the full image.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, Image, or NvmeCompletion
+                                     arguments are NULL. NumDwords is 0.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareImageDownload (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  IN  CONST VOID                                  *Image,
+  IN  UINT32                                      NumDwords,
+  IN  UINT32                                      DwordOffset,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  );
+
+/**
+
+  Executes a firmware commit command.
+  (ref. spec. v1.1 5.7).
+
+  Firmware Commit – Command Specific Status Values.
+  (ref. spec. v1.1 figure 61).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  FirmwareSlot          The firmware slot that shall be used for 
the Activate Action.
+  @param[in]  ActivateAction        Action that is taken on the image 
downloaded with the Firmware Image Download command.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCESS  Successful.
+  @retval Other       Error.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareActivate (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  IN  NVME_FW_ACTIVATE_SLOT                       FirmwareSlot,
+  IN  NVME_FW_ACTIVATE_ACTION                     ActivateAction,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  );
+
+/**
+
+  Executes an Identify command.
+  The Identify command returns a data buffer that describes information about 
the NVM subsystem.
+  (ref. spec. v1.1 5.11).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  NsId                  The namespace identifier to use for the 
command. 0 if not used 0xFFFFFFFF indicates all namespaces.
+  @param[in]  IdentifyCns           Controller or Namespace Structure (CNS) 
value determines what datastructure is returned. (ref. spec. v1.1 figure 82).
+  @param[in]  BufferSize            Size in bytes of Buffer.
+  @param[out] Buffer                Pointer to buffer in which to return the 
identify datastructure.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, Buffer, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+Identify (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  IN  UINT32                             NsId,
+  IN  NVME_ADMIN_IDENTIFY_CNS            IdentifyCns,
+  IN  UINT32                             BufferSize,
+  OUT VOID                               *Buffer,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  );
+
+/**
+
+  Executes an Identify command that returns the Identify Controller Data 
Structure.
+  (ref. spec. v1.1 Figure  83).
+
+
+  @param[in]  NVMePassThruProtocol        Pointer to an instance of the NVMe 
pass thru protocol.
+  @param[out] IdentifyControllerStruct    Pointer to buffer in which to return 
the identify datastructure.
+  @param[out] NvmeCompletion              Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, IdentifyController, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+IdentifyController (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  OUT NVME_ADMIN_CONTROLLER_DATA         *IdentifyControllerStruct,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  );
+#endif
diff --git a/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.c 
b/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.c
new file mode 100644
index 0000000..f34ca53
--- /dev/null
+++ b/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.c
@@ -0,0 +1,635 @@
+/** @file
+  Functions for sending NVMe commands to an NVMe controller that supports
+  the NVMe Specification version 1.1.
+
+  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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 <Uefi.h>
+
+#include <IndustryStandard/Nvme.h>
+
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include <Protocol/NvmExpressPassthru.h>
+#include <Library/NvmExpressLib.h>
+
+/**
+
+  Executes a Get Log Page command.
+  (ref. spec. v1.1 5.10).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  LogId                 Log Page Identifier.
+  @param[in]  LogSize               Size in bytes of LogBuffer.
+  @param[out] LogBuffer             Pointer to buffer in which to return the 
log.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, LogBuffer, or NvmeCompletion
+                                     arguments are NULL. LogSize is 0.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  IN  NVME_LOG_ID                        LogId,
+  IN  UINT32                             LogSize,
+  OUT VOID                               *LogBuffer,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  )
+{
+  UINT32                                      NsId;
+  EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET    Packet;
+  EFI_NVM_EXPRESS_COMMAND                     NvmeCmd;
+  NVME_ADMIN_GET_LOG_PAGE                     Cdw10;
+  EFI_STATUS                                  Status;
+  UINT32                                      NumPages;
+
+  if(NVMePassThruProtocol == NULL || LogSize == 0 || LogBuffer == NULL || 
NvmeCompletion == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Execute a "Get Log Page" Admin command.
+  //
+  ZeroMem(&Packet, sizeof(Packet));
+  ZeroMem(&NvmeCmd, sizeof(NvmeCmd));
+  ZeroMem(NvmeCompletion, sizeof(*NvmeCompletion));
+
+  NumPages = EFI_SIZE_TO_PAGES(LogSize);
+
+  //
+  // Send command to all valid Namespaces.
+  //
+  NsId = 0xFFFFFFFF;
+
+  //
+  // Fill in the command packet.
+  //
+  Packet.CommandTimeout = NVME_GENERIC_TIMEOUT;
+
+  //
+  // This command uses a PRP for data transfer so allocate memory using 
AllocateAlignedPages ().
+  // PRP = physical region page.
+  // (ref. spec. v1.1 4.3)
+  //
+  Packet.TransferBuffer = AllocateAlignedPages (NumPages, 0);
+
+  if(Packet.TransferBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Packet.TransferLength = LogSize;
+  ZeroMem(Packet.TransferBuffer, LogSize);
+
+  //
+  // Get Log command does not use the MetaData pointer.
+  //
+  Packet.MetadataBuffer = NULL;
+  Packet.MetadataLength = 0;
+
+  //
+  // This is an Admin command so use the admin queue.
+  //
+  Packet.QueueType = NVME_ADMIN_QUEUE;
+
+  //
+  // Set opcode to Get Log command.
+  // (ref. spec. v1.1 Figure 39).
+  //
+  NvmeCmd.Cdw0.Opcode = GetLogPageOpcode;
+  NvmeCmd.Cdw0.FusedOperation = NORMAL_CMD;
+  NvmeCmd.Cdw0.Reserved = 0;
+  NvmeCmd.Flags = CDW10_VALID;
+  NvmeCmd.Nsid = NsId;
+
+  //
+  // Set CDW10. NumDwords + Log ID.
+  //
+  Cdw10.Numd = (LogSize >> 2) + ((LogSize & 0x3) != 0);
+  Cdw10.Lid = LogId;
+
+  CopyMem(&NvmeCmd.Cdw10, &Cdw10, sizeof(NvmeCmd.Cdw10));
+
+  Packet.NvmeCmd = &NvmeCmd;
+  Packet.NvmeCompletion = NvmeCompletion;
+
+  //
+  // Execute the command.
+  //
+  Status = NVMePassThruProtocol->PassThru(NVMePassThruProtocol, NsId, &Packet, 
NULL);
+
+  CopyMem(LogBuffer, Packet.TransferBuffer, LogSize);
+
+  //
+  // Cleanup.
+  //
+  FreeAlignedPages (Packet.TransferBuffer, NumPages);
+
+  return Status;
+}
+
+/**
+
+  Gets the NVMe firmware slot information log.
+  (ref. spec. v1.1 5.10.1.3).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[out] FwSlotInfoLog         Pointer to an NVMe firmware info. log 
struct.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, FwSlotInfoLog, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFwSlotInfoLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  OUT NVME_FW_SLOT_INFO_LOG              *FwSlotInfoLog,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  )
+{
+  EFI_STATUS                                  Status;
+
+  if(NVMePassThruProtocol == NULL || FwSlotInfoLog == NULL || NvmeCompletion 
== NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Execute a "Get Log Firmware slot Information" Admin command.
+  //
+  Status = GetLog (
+            NVMePassThruProtocol,
+            FirmwareSlotInfoLogID,
+            (UINT32)sizeof(*FwSlotInfoLog),
+            FwSlotInfoLog,
+            NvmeCompletion
+            );
+
+  return Status;
+}
+
+/**
+
+  Gets the NVMe smart health information log.
+  (ref. spec. v1.1 5.10.1.2).
+
+  Get Log Page – Command Specific Status Values
+  (ref. spec. v1.1 figure 79).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[out] SmartHealthInfoLog    Pointer to an NVMe smart health log struct.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, SmartHealthInfoLog, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSmartHealthInfoLog (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  OUT NVME_SMART_HEALTH_INFO_LOG                  *SmartHealthInfoLog,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  )
+{
+  EFI_STATUS                                  Status;
+
+  if(NVMePassThruProtocol == NULL || SmartHealthInfoLog == NULL || 
NvmeCompletion == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Execute a "SMART / Health Information Log" command.
+  //
+  Status = GetLog (
+            NVMePassThruProtocol,
+            SmartHealthInfoLogID,
+            (UINT32)sizeof(*SmartHealthInfoLog),
+            SmartHealthInfoLog,
+            NvmeCompletion
+            );
+
+  return Status;
+}
+
+/**
+
+  Executes a firmware image download command.
+  (ref. spec. v1.1 5.8).
+
+  Note: This command is optional in the NVMe spec. so it may not be supported.
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  Image                 Points to the new image.
+  @param[in]  NumDwords             Size of the Image in dwords.
+  @param[in]  DwordOffset           Dword offset from start of the full image.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, Image, or NvmeCompletion
+                                     arguments are NULL. NumDwords is 0.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareImageDownload (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  IN  CONST VOID                                  *Image,
+  IN  UINT32                                      NumDwords,
+  IN  UINT32                                      DwordOffset,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  )
+{
+  UINT32                                      NsId;
+  EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET    Packet;
+  EFI_NVM_EXPRESS_COMMAND                     NvmeCmd;
+  EFI_STATUS                                  Status;
+  UINT32                                      NumPages;
+  UINTN                                       NumBytes;
+
+  if(NVMePassThruProtocol == NULL || Image == NULL || NvmeCompletion == NULL 
|| NumDwords == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem(&Packet, sizeof(Packet));
+  ZeroMem(&NvmeCmd, sizeof(NvmeCmd));
+  ZeroMem(NvmeCompletion, sizeof(*NvmeCompletion));
+
+  //
+  // Namespace ID is not used.
+  // (ref. spec. v1.1 figure 39).
+  //
+  NsId = 0x0;
+
+  //
+  // Fill in the command packet.
+  //
+  Packet.CommandTimeout = NVME_GENERIC_TIMEOUT;
+
+  NumBytes = NumDwords << 2;
+
+  NumPages = (UINT32) EFI_SIZE_TO_PAGES(NumBytes);
+
+  Packet.TransferBuffer = AllocateAlignedPages (NumPages, 0);
+
+  if(Packet.TransferBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Packet.TransferLength = (UINT32) NumBytes;
+  CopyMem(Packet.TransferBuffer, Image, NumBytes);
+  Packet.MetadataBuffer = NULL;
+  Packet.MetadataLength = 0;
+  Packet.QueueType = NVME_ADMIN_QUEUE;
+
+  NvmeCmd.Cdw0.Opcode = FirmwareImageDownloadOpcode;
+  NvmeCmd.Cdw0.FusedOperation = NORMAL_CMD;
+  NvmeCmd.Cdw0.Reserved = 0;
+  NvmeCmd.Flags = CDW10_VALID | CDW11_VALID;
+  NvmeCmd.Nsid = NsId;
+
+  //
+  // CDW10 = Number of Dwords in this portion of the fw.
+  // CDW11 = Dword offset from the start of the image.
+  // (ref. spec. v1.1 figure 63/64).
+  //
+  NvmeCmd.Cdw10 = NumDwords - 1; // 0 based value
+  NvmeCmd.Cdw11 = DwordOffset;
+
+  Packet.NvmeCmd = &NvmeCmd;
+  Packet.NvmeCompletion = NvmeCompletion;
+
+  //
+  // Execute the command.
+  //
+  Status = NVMePassThruProtocol->PassThru(NVMePassThruProtocol, NsId, &Packet, 
NULL);
+
+  //
+  // Cleanup.
+  //
+  FreeAlignedPages (Packet.TransferBuffer, NumPages);
+
+  return Status;
+}
+
+/**
+
+  Executes a firmware commit command.
+  (ref. spec. v1.1 5.7).
+
+  Firmware Commit – Command Specific Status Values.
+  (ref. spec. v1.1 figure 61).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  FirmwareSlot          The firmware slot that shall be used for 
the Activate Action.
+  @param[in]  ActivateAction        Action that is taken on the image 
downloaded with the Firmware Image Download command.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCESS  Successful.
+  @retval Other       Error.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareActivate (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL          *NVMePassThruProtocol,
+  IN  NVME_FW_ACTIVATE_SLOT                       FirmwareSlot,
+  IN  NVME_FW_ACTIVATE_ACTION                     ActivateAction,
+  OUT EFI_NVM_EXPRESS_COMPLETION                  *NvmeCompletion
+  )
+{
+  UINT32                                      NsId;
+  EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET    Packet;
+  EFI_NVM_EXPRESS_COMMAND                     NvmeCmd;
+  EFI_STATUS                                  Status;
+  UINT32                                      NumPages;
+  NVME_ADMIN_FIRMWARE_ACTIVATE                Cdw10;
+
+  if(NVMePassThruProtocol == NULL || NvmeCompletion == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem(&Packet, sizeof(Packet));
+  ZeroMem(&NvmeCmd, sizeof(NvmeCmd));
+  ZeroMem(NvmeCompletion, sizeof(*NvmeCompletion));
+
+  //
+  // Namespace ID is not used.
+  // (ref. spec. v1.1 figure 39).
+  //
+  NsId = 0x0;
+
+  //
+  // Fill in the command packet.
+  //
+  Packet.CommandTimeout = NVME_GENERIC_TIMEOUT;
+
+  //
+  // This command does not involve a data transfer.
+  // (ref. spec. v1.1 figure 39).
+  //
+  NumPages = 0;
+
+  Packet.TransferBuffer = NULL;
+  Packet.TransferLength = 0;
+  Packet.MetadataBuffer = NULL;
+  Packet.MetadataLength = 0;
+  Packet.QueueType = NVME_ADMIN_QUEUE;
+
+  NvmeCmd.Cdw0.Opcode = FirmwareCommitOpcode;
+  NvmeCmd.Cdw0.FusedOperation = NORMAL_CMD;
+  NvmeCmd.Cdw0.Reserved = 0;
+  NvmeCmd.Flags = CDW10_VALID;
+  NvmeCmd.Nsid = NsId;
+
+  //
+  // Set the fw slot number and activate action.
+  //
+  Cdw10.Fs = FirmwareSlot;
+  Cdw10.Aa = ActivateAction;
+
+  CopyMem(&NvmeCmd.Cdw10, &Cdw10, sizeof(NvmeCmd.Cdw10));
+
+  Packet.NvmeCmd = &NvmeCmd;
+  Packet.NvmeCompletion = NvmeCompletion;
+
+  //
+  // Execute the command.
+  //
+  Status = NVMePassThruProtocol->PassThru(NVMePassThruProtocol, NsId, &Packet, 
NULL);
+
+  return Status;
+}
+
+/**
+
+  Executes an Identify command.
+  The Identify command returns a data buffer that describes information about 
the NVM subsystem.
+  (ref. spec. v1.1 5.11).
+
+  @param[in]  NVMePassThruProtocol  Pointer to an instance of the NVMe pass 
thru protocol.
+  @param[in]  NsId                  The namespace identifier to use for the 
command. 0 if not used 0xFFFFFFFF indicates all namespaces.
+  @param[in]  IdentifyCns           Controller or Namespace Structure (CNS) 
value determines what datastructure is returned. (ref. spec. v1.1 figure 82).
+  @param[in]  BufferSize            Size in bytes of Buffer.
+  @param[out] Buffer                Pointer to buffer in which to return the 
identify datastructure.
+  @param[out] NvmeCompletion        Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, Buffer, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+Identify (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  IN  UINT32                             NsId,
+  IN  NVME_ADMIN_IDENTIFY_CNS            IdentifyCns,
+  IN  UINT32                             BufferSize,
+  OUT VOID                               *Buffer,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  )
+{
+  EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET    Packet;
+  EFI_NVM_EXPRESS_COMMAND                     NvmeCmd;
+  NVME_ADMIN_IDENTIFY                         Cdw10;
+  EFI_STATUS                                  Status;
+  UINT32                                      NumPages;
+
+  if(NVMePassThruProtocol == NULL || Buffer == NULL || NvmeCompletion == NULL) 
{
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ZeroMem(&Packet, sizeof(Packet));
+  ZeroMem(&NvmeCmd, sizeof(NvmeCmd));
+  ZeroMem(NvmeCompletion, sizeof(*NvmeCompletion));
+
+  NumPages = EFI_SIZE_TO_PAGES(BufferSize);
+
+  //
+  // Fill in the command packet.
+  //
+  Packet.CommandTimeout = NVME_GENERIC_TIMEOUT;
+
+  //
+  // This command uses a PRP for data transfer so allocate memory using 
AllocateAlignedPages ().
+  // PRP = physical region page.
+  // (ref. spec. v1.1 4.3)
+  //
+  Packet.TransferBuffer = AllocateAlignedPages (NumPages, 0);
+
+  if(Packet.TransferBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Packet.TransferLength = BufferSize;
+  ZeroMem(Packet.TransferBuffer, BufferSize);
+
+  //
+  // Get Log command does not use the MetaData pointer.
+  //
+  Packet.MetadataBuffer = NULL;
+  Packet.MetadataLength = 0;
+
+  //
+  // This is an Admin command so use the admin queue.
+  //
+  Packet.QueueType = NVME_ADMIN_QUEUE;
+
+  //
+  // Set opcode to Get Log command.
+  // (ref. spec. v1.1 Figure 39).
+  //
+  NvmeCmd.Cdw0.Opcode = IdentifyOpcode;
+  NvmeCmd.Cdw0.FusedOperation = NORMAL_CMD;
+  NvmeCmd.Cdw0.Reserved = 0;
+  NvmeCmd.Flags = CDW10_VALID;
+  NvmeCmd.Nsid = NsId;
+
+  //
+  // Set CDW10.
+  //
+  Cdw10.Cns = IdentifyCns;
+
+  CopyMem(&NvmeCmd.Cdw10, &Cdw10, sizeof(NvmeCmd.Cdw10));
+
+  Packet.NvmeCmd = &NvmeCmd;
+  Packet.NvmeCompletion = NvmeCompletion;
+
+  //
+  // Execute the command.
+  //
+  Status = NVMePassThruProtocol->PassThru(NVMePassThruProtocol, NsId, &Packet, 
NULL);
+
+  CopyMem(Buffer, Packet.TransferBuffer, BufferSize);
+
+  //
+  // Cleanup.
+  //
+  FreeAlignedPages (Packet.TransferBuffer, NumPages);
+
+  return Status;
+}
+
+/**
+
+  Executes an Identify command that returns the Identify Controller Data 
Structure.
+  (ref. spec. v1.1 Figure  83).
+
+
+  @param[in]  NVMePassThruProtocol        Pointer to an instance of the NVMe 
pass thru protocol.
+  @param[out] IdentifyControllerStruct    Pointer to buffer in which to return 
the identify datastructure.
+  @param[out] NvmeCompletion              Pointer to an NVMe completion struct.
+
+  @retval EFI_SUCCESS                The NVM Express Command Packet was sent 
by the host.
+  @retval EFI_BAD_BUFFER_SIZE        The NVM Express Command Packet was not 
executed.
+  @retval EFI_NOT_READY              The NVM Express Command Packet could not 
be sent because the controller is not ready. The caller
+                                     may retry again later.
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting 
to send the NVM Express Command Packet.
+  @retval EFI_INVALID_PARAMETER      The contents of the command are invalid. 
The NVM Express Command Packet was not sent,
+                                     so no additional status information is 
available. NVMePassThruProtocol, IdentifyController, or NvmeCompletion
+                                     arguments are NULL.
+  @retval EFI_UNSUPPORTED            The command described by the NVM Express 
Command Packet is not supported by the NVM Express
+                                     controller. The NVM Express Command 
Packet was not sent so no additional status information
+                                     is available.
+  @retval EFI_TIMEOUT                A timeout occurred while waiting for the 
NVM Express Command Packet to execute.
+  @retval EFI_OUT_OF_RESOURCES       Unable to allocate memory to execute the 
command.
+
+**/
+EFI_STATUS
+EFIAPI
+IdentifyController (
+  IN  EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NVMePassThruProtocol,
+  OUT NVME_ADMIN_CONTROLLER_DATA         *IdentifyControllerStruct,
+  OUT EFI_NVM_EXPRESS_COMPLETION         *NvmeCompletion
+  )
+{
+  EFI_STATUS                                  Status;
+
+  if(NVMePassThruProtocol == NULL || IdentifyController == NULL || 
NvmeCompletion == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = Identify (
+            NVMePassThruProtocol,
+            0,
+            IdentifyControllerCns,
+            (UINT32)sizeof(*IdentifyControllerStruct),
+            IdentifyControllerStruct,
+            NvmeCompletion
+            );
+
+  return Status;
+}
diff --git a/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.inf 
b/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.inf
new file mode 100644
index 0000000..26de2e8
--- /dev/null
+++ b/MdeModulePkg/Library/DxeNvmExpressLib/DxeNvmExpressLib.inf
@@ -0,0 +1,41 @@
+## @file
+#
+# Functions for sending NVMe commands to an NVMe controller that supports
+# the NVMe Specification version 1.1.
+#
+# (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeNvmExpressLib
+  FILE_GUID                      = C6D524A5-A228-41DE-BF04-390CBF6A0E70
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NvmExpressLib| DXE_DRIVER UEFI_APPLICATION
+
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  DxeNvmExpressLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiLib
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index a133824..68c9801 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -153,6 +153,10 @@
   #
   PciHostBridgeLib|Include/Library/PciHostBridgeLib.h
 
+  ## @libraryclass  Functions for sending NVMe commands to an NVMe controller 
that supports the NVMe Specification version 1.1.
+  #
+  NvmExpressLib|Include/Library/NvmExpressLib.h
+
 [Guids]
   ## MdeModule package token space guid
   # Include/Guid/MdeModulePkgTokenSpace.h
-- 
2.8.2

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to