Hi, Darbin We have discussed this library internally. We would like to know the usage model of this library, that's who will use/consume this lib? Currently there is no EDKII module using it. And the intention of a new library is for code sharing/reuse.
Besides that, here are some comments on the library: 1. Please don't use a common name as function name. usually we add a "NvmExpress" prefix prior to such function name. 2. Why you include UefiLib.h at NvmExpressLib.h? it should be redundant. 3. Identify() looks like a little overlap with IdentifyController(). GetLog() is same case with other GetLog variant. Do we need all of them? 4. Suggest you to follow the style of UefiScsiLib, then we can put it to MdePkg. Such as the library instance name is UefiNvmExpressLib rather than DxeNvmExpressLib. Such as you can fill INF like this LIBRARY_CLASS = UefiNvmExpressLib |DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER Thanks Feng -----Original Message----- From: darbin.emm.re...@hpe.com [mailto:darbin.emm.re...@hpe.com] Sent: Wednesday, May 18, 2016 5:59 AM To: edk2-devel@lists.01.org Cc: Tian, Feng <feng.t...@intel.com>; Zeng, Star <star.z...@intel.com>; Kinney, Michael D <michael.d.kin...@intel.com>; Gao, Liming <liming....@intel.com>; samer.el-haj-mahm...@hpe.com; Darbin Reyes <darbin.emm.re...@hpe.com> Subject: [PATCH v2 3/3] MdeModulePkg: Add NvmExpressLib. 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