NVM Express specification.\r
\r
(C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
- Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
**/\r
VOID\r
NvmeDumpStatus (\r
- IN NVME_CQ *Cq\r
+ IN NVME_CQ *Cq\r
)\r
{\r
- DEBUG ((EFI_D_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));\r
+ DEBUG ((DEBUG_VERBOSE, "Dump NVMe Completion Entry Status from [0x%x]:\n", Cq));\r
\r
- DEBUG ((EFI_D_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));\r
+ DEBUG ((DEBUG_VERBOSE, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));\r
\r
- DEBUG ((EFI_D_VERBOSE, " NVMe Cmd Execution Result - "));\r
+ DEBUG ((DEBUG_VERBOSE, " NVMe Cmd Execution Result - "));\r
\r
switch (Cq->Sct) {\r
case 0x0:\r
switch (Cq->Sc) {\r
case 0x0:\r
- DEBUG ((EFI_D_VERBOSE, "Successful Completion\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Successful Completion\n"));\r
break;\r
case 0x1:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Command Opcode\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Command Opcode\n"));\r
break;\r
case 0x2:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Field in Command\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Field in Command\n"));\r
break;\r
case 0x3:\r
- DEBUG ((EFI_D_VERBOSE, "Command ID Conflict\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command ID Conflict\n"));\r
break;\r
case 0x4:\r
- DEBUG ((EFI_D_VERBOSE, "Data Transfer Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Data Transfer Error\n"));\r
break;\r
case 0x5:\r
- DEBUG ((EFI_D_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Commands Aborted due to Power Loss Notification\n"));\r
break;\r
case 0x6:\r
- DEBUG ((EFI_D_VERBOSE, "Internal Device Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Internal Device Error\n"));\r
break;\r
case 0x7:\r
- DEBUG ((EFI_D_VERBOSE, "Command Abort Requested\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command Abort Requested\n"));\r
break;\r
case 0x8:\r
- DEBUG ((EFI_D_VERBOSE, "Command Aborted due to SQ Deletion\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command Aborted due to SQ Deletion\n"));\r
break;\r
case 0x9:\r
- DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Failed Fused Command\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Failed Fused Command\n"));\r
break;\r
case 0xA:\r
- DEBUG ((EFI_D_VERBOSE, "Command Aborted due to Missing Fused Command\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command Aborted due to Missing Fused Command\n"));\r
break;\r
case 0xB:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Namespace or Format\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Namespace or Format\n"));\r
break;\r
case 0xC:\r
- DEBUG ((EFI_D_VERBOSE, "Command Sequence Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Command Sequence Error\n"));\r
break;\r
case 0xD:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid SGL Last Segment Descriptor\n"));\r
break;\r
case 0xE:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Number of SGL Descriptors\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Number of SGL Descriptors\n"));\r
break;\r
case 0xF:\r
- DEBUG ((EFI_D_VERBOSE, "Data SGL Length Invalid\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Data SGL Length Invalid\n"));\r
break;\r
case 0x10:\r
- DEBUG ((EFI_D_VERBOSE, "Metadata SGL Length Invalid\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Metadata SGL Length Invalid\n"));\r
break;\r
case 0x11:\r
- DEBUG ((EFI_D_VERBOSE, "SGL Descriptor Type Invalid\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "SGL Descriptor Type Invalid\n"));\r
break;\r
case 0x80:\r
- DEBUG ((EFI_D_VERBOSE, "LBA Out of Range\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "LBA Out of Range\n"));\r
break;\r
case 0x81:\r
- DEBUG ((EFI_D_VERBOSE, "Capacity Exceeded\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Capacity Exceeded\n"));\r
break;\r
case 0x82:\r
- DEBUG ((EFI_D_VERBOSE, "Namespace Not Ready\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Namespace Not Ready\n"));\r
break;\r
case 0x83:\r
- DEBUG ((EFI_D_VERBOSE, "Reservation Conflict\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Reservation Conflict\n"));\r
break;\r
}\r
+\r
break;\r
\r
case 0x1:\r
switch (Cq->Sc) {\r
case 0x0:\r
- DEBUG ((EFI_D_VERBOSE, "Completion Queue Invalid\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Completion Queue Invalid\n"));\r
break;\r
case 0x1:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Queue Identifier\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Queue Identifier\n"));\r
break;\r
case 0x2:\r
- DEBUG ((EFI_D_VERBOSE, "Maximum Queue Size Exceeded\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Maximum Queue Size Exceeded\n"));\r
break;\r
case 0x3:\r
- DEBUG ((EFI_D_VERBOSE, "Abort Command Limit Exceeded\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Abort Command Limit Exceeded\n"));\r
break;\r
case 0x5:\r
- DEBUG ((EFI_D_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Asynchronous Event Request Limit Exceeded\n"));\r
break;\r
case 0x6:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Slot\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Slot\n"));\r
break;\r
case 0x7:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Firmware Image\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Firmware Image\n"));\r
break;\r
case 0x8:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Interrupt Vector\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Interrupt Vector\n"));\r
break;\r
case 0x9:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Log Page\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Log Page\n"));\r
break;\r
case 0xA:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Format\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Format\n"));\r
break;\r
case 0xB:\r
- DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires Conventional Reset\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires Conventional Reset\n"));\r
break;\r
case 0xC:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Queue Deletion\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Queue Deletion\n"));\r
break;\r
case 0xD:\r
- DEBUG ((EFI_D_VERBOSE, "Feature Identifier Not Saveable\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Feature Identifier Not Saveable\n"));\r
break;\r
case 0xE:\r
- DEBUG ((EFI_D_VERBOSE, "Feature Not Changeable\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Feature Not Changeable\n"));\r
break;\r
case 0xF:\r
- DEBUG ((EFI_D_VERBOSE, "Feature Not Namespace Specific\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Feature Not Namespace Specific\n"));\r
break;\r
case 0x10:\r
- DEBUG ((EFI_D_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Firmware Application Requires NVM Subsystem Reset\n"));\r
break;\r
case 0x80:\r
- DEBUG ((EFI_D_VERBOSE, "Conflicting Attributes\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Conflicting Attributes\n"));\r
break;\r
case 0x81:\r
- DEBUG ((EFI_D_VERBOSE, "Invalid Protection Information\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Invalid Protection Information\n"));\r
break;\r
case 0x82:\r
- DEBUG ((EFI_D_VERBOSE, "Attempted Write to Read Only Range\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Attempted Write to Read Only Range\n"));\r
break;\r
}\r
+\r
break;\r
\r
case 0x2:\r
switch (Cq->Sc) {\r
case 0x80:\r
- DEBUG ((EFI_D_VERBOSE, "Write Fault\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Write Fault\n"));\r
break;\r
case 0x81:\r
- DEBUG ((EFI_D_VERBOSE, "Unrecovered Read Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Unrecovered Read Error\n"));\r
break;\r
case 0x82:\r
- DEBUG ((EFI_D_VERBOSE, "End-to-end Guard Check Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "End-to-end Guard Check Error\n"));\r
break;\r
case 0x83:\r
- DEBUG ((EFI_D_VERBOSE, "End-to-end Application Tag Check Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "End-to-end Application Tag Check Error\n"));\r
break;\r
case 0x84:\r
- DEBUG ((EFI_D_VERBOSE, "End-to-end Reference Tag Check Error\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "End-to-end Reference Tag Check Error\n"));\r
break;\r
case 0x85:\r
- DEBUG ((EFI_D_VERBOSE, "Compare Failure\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Compare Failure\n"));\r
break;\r
case 0x86:\r
- DEBUG ((EFI_D_VERBOSE, "Access Denied\n"));\r
+ DEBUG ((DEBUG_VERBOSE, "Access Denied\n"));\r
break;\r
}\r
+\r
break;\r
\r
default:\r
@retval The pointer to the first PRP List of the PRP lists.\r
\r
**/\r
-VOID*\r
+VOID *\r
NvmeCreatePrpList (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN EFI_PHYSICAL_ADDRESS PhysicalAddr,\r
- IN UINTN Pages,\r
- OUT VOID **PrpListHost,\r
- IN OUT UINTN *PrpListNo,\r
- OUT VOID **Mapping\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,\r
+ IN UINTN Pages,\r
+ OUT VOID **PrpListHost,\r
+ IN OUT UINTN *PrpListNo,\r
+ OUT VOID **Mapping\r
)\r
{\r
- UINTN PrpEntryNo;\r
- UINT64 PrpListBase;\r
- UINTN PrpListIndex;\r
- UINTN PrpEntryIndex;\r
- UINT64 Remainder;\r
- EFI_PHYSICAL_ADDRESS PrpListPhyAddr;\r
- UINTN Bytes;\r
- EFI_STATUS Status;\r
+ UINTN PrpEntryNo;\r
+ UINT64 PrpListBase;\r
+ UINTN PrpListIndex;\r
+ UINTN PrpEntryIndex;\r
+ UINT64 Remainder;\r
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;\r
+ UINTN Bytes;\r
+ EFI_STATUS Status;\r
\r
//\r
// The number of Prp Entry in a memory page.\r
return NULL;\r
}\r
\r
- Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);\r
+ Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);\r
Status = PciIo->Map (\r
PciIo,\r
EfiPciIoOperationBusMasterCommonBuffer,\r
);\r
\r
if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (*PrpListNo))) {\r
- DEBUG ((EFI_D_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));\r
+ DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList: create PrpList failure!\n"));\r
goto EXIT;\r
}\r
+\r
//\r
// Fill all PRP lists except of last one.\r
//\r
ZeroMem (*PrpListHost, Bytes);\r
for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {\r
- PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+ PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
\r
for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {\r
if (PrpEntryIndex != PrpEntryNo - 1) {\r
//\r
// Fill all PRP entries except of last one.\r
//\r
- *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
- PhysicalAddr += EFI_PAGE_SIZE;\r
+ *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
} else {\r
//\r
// Fill last PRP entries with next PRP List pointer.\r
//\r
- *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;\r
+ *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE;\r
}\r
}\r
}\r
+\r
//\r
// Fill last PRP list.\r
//\r
- PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
+ PrpListBase = *(UINT64 *)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;\r
for (PrpEntryIndex = 0; PrpEntryIndex < Remainder; ++PrpEntryIndex) {\r
- *((UINT64*)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
- PhysicalAddr += EFI_PAGE_SIZE;\r
+ *((UINT64 *)(UINTN)PrpListBase + PrpEntryIndex) = PhysicalAddr;\r
+ PhysicalAddr += EFI_PAGE_SIZE;\r
}\r
\r
- return (VOID*)(UINTN)PrpListPhyAddr;\r
+ return (VOID *)(UINTN)PrpListPhyAddr;\r
\r
EXIT:\r
PciIo->FreeBuffer (PciIo, *PrpListNo, *PrpListHost);\r
return NULL;\r
}\r
\r
+/**\r
+ Aborts the asynchronous PassThru requests.\r
+\r
+ @param[in] Private The pointer to the NVME_CONTROLLER_PRIVATE_DATA\r
+ data structure.\r
+\r
+ @retval EFI_SUCCESS The asynchronous PassThru requests have been aborted.\r
+ @return EFI_DEVICE_ERROR Fail to abort all the asynchronous PassThru requests.\r
+\r
+**/\r
+EFI_STATUS\r
+AbortAsyncPassThruTasks (\r
+ IN NVME_CONTROLLER_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *NextLink;\r
+ NVME_BLKIO2_SUBTASK *Subtask;\r
+ NVME_BLKIO2_REQUEST *BlkIo2Request;\r
+ NVME_PASS_THRU_ASYNC_REQ *AsyncRequest;\r
+ EFI_BLOCK_IO2_TOKEN *Token;\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+\r
+ PciIo = Private->PciIo;\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+\r
+ //\r
+ // Cancel the unsubmitted subtasks.\r
+ //\r
+ for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);\r
+ !IsNull (&Private->UnsubmittedSubtasks, Link);\r
+ Link = NextLink)\r
+ {\r
+ NextLink = GetNextNode (&Private->UnsubmittedSubtasks, Link);\r
+ Subtask = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);\r
+ BlkIo2Request = Subtask->BlockIo2Request;\r
+ Token = BlkIo2Request->Token;\r
+\r
+ BlkIo2Request->UnsubmittedSubtaskNum--;\r
+ if (Subtask->IsLast) {\r
+ BlkIo2Request->LastSubtaskSubmitted = TRUE;\r
+ }\r
+\r
+ Token->TransactionStatus = EFI_ABORTED;\r
+\r
+ RemoveEntryList (Link);\r
+ InsertTailList (&BlkIo2Request->SubtasksQueue, Link);\r
+ gBS->SignalEvent (Subtask->Event);\r
+ }\r
+\r
+ //\r
+ // Cleanup the resources for the asynchronous PassThru requests.\r
+ //\r
+ for (Link = GetFirstNode (&Private->AsyncPassThruQueue);\r
+ !IsNull (&Private->AsyncPassThruQueue, Link);\r
+ Link = NextLink)\r
+ {\r
+ NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);\r
+ AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);\r
+\r
+ if (AsyncRequest->MapData != NULL) {\r
+ PciIo->Unmap (PciIo, AsyncRequest->MapData);\r
+ }\r
+\r
+ if (AsyncRequest->MapMeta != NULL) {\r
+ PciIo->Unmap (PciIo, AsyncRequest->MapMeta);\r
+ }\r
+\r
+ if (AsyncRequest->MapPrpList != NULL) {\r
+ PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);\r
+ }\r
+\r
+ if (AsyncRequest->PrpListHost != NULL) {\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ AsyncRequest->PrpListNo,\r
+ AsyncRequest->PrpListHost\r
+ );\r
+ }\r
+\r
+ RemoveEntryList (Link);\r
+ gBS->SignalEvent (AsyncRequest->CallerEvent);\r
+ FreePool (AsyncRequest);\r
+ }\r
+\r
+ if (IsListEmpty (&Private->AsyncPassThruQueue) &&\r
+ IsListEmpty (&Private->UnsubmittedSubtasks))\r
+ {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
\r
/**\r
Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
EFI_STATUS\r
EFIAPI\r
NvmExpressPassThru (\r
- IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
- IN UINT32 NamespaceId,\r
- IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
- IN EFI_EVENT Event OPTIONAL\r
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN OUT EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet,\r
+ IN EFI_EVENT Event OPTIONAL\r
)\r
{\r
NVME_CONTROLLER_PRIVATE_DATA *Private;\r
EFI_STATUS Status;\r
+ EFI_STATUS PreviousStatus;\r
EFI_PCI_IO_PROTOCOL *PciIo;\r
NVME_SQ *Sq;\r
NVME_CQ *Cq;\r
UINT16 QueueId;\r
+ UINT16 QueueSize;\r
UINT32 Bytes;\r
UINT16 Offset;\r
EFI_EVENT TimerEvent;\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (Packet->QueueType != NVME_ADMIN_QUEUE && Packet->QueueType != NVME_IO_QUEUE) {\r
+ if ((Packet->QueueType != NVME_ADMIN_QUEUE) && (Packet->QueueType != NVME_IO_QUEUE)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
// EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL set is an illegal\r
// configuration.\r
//\r
- Attributes = This->Mode->Attributes;\r
+ Attributes = This->Mode->Attributes;\r
if ((Attributes & (EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
- EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0) {\r
+ EFI_NVM_EXPRESS_PASS_THRU_ATTRIBUTES_LOGICAL)) == 0)\r
+ {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
//\r
// Buffer alignment check for TransferBuffer & MetadataBuffer.\r
//\r
- IoAlign = This->Mode->IoAlign;\r
- if (IoAlign > 0 && (((UINTN) Packet->TransferBuffer & (IoAlign - 1)) != 0)) {\r
+ IoAlign = This->Mode->IoAlign;\r
+ if ((IoAlign > 0) && (((UINTN)Packet->TransferBuffer & (IoAlign - 1)) != 0)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (IoAlign > 0 && (((UINTN) Packet->MetadataBuffer & (IoAlign - 1)) != 0)) {\r
+ if ((IoAlign > 0) && (((UINTN)Packet->MetadataBuffer & (IoAlign - 1)) != 0)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
+ Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
\r
//\r
// Check NamespaceId is valid or not.\r
//\r
if ((NamespaceId > Private->ControllerData->Nn) &&\r
- (NamespaceId != (UINT32) -1)) {\r
+ (NamespaceId != (UINT32)-1))\r
+ {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
Prp = NULL;\r
TimerEvent = NULL;\r
Status = EFI_SUCCESS;\r
+ QueueSize = MIN (NVME_ASYNC_CSQ_SIZE, Private->Cap.Mqes) + 1;\r
\r
if (Packet->QueueType == NVME_ADMIN_QUEUE) {\r
QueueId = 0;\r
//\r
// Submission queue full check.\r
//\r
- if ((Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1) ==\r
- Private->AsyncSqHead) {\r
+ if ((Private->SqTdbl[QueueId].Sqt + 1) % QueueSize ==\r
+ Private->AsyncSqHead)\r
+ {\r
return EFI_NOT_READY;\r
}\r
}\r
}\r
- Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;\r
- Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
+\r
+ Sq = Private->SqBuffer[QueueId] + Private->SqTdbl[QueueId].Sqt;\r
+ Cq = Private->CqBuffer[QueueId] + Private->CqHdbl[QueueId].Cqh;\r
\r
if (Packet->NvmeCmd->Nsid != NamespaceId) {\r
return EFI_INVALID_PARAMETER;\r
//\r
ASSERT (Sq->Psdt == 0);\r
if (Sq->Psdt != 0) {\r
- DEBUG ((EFI_D_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));\r
+ DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: doesn't support SGL mechanism\n"));\r
return EFI_UNSUPPORTED;\r
}\r
\r
Sq->Prp[0] = (UINT64)(UINTN)Packet->TransferBuffer;\r
- //\r
- // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.\r
- // Note here we don't handle data buffer for CreateIOSubmitionQueue and CreateIOCompletionQueue cmds because\r
- // these two cmds are special which requires their data buffer must support simultaneous access by both the\r
- // processor and a PCI Bus Master. It's caller's responsbility to ensure this.\r
- //\r
- if (((Sq->Opc & (BIT0 | BIT1)) != 0) && (Sq->Opc != NVME_ADMIN_CRIOCQ_CMD) && (Sq->Opc != NVME_ADMIN_CRIOSQ_CMD)) {\r
- if ((Packet->TransferLength == 0) || (Packet->TransferBuffer == NULL)) {\r
+ if ((Packet->QueueType == NVME_ADMIN_QUEUE) &&\r
+ ((Sq->Opc == NVME_ADMIN_CRIOCQ_CMD) || (Sq->Opc == NVME_ADMIN_CRIOSQ_CMD)))\r
+ {\r
+ //\r
+ // Currently, we only use the IO Completion/Submission queues created internally\r
+ // by this driver during controller initialization. Any other IO queues created\r
+ // will not be consumed here. The value is little to accept external IO queue\r
+ // creation requests, so here we will return EFI_UNSUPPORTED for external IO\r
+ // queue creation request.\r
+ //\r
+ if (!Private->CreateIoQueue) {\r
+ DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Does not support external IO queues creation request.\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } else if ((Sq->Opc & (BIT0 | BIT1)) != 0) {\r
+ //\r
+ // If the NVMe cmd has data in or out, then mapping the user buffer to the PCI controller specific addresses.\r
+ //\r
+ if (((Packet->TransferLength != 0) && (Packet->TransferBuffer == NULL)) ||\r
+ ((Packet->TransferLength == 0) && (Packet->TransferBuffer != NULL)))\r
+ {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
Flag = EfiPciIoOperationBusMasterWrite;\r
}\r
\r
- MapLength = Packet->TransferLength;\r
- Status = PciIo->Map (\r
- PciIo,\r
- Flag,\r
- Packet->TransferBuffer,\r
- &MapLength,\r
- &PhyAddr,\r
- &MapData\r
- );\r
- if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ if ((Packet->TransferLength != 0) && (Packet->TransferBuffer != NULL)) {\r
+ MapLength = Packet->TransferLength;\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ Flag,\r
+ Packet->TransferBuffer,\r
+ &MapLength,\r
+ &PhyAddr,\r
+ &MapData\r
+ );\r
+ if (EFI_ERROR (Status) || (Packet->TransferLength != MapLength)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
\r
- Sq->Prp[0] = PhyAddr;\r
- Sq->Prp[1] = 0;\r
+ Sq->Prp[0] = PhyAddr;\r
+ Sq->Prp[1] = 0;\r
+ }\r
\r
- if((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {\r
+ if ((Packet->MetadataLength != 0) && (Packet->MetadataBuffer != NULL)) {\r
MapLength = Packet->MetadataLength;\r
- Status = PciIo->Map (\r
- PciIo,\r
- Flag,\r
- Packet->MetadataBuffer,\r
- &MapLength,\r
- &PhyAddr,\r
- &MapMeta\r
- );\r
+ Status = PciIo->Map (\r
+ PciIo,\r
+ Flag,\r
+ Packet->MetadataBuffer,\r
+ &MapLength,\r
+ &PhyAddr,\r
+ &MapMeta\r
+ );\r
if (EFI_ERROR (Status) || (Packet->MetadataLength != MapLength)) {\r
PciIo->Unmap (\r
PciIo,\r
\r
return EFI_OUT_OF_RESOURCES;\r
}\r
+\r
Sq->Mptr = PhyAddr;\r
}\r
}\r
+\r
//\r
// If the buffer size spans more than two memory pages (page size as defined in CC.Mps),\r
// then build a PRP list in the second PRP submission queue entry.\r
// Create PrpList for remaining data buffer.\r
//\r
PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
- Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);\r
+ Prp = NvmeCreatePrpList (PciIo, PhyAddr, EFI_SIZE_TO_PAGES (Offset + Bytes) - 1, &PrpListHost, &PrpListNo, &MapPrpList);\r
if (Prp == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
goto EXIT;\r
}\r
\r
Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);\r
}\r
\r
- if(Packet->NvmeCmd->Flags & CDW2_VALID) {\r
+ if (Packet->NvmeCmd->Flags & CDW2_VALID) {\r
Sq->Rsvd2 = (UINT64)Packet->NvmeCmd->Cdw2;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW3_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW3_VALID) {\r
Sq->Rsvd2 |= LShiftU64 ((UINT64)Packet->NvmeCmd->Cdw3, 32);\r
}\r
- if(Packet->NvmeCmd->Flags & CDW10_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW10_VALID) {\r
Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW11_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW11_VALID) {\r
Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW12_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW12_VALID) {\r
Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW13_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW13_VALID) {\r
Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW14_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW14_VALID) {\r
Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;\r
}\r
- if(Packet->NvmeCmd->Flags & CDW15_VALID) {\r
+\r
+ if (Packet->NvmeCmd->Flags & CDW15_VALID) {\r
Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;\r
}\r
\r
//\r
if ((Event != NULL) && (QueueId != 0)) {\r
Private->SqTdbl[QueueId].Sqt =\r
- (Private->SqTdbl[QueueId].Sqt + 1) % (NVME_ASYNC_CSQ_SIZE + 1);\r
+ (Private->SqTdbl[QueueId].Sqt + 1) % QueueSize;\r
} else {\r
Private->SqTdbl[QueueId].Sqt ^= 1;\r
}\r
- Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueId]);\r
- PciIo->Mem.Write (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- NVME_BAR,\r
- NVME_SQTDBL_OFFSET(QueueId, Private->Cap.Dstrd),\r
- 1,\r
- &Data\r
- );\r
+\r
+ Data = ReadUnaligned32 ((UINT32 *)&Private->SqTdbl[QueueId]);\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_SQTDBL_OFFSET (QueueId, Private->Cap.Dstrd),\r
+ 1,\r
+ &Data\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
\r
//\r
// For non-blocking requests, return directly if the command is placed\r
goto EXIT;\r
}\r
\r
- AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;\r
- AsyncRequest->Packet = Packet;\r
- AsyncRequest->CommandId = Sq->Cid;\r
- AsyncRequest->CallerEvent = Event;\r
+ AsyncRequest->Signature = NVME_PASS_THRU_ASYNC_REQ_SIG;\r
+ AsyncRequest->Packet = Packet;\r
+ AsyncRequest->CommandId = Sq->Cid;\r
+ AsyncRequest->CallerEvent = Event;\r
+ AsyncRequest->MapData = MapData;\r
+ AsyncRequest->MapMeta = MapMeta;\r
+ AsyncRequest->MapPrpList = MapPrpList;\r
+ AsyncRequest->PrpListNo = PrpListNo;\r
+ AsyncRequest->PrpListHost = PrpListHost;\r
\r
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
InsertTailList (&Private->AsyncPassThruQueue, &AsyncRequest->Link);\r
goto EXIT;\r
}\r
\r
- Status = gBS->SetTimer(TimerEvent, TimerRelative, Packet->CommandTimeout);\r
+ Status = gBS->SetTimer (TimerEvent, TimerRelative, Packet->CommandTimeout);\r
\r
- if (EFI_ERROR(Status)) {\r
+ if (EFI_ERROR (Status)) {\r
goto EXIT;\r
}\r
\r
Status = EFI_SUCCESS;\r
} else {\r
Status = EFI_DEVICE_ERROR;\r
- //\r
- // Copy the Respose Queue entry for this command to the callers response buffer\r
- //\r
- CopyMem(Packet->NvmeCompletion, Cq, sizeof(EFI_NVM_EXPRESS_COMPLETION));\r
- \r
//\r
// Dump every completion entry status for debugging.\r
//\r
- DEBUG_CODE_BEGIN();\r
- NvmeDumpStatus(Cq);\r
- DEBUG_CODE_END();\r
+ DEBUG_CODE_BEGIN ();\r
+ NvmeDumpStatus (Cq);\r
+ DEBUG_CODE_END ();\r
+ }\r
+\r
+ //\r
+ // Copy the Respose Queue entry for this command to the callers response buffer\r
+ //\r
+ CopyMem (Packet->NvmeCompletion, Cq, sizeof (EFI_NVM_EXPRESS_COMPLETION));\r
+ } else {\r
+ //\r
+ // Timeout occurs for an NVMe command. Reset the controller to abort the\r
+ // outstanding commands.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "NvmExpressPassThru: Timeout occurs for an NVMe command.\n"));\r
+\r
+ //\r
+ // Disable the timer to trigger the process of async transfers temporarily.\r
+ //\r
+ Status = gBS->SetTimer (Private->TimerEvent, TimerCancel, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
}\r
+\r
+ //\r
+ // Reset the NVMe controller.\r
+ //\r
+ Status = NvmeControllerInit (Private);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = AbortAsyncPassThruTasks (Private);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Re-enable the timer to trigger the process of async transfers.\r
+ //\r
+ Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, NVME_HC_ASYNC_TIMER);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Return EFI_TIMEOUT to indicate a timeout occurs for NVMe PassThru command.\r
+ //\r
+ Status = EFI_TIMEOUT;\r
+ }\r
+ }\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ goto EXIT;\r
}\r
\r
if ((Private->CqHdbl[QueueId].Cqh ^= 1) == 0) {\r
Private->Pt[QueueId] ^= 1;\r
}\r
\r
- Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);\r
- PciIo->Mem.Write (\r
- PciIo,\r
- EfiPciIoWidthUint32,\r
- NVME_BAR,\r
- NVME_CQHDBL_OFFSET(QueueId, Private->Cap.Dstrd),\r
- 1,\r
- &Data\r
- );\r
+ Data = ReadUnaligned32 ((UINT32 *)&Private->CqHdbl[QueueId]);\r
+ PreviousStatus = Status;\r
+ Status = PciIo->Mem.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ NVME_BAR,\r
+ NVME_CQHDBL_OFFSET (QueueId, Private->Cap.Dstrd),\r
+ 1,\r
+ &Data\r
+ );\r
+ // The return status of PciIo->Mem.Write should not override\r
+ // previous status if previous status contains error.\r
+ Status = EFI_ERROR (PreviousStatus) ? PreviousStatus : Status;\r
\r
//\r
// For now, the code does not support the non-blocking feature for admin queue.\r
if (TimerEvent != NULL) {\r
gBS->CloseEvent (TimerEvent);\r
}\r
+\r
return Status;\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
NvmExpressGetNextNamespace (\r
- IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
- IN OUT UINT32 *NamespaceId\r
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN OUT UINT32 *NamespaceId\r
)\r
{\r
- NVME_CONTROLLER_PRIVATE_DATA *Private;\r
- NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
- UINT32 NextNamespaceId;\r
- EFI_STATUS Status;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
+ UINT32 NextNamespaceId;\r
+ EFI_STATUS Status;\r
\r
if ((This == NULL) || (NamespaceId == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
- if (EFI_ERROR(Status)) {\r
+ if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
\r
}\r
\r
Status = NvmeIdentifyNamespace (Private, NextNamespaceId, NamespaceData);\r
- if (EFI_ERROR(Status)) {\r
+ if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
\r
\r
Done:\r
if (NamespaceData != NULL) {\r
- FreePool(NamespaceData);\r
+ FreePool (NamespaceData);\r
}\r
\r
return Status;\r
EFI_STATUS\r
EFIAPI\r
NvmExpressGetNamespace (\r
- IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
- OUT UINT32 *NamespaceId\r
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT UINT32 *NamespaceId\r
)\r
{\r
- NVME_NAMESPACE_DEVICE_PATH *Node;\r
- NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ NVME_NAMESPACE_DEVICE_PATH *Node;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
\r
if ((This == NULL) || (DevicePath == NULL) || (NamespaceId == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
Private = NVME_CONTROLLER_PRIVATE_DATA_FROM_PASS_THRU (This);\r
\r
if (DevicePath->SubType == MSG_NVME_NAMESPACE_DP) {\r
- if (DevicePathNodeLength(DevicePath) != sizeof(NVME_NAMESPACE_DEVICE_PATH)) {\r
+ if (DevicePathNodeLength (DevicePath) != sizeof (NVME_NAMESPACE_DEVICE_PATH)) {\r
return EFI_NOT_FOUND;\r
}\r
\r
// Check NamespaceId in the device path node is valid or not.\r
//\r
if ((Node->NamespaceId == 0) ||\r
- (Node->NamespaceId > Private->ControllerData->Nn)) {\r
+ (Node->NamespaceId > Private->ControllerData->Nn))\r
+ {\r
return EFI_NOT_FOUND;\r
}\r
\r
EFI_STATUS\r
EFIAPI\r
NvmExpressBuildDevicePath (\r
- IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
- IN UINT32 NamespaceId,\r
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
+ IN EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *This,\r
+ IN UINT32 NamespaceId,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
)\r
{\r
- NVME_NAMESPACE_DEVICE_PATH *Node;\r
- NVME_CONTROLLER_PRIVATE_DATA *Private;\r
- EFI_STATUS Status;\r
- NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
+ NVME_NAMESPACE_DEVICE_PATH *Node;\r
+ NVME_CONTROLLER_PRIVATE_DATA *Private;\r
+ EFI_STATUS Status;\r
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;\r
\r
//\r
// Validate parameters\r
// Check NamespaceId is valid or not.\r
//\r
if ((NamespaceId == 0) ||\r
- (NamespaceId > Private->ControllerData->Nn)) {\r
+ (NamespaceId > Private->ControllerData->Nn))\r
+ {\r
return EFI_NOT_FOUND;\r
}\r
\r
Node->Header.Type = MESSAGING_DEVICE_PATH;\r
Node->Header.SubType = MSG_NVME_NAMESPACE_DP;\r
SetDevicePathNodeLength (&Node->Header, sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
- Node->NamespaceId = NamespaceId;\r
+ Node->NamespaceId = NamespaceId;\r
\r
//\r
// Allocate a buffer for Identify Namespace data.\r
//\r
NamespaceData = NULL;\r
- NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
- if(NamespaceData == NULL) {\r
+ NamespaceData = AllocateZeroPool (sizeof (NVME_ADMIN_NAMESPACE_DATA));\r
+ if (NamespaceData == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Exit;\r
}\r
(VOID *)NamespaceData\r
);\r
\r
- if (EFI_ERROR(Status)) {\r
+ if (EFI_ERROR (Status)) {\r
goto Exit;\r
}\r
\r
*DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;\r
\r
Exit:\r
- if(NamespaceData != NULL) {\r
+ if (NamespaceData != NULL) {\r
FreePool (NamespaceData);\r
}\r
\r
\r
return Status;\r
}\r
-\r