MdeModulePkg NvmExpressDxe: Add BlockIo2 support

Together with EFI_BLOCK_IO_PROTOCOL, EFI_BLOCK_IO2_PROTOCOL is also
produced on NVMe devices.

The following Block I/O 2 functions are implemented:
Reset
ReadBlocksEx
WriteBlocksEx
FlushBlocksEx

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Feng Tian <feng.tian@intel.com>
This commit is contained in:
Hao Wu
2016-04-27 13:15:24 +08:00
parent b6c8ee6865
commit 758ea94651
7 changed files with 1632 additions and 82 deletions

View File

@@ -28,6 +28,7 @@
#include <Protocol/PciIo.h>
#include <Protocol/NvmExpressPassthru.h>
#include <Protocol/BlockIo.h>
#include <Protocol/BlockIo2.h>
#include <Protocol/DiskInfo.h>
#include <Protocol/DriverSupportedEfiVersion.h>
#include <Protocol/StorageSecurityCommand.h>
@@ -63,7 +64,18 @@ extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiV
#define NVME_CSQ_SIZE 1 // Number of I/O submission queue entries, which is 0-based
#define NVME_CCQ_SIZE 1 // Number of I/O completion queue entries, which is 0-based
#define NVME_MAX_QUEUES 2 // Number of queues supported by the driver
//
// Number of asynchronous I/O submission queue entries, which is 0-based.
// The asynchronous I/O submission queue size is 4kB in total.
//
#define NVME_ASYNC_CSQ_SIZE 63
//
// Number of asynchronous I/O completion queue entries, which is 0-based.
// The asynchronous I/O completion queue size is 4kB in total.
//
#define NVME_ASYNC_CCQ_SIZE 255
#define NVME_MAX_QUEUES 3 // Number of queues supported by the driver
#define NVME_CONTROLLER_ID 0
@@ -72,6 +84,11 @@ extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gNvmExpressDriverSupportedEfiV
//
#define NVME_GENERIC_TIMEOUT EFI_TIMER_PERIOD_SECONDS (5)
//
// Nvme async transfer timer interval, set by experience.
//
#define NVME_HC_ASYNC_TIMER EFI_TIMER_PERIOD_MILLISECONDS (1)
//
// Unique signature for private data structure.
//
@@ -101,11 +118,13 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
NVME_ADMIN_CONTROLLER_DATA *ControllerData;
//
// 4 x 4kB aligned buffers will be carved out of this buffer.
// 6 x 4kB aligned buffers will be carved out of this buffer.
// 1st 4kB boundary is the start of the admin submission queue.
// 2nd 4kB boundary is the start of the admin completion queue.
// 3rd 4kB boundary is the start of I/O submission queue #1.
// 4th 4kB boundary is the start of I/O completion queue #1.
// 5th 4kB boundary is the start of I/O submission queue #2.
// 6th 4kB boundary is the start of I/O completion queue #2.
//
UINT8 *Buffer;
UINT8 *BufferPciAddr;
@@ -123,6 +142,7 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
//
NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES];
NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES];
UINT16 AsyncSqHead;
UINT8 Pt[NVME_MAX_QUEUES];
UINT16 Cid[NVME_MAX_QUEUES];
@@ -133,6 +153,13 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
NVME_CAP Cap;
VOID *Mapping;
//
// For Non-blocking operations.
//
EFI_EVENT TimerEvent;
LIST_ENTRY AsyncPassThruQueue;
LIST_ENTRY UnsubmittedSubtasks;
};
#define NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU(a) \
@@ -166,9 +193,12 @@ struct _NVME_DEVICE_PRIVATE_DATA {
EFI_BLOCK_IO_MEDIA Media;
EFI_BLOCK_IO_PROTOCOL BlockIo;
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
EFI_DISK_INFO_PROTOCOL DiskInfo;
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
LIST_ENTRY AsyncQueue;
EFI_LBA NumBlocks;
CHAR16 ModelName[80];
@@ -188,6 +218,13 @@ struct _NVME_DEVICE_PRIVATE_DATA {
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
)
#define NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2(a) \
CR (a, \
NVME_DEVICE_PRIVATE_DATA, \
BlockIo2, \
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
)
#define NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO(a) \
CR (a, \
NVME_DEVICE_PRIVATE_DATA, \
@@ -202,6 +239,67 @@ struct _NVME_DEVICE_PRIVATE_DATA {
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
)
//
// Nvme block I/O 2 request.
//
#define NVME_BLKIO2_REQUEST_SIGNATURE SIGNATURE_32 ('N', 'B', '2', 'R')
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_BLOCK_IO2_TOKEN *Token;
UINTN UnsubmittedSubtaskNum;
BOOLEAN LastSubtaskSubmitted;
//
// The queue for Nvme read/write sub-tasks of a BlockIo2 request.
//
LIST_ENTRY SubtasksQueue;
} NVME_BLKIO2_REQUEST;
#define NVME_BLKIO2_REQUEST_FROM_LINK(a) \
CR (a, NVME_BLKIO2_REQUEST, Link, NVME_BLKIO2_REQUEST_SIGNATURE)
#define NVME_BLKIO2_SUBTASK_SIGNATURE SIGNATURE_32 ('N', 'B', '2', 'S')
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
BOOLEAN IsLast;
UINT32 NamespaceId;
EFI_EVENT Event;
EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;
//
// The BlockIo2 request this subtask belongs to
//
NVME_BLKIO2_REQUEST *BlockIo2Request;
} NVME_BLKIO2_SUBTASK;
#define NVME_BLKIO2_SUBTASK_FROM_LINK(a) \
CR (a, NVME_BLKIO2_SUBTASK, Link, NVME_BLKIO2_SUBTASK_SIGNATURE)
//
// Nvme asynchronous passthru request.
//
#define NVME_PASS_THRU_ASYNC_REQ_SIG SIGNATURE_32 ('N', 'P', 'A', 'R')
typedef struct {
UINT32 Signature;
LIST_ENTRY Link;
EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet;
UINT16 CommandId;
EFI_EVENT CallerEvent;
} NVME_PASS_THRU_ASYNC_REQ;
#define NVME_PASS_THRU_ASYNC_REQ_FROM_THIS(a) \
CR (a, \
NVME_PASS_THRU_ASYNC_REQ, \
Link, \
NVME_PASS_THRU_ASYNC_REQ_SIG \
)
/**
Retrieves a Unicode string that is the user readable name of the driver.
@@ -605,4 +703,15 @@ NvmExpressBuildDevicePath (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
);
/**
Dump the execution status from a given completion queue entry.
@param[in] Cq A pointer to the NVME_CQ item.
**/
VOID
NvmeDumpStatus (
IN NVME_CQ *Cq
);
#endif