NVME_CONTROLLER_PRIVATE_DATA *Private;\r
UINT32 MaxTransferBlocks;\r
UINTN OrginalBlocks;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Wait for the device's asynchronous I/O queue to become empty.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (IsEmpty) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (100);\r
+ }\r
\r
Status = EFI_SUCCESS;\r
Private = Device->Controller;\r
NVME_CONTROLLER_PRIVATE_DATA *Private;\r
UINT32 MaxTransferBlocks;\r
UINTN OrginalBlocks;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Wait for the device's asynchronous I/O queue to become empty.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (IsEmpty) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (100);\r
+ }\r
\r
Status = EFI_SUCCESS;\r
Private = Device->Controller;\r
return Status;\r
}\r
\r
+/**\r
+ Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+ @param[in] Event The Event this notify function registered to.\r
+ @param[in] Context Pointer to the context data registered to the\r
+ Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ NVME_BLKIO2_SUBTASK *Subtask;\r
+ NVME_BLKIO2_REQUEST *Request;\r
+ NVME_CQ *Completion;\r
+ EFI_BLOCK_IO2_TOKEN *Token;\r
+\r
+ gBS->CloseEvent (Event);\r
+\r
+ Subtask = (NVME_BLKIO2_SUBTASK *) Context;\r
+ Completion = (NVME_CQ *) Subtask->CommandPacket->NvmeCompletion;\r
+ Request = Subtask->BlockIo2Request;\r
+ Token = Request->Token;\r
+\r
+ if (Token->TransactionStatus == EFI_SUCCESS) {\r
+ //\r
+ // If previous subtask already fails, do not check the result of\r
+ // subsequent subtasks.\r
+ //\r
+ if ((Completion->Sct != 0) || (Completion->Sc != 0)) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+\r
+ //\r
+ // Dump completion entry status for debugging.\r
+ //\r
+ DEBUG_CODE_BEGIN();\r
+ NvmeDumpStatus (Completion);\r
+ DEBUG_CODE_END();\r
+ }\r
+ }\r
+\r
+ //\r
+ // Remove the subtask from the BlockIo2 subtasks list.\r
+ //\r
+ RemoveEntryList (&Subtask->Link);\r
+\r
+ if (IsListEmpty (&Request->SubtasksQueue) && Request->LastSubtaskSubmitted) {\r
+ //\r
+ // Remove the BlockIo2 request from the device asynchronous queue.\r
+ //\r
+ RemoveEntryList (&Request->Link);\r
+ FreePool (Request);\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ FreePool (Subtask->CommandPacket->NvmeCmd);\r
+ FreePool (Subtask->CommandPacket->NvmeCompletion);\r
+ FreePool (Subtask->CommandPacket);\r
+ FreePool (Subtask);\r
+}\r
+\r
+/**\r
+ Read some sectors from the device in an asynchronous manner.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data\r
+ structure.\r
+ @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.\r
+ @param Buffer The buffer used to store the data read from the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be read.\r
+ @param IsLast The last subtask of an asynchronous read request.\r
+\r
+ @retval EFI_SUCCESS Asynchronous read request has been queued.\r
+ @retval Others Fail to send the asynchronous request.\r
+\r
+**/\r
+EFI_STATUS\r
+AsyncReadSectors (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN NVME_BLKIO2_REQUEST *Request,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks,\r
+ IN BOOLEAN IsLast\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ UINT32 Bytes;\r
+ NVME_BLKIO2_SUBTASK *Subtask;\r
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;\r
+ EFI_NVM_EXPRESS_COMMAND *Command;\r
+ EFI_NVM_EXPRESS_COMPLETION *Completion;\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ EFI_TPL OldTpl;\r
+\r
+ Private = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+ CommandPacket = NULL;\r
+ Command = NULL;\r
+ Completion = NULL;\r
+\r
+ Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));\r
+ if (Subtask == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;\r
+ Subtask->IsLast = IsLast;\r
+ Subtask->NamespaceId = Device->NamespaceId;\r
+ Subtask->BlockIo2Request = Request;\r
+\r
+ CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ if (CommandPacket == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ } else {\r
+ Subtask->CommandPacket = CommandPacket;\r
+ }\r
+\r
+ Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));\r
+ if (Command == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));\r
+ if (Completion == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ AsyncIoCallback,\r
+ Subtask,\r
+ &Subtask->Event\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ CommandPacket->NvmeCmd = Command;\r
+ CommandPacket->NvmeCompletion = Completion;\r
+\r
+ CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;\r
+ CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;\r
+ CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;\r
+\r
+ CommandPacket->TransferLength = Bytes;\r
+ CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket->QueueType = NVME_IO_QUEUE;\r
+\r
+ CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);\r
+ CommandPacket->NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;\r
+\r
+ CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);\r
+ Request->UnsubmittedSubtaskNum++;\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ //\r
+ // Resource cleanup if asynchronous read request has not been queued.\r
+ //\r
+ if (Completion != NULL) {\r
+ FreePool (Completion);\r
+ }\r
+\r
+ if (Command != NULL) {\r
+ FreePool (Command);\r
+ }\r
+\r
+ if (CommandPacket != NULL) {\r
+ FreePool (CommandPacket);\r
+ }\r
+\r
+ if (Subtask != NULL) {\r
+ if (Subtask->Event != NULL) {\r
+ gBS->CloseEvent (Subtask->Event);\r
+ }\r
+\r
+ FreePool (Subtask);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write some sectors from the device in an asynchronous manner.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data\r
+ structure.\r
+ @param Request The pointer to the NVME_BLKIO2_REQUEST data structure.\r
+ @param Buffer The buffer used to store the data written to the\r
+ device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be written.\r
+ @param IsLast The last subtask of an asynchronous write request.\r
+\r
+ @retval EFI_SUCCESS Asynchronous write request has been queued.\r
+ @retval Others Fail to send the asynchronous request.\r
+\r
+**/\r
+EFI_STATUS\r
+AsyncWriteSectors (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN NVME_BLKIO2_REQUEST *Request,\r
+ IN UINT64 Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINT32 Blocks,\r
+ IN BOOLEAN IsLast\r
+ )\r
+{\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ UINT32 Bytes;\r
+ NVME_BLKIO2_SUBTASK *Subtask;\r
+ EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *CommandPacket;\r
+ EFI_NVM_EXPRESS_COMMAND *Command;\r
+ EFI_NVM_EXPRESS_COMPLETION *Completion;\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ EFI_TPL OldTpl;\r
+\r
+ Private = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ Bytes = Blocks * BlockSize;\r
+ CommandPacket = NULL;\r
+ Command = NULL;\r
+ Completion = NULL;\r
+\r
+ Subtask = AllocateZeroPool (sizeof (NVME_BLKIO2_SUBTASK));\r
+ if (Subtask == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Subtask->Signature = NVME_BLKIO2_SUBTASK_SIGNATURE;\r
+ Subtask->IsLast = IsLast;\r
+ Subtask->NamespaceId = Device->NamespaceId;\r
+ Subtask->BlockIo2Request = Request;\r
+\r
+ CommandPacket = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));\r
+ if (CommandPacket == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ } else {\r
+ Subtask->CommandPacket = CommandPacket;\r
+ }\r
+\r
+ Command = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMMAND));\r
+ if (Command == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Completion = AllocateZeroPool (sizeof (EFI_NVM_EXPRESS_COMPLETION));\r
+ if (Completion == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ AsyncIoCallback,\r
+ Subtask,\r
+ &Subtask->Event\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ CommandPacket->NvmeCmd = Command;\r
+ CommandPacket->NvmeCompletion = Completion;\r
+\r
+ CommandPacket->NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;\r
+ CommandPacket->NvmeCmd->Nsid = Device->NamespaceId;\r
+ CommandPacket->TransferBuffer = (VOID *)(UINTN)Buffer;\r
+\r
+ CommandPacket->TransferLength = Bytes;\r
+ CommandPacket->CommandTimeout = NVME_GENERIC_TIMEOUT;\r
+ CommandPacket->QueueType = NVME_IO_QUEUE;\r
+\r
+ CommandPacket->NvmeCmd->Cdw10 = (UINT32)Lba;\r
+ CommandPacket->NvmeCmd->Cdw11 = (UINT32)RShiftU64(Lba, 32);\r
+ //\r
+ // Set Force Unit Access bit (bit 30) to use write-through behaviour\r
+ //\r
+ CommandPacket->NvmeCmd->Cdw12 = ((Blocks - 1) & 0xFFFF) | BIT30;\r
+\r
+ CommandPacket->NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Private->UnsubmittedSubtasks, &Subtask->Link);\r
+ Request->UnsubmittedSubtaskNum++;\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ //\r
+ // Resource cleanup if asynchronous read request has not been queued.\r
+ //\r
+ if (Completion != NULL) {\r
+ FreePool (Completion);\r
+ }\r
+\r
+ if (Command != NULL) {\r
+ FreePool (Command);\r
+ }\r
+\r
+ if (CommandPacket != NULL) {\r
+ FreePool (CommandPacket);\r
+ }\r
+\r
+ if (Subtask != NULL) {\r
+ if (Subtask->Event != NULL) {\r
+ gBS->CloseEvent (Subtask->Event);\r
+ }\r
+\r
+ FreePool (Subtask);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read some blocks from the device in an asynchronous manner.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data\r
+ structure.\r
+ @param Buffer The buffer used to store the data read from the device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be read.\r
+ @param Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS Data are read from the device.\r
+ @retval Others Fail to read all the data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeAsyncRead (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ OUT VOID *Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_BLKIO2_REQUEST *BlkIo2Req;\r
+ UINT32 MaxTransferBlocks;\r
+ UINTN OrginalBlocks;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Private = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ OrginalBlocks = Blocks;\r
+ BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));\r
+ if (BlkIo2Req == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;\r
+ BlkIo2Req->Token = Token;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ InitializeListHead (&BlkIo2Req->SubtasksQueue);\r
+\r
+ if (Private->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = AsyncReadSectors (\r
+ Device,\r
+ BlkIo2Req, (UINT64)(UINTN)Buffer,\r
+ Lba,\r
+ MaxTransferBlocks,\r
+ FALSE\r
+ );\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = AsyncReadSectors (\r
+ Device,\r
+ BlkIo2Req,\r
+ (UINT64)(UINTN)Buffer,\r
+ Lba,\r
+ (UINT32)Blocks,\r
+ TRUE\r
+ );\r
+\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&\r
+ (BlkIo2Req->UnsubmittedSubtaskNum == 0);\r
+\r
+ if (IsEmpty) {\r
+ //\r
+ // Remove the BlockIo2 request from the device asynchronous queue.\r
+ //\r
+ RemoveEntryList (&BlkIo2Req->Link);\r
+ FreePool (BlkIo2Req);\r
+ Status = EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // There are previous BlockIo2 subtasks still running, EFI_SUCCESS\r
+ // should be returned to make sure that the caller does not free\r
+ // resources still using by these requests.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ BlkIo2Req->LastSubtaskSubmitted = TRUE;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "\r
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,\r
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write some blocks from the device in an asynchronous manner.\r
+\r
+ @param Device The pointer to the NVME_DEVICE_PRIVATE_DATA data\r
+ structure.\r
+ @param Buffer The buffer used to store the data written to the\r
+ device.\r
+ @param Lba The start block number.\r
+ @param Blocks Total block number to be written.\r
+ @param Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS Data are written to the device.\r
+ @retval Others Fail to write all the data.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeAsyncWrite (\r
+ IN NVME_DEVICE_PRIVATE_DATA *Device,\r
+ IN VOID *Buffer,\r
+ IN UINT64 Lba,\r
+ IN UINTN Blocks,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_BLKIO2_REQUEST *BlkIo2Req;\r
+ UINT32 MaxTransferBlocks;\r
+ UINTN OrginalBlocks;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ Status = EFI_SUCCESS;\r
+ Private = Device->Controller;\r
+ BlockSize = Device->Media.BlockSize;\r
+ OrginalBlocks = Blocks;\r
+ BlkIo2Req = AllocateZeroPool (sizeof (NVME_BLKIO2_REQUEST));\r
+ if (BlkIo2Req == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ BlkIo2Req->Signature = NVME_BLKIO2_REQUEST_SIGNATURE;\r
+ BlkIo2Req->Token = Token;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ InsertTailList (&Device->AsyncQueue, &BlkIo2Req->Link);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ InitializeListHead (&BlkIo2Req->SubtasksQueue);\r
+\r
+ if (Private->ControllerData->Mdts != 0) {\r
+ MaxTransferBlocks = (1 << (Private->ControllerData->Mdts)) * (1 << (Private->Cap.Mpsmin + 12)) / BlockSize;\r
+ } else {\r
+ MaxTransferBlocks = 1024;\r
+ }\r
+\r
+ while (Blocks > 0) {\r
+ if (Blocks > MaxTransferBlocks) {\r
+ Status = AsyncWriteSectors (\r
+ Device,\r
+ BlkIo2Req,\r
+ (UINT64)(UINTN)Buffer,\r
+ Lba,\r
+ MaxTransferBlocks,\r
+ FALSE\r
+ );\r
+\r
+ Blocks -= MaxTransferBlocks;\r
+ Buffer = (VOID *)(UINTN)((UINT64)(UINTN)Buffer + MaxTransferBlocks * BlockSize);\r
+ Lba += MaxTransferBlocks;\r
+ } else {\r
+ Status = AsyncWriteSectors (\r
+ Device,\r
+ BlkIo2Req,\r
+ (UINT64)(UINTN)Buffer,\r
+ Lba,\r
+ (UINT32)Blocks,\r
+ TRUE\r
+ );\r
+\r
+ Blocks = 0;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&BlkIo2Req->SubtasksQueue) &&\r
+ (BlkIo2Req->UnsubmittedSubtaskNum == 0);\r
+\r
+ if (IsEmpty) {\r
+ //\r
+ // Remove the BlockIo2 request from the device asynchronous queue.\r
+ //\r
+ RemoveEntryList (&BlkIo2Req->Link);\r
+ FreePool (BlkIo2Req);\r
+ Status = EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // There are previous BlockIo2 subtasks still running, EFI_SUCCESS\r
+ // should be returned to make sure that the caller does not free\r
+ // resources still using by these requests.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ BlkIo2Req->LastSubtaskSubmitted = TRUE;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ DEBUG ((EFI_D_VERBOSE, "%a: Lba = 0x%08Lx, Original = 0x%08Lx, "\r
+ "Remaining = 0x%08Lx, BlockSize = 0x%x, Status = %r\n", __FUNCTION__, Lba,\r
+ (UINT64)OrginalBlocks, (UINT64)Blocks, BlockSize, Status));\r
+\r
+ return Status;\r
+}\r
\r
/**\r
Reset the Block Device.\r
return Status;\r
}\r
\r
+/**\r
+ Reset the block device hardware.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] ExtendedVerification Indicates that the driver may perform a more\r
+ exhausive verfication operation of the\r
+ device during reset.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);\r
+ Private = Device->Controller;\r
+\r
+ //\r
+ // Wait for the asynchronous PassThru queue to become empty.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&Private->AsyncPassThruQueue) &&\r
+ IsListEmpty (&Private->UnsubmittedSubtasks);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (IsEmpty) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (100);\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Status = NvmeControllerInit (Private);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read BufferSize bytes from Lba into Buffer.\r
+\r
+ This function reads the requested number of blocks from the device. All the\r
+ blocks are read, or an error is returned.\r
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r
+ non-blocking I/O is being used, the Event associated with this request will\r
+ not be signaled.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId Id of the media, changes every time the media is\r
+ replaced.\r
+ @param[in] Lba The starting Logical Block Address to read from.\r
+ @param[in, out] Token A pointer to the token associated with the\r
+ transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device\r
+ block size.\r
+ @param[out] Buffer A pointer to the destination buffer for the data.\r
+ The caller is responsible for either having\r
+ implicit or explicit ownership of the buffer.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Token->Event is\r
+ not NULL.The data was read correctly from the\r
+ device if the Token->Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the read.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not on proper\r
+ alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ UINTN IoAlign;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Media = This->Media;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ Status = NvmeAsyncRead (Device, Buffer, Lba, NumberOfBlocks, Token);\r
+ } else {\r
+ Status = NvmeRead (Device, Buffer, Lba, NumberOfBlocks);\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write BufferSize bytes from Lba into Buffer.\r
+\r
+ This function writes the requested number of blocks to the device. All blocks\r
+ are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r
+ EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r
+ being used, the Event associated with this request will not be signaled.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in] MediaId The media ID that the write request is for.\r
+ @param[in] Lba The starting logical block address to be written.\r
+ The caller is responsible for writing to only\r
+ legitimate locations.\r
+ @param[in, out] Token A pointer to the token associated with the\r
+ transaction.\r
+ @param[in] BufferSize Size of Buffer, must be a multiple of device\r
+ block size.\r
+ @param[in] Buffer A pointer to the source buffer for the data.\r
+\r
+ @retval EFI_SUCCESS The write request was queued if Event is not\r
+ NULL.\r
+ The data was written correctly to the device if\r
+ the Event is NULL.\r
+ @retval EFI_WRITE_PROTECTED The device can not be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current\r
+ device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while performing\r
+ the write.\r
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size\r
+ of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not\r
+ valid, or the buffer is not on proper\r
+ alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ EFI_STATUS Status;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ UINTN IoAlign;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Media = This->Media;\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ return EFI_MEDIA_CHANGED;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ BlockSize = Media->BlockSize;\r
+ if ((BufferSize % BlockSize) != 0) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ IoAlign = Media->IoAlign;\r
+ if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);\r
+\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ Status = NvmeAsyncWrite (Device, Buffer, Lba, NumberOfBlocks, Token);\r
+ } else {\r
+ Status = NvmeWrite (Device, Buffer, Lba, NumberOfBlocks);\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r
+ is returned and non-blocking I/O is being used, the Event associated with\r
+ this request will not be signaled.\r
+\r
+ @param[in] This Indicates a pointer to the calling context.\r
+ @param[in,out] Token A pointer to the token associated with the\r
+ transaction.\r
+\r
+ @retval EFI_SUCCESS The flush request was queued if Event is not\r
+ NULL.\r
+ All outstanding data was written correctly to\r
+ the device if the Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back\r
+ the data.\r
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+NvmeBlockIoFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ NVME_DEVICE_PRIVATE_DATA *Device;\r
+ BOOLEAN IsEmpty;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Check parameters.\r
+ //\r
+ if (This == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Device = NVME_DEVICE_PRIVATE_DATA_FROM_BLOCK_IO2 (This);\r
+\r
+ //\r
+ // Wait for the asynchronous I/O queue to become empty.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ IsEmpty = IsListEmpty (&Device->AsyncQueue);\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (IsEmpty) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (100);\r
+ }\r
+\r
+ //\r
+ // Signal caller event\r
+ //\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Trust transfer data from/to NVMe device.\r
\r
CommandPacket.NvmeCmd = &Command;\r
CommandPacket.NvmeCompletion = &Completion;\r
\r
- // \r
+ //\r
// Change Endianness of SecurityProtocolSpecificData\r
//\r
SpecificData = (((SecurityProtocolSpecificData << 8) & 0xFF00) | (SecurityProtocolSpecificData >> 8));\r
{\r
EFI_STATUS Status;\r
NVME_DEVICE_PRIVATE_DATA *Device;\r
- \r
+\r
Status = EFI_SUCCESS;\r
\r
if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL) || (PayloadBufferSize == 0)) {\r
IN VOID *PayloadBuffer\r
)\r
{\r
- EFI_STATUS Status; \r
+ EFI_STATUS Status;\r
NVME_DEVICE_PRIVATE_DATA *Device;\r
\r
Status = EFI_SUCCESS;\r