mirror of https://github.com/acidanthera/audk.git
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:
parent
b6c8ee6865
commit
758ea94651
|
@ -157,6 +157,16 @@ EnumerateNvmeDevNamespace (
|
||||||
Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;
|
Device->BlockIo.WriteBlocks = NvmeBlockIoWriteBlocks;
|
||||||
Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;
|
Device->BlockIo.FlushBlocks = NvmeBlockIoFlushBlocks;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create BlockIo2 Protocol instance
|
||||||
|
//
|
||||||
|
Device->BlockIo2.Media = &Device->Media;
|
||||||
|
Device->BlockIo2.Reset = NvmeBlockIoResetEx;
|
||||||
|
Device->BlockIo2.ReadBlocksEx = NvmeBlockIoReadBlocksEx;
|
||||||
|
Device->BlockIo2.WriteBlocksEx = NvmeBlockIoWriteBlocksEx;
|
||||||
|
Device->BlockIo2.FlushBlocksEx = NvmeBlockIoFlushBlocksEx;
|
||||||
|
InitializeListHead (&Device->AsyncQueue);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create StorageSecurityProtocol Instance
|
// Create StorageSecurityProtocol Instance
|
||||||
//
|
//
|
||||||
|
@ -213,6 +223,8 @@ EnumerateNvmeDevNamespace (
|
||||||
Device->DevicePath,
|
Device->DevicePath,
|
||||||
&gEfiBlockIoProtocolGuid,
|
&gEfiBlockIoProtocolGuid,
|
||||||
&Device->BlockIo,
|
&Device->BlockIo,
|
||||||
|
&gEfiBlockIo2ProtocolGuid,
|
||||||
|
&Device->BlockIo2,
|
||||||
&gEfiDiskInfoProtocolGuid,
|
&gEfiDiskInfoProtocolGuid,
|
||||||
&Device->DiskInfo,
|
&Device->DiskInfo,
|
||||||
NULL
|
NULL
|
||||||
|
@ -239,6 +251,8 @@ EnumerateNvmeDevNamespace (
|
||||||
Device->DevicePath,
|
Device->DevicePath,
|
||||||
&gEfiBlockIoProtocolGuid,
|
&gEfiBlockIoProtocolGuid,
|
||||||
&Device->BlockIo,
|
&Device->BlockIo,
|
||||||
|
&gEfiBlockIo2ProtocolGuid,
|
||||||
|
&Device->BlockIo2,
|
||||||
&gEfiDiskInfoProtocolGuid,
|
&gEfiDiskInfoProtocolGuid,
|
||||||
&Device->DiskInfo,
|
&Device->DiskInfo,
|
||||||
NULL
|
NULL
|
||||||
|
@ -380,6 +394,8 @@ UnregisterNvmeNamespace (
|
||||||
NVME_DEVICE_PRIVATE_DATA *Device;
|
NVME_DEVICE_PRIVATE_DATA *Device;
|
||||||
NVME_CONTROLLER_PRIVATE_DATA *Private;
|
NVME_CONTROLLER_PRIVATE_DATA *Private;
|
||||||
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
|
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *StorageSecurity;
|
||||||
|
BOOLEAN IsEmpty;
|
||||||
|
EFI_TPL OldTpl;
|
||||||
|
|
||||||
BlockIo = NULL;
|
BlockIo = NULL;
|
||||||
|
|
||||||
|
@ -398,6 +414,21 @@ UnregisterNvmeNamespace (
|
||||||
Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);
|
Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO (BlockIo);
|
||||||
Private = Device->Controller;
|
Private = Device->Controller;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait for the device's asynchronous I/O queue to become empty.
|
||||||
|
//
|
||||||
|
while (TRUE) {
|
||||||
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
||||||
|
IsEmpty = IsListEmpty (&Device->AsyncQueue);
|
||||||
|
gBS->RestoreTPL (OldTpl);
|
||||||
|
|
||||||
|
if (IsEmpty) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gBS->Stall (100);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Close the child handle
|
// Close the child handle
|
||||||
//
|
//
|
||||||
|
@ -418,6 +449,8 @@ UnregisterNvmeNamespace (
|
||||||
Device->DevicePath,
|
Device->DevicePath,
|
||||||
&gEfiBlockIoProtocolGuid,
|
&gEfiBlockIoProtocolGuid,
|
||||||
&Device->BlockIo,
|
&Device->BlockIo,
|
||||||
|
&gEfiBlockIo2ProtocolGuid,
|
||||||
|
&Device->BlockIo2,
|
||||||
&gEfiDiskInfoProtocolGuid,
|
&gEfiDiskInfoProtocolGuid,
|
||||||
&Device->DiskInfo,
|
&Device->DiskInfo,
|
||||||
NULL
|
NULL
|
||||||
|
@ -479,6 +512,170 @@ UnregisterNvmeNamespace (
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Call back function when the timer event is signaled.
|
||||||
|
|
||||||
|
@param[in] Event The Event this notify function registered to.
|
||||||
|
@param[in] Context Pointer to the context data registered to the
|
||||||
|
Event.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
ProcessAsyncTaskList (
|
||||||
|
IN EFI_EVENT Event,
|
||||||
|
IN VOID* Context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NVME_CONTROLLER_PRIVATE_DATA *Private;
|
||||||
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||||
|
NVME_CQ *Cq;
|
||||||
|
UINT16 QueueId;
|
||||||
|
UINT32 Data;
|
||||||
|
LIST_ENTRY *Link;
|
||||||
|
LIST_ENTRY *NextLink;
|
||||||
|
NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
|
||||||
|
NVME_BLKIO2_SUBTASK *Subtask;
|
||||||
|
NVME_BLKIO2_REQUEST *BlkIo2Request;
|
||||||
|
EFI_BLOCK_IO2_TOKEN *Token;
|
||||||
|
BOOLEAN HasNewItem;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
Private = (NVME_CONTROLLER_PRIVATE_DATA*)Context;
|
||||||
|
QueueId = 2;
|
||||||
|
Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
|
||||||
|
HasNewItem = FALSE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Submit asynchronous subtasks to the NVMe Submission Queue
|
||||||
|
//
|
||||||
|
for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
|
||||||
|
!IsNull (&Private->UnsubmittedSubtasks, Link);
|
||||||
|
Link = NextLink) {
|
||||||
|
NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);
|
||||||
|
Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
|
||||||
|
BlkIo2Request = Subtask->BlockIo2Request;
|
||||||
|
Token = BlkIo2Request->Token;
|
||||||
|
RemoveEntryList (Link);
|
||||||
|
BlkIo2Request->UnsubmittedSubtaskNum--;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If any previous subtask fails, do not process subsequent ones.
|
||||||
|
//
|
||||||
|
if (Token->TransactionStatus != EFI_SUCCESS) {
|
||||||
|
if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
|
||||||
|
BlkIo2Request->LastSubtaskSubmitted &&
|
||||||
|
(BlkIo2Request->UnsubmittedSubtaskNum == 0)) {
|
||||||
|
//
|
||||||
|
// Remove the BlockIo2 request from the device asynchronous queue.
|
||||||
|
//
|
||||||
|
RemoveEntryList (&BlkIo2Request->Link);
|
||||||
|
FreePool (BlkIo2Request);
|
||||||
|
gBS->SignalEvent (Token->Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (Subtask->CommandPacket->NvmeCmd);
|
||||||
|
FreePool (Subtask->CommandPacket->NvmeCompletion);
|
||||||
|
FreePool (Subtask->CommandPacket);
|
||||||
|
FreePool (Subtask);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = Private->Passthru.PassThru (
|
||||||
|
&Private->Passthru,
|
||||||
|
Subtask->NamespaceId,
|
||||||
|
Subtask->CommandPacket,
|
||||||
|
Subtask->Event
|
||||||
|
);
|
||||||
|
if (Status == EFI_NOT_READY) {
|
||||||
|
InsertHeadList (&Private->UnsubmittedSubtasks, Link);
|
||||||
|
BlkIo2Request->UnsubmittedSubtaskNum++;
|
||||||
|
break;
|
||||||
|
} else if (EFI_ERROR (Status)) {
|
||||||
|
Token->TransactionStatus = EFI_DEVICE_ERROR;
|
||||||
|
|
||||||
|
if (IsListEmpty (&BlkIo2Request->SubtasksQueue) &&
|
||||||
|
Subtask->IsLast) {
|
||||||
|
//
|
||||||
|
// Remove the BlockIo2 request from the device asynchronous queue.
|
||||||
|
//
|
||||||
|
RemoveEntryList (&BlkIo2Request->Link);
|
||||||
|
FreePool (BlkIo2Request);
|
||||||
|
gBS->SignalEvent (Token->Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (Subtask->CommandPacket->NvmeCmd);
|
||||||
|
FreePool (Subtask->CommandPacket->NvmeCompletion);
|
||||||
|
FreePool (Subtask->CommandPacket);
|
||||||
|
FreePool (Subtask);
|
||||||
|
} else {
|
||||||
|
InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
|
||||||
|
if (Subtask->IsLast) {
|
||||||
|
BlkIo2Request->LastSubtaskSubmitted = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Cq->Pt != Private->Pt[QueueId]) {
|
||||||
|
ASSERT (Cq->Sqid == QueueId);
|
||||||
|
|
||||||
|
HasNewItem = TRUE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Find the command with given Command Id.
|
||||||
|
//
|
||||||
|
for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
|
||||||
|
!IsNull (&Private->AsyncPassThruQueue, Link);
|
||||||
|
Link = NextLink) {
|
||||||
|
NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
|
||||||
|
AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);
|
||||||
|
if (AsyncRequest->CommandId == Cq->Cid) {
|
||||||
|
//
|
||||||
|
// Copy the Respose Queue entry for this command to the callers
|
||||||
|
// response buffer.
|
||||||
|
//
|
||||||
|
CopyMem (
|
||||||
|
AsyncRequest->Packet->NvmeCompletion,
|
||||||
|
Cq,
|
||||||
|
sizeof(EFI_NVM_EXPRESS_COMPLETION)
|
||||||
|
);
|
||||||
|
|
||||||
|
RemoveEntryList (Link);
|
||||||
|
gBS->SignalEvent (AsyncRequest->CallerEvent);
|
||||||
|
FreePool (AsyncRequest);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update submission queue head.
|
||||||
|
//
|
||||||
|
Private->AsyncSqHead = Cq->Sqhd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Private->CqHdbl[QueueId].Cqh++;
|
||||||
|
if (Private->CqHdbl[QueueId].Cqh > NVME_ASYNC_CCQ_SIZE) {
|
||||||
|
Private->CqHdbl[QueueId].Cqh = 0;
|
||||||
|
Private->Pt[QueueId] ^= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasNewItem) {
|
||||||
|
PciIo = Private->PciIo;
|
||||||
|
Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);
|
||||||
|
PciIo->Mem.Write (
|
||||||
|
PciIo,
|
||||||
|
EfiPciIoWidthUint32,
|
||||||
|
NVME_BAR,
|
||||||
|
NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),
|
||||||
|
1,
|
||||||
|
&Data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Tests to see if this driver supports a given controller. If a child device is provided,
|
Tests to see if this driver supports a given controller. If a child device is provided,
|
||||||
it further tests to see if this driver supports creating a handle for the specified child device.
|
it further tests to see if this driver supports creating a handle for the specified child device.
|
||||||
|
@ -736,19 +933,21 @@ NvmExpressDriverBindingStart (
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// 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.
|
// 1st 4kB boundary is the start of the admin submission queue.
|
||||||
// 2nd 4kB boundary is the start of the admin completion queue.
|
// 2nd 4kB boundary is the start of the admin completion queue.
|
||||||
// 3rd 4kB boundary is the start of I/O submission queue #1.
|
// 3rd 4kB boundary is the start of I/O submission queue #1.
|
||||||
// 4th 4kB boundary is the start of I/O completion 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.
|
||||||
//
|
//
|
||||||
// Allocate 4 pages of memory, then map it for bus master read and write.
|
// Allocate 6 pages of memory, then map it for bus master read and write.
|
||||||
//
|
//
|
||||||
Status = PciIo->AllocateBuffer (
|
Status = PciIo->AllocateBuffer (
|
||||||
PciIo,
|
PciIo,
|
||||||
AllocateAnyPages,
|
AllocateAnyPages,
|
||||||
EfiBootServicesData,
|
EfiBootServicesData,
|
||||||
4,
|
6,
|
||||||
(VOID**)&Private->Buffer,
|
(VOID**)&Private->Buffer,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
@ -756,7 +955,7 @@ NvmExpressDriverBindingStart (
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bytes = EFI_PAGES_TO_SIZE (4);
|
Bytes = EFI_PAGES_TO_SIZE (6);
|
||||||
Status = PciIo->Map (
|
Status = PciIo->Map (
|
||||||
PciIo,
|
PciIo,
|
||||||
EfiPciIoOperationBusMasterCommonBuffer,
|
EfiPciIoOperationBusMasterCommonBuffer,
|
||||||
|
@ -766,7 +965,7 @@ NvmExpressDriverBindingStart (
|
||||||
&Private->Mapping
|
&Private->Mapping
|
||||||
);
|
);
|
||||||
|
|
||||||
if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (4))) {
|
if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (6))) {
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -784,12 +983,37 @@ NvmExpressDriverBindingStart (
|
||||||
Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;
|
Private->Passthru.BuildDevicePath = NvmExpressBuildDevicePath;
|
||||||
Private->Passthru.GetNamespace = NvmExpressGetNamespace;
|
Private->Passthru.GetNamespace = NvmExpressGetNamespace;
|
||||||
CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));
|
CopyMem (&Private->PassThruMode, &gEfiNvmExpressPassThruMode, sizeof (EFI_NVM_EXPRESS_PASS_THRU_MODE));
|
||||||
|
InitializeListHead (&Private->AsyncPassThruQueue);
|
||||||
|
InitializeListHead (&Private->UnsubmittedSubtasks);
|
||||||
|
|
||||||
Status = NvmeControllerInit (Private);
|
Status = NvmeControllerInit (Private);
|
||||||
if (EFI_ERROR(Status)) {
|
if (EFI_ERROR(Status)) {
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start the asynchronous I/O completion monitor
|
||||||
|
//
|
||||||
|
Status = gBS->CreateEvent (
|
||||||
|
EVT_TIMER | EVT_NOTIFY_SIGNAL,
|
||||||
|
TPL_NOTIFY,
|
||||||
|
ProcessAsyncTaskList,
|
||||||
|
Private,
|
||||||
|
&Private->TimerEvent
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = gBS->SetTimer (
|
||||||
|
Private->TimerEvent,
|
||||||
|
TimerPeriodic,
|
||||||
|
NVME_HC_ASYNC_TIMER
|
||||||
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
goto Exit;
|
||||||
|
}
|
||||||
|
|
||||||
Status = gBS->InstallMultipleProtocolInterfaces (
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
||||||
&Controller,
|
&Controller,
|
||||||
&gEfiNvmExpressPassThruProtocolGuid,
|
&gEfiNvmExpressPassThruProtocolGuid,
|
||||||
|
@ -850,7 +1074,7 @@ Exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Private != NULL) && (Private->Buffer != NULL)) {
|
if ((Private != NULL) && (Private->Buffer != NULL)) {
|
||||||
PciIo->FreeBuffer (PciIo, 4, Private->Buffer);
|
PciIo->FreeBuffer (PciIo, 6, Private->Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Private != NULL) && (Private->ControllerData != NULL)) {
|
if ((Private != NULL) && (Private->ControllerData != NULL)) {
|
||||||
|
@ -858,6 +1082,10 @@ Exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Private != NULL) {
|
if (Private != NULL) {
|
||||||
|
if (Private->TimerEvent != NULL) {
|
||||||
|
gBS->CloseEvent (Private->TimerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
FreePool (Private);
|
FreePool (Private);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,6 +1149,8 @@ NvmExpressDriverBindingStop (
|
||||||
UINTN Index;
|
UINTN Index;
|
||||||
NVME_CONTROLLER_PRIVATE_DATA *Private;
|
NVME_CONTROLLER_PRIVATE_DATA *Private;
|
||||||
EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;
|
EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *PassThru;
|
||||||
|
BOOLEAN IsEmpty;
|
||||||
|
EFI_TPL OldTpl;
|
||||||
|
|
||||||
if (NumberOfChildren == 0) {
|
if (NumberOfChildren == 0) {
|
||||||
Status = gBS->OpenProtocol (
|
Status = gBS->OpenProtocol (
|
||||||
|
@ -934,6 +1164,23 @@ NvmExpressDriverBindingStop (
|
||||||
|
|
||||||
if (!EFI_ERROR (Status)) {
|
if (!EFI_ERROR (Status)) {
|
||||||
Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);
|
Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (PassThru);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait for the asynchronous PassThru queue to become empty.
|
||||||
|
//
|
||||||
|
while (TRUE) {
|
||||||
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
||||||
|
IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&
|
||||||
|
IsListEmpty (&Private->UnsubmittedSubtasks);
|
||||||
|
gBS->RestoreTPL (OldTpl);
|
||||||
|
|
||||||
|
if (IsEmpty) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gBS->Stall (100);
|
||||||
|
}
|
||||||
|
|
||||||
gBS->UninstallMultipleProtocolInterfaces (
|
gBS->UninstallMultipleProtocolInterfaces (
|
||||||
Controller,
|
Controller,
|
||||||
&gEfiNvmExpressPassThruProtocolGuid,
|
&gEfiNvmExpressPassThruProtocolGuid,
|
||||||
|
@ -941,12 +1188,16 @@ NvmExpressDriverBindingStop (
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (Private->TimerEvent != NULL) {
|
||||||
|
gBS->CloseEvent (Private->TimerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
if (Private->Mapping != NULL) {
|
if (Private->Mapping != NULL) {
|
||||||
Private->PciIo->Unmap (Private->PciIo, Private->Mapping);
|
Private->PciIo->Unmap (Private->PciIo, Private->Mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Private->Buffer != NULL) {
|
if (Private->Buffer != NULL) {
|
||||||
Private->PciIo->FreeBuffer (Private->PciIo, 4, Private->Buffer);
|
Private->PciIo->FreeBuffer (Private->PciIo, 6, Private->Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
FreePool (Private->ControllerData);
|
FreePool (Private->ControllerData);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <Protocol/PciIo.h>
|
#include <Protocol/PciIo.h>
|
||||||
#include <Protocol/NvmExpressPassthru.h>
|
#include <Protocol/NvmExpressPassthru.h>
|
||||||
#include <Protocol/BlockIo.h>
|
#include <Protocol/BlockIo.h>
|
||||||
|
#include <Protocol/BlockIo2.h>
|
||||||
#include <Protocol/DiskInfo.h>
|
#include <Protocol/DiskInfo.h>
|
||||||
#include <Protocol/DriverSupportedEfiVersion.h>
|
#include <Protocol/DriverSupportedEfiVersion.h>
|
||||||
#include <Protocol/StorageSecurityCommand.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_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_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
|
#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)
|
#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.
|
// Unique signature for private data structure.
|
||||||
//
|
//
|
||||||
|
@ -101,11 +118,13 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
|
||||||
NVME_ADMIN_CONTROLLER_DATA *ControllerData;
|
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.
|
// 1st 4kB boundary is the start of the admin submission queue.
|
||||||
// 2nd 4kB boundary is the start of the admin completion queue.
|
// 2nd 4kB boundary is the start of the admin completion queue.
|
||||||
// 3rd 4kB boundary is the start of I/O submission queue #1.
|
// 3rd 4kB boundary is the start of I/O submission queue #1.
|
||||||
// 4th 4kB boundary is the start of I/O completion 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 *Buffer;
|
||||||
UINT8 *BufferPciAddr;
|
UINT8 *BufferPciAddr;
|
||||||
|
@ -123,6 +142,7 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
|
||||||
//
|
//
|
||||||
NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES];
|
NVME_SQTDBL SqTdbl[NVME_MAX_QUEUES];
|
||||||
NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES];
|
NVME_CQHDBL CqHdbl[NVME_MAX_QUEUES];
|
||||||
|
UINT16 AsyncSqHead;
|
||||||
|
|
||||||
UINT8 Pt[NVME_MAX_QUEUES];
|
UINT8 Pt[NVME_MAX_QUEUES];
|
||||||
UINT16 Cid[NVME_MAX_QUEUES];
|
UINT16 Cid[NVME_MAX_QUEUES];
|
||||||
|
@ -133,6 +153,13 @@ struct _NVME_CONTROLLER_PRIVATE_DATA {
|
||||||
NVME_CAP Cap;
|
NVME_CAP Cap;
|
||||||
|
|
||||||
VOID *Mapping;
|
VOID *Mapping;
|
||||||
|
|
||||||
|
//
|
||||||
|
// For Non-blocking operations.
|
||||||
|
//
|
||||||
|
EFI_EVENT TimerEvent;
|
||||||
|
LIST_ENTRY AsyncPassThruQueue;
|
||||||
|
LIST_ENTRY UnsubmittedSubtasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU(a) \
|
#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_MEDIA Media;
|
||||||
EFI_BLOCK_IO_PROTOCOL BlockIo;
|
EFI_BLOCK_IO_PROTOCOL BlockIo;
|
||||||
|
EFI_BLOCK_IO2_PROTOCOL BlockIo2;
|
||||||
EFI_DISK_INFO_PROTOCOL DiskInfo;
|
EFI_DISK_INFO_PROTOCOL DiskInfo;
|
||||||
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
|
EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;
|
||||||
|
|
||||||
|
LIST_ENTRY AsyncQueue;
|
||||||
|
|
||||||
EFI_LBA NumBlocks;
|
EFI_LBA NumBlocks;
|
||||||
|
|
||||||
CHAR16 ModelName[80];
|
CHAR16 ModelName[80];
|
||||||
|
@ -188,6 +218,13 @@ struct _NVME_DEVICE_PRIVATE_DATA {
|
||||||
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
|
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) \
|
#define NVME_DEVICE_PRIVATE_DATA_FROM_DISK_INFO(a) \
|
||||||
CR (a, \
|
CR (a, \
|
||||||
NVME_DEVICE_PRIVATE_DATA, \
|
NVME_DEVICE_PRIVATE_DATA, \
|
||||||
|
@ -202,6 +239,67 @@ struct _NVME_DEVICE_PRIVATE_DATA {
|
||||||
NVME_DEVICE_PRIVATE_DATA_SIGNATURE \
|
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.
|
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
|
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
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
Header file for EFI_BLOCK_IO_PROTOCOL interface.
|
Header file for EFI_BLOCK_IO_PROTOCOL interface.
|
||||||
|
|
||||||
Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
|
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -108,6 +108,154 @@ NvmeBlockIoFlushBlocks (
|
||||||
IN EFI_BLOCK_IO_PROTOCOL *This
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Reset the block device hardware.
|
||||||
|
|
||||||
|
@param[in] This Indicates a pointer to the calling context.
|
||||||
|
@param[in] ExtendedVerification Indicates that the driver may perform a more
|
||||||
|
exhausive verfication operation of the
|
||||||
|
device during reset.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The device was reset.
|
||||||
|
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
|
||||||
|
not be reset.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
NvmeBlockIoResetEx (
|
||||||
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||||
|
IN BOOLEAN ExtendedVerification
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read BufferSize bytes from Lba into Buffer.
|
||||||
|
|
||||||
|
This function reads the requested number of blocks from the device. All the
|
||||||
|
blocks are read, or an error is returned.
|
||||||
|
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
|
||||||
|
non-blocking I/O is being used, the Event associated with this request will
|
||||||
|
not be signaled.
|
||||||
|
|
||||||
|
@param[in] This Indicates a pointer to the calling context.
|
||||||
|
@param[in] MediaId Id of the media, changes every time the media is
|
||||||
|
replaced.
|
||||||
|
@param[in] Lba The starting Logical Block Address to read from.
|
||||||
|
@param[in, out] Token A pointer to the token associated with the
|
||||||
|
transaction.
|
||||||
|
@param[in] BufferSize Size of Buffer, must be a multiple of device
|
||||||
|
block size.
|
||||||
|
@param[out] Buffer A pointer to the destination buffer for the data.
|
||||||
|
The caller is responsible for either having
|
||||||
|
implicit or explicit ownership of the buffer.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The read request was queued if Token->Event is
|
||||||
|
not NULL.The data was read correctly from the
|
||||||
|
device if the Token->Event is NULL.
|
||||||
|
@retval EFI_DEVICE_ERROR The device reported an error while performing
|
||||||
|
the read.
|
||||||
|
@retval EFI_NO_MEDIA There is no media in the device.
|
||||||
|
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
||||||
|
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
|
||||||
|
the intrinsic block size of the device.
|
||||||
|
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
|
||||||
|
valid, or the buffer is not on proper
|
||||||
|
alignment.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
|
||||||
|
lack of resources.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
NvmeBlockIoReadBlocksEx (
|
||||||
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||||
|
IN UINT32 MediaId,
|
||||||
|
IN EFI_LBA Lba,
|
||||||
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
||||||
|
IN UINTN BufferSize,
|
||||||
|
OUT VOID *Buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Write BufferSize bytes from Lba into Buffer.
|
||||||
|
|
||||||
|
This function writes the requested number of blocks to the device. All blocks
|
||||||
|
are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
|
||||||
|
EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
|
||||||
|
being used, the Event associated with this request will not be signaled.
|
||||||
|
|
||||||
|
@param[in] This Indicates a pointer to the calling context.
|
||||||
|
@param[in] MediaId The media ID that the write request is for.
|
||||||
|
@param[in] Lba The starting logical block address to be written.
|
||||||
|
The caller is responsible for writing to only
|
||||||
|
legitimate locations.
|
||||||
|
@param[in, out] Token A pointer to the token associated with the
|
||||||
|
transaction.
|
||||||
|
@param[in] BufferSize Size of Buffer, must be a multiple of device
|
||||||
|
block size.
|
||||||
|
@param[in] Buffer A pointer to the source buffer for the data.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The write request was queued if Event is not
|
||||||
|
NULL.
|
||||||
|
The data was written correctly to the device if
|
||||||
|
the Event is NULL.
|
||||||
|
@retval EFI_WRITE_PROTECTED The device can not be written to.
|
||||||
|
@retval EFI_NO_MEDIA There is no media in the device.
|
||||||
|
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current
|
||||||
|
device.
|
||||||
|
@retval EFI_DEVICE_ERROR The device reported an error while performing
|
||||||
|
the write.
|
||||||
|
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size
|
||||||
|
of the device.
|
||||||
|
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not
|
||||||
|
valid, or the buffer is not on proper
|
||||||
|
alignment.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
|
||||||
|
lack of resources.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
NvmeBlockIoWriteBlocksEx (
|
||||||
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||||
|
IN UINT32 MediaId,
|
||||||
|
IN EFI_LBA Lba,
|
||||||
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
|
||||||
|
IN UINTN BufferSize,
|
||||||
|
IN VOID *Buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Flush the Block Device.
|
||||||
|
|
||||||
|
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
|
||||||
|
is returned and non-blocking I/O is being used, the Event associated with
|
||||||
|
this request will not be signaled.
|
||||||
|
|
||||||
|
@param[in] This Indicates a pointer to the calling context.
|
||||||
|
@param[in,out] Token A pointer to the token associated with the
|
||||||
|
transaction.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The flush request was queued if Event is not
|
||||||
|
NULL.
|
||||||
|
All outstanding data was written correctly to
|
||||||
|
the device if the Event is NULL.
|
||||||
|
@retval EFI_DEVICE_ERROR The device reported an error while writting back
|
||||||
|
the data.
|
||||||
|
@retval EFI_WRITE_PROTECTED The device cannot be written to.
|
||||||
|
@retval EFI_NO_MEDIA There is no media in the device.
|
||||||
|
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
||||||
|
of resources.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
NvmeBlockIoFlushBlocksEx (
|
||||||
|
IN EFI_BLOCK_IO2_PROTOCOL *This,
|
||||||
|
IN OUT EFI_BLOCK_IO2_TOKEN *Token
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Send a security protocol command to a device that receives data and/or the result
|
Send a security protocol command to a device that receives data and/or the result
|
||||||
of one or more commands sent by SendData.
|
of one or more commands sent by SendData.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
|
# NvmExpressDxe driver is used to manage non-volatile memory subsystem which follows
|
||||||
# NVM Express specification.
|
# NVM Express specification.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
|
# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
#
|
#
|
||||||
# This program and the accompanying materials
|
# This program and the accompanying materials
|
||||||
# are licensed and made available under the terms and conditions of the BSD License
|
# are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
@ -67,6 +67,7 @@
|
||||||
gEfiDevicePathProtocolGuid
|
gEfiDevicePathProtocolGuid
|
||||||
gEfiNvmExpressPassThruProtocolGuid ## BY_START
|
gEfiNvmExpressPassThruProtocolGuid ## BY_START
|
||||||
gEfiBlockIoProtocolGuid ## BY_START
|
gEfiBlockIoProtocolGuid ## BY_START
|
||||||
|
gEfiBlockIo2ProtocolGuid ## BY_START
|
||||||
gEfiDiskInfoProtocolGuid ## BY_START
|
gEfiDiskInfoProtocolGuid ## BY_START
|
||||||
gEfiStorageSecurityCommandProtocolGuid ## BY_START
|
gEfiStorageSecurityCommandProtocolGuid ## BY_START
|
||||||
gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES
|
gEfiDriverSupportedEfiVersionProtocolGuid ## PRODUCES
|
||||||
|
|
|
@ -682,33 +682,39 @@ NvmeCreateIoCompletionQueue (
|
||||||
EFI_NVM_EXPRESS_COMPLETION Completion;
|
EFI_NVM_EXPRESS_COMPLETION Completion;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
NVME_ADMIN_CRIOCQ CrIoCq;
|
NVME_ADMIN_CRIOCQ CrIoCq;
|
||||||
|
UINT32 Index;
|
||||||
|
|
||||||
ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
|
for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
|
||||||
ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
|
ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
|
||||||
ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
|
ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
|
||||||
ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
|
ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
|
||||||
|
ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
|
||||||
|
|
||||||
CommandPacket.NvmeCmd = &Command;
|
CommandPacket.NvmeCmd = &Command;
|
||||||
CommandPacket.NvmeCompletion = &Completion;
|
CommandPacket.NvmeCompletion = &Completion;
|
||||||
|
|
||||||
Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
|
Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_CMD;
|
||||||
CommandPacket.TransferBuffer = Private->CqBufferPciAddr[1];
|
CommandPacket.TransferBuffer = Private->CqBufferPciAddr[Index];
|
||||||
CommandPacket.TransferLength = EFI_PAGE_SIZE;
|
CommandPacket.TransferLength = EFI_PAGE_SIZE;
|
||||||
CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
|
CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
|
||||||
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
|
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
|
||||||
|
|
||||||
CrIoCq.Qid = NVME_IO_QUEUE;
|
CrIoCq.Qid = Index;
|
||||||
CrIoCq.Qsize = NVME_CCQ_SIZE;
|
CrIoCq.Qsize = (Index == 1) ? NVME_CCQ_SIZE : NVME_ASYNC_CCQ_SIZE;
|
||||||
CrIoCq.Pc = 1;
|
CrIoCq.Pc = 1;
|
||||||
CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
|
CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
|
||||||
CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
|
CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
|
||||||
|
|
||||||
Status = Private->Passthru.PassThru (
|
Status = Private->Passthru.PassThru (
|
||||||
&Private->Passthru,
|
&Private->Passthru,
|
||||||
0,
|
0,
|
||||||
&CommandPacket,
|
&CommandPacket,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -732,35 +738,41 @@ NvmeCreateIoSubmissionQueue (
|
||||||
EFI_NVM_EXPRESS_COMPLETION Completion;
|
EFI_NVM_EXPRESS_COMPLETION Completion;
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
NVME_ADMIN_CRIOSQ CrIoSq;
|
NVME_ADMIN_CRIOSQ CrIoSq;
|
||||||
|
UINT32 Index;
|
||||||
|
|
||||||
ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
|
for (Index = 1; Index < NVME_MAX_QUEUES; Index++) {
|
||||||
ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
|
ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
|
||||||
ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
|
ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
|
||||||
ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
|
ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
|
||||||
|
ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
|
||||||
|
|
||||||
CommandPacket.NvmeCmd = &Command;
|
CommandPacket.NvmeCmd = &Command;
|
||||||
CommandPacket.NvmeCompletion = &Completion;
|
CommandPacket.NvmeCompletion = &Completion;
|
||||||
|
|
||||||
Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
|
Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_CMD;
|
||||||
CommandPacket.TransferBuffer = Private->SqBufferPciAddr[1];
|
CommandPacket.TransferBuffer = Private->SqBufferPciAddr[Index];
|
||||||
CommandPacket.TransferLength = EFI_PAGE_SIZE;
|
CommandPacket.TransferLength = EFI_PAGE_SIZE;
|
||||||
CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
|
CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
|
||||||
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
|
CommandPacket.QueueType = NVME_ADMIN_QUEUE;
|
||||||
|
|
||||||
CrIoSq.Qid = NVME_IO_QUEUE;
|
CrIoSq.Qid = Index;
|
||||||
CrIoSq.Qsize = NVME_CSQ_SIZE;
|
CrIoSq.Qsize = (Index == 1) ? NVME_CSQ_SIZE : NVME_ASYNC_CSQ_SIZE;
|
||||||
CrIoSq.Pc = 1;
|
CrIoSq.Pc = 1;
|
||||||
CrIoSq.Cqid = NVME_IO_QUEUE;
|
CrIoSq.Cqid = Index;
|
||||||
CrIoSq.Qprio = 0;
|
CrIoSq.Qprio = 0;
|
||||||
CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
|
CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
|
||||||
CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
|
CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
|
||||||
|
|
||||||
Status = Private->Passthru.PassThru (
|
Status = Private->Passthru.PassThru (
|
||||||
&Private->Passthru,
|
&Private->Passthru,
|
||||||
0,
|
0,
|
||||||
&CommandPacket,
|
&CommandPacket,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
@ -844,12 +856,17 @@ NvmeControllerInit (
|
||||||
|
|
||||||
Private->Cid[0] = 0;
|
Private->Cid[0] = 0;
|
||||||
Private->Cid[1] = 0;
|
Private->Cid[1] = 0;
|
||||||
|
Private->Cid[2] = 0;
|
||||||
Private->Pt[0] = 0;
|
Private->Pt[0] = 0;
|
||||||
Private->Pt[1] = 0;
|
Private->Pt[1] = 0;
|
||||||
|
Private->Pt[2] = 0;
|
||||||
Private->SqTdbl[0].Sqt = 0;
|
Private->SqTdbl[0].Sqt = 0;
|
||||||
Private->SqTdbl[1].Sqt = 0;
|
Private->SqTdbl[1].Sqt = 0;
|
||||||
|
Private->SqTdbl[2].Sqt = 0;
|
||||||
Private->CqHdbl[0].Cqh = 0;
|
Private->CqHdbl[0].Cqh = 0;
|
||||||
Private->CqHdbl[1].Cqh = 0;
|
Private->CqHdbl[1].Cqh = 0;
|
||||||
|
Private->CqHdbl[2].Cqh = 0;
|
||||||
|
Private->AsyncSqHead = 0;
|
||||||
|
|
||||||
Status = NvmeDisableController (Private);
|
Status = NvmeDisableController (Private);
|
||||||
|
|
||||||
|
@ -878,7 +895,7 @@ NvmeControllerInit (
|
||||||
//
|
//
|
||||||
// Address of I/O submission & completion queue.
|
// Address of I/O submission & completion queue.
|
||||||
//
|
//
|
||||||
ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (4));
|
ZeroMem (Private->Buffer, EFI_PAGES_TO_SIZE (6));
|
||||||
Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);
|
Private->SqBuffer[0] = (NVME_SQ *)(UINTN)(Private->Buffer);
|
||||||
Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);
|
Private->SqBufferPciAddr[0] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr);
|
||||||
Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);
|
Private->CqBuffer[0] = (NVME_CQ *)(UINTN)(Private->Buffer + 1 * EFI_PAGE_SIZE);
|
||||||
|
@ -887,14 +904,20 @@ NvmeControllerInit (
|
||||||
Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);
|
Private->SqBufferPciAddr[1] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 2 * EFI_PAGE_SIZE);
|
||||||
Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);
|
Private->CqBuffer[1] = (NVME_CQ *)(UINTN)(Private->Buffer + 3 * EFI_PAGE_SIZE);
|
||||||
Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);
|
Private->CqBufferPciAddr[1] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 3 * EFI_PAGE_SIZE);
|
||||||
|
Private->SqBuffer[2] = (NVME_SQ *)(UINTN)(Private->Buffer + 4 * EFI_PAGE_SIZE);
|
||||||
|
Private->SqBufferPciAddr[2] = (NVME_SQ *)(UINTN)(Private->BufferPciAddr + 4 * EFI_PAGE_SIZE);
|
||||||
|
Private->CqBuffer[2] = (NVME_CQ *)(UINTN)(Private->Buffer + 5 * EFI_PAGE_SIZE);
|
||||||
|
Private->CqBufferPciAddr[2] = (NVME_CQ *)(UINTN)(Private->BufferPciAddr + 5 * EFI_PAGE_SIZE);
|
||||||
|
|
||||||
DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));
|
DEBUG ((EFI_D_INFO, "Private->Buffer = [%016X]\n", (UINT64)(UINTN)Private->Buffer));
|
||||||
DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
|
DEBUG ((EFI_D_INFO, "Admin Submission Queue size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
|
||||||
DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
|
DEBUG ((EFI_D_INFO, "Admin Completion Queue size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
|
||||||
DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));
|
DEBUG ((EFI_D_INFO, "Admin Submission Queue (SqBuffer[0]) = [%016X]\n", Private->SqBuffer[0]));
|
||||||
DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));
|
DEBUG ((EFI_D_INFO, "Admin Completion Queue (CqBuffer[0]) = [%016X]\n", Private->CqBuffer[0]));
|
||||||
DEBUG ((EFI_D_INFO, "I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));
|
DEBUG ((EFI_D_INFO, "Sync I/O Submission Queue (SqBuffer[1]) = [%016X]\n", Private->SqBuffer[1]));
|
||||||
DEBUG ((EFI_D_INFO, "I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));
|
DEBUG ((EFI_D_INFO, "Sync I/O Completion Queue (CqBuffer[1]) = [%016X]\n", Private->CqBuffer[1]));
|
||||||
|
DEBUG ((EFI_D_INFO, "Async I/O Submission Queue (SqBuffer[2]) = [%016X]\n", Private->SqBuffer[2]));
|
||||||
|
DEBUG ((EFI_D_INFO, "Async I/O Completion Queue (CqBuffer[2]) = [%016X]\n", Private->CqBuffer[2]));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Program admin queue attributes.
|
// Program admin queue attributes.
|
||||||
|
@ -971,7 +994,8 @@ NvmeControllerInit (
|
||||||
DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));
|
DEBUG ((EFI_D_INFO, " NN : 0x%x\n", Private->ControllerData->Nn));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create one I/O completion queue.
|
// Create two I/O completion queues.
|
||||||
|
// One for blocking I/O, one for non-blocking I/O.
|
||||||
//
|
//
|
||||||
Status = NvmeCreateIoCompletionQueue (Private);
|
Status = NvmeCreateIoCompletionQueue (Private);
|
||||||
if (EFI_ERROR(Status)) {
|
if (EFI_ERROR(Status)) {
|
||||||
|
@ -979,7 +1003,8 @@ NvmeControllerInit (
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create one I/O Submission queue.
|
// Create two I/O Submission queues.
|
||||||
|
// One for blocking I/O, one for non-blocking I/O.
|
||||||
//
|
//
|
||||||
Status = NvmeCreateIoSubmissionQueue (Private);
|
Status = NvmeCreateIoSubmissionQueue (Private);
|
||||||
if (EFI_ERROR(Status)) {
|
if (EFI_ERROR(Status)) {
|
||||||
|
|
|
@ -362,7 +362,7 @@ NvmExpressPassThru (
|
||||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||||
NVME_SQ *Sq;
|
NVME_SQ *Sq;
|
||||||
NVME_CQ *Cq;
|
NVME_CQ *Cq;
|
||||||
UINT8 QueueType;
|
UINT16 QueueId;
|
||||||
UINT32 Bytes;
|
UINT32 Bytes;
|
||||||
UINT16 Offset;
|
UINT16 Offset;
|
||||||
EFI_EVENT TimerEvent;
|
EFI_EVENT TimerEvent;
|
||||||
|
@ -376,6 +376,8 @@ NvmExpressPassThru (
|
||||||
VOID *PrpListHost;
|
VOID *PrpListHost;
|
||||||
UINTN PrpListNo;
|
UINTN PrpListNo;
|
||||||
UINT32 Data;
|
UINT32 Data;
|
||||||
|
NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;
|
||||||
|
EFI_TPL OldTpl;
|
||||||
|
|
||||||
//
|
//
|
||||||
// check the data fields in Packet parameter.
|
// check the data fields in Packet parameter.
|
||||||
|
@ -403,9 +405,25 @@ NvmExpressPassThru (
|
||||||
TimerEvent = NULL;
|
TimerEvent = NULL;
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
QueueType = Packet->QueueType;
|
if (Packet->QueueType == NVME_ADMIN_QUEUE) {
|
||||||
Sq = Private->SqBuffer[QueueType] + Private->SqTdbl[QueueType].Sqt;
|
QueueId = 0;
|
||||||
Cq = Private->CqBuffer[QueueType] + Private->CqHdbl[QueueType].Cqh;
|
} else {
|
||||||
|
if (Event == NULL) {
|
||||||
|
QueueId = 1;
|
||||||
|
} else {
|
||||||
|
QueueId = 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Submission queue full check.
|
||||||
|
//
|
||||||
|
if ((Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1) ==
|
||||||
|
Private->AsyncSqHead) {
|
||||||
|
return EFI_NOT_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;
|
||||||
|
Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;
|
||||||
|
|
||||||
if (Packet->NvmeCmd->Nsid != NamespaceId) {
|
if (Packet->NvmeCmd->Nsid != NamespaceId) {
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
|
@ -414,7 +432,7 @@ NvmExpressPassThru (
|
||||||
ZeroMem (Sq, sizeof (NVME_SQ));
|
ZeroMem (Sq, sizeof (NVME_SQ));
|
||||||
Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
|
Sq->Opc = (UINT8)Packet->NvmeCmd->Cdw0.Opcode;
|
||||||
Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
|
Sq->Fuse = (UINT8)Packet->NvmeCmd->Cdw0.FusedOperation;
|
||||||
Sq->Cid = Private->Cid[QueueType]++;
|
Sq->Cid = Private->Cid[QueueId]++;
|
||||||
Sq->Nsid = Packet->NvmeCmd->Nsid;
|
Sq->Nsid = Packet->NvmeCmd->Nsid;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -528,17 +546,45 @@ NvmExpressPassThru (
|
||||||
//
|
//
|
||||||
// Ring the submission queue doorbell.
|
// Ring the submission queue doorbell.
|
||||||
//
|
//
|
||||||
Private->SqTdbl[QueueType].Sqt ^= 1;
|
if (Event != NULL) {
|
||||||
Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueType]);
|
Private->SqTdbl[QueueId].Sqt =
|
||||||
|
(Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1);
|
||||||
|
} else {
|
||||||
|
Private->SqTdbl[QueueId].Sqt ^= 1;
|
||||||
|
}
|
||||||
|
Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueId]);
|
||||||
PciIo->Mem.Write (
|
PciIo->Mem.Write (
|
||||||
PciIo,
|
PciIo,
|
||||||
EfiPciIoWidthUint32,
|
EfiPciIoWidthUint32,
|
||||||
NVME_BAR,
|
NVME_BAR,
|
||||||
NVME_SQTDBL_OFFSET(QueueType, Private->Cap.Dstrd),
|
NVME_SQTDBL_OFFSET(QueueId, Private->Cap.Dstrd),
|
||||||
1,
|
1,
|
||||||
&Data
|
&Data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// For non-blocking requests, return directly if the command is placed
|
||||||
|
// in the submission queue.
|
||||||
|
//
|
||||||
|
if (Event != NULL) {
|
||||||
|
AsyncRequest = AllocateZeroPool (sizeof (NVME_PASS_THRU_ASYNC_REQ));
|
||||||
|
if (AsyncRequest == NULL) {
|
||||||
|
Status = EFI_DEVICE_ERROR;
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;
|
||||||
|
AsyncRequest->Packet = Packet;
|
||||||
|
AsyncRequest->CommandId = Sq->Cid;
|
||||||
|
AsyncRequest->CallerEvent = Event;
|
||||||
|
|
||||||
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
||||||
|
InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link);
|
||||||
|
gBS->RestoreTPL (OldTpl);
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
Status = gBS->CreateEvent (
|
Status = gBS->CreateEvent (
|
||||||
EVT_TIMER,
|
EVT_TIMER,
|
||||||
TPL_CALLBACK,
|
TPL_CALLBACK,
|
||||||
|
@ -561,7 +607,7 @@ NvmExpressPassThru (
|
||||||
//
|
//
|
||||||
Status = EFI_TIMEOUT;
|
Status = EFI_TIMEOUT;
|
||||||
while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {
|
while (EFI_ERROR (gBS->CheckEvent (TimerEvent))) {
|
||||||
if (Cq->Pt != Private->Pt[QueueType]) {
|
if (Cq->Pt != Private->Pt[QueueId]) {
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -589,16 +635,16 @@ NvmExpressPassThru (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Private->CqHdbl[QueueType].Cqh ^= 1) == 0) {
|
if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {
|
||||||
Private->Pt[QueueType] ^= 1;
|
Private->Pt[QueueId] ^= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueType]);
|
Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);
|
||||||
PciIo->Mem.Write (
|
PciIo->Mem.Write (
|
||||||
PciIo,
|
PciIo,
|
||||||
EfiPciIoWidthUint32,
|
EfiPciIoWidthUint32,
|
||||||
NVME_BAR,
|
NVME_BAR,
|
||||||
NVME_CQHDBL_OFFSET(QueueType, Private->Cap.Dstrd),
|
NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),
|
||||||
1,
|
1,
|
||||||
&Data
|
&Data
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue