]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressPassthru.c
MdeModulePkg/NvmExpressDxe: Handle timeout for blocking PassThru req
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressDxe / NvmExpressPassthru.c
index ef3d772cc28b1ebe640b066ee24da505fc5f4144..c33038f0e926555deca50827b021f9a38cd55d68 100644 (file)
@@ -3,7 +3,7 @@
   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
+  Copyright (c) 2013 - 2017, 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
@@ -316,6 +316,100 @@ EXIT:
 }\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
+    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
+    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
+    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
+    if (AsyncRequest->MapMeta != NULL) {\r
+      PciIo->Unmap (PciIo, AsyncRequest->MapMeta);\r
+    }\r
+    if (AsyncRequest->MapPrpList != NULL) {\r
+      PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);\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
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
 /**\r
   Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports\r
   both blocking I/O and non-blocking I/O. The blocking I/O functionality is required, and the non-blocking\r
@@ -603,7 +697,7 @@ NvmExpressPassThru (
     Private->SqTdbl[QueueId].Sqt ^= 1;\r
   }\r
   Data = ReadUnaligned32 ((UINT32*)&Private->SqTdbl[QueueId]);\r
-  PciIo->Mem.Write (\r
+  Status = PciIo->Mem.Write (\r
                PciIo,\r
                EfiPciIoWidthUint32,\r
                NVME_BAR,\r
@@ -612,6 +706,10 @@ NvmExpressPassThru (
                &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
   // in the submission queue.\r
@@ -688,6 +786,44 @@ NvmExpressPassThru (
         NvmeDumpStatus(Cq);\r
       DEBUG_CODE_END();\r
     }\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
@@ -695,7 +831,7 @@ NvmExpressPassThru (
   }\r
 \r
   Data = ReadUnaligned32 ((UINT32*)&Private->CqHdbl[QueueId]);\r
-  PciIo->Mem.Write (\r
+  Status = PciIo->Mem.Write (\r
                PciIo,\r
                EfiPciIoWidthUint32,\r
                NVME_BAR,\r