]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
Clean up the hard code offset in MdePkg BaseLib Ia32 Thunk16.S and EcpPkg GlueLib...
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AtaAtapiPassThru.c
index bbaf5523ac1b5856eef3b9be3b53a6883caff8bb..72196a00401b650cf42aae7a03be260ab2118ed2 100644 (file)
@@ -2,7 +2,7 @@
   This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces\r
   for managed ATA controllers.\r
     \r
-  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2011, 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
@@ -39,7 +39,7 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
     // bits.\r
     // Note that the driver doesn't support AtaPassThru non blocking I/O.\r
     //\r
-    EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+    EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_NONBLOCKIO,\r
     //\r
     // IoAlign\r
     //\r
@@ -98,7 +98,12 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
   0,                  // PreviousPort\r
   0,                  // PreviousPortMultiplier\r
   0,                  // PreviousTargetId\r
-  0                   // PreviousLun\r
+  0,                  // PreviousLun\r
+  NULL,               // Timer event\r
+  {                   // NonBlocking TaskList\r
+    NULL,             \r
+    NULL\r
+  }\r
 };\r
 \r
 ATAPI_DEVICE_PATH    mAtapiDevicePathTemplate = {\r
@@ -132,12 +137,304 @@ UINT8 mScsiId[TARGET_MAX_BYTES] = {
   0xFF, 0xFF, 0xFF, 0xFF\r
 };\r
 \r
+/**\r
+  Sends an ATA command to an ATA device that is attached to the ATA controller. This function\r
+  supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,\r
+  and the non-blocking I/O functionality is optional.\r
+\r
+  @param[in]      Port               The port number of the ATA device to send the command. \r
+  @param[in]      PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+                                     If there is no port multiplier, then specify 0.\r
+  @param[in, out] Packet             A pointer to the ATA command to send to the ATA device specified by Port\r
+                                     and PortMultiplierPort.\r
+  @param[in]      Instance           Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE.\r
+  @param[in]      Task               Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                     used by non-blocking mode.\r
+\r
+  @retval EFI_SUCCESS                The ATA command was sent by the host. For\r
+                                     bi-directional commands, InTransferLength bytes\r
+                                     were transferred from InDataBuffer. For\r
+                                     write and bi-directional commands, OutTransferLength\r
+                                     bytes were transferred by OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE        The ATA command was not executed. The number\r
+                                     of bytes that could be transferred is returned\r
+                                     in InTransferLength. For write and bi-directional\r
+                                     commands, OutTransferLength bytes were transferred\r
+                                     by OutDataBuffer.\r
+  @retval EFI_NOT_READY              The ATA command could not be sent because\r
+                                     there are too many ATA commands already\r
+                                     queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting\r
+                                     to send the ATA command.\r
+  @retval EFI_INVALID_PARAMETER      Port, PortMultiplierPort, or the contents\r
+                                     of Acb are invalid. The ATA command was\r
+                                     not sent, so no additional status information\r
+                                     is available.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruPassThruExecute (\r
+  IN     UINT16                           Port,\r
+  IN     UINT16                           PortMultiplierPort,\r
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE     *Instance, \r
+  IN     ATA_NONBLOCK_TASK                *Task OPTIONAL\r
+  )\r
+{\r
+  EFI_ATA_PASS_THRU_CMD_PROTOCOL  Protocol;\r
+  EFI_ATA_HC_WORK_MODE            Mode;\r
+  EFI_STATUS                      Status;\r
+  \r
+  Protocol = Packet->Protocol;\r
+\r
+  Mode = Instance->Mode;\r
+  switch (Mode) {\r
+    case EfiAtaIdeMode:\r
+      //\r
+      // Reassign IDE mode io port registers' base addresses\r
+      //\r
+      Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      \r
+      switch (Protocol) {\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
+          Status = AtaNonDataCommandIn (\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout, \r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
+          Status = AtaPioDataInOut (\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
+          Status = AtaPioDataInOut (\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
+          Status = AtaUdmaInOut (\r
+                     Instance,\r
+                     &Instance->IdeRegisters[Port],\r
+                     TRUE,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
+          Status = AtaUdmaInOut (\r
+                     Instance,\r
+                     &Instance->IdeRegisters[Port],\r
+                     FALSE,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        default :\r
+          return EFI_UNSUPPORTED;\r
+      }\r
+      break;\r
+    case EfiAtaAhciMode :\r
+      switch (Protocol) {\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
+          Status = AhciNonDataTransfer (\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
+          Status = AhciPioTransfer (\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
+          Status = AhciPioTransfer (\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Timeout, \r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
+          Status = AhciDmaTransfer (\r
+                     Instance,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
+          Status = AhciDmaTransfer (\r
+                     Instance,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Timeout,\r
+                     Task\r
+                     );\r
+          break;\r
+        default :\r
+          return EFI_UNSUPPORTED;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Call back function when the timer 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
+AsyncNonBlockingTransferRoutine (\r
+  EFI_EVENT  Event,\r
+  VOID*      Context\r
+  )\r
+{\r
+  LIST_ENTRY                   *Entry;\r
+  LIST_ENTRY                   *EntryHeader;\r
+  ATA_NONBLOCK_TASK            *Task;\r
+  EFI_STATUS                   Status;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE *Instance;\r
+\r
+  Instance   = (ATA_ATAPI_PASS_THRU_INSTANCE *) Context;\r
+  EntryHeader = &Instance->NonBlockingTaskList;\r
+  //\r
+  // Get the Taks from the Taks List and execute it, until there is \r
+  // no task in the list or the device is busy with task (EFI_NOT_READY).\r
+  //\r
+  while (TRUE) {\r
+    if (!IsListEmpty (EntryHeader)) {\r
+      Entry = GetFirstNode (EntryHeader);\r
+      Task  = ATA_NON_BLOCK_TASK_FROM_ENTRY (Entry);\r
+    } else {\r
+      return;\r
+    }\r
+\r
+    Status = AtaPassThruPassThruExecute (\r
+               Task->Port,\r
+               Task->PortMultiplier,\r
+               Task->Packet,\r
+               Instance,\r
+               Task\r
+               );\r
+\r
+    //\r
+    // If the data transfer meet a error which is not dumped into the status block\r
+    // set the Status block related bit.\r
+    //\r
+    if ((Status != EFI_NOT_READY) && (Status != EFI_SUCCESS)) {\r
+      Task->Packet->Asb->AtaStatus = 0x01;\r
+    }\r
+    //\r
+    // For Non blocking mode, the Status of EFI_NOT_READY means the operation\r
+    // is not finished yet. Other Status indicate the operation is either\r
+    // successful or failed. \r
+    //\r
+    if (Status != EFI_NOT_READY) {\r
+      RemoveEntryList (&Task->Link);\r
+      gBS->SignalEvent (Task->Event);\r
+      FreePool (Task);\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   The Entry Point of module.\r
 \r
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
   @param[in] SystemTable    A pointer to the EFI System Table.\r
-  \r
+\r
   @retval EFI_SUCCESS       The entry point is executed successfully.\r
   @retval other             Some error occurs when executing this entry point.\r
 \r
@@ -266,7 +563,7 @@ AtaAtapiPassThruSupported (
     //\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Close the I/O Abstraction(s) used to perform the supported test\r
   //\r
@@ -324,7 +621,7 @@ AtaAtapiPassThruSupported (
   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
      EFI_DEVICE_PATH_PROTOCOL.\r
   3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
-     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
 \r
   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
   @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
@@ -333,7 +630,7 @@ AtaAtapiPassThruSupported (
   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
                                    parameter is ignored by device drivers, and is optional for bus \r
                                    drivers. For a bus driver, if this parameter is NULL, then handles \r
-                                   for all the children of Controller are created by this driver.  \r
+                                   for all the children of Controller are created by this driver.\r
                                    If this parameter is not NULL and the first Device Path Node is \r
                                    not the End of Device Path Node, then only the handle for the \r
                                    child device specified by the first Device Path Node of \r
@@ -361,13 +658,11 @@ AtaAtapiPassThruStart (
   ATA_ATAPI_PASS_THRU_INSTANCE      *Instance;\r
   EFI_PCI_IO_PROTOCOL               *PciIo;\r
   UINT64                            Supports;\r
-  BOOLEAN                           PciAttributesSaved;\r
   UINT64                            OriginalPciAttributes;\r
 \r
   Status                = EFI_SUCCESS;\r
   IdeControllerInit     = NULL;\r
   Instance              = NULL;\r
-  PciAttributesSaved    = FALSE;\r
   OriginalPciAttributes = 0;\r
 \r
   DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Start== Controller = %x\n", Controller));\r
@@ -409,7 +704,6 @@ AtaAtapiPassThruStart (
   if (EFI_ERROR (Status)) {\r
     goto ErrorExit;\r
   }\r
-  PciAttributesSaved = TRUE;\r
 \r
   Status = PciIo->Attributes (\r
                     PciIo,\r
@@ -446,6 +740,28 @@ AtaAtapiPassThruStart (
   Instance->AtaPassThru.Mode      = &Instance->AtaPassThruMode;\r
   Instance->ExtScsiPassThru.Mode  = &Instance->ExtScsiPassThruMode;\r
   InitializeListHead(&Instance->DeviceList);\r
+  InitializeListHead(&Instance->NonBlockingTaskList);\r
+\r
+  Instance->TimerEvent = NULL;\r
+\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  AsyncNonBlockingTransferRoutine,\r
+                  Instance,\r
+                  &Instance->TimerEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+  \r
+  //\r
+  // Set 1ms timer.\r
+  //\r
+  Status = gBS->SetTimer (Instance->TimerEvent, TimerPeriodic, 10000);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
 \r
   //\r
   // Enumerate all inserted ATA devices.\r
@@ -475,6 +791,10 @@ ErrorExit:
            );\r
   }\r
 \r
+  if ((Instance != NULL) && (Instance->TimerEvent != NULL)) {\r
+    gBS->CloseEvent (Instance->TimerEvent);\r
+  }\r
+\r
   //\r
   // Remove all inserted ATA devices.\r
   //\r
@@ -542,13 +862,22 @@ AtaAtapiPassThruStop (
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
-  \r
-  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(AtaPassThru);\r
-  PciIo    = Instance->PciIo;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (AtaPassThru);\r
+\r
+  //\r
+  // Close Non-Blocking timer and free Task list.\r
+  //\r
+  if (Instance->TimerEvent != NULL) {\r
+    gBS->CloseEvent (Instance->TimerEvent);\r
+    Instance->TimerEvent = NULL;\r
+  }\r
+  DestroyAsynTaskList (Instance);\r
 \r
   //\r
   // Disable this ATA host controller.\r
   //\r
+  PciIo  = Instance->PciIo;\r
   Status = PciIo->Attributes (\r
                     PciIo,\r
                     EfiPciIoAttributeOperationSupported,\r
@@ -610,7 +939,7 @@ AtaAtapiPassThruStop (
              );\r
     PciIo->FreeBuffer (\r
              PciIo,\r
-             (UINTN) EFI_SIZE_TO_PAGES (AhciRegisters->MaxCommandTableSize),\r
+             EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxCommandTableSize),\r
              AhciRegisters->AhciCommandTable\r
              );\r
     PciIo->Unmap (\r
@@ -619,7 +948,7 @@ AtaAtapiPassThruStop (
              );\r
     PciIo->FreeBuffer (\r
              PciIo,\r
-             (UINTN) EFI_SIZE_TO_PAGES (AhciRegisters->MaxCommandListSize),\r
+             EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxCommandListSize),\r
              AhciRegisters->AhciCmdList\r
              );\r
     PciIo->Unmap (\r
@@ -628,7 +957,7 @@ AtaAtapiPassThruStop (
              );\r
     PciIo->FreeBuffer (\r
              PciIo,\r
-             (UINTN) EFI_SIZE_TO_PAGES (AhciRegisters->MaxReceiveFisSize),\r
+             EFI_SIZE_TO_PAGES ((UINTN) AhciRegisters->MaxReceiveFisSize),\r
              AhciRegisters->AhciRFis\r
              );\r
   }\r
@@ -672,7 +1001,7 @@ SearchDeviceInfoList (
     }\r
 \r
     Node = GetNextNode (&Instance->DeviceList, Node);\r
-  }  \r
+  }\r
 \r
   return NULL;\r
 }\r
@@ -757,6 +1086,42 @@ DestroyDeviceInfoList (
   }\r
 }\r
 \r
+/**\r
+  Destroy all pending non blocking tasks.\r
+  \r
+  @param[in]  Instance  A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DestroyAsynTaskList (\r
+  IN ATA_ATAPI_PASS_THRU_INSTANCE *Instance\r
+  )\r
+{\r
+  LIST_ENTRY           *Entry;\r
+  LIST_ENTRY           *DelEntry;\r
+  ATA_NONBLOCK_TASK    *Task;\r
+  EFI_TPL              OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+  if (!IsListEmpty (&Instance->NonBlockingTaskList)) {\r
+    //\r
+    // Free the Subtask list.\r
+    //\r
+    for (Entry = (&Instance->NonBlockingTaskList)->ForwardLink; \r
+        Entry != (&Instance->NonBlockingTaskList);\r
+       ) {\r
+      DelEntry = Entry;\r
+      Entry    = Entry->ForwardLink;\r
+      Task     = ATA_NON_BLOCK_TASK_FROM_ENTRY (DelEntry);\r
+\r
+      RemoveEntryList (DelEntry);\r
+      FreePool (Task);\r
+    }\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+}\r
+\r
 /**\r
   Enumerate all attached ATA devices at IDE mode or AHCI mode separately.\r
   \r
@@ -863,17 +1228,16 @@ AtaPassThruPassThru (
   IN     UINT16                           PortMultiplierPort,\r
   IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,\r
   IN     EFI_EVENT                        Event OPTIONAL\r
-  ) \r
+  )\r
 {\r
-  EFI_STATUS                      Status;\r
   ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
-  EFI_ATA_PASS_THRU_CMD_PROTOCOL  Protocol;\r
-  EFI_ATA_HC_WORK_MODE            Mode;\r
   LIST_ENTRY                      *Node;\r
   EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
   EFI_IDENTIFY_DATA               *IdentifyData;\r
   UINT64                          Capacity;\r
   UINT32                          MaxSectorCount;\r
+  ATA_NONBLOCK_TASK               *Task;\r
+  EFI_TPL                         OldTpl;\r
 \r
   Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
 \r
@@ -940,173 +1304,37 @@ AtaPassThruPassThru (
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
-  Status   = EFI_UNSUPPORTED;\r
-  Protocol = Packet->Protocol;\r
-\r
-  Mode = Instance->Mode;\r
-  switch (Mode) {\r
-    case EfiAtaIdeMode:\r
-      //\r
-      // Reassign IDE mode io port registers' base addresses\r
-      //\r
-      Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);\r
-      \r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-      \r
-      switch (Protocol) {\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
-          Status = AtaNonDataCommandIn(\r
-                     Instance->PciIo,\r
-                     &Instance->IdeRegisters[Port],\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
-          Status = AtaPioDataInOut(\r
-                     Instance->PciIo,\r
-                     &Instance->IdeRegisters[Port],\r
-                     Packet->InDataBuffer,\r
-                     Packet->InTransferLength,\r
-                     TRUE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
-          Status = AtaPioDataInOut(\r
-                     Instance->PciIo,\r
-                     &Instance->IdeRegisters[Port],\r
-                     Packet->OutDataBuffer,\r
-                     Packet->OutTransferLength,\r
-                     FALSE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
-          Status = AtaUdmaInOut(\r
-                     Instance->PciIo,\r
-                     &Instance->IdeRegisters[Port],\r
-                     TRUE,\r
-                     Packet->InDataBuffer,\r
-                     Packet->InTransferLength,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
-          Status = AtaUdmaInOut(\r
-                     Instance->PciIo,\r
-                     &Instance->IdeRegisters[Port],\r
-                     FALSE,\r
-                     Packet->OutDataBuffer,\r
-                     Packet->OutTransferLength,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        default :\r
-          return EFI_UNSUPPORTED;\r
-      }\r
-      break;\r
-    case EfiAtaAhciMode :\r
-      switch (Protocol) {\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
-          Status = AhciNonDataTransfer(\r
-                     Instance->PciIo,\r
-                     &Instance->AhciRegisters,\r
-                     (UINT8)Port,\r
-                     (UINT8)PortMultiplierPort,\r
-                     NULL,\r
-                     0,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
-          Status = AhciPioTransfer(\r
-                     Instance->PciIo,\r
-                     &Instance->AhciRegisters,\r
-                     (UINT8)Port,\r
-                     (UINT8)PortMultiplierPort,\r
-                     NULL,\r
-                     0,\r
-                     TRUE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->InDataBuffer,\r
-                     Packet->InTransferLength,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
-          Status = AhciPioTransfer(\r
-                     Instance->PciIo,\r
-                     &Instance->AhciRegisters,\r
-                     (UINT8)Port,\r
-                     (UINT8)PortMultiplierPort,\r
-                     NULL,\r
-                     0,\r
-                     FALSE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->OutDataBuffer,\r
-                     Packet->OutTransferLength,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
-          Status = AhciDmaTransfer(\r
-                     Instance->PciIo,\r
-                     &Instance->AhciRegisters,\r
-                     (UINT8)Port,\r
-                     (UINT8)PortMultiplierPort,\r
-                     NULL,\r
-                     0,\r
-                     TRUE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->InDataBuffer,\r
-                     Packet->InTransferLength,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
-          Status = AhciDmaTransfer(\r
-                     Instance->PciIo,\r
-                     &Instance->AhciRegisters,\r
-                     (UINT8)Port,\r
-                     (UINT8)PortMultiplierPort,\r
-                     NULL,\r
-                     0,\r
-                     FALSE,\r
-                     Packet->Acb,\r
-                     Packet->Asb,\r
-                     Packet->OutDataBuffer,\r
-                     Packet->OutTransferLength,\r
-                     Packet->Timeout\r
-                     );\r
-          break;\r
-        default :\r
-          return EFI_UNSUPPORTED;\r
-      }\r
-      break;\r
+  //\r
+  // For non-blocking mode, queue the Task into the list.\r
+  //\r
+  if (Event != NULL) {\r
+    Task = AllocateZeroPool (sizeof (ATA_NONBLOCK_TASK));\r
+    if (Task == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    \r
+    Task->Signature      = ATA_NONBLOCKING_TASK_SIGNATURE;\r
+    Task->Port           = Port;\r
+    Task->PortMultiplier = PortMultiplierPort;\r
+    Task->Packet         = Packet;\r
+    Task->Event          = Event;\r
+    Task->IsStart        = FALSE;\r
+    Task->RetryTimes     = 0;\r
+\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    InsertTailList (&Instance->NonBlockingTaskList, &Task->Link);\r
+    gBS->RestoreTPL (OldTpl);\r
 \r
-    default:\r
-      Status = EFI_DEVICE_ERROR;\r
-      break;\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return AtaPassThruPassThruExecute (\r
+             Port,\r
+             PortMultiplierPort,\r
+             Packet,\r
+             Instance,\r
+             NULL\r
+             );\r
   }\r
-\r
-  return Status;\r
 }\r
 \r
 /**\r
@@ -1197,7 +1425,7 @@ AtaPassThruGetNextPort (
     //\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
 Exit:\r
   //\r
   // Update the PreviousPort and PreviousPortMultiplier.\r
@@ -1216,20 +1444,20 @@ Exit:
 \r
   The GetNextDevice() function retrieves the port multiplier port number of an ATA device \r
   present on a port of an ATA controller.\r
-  \r
+\r
   If PortMultiplierPort points to a port multiplier port number value that was returned on a \r
   previous call to GetNextDevice(), then the port multiplier port number of the next ATA device\r
   on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is\r
   returned.\r
-  \r
+\r
   If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first \r
   ATA device on port of the ATA controller is returned in PortMultiplierPort and \r
   EFI_SUCCESS is returned.\r
-  \r
+\r
   If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort\r
   was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER\r
   is returned.\r
-  \r
+\r
   If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of \r
   the ATA controller, then EFI_NOT_FOUND is returned.\r
 \r
@@ -1309,7 +1537,7 @@ AtaPassThruGetNextDevice (
     //\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
 Exit:\r
   //\r
   // Update the PreviousPort and PreviousPortMultiplier.\r
@@ -1377,7 +1605,7 @@ AtaPassThruBuildDevicePath (
   if (Node == NULL) {\r
     return EFI_NOT_FOUND;\r
   }\r
-  \r
+\r
   if (Instance->Mode == EfiAtaIdeMode) {\r
     DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);\r
     if (DevicePathNode == NULL) {\r
@@ -1719,7 +1947,7 @@ ExtScsiPassThruPassThru (
   can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal\r
   Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the       \r
   Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI    \r
-  channel.                                                                                               \r
+  channel.\r
 \r
   @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
   @param  Target On input, a pointer to the Target ID (an array of size\r
@@ -1840,7 +2068,7 @@ Exit:
   Instance->PreviousLun      = *Lun;\r
   \r
   return EFI_SUCCESS;\r
-}   \r
+}\r
 \r
 /**\r
   Used to allocate and build a device path node for a SCSI device on a SCSI channel.\r
@@ -2031,8 +2259,8 @@ ExtScsiPassThruResetChannel (
   )\r
 {\r
   return EFI_UNSUPPORTED;\r
-}    \r
-  \r
+}\r
+\r
 /**\r
   Resets a SCSI logical unit that is connected to a SCSI channel.\r
 \r
@@ -2061,7 +2289,7 @@ ExtScsiPassThruResetTargetLun (
   )\r
 {\r
   return EFI_UNSUPPORTED;\r
-}         \r
+}\r
 \r
 /**\r
   Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either     \r
@@ -2176,5 +2404,5 @@ Exit:
   Instance->PreviousTargetId = *Target16;\r
 \r
   return EFI_SUCCESS;\r
-}    \r
+}\r
 \r