]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
Add BlockIO2 Protocol.
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / IdeMode.c
index 50b95a6713263bb2d00e8d6c2e49c52b339d91f8..915e4bb296fd3cab4ed4c6307b940e9c6619443f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Header file for AHCI mode of ATA host controller.\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
@@ -1123,16 +1123,20 @@ AtaIssueCommand (
 /**\r
   This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Buffer           A pointer to the source buffer for the data.\r
-  @param ByteCount        The length of  the data.\r
-  @param Read             Flag used to determine the data transfer direction.\r
-                          Read equals 1, means data transferred from device to host;\r
-                          Read equals 0, means data transferred from host to device.  \r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
+                                   structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in, out] Buffer           A pointer to the source buffer for the data.\r
+  @param[in]      ByteCount        The length of the data.\r
+  @param[in] Read                  Flag used to determine the data transfer direction.\r
+                                   Read equals 1, means data transferred from device\r
+                                   to host;Read equals 0, means data transferred\r
+                                   from host to device.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param[in]      AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
   \r
   @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
@@ -1148,7 +1152,8 @@ AtaPioDataInOut (
   IN     BOOLEAN                   Read,\r
   IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     UINT64                    Timeout,\r
+  IN     ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   UINTN       WordCount;\r
@@ -1248,17 +1253,24 @@ Exit:
   //\r
   DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
 \r
+  //\r
+  // Not support the Non-blocking now,just do the blocking process.\r
+  //\r
   return Status;\r
 }\r
 \r
 /**\r
   Send ATA command into device with NON_DATA protocol\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE\r
+                                   data structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data\r
+                                   structure.\r
+  @param[in, out] AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
 \r
   @retval  EFI_SUCCESS Reading succeed\r
   @retval  EFI_ABORTED Command failed\r
@@ -1272,7 +1284,8 @@ AtaNonDataCommandIn (
   IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
   IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     UINT64                    Timeout,\r
+  IN     ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   EFI_STATUS  Status;\r
@@ -1310,24 +1323,123 @@ Exit:
   // Dump All Ide registers to ATA_STATUS_BLOCK\r
   //\r
   DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  \r
+  //\r
+  // Not support the Non-blocking now,just do the blocking process.\r
+  //\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for memory to be set.\r
+    \r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  PortNum         The IDE Port number.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmStatusWait (\r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     UINT16                    PortNum\r
+ ) \r
+{\r
+  UINT8                         RegisterValue;\r
+  EFI_STATUS                    Status;\r
+  UINT64                        Timeout;\r
+\r
+  Timeout = 2000;\r
+\r
+  while (TRUE) {\r
+    RegisterValue  = IdeReadPortB (PciIo, PortNum);\r
+\r
+    if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
+      DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
+      Status = EFI_SUCCESS;\r
+      DEBUG ((DEBUG_INFO, "Task->RetryTimes = %x\n", Timeout));      \r
+      break;\r
+    }\r
+    //\r
+    // Stall for 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+    Timeout--;\r
+  }\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Check if the memory to be set.\r
+    \r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Task            Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                              used by non-blocking mode.\r
+  @param[in]  PortForBit      The bit to be checked.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory setting met a issue.\r
+  @retval EFI_NOT_READY     The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmStatusCheck (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     ATA_NONBLOCK_TASK          *Task,\r
+  IN     UINT16                     PortForBit\r
+ )\r
+{\r
+  UINT8                         RegisterValue;\r
+\r
+  Task->RetryTimes--;\r
+  RegisterValue  = IdeReadPortB(PciIo, PortForBit);\r
+\r
+  if ((RegisterValue & BMIS_ERROR) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
+    DEBUG ((DEBUG_INFO, "Task->RetryTimes = %x\n", Task->RetryTimes));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Task->RetryTimes == 0) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    //\r
+    // The memory is not set.\r
+    //\r
+    return EFI_NOT_READY;\r
+  }\r
+}\r
 \r
 /**\r
   Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Read             Flag used to determine the data transfer direction.\r
-                          Read equals 1, means data transferred from device to host;\r
-                          Read equals 0, means data transferred from host to device.\r
-  @param DataBuffer       A pointer to the source buffer for the data.\r
-  @param DataLength       The length of  the data.\r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
+                                   structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in]      Read             Flag used to determine the data transfer\r
+                                   direction. Read equals 1, means data transferred\r
+                                   from device to host;Read equals 0, means data\r
+                                   transferred from host to device.\r
+  @param[in]      DataBuffer       A pointer to the source buffer for the data.\r
+  @param[in]      DataLength       The length of  the data.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param[in, out] AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
 \r
   @retval EFI_SUCCESS          the operation is successful.\r
   @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
@@ -1338,14 +1450,15 @@ Exit:
 EFI_STATUS\r
 EFIAPI\r
 AtaUdmaInOut (\r
-  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
-  IN     BOOLEAN                   Read,\r
-  IN     VOID                      *DataBuffer,\r
-  IN     UINT64                    DataLength,\r
-  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
-  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     EFI_IDE_REGISTERS             *IdeRegisters,\r
+  IN     BOOLEAN                       Read,\r
+  IN     VOID                          *DataBuffer,\r
+  IN     UINT64                        DataLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
+  IN     UINT64                        Timeout,\r
+  IN     ATA_NONBLOCK_TASK             *Task\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
@@ -1353,18 +1466,16 @@ AtaUdmaInOut (
   UINT16                        IoPortForBmis;\r
   UINT16                        IoPortForBmid;\r
 \r
-  UINT8                         RegisterValue;\r
-\r
-  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
-  UINTN                         PrdTableNum;\r
   UINTN                         PrdTableSize;\r
   EFI_PHYSICAL_ADDRESS          PrdTableMapAddr;\r
   VOID                          *PrdTableMap;\r
+  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
+  UINTN                         PrdTableNum;\r
 \r
+  UINT8                         RegisterValue;\r
   UINTN                         PageCount;\r
   UINTN                         ByteCount;\r
   UINTN                         ByteRemaining;\r
-\r
   UINT8                         DeviceControl;\r
 \r
   VOID                          *BufferMap;\r
@@ -1373,14 +1484,36 @@ AtaUdmaInOut (
 \r
   UINT8                         DeviceHead;\r
   UINT8                         AtaCommand;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  EFI_TPL                       OldTpl;\r
 \r
-  Status      = EFI_SUCCESS;\r
-  PrdBaseAddr = NULL;\r
+\r
+  Status        = EFI_SUCCESS;\r
+  PrdBaseAddr   = NULL;\r
+  PrdTableMap   = NULL;\r
+  BufferMap     = NULL;\r
+  PageCount     = 0;\r
+  PciIo         = Instance->PciIo;\r
 \r
   if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  //\r
+  // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
+  // BlockIO tasks.\r
+  // Delay 1ms to simulate the blocking time out checking.\r
+  //\r
+  while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+    AsyncNonBlockingTransferRoutine (NULL, Instance);\r
+    gBS->RestoreTPL (OldTpl);\r
+    //\r
+    // Stall for 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+  } \r
+\r
   //\r
   // The data buffer should be even alignment\r
   //\r
@@ -1389,234 +1522,260 @@ AtaUdmaInOut (
   }\r
 \r
   //\r
-  // Calculate the number of PRD entry.\r
-  // Every entry in PRD table can specify a 64K memory region.\r
+  // Set relevant IO Port address.\r
   //\r
-  PrdTableNum   = (UINTN)(RShiftU64(DataLength, 16) + 1);\r
+  IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);\r
+  IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
+  IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);\r
 \r
   //\r
-  // Make sure that the memory region of PRD table is not cross 64K boundary\r
-  //\r
-  PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
-  if (PrdTableSize > 0x10000) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  // For Blocking mode, start the command. \r
+  // For non-blocking mode, when the command is not started, start it, otherwise\r
+  // go to check the status.\r
+  //  \r
+  if (((Task != NULL) && (!Task->IsStart)) || (Task == NULL)) {\r
+    //\r
+    // Calculate the number of PRD entry.\r
+    // Every entry in PRD table can specify a 64K memory region.\r
+    //\r
+    PrdTableNum   = (UINTN)(RShiftU64(DataLength, 16) + 1);\r
 \r
-  //\r
-  // Allocate buffer for PRD table initialization.\r
-  //\r
-  PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
-  Status    = PciIo->AllocateBuffer (\r
-                       PciIo,\r
-                       AllocateAnyPages,\r
-                       EfiBootServicesData,\r
-                       PageCount,\r
-                       (VOID **)&PrdBaseAddr,\r
-                       0\r
-                       );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Make sure that the memory region of PRD table is not cross 64K boundary\r
+    //\r
+    PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
+    if (PrdTableSize > 0x10000) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
-  ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
-  Status    = PciIo->Map (\r
-                       PciIo,\r
-                       EfiPciIoOperationBusMasterCommonBuffer,\r
-                       PrdBaseAddr,\r
-                       &ByteCount,\r
-                       &PrdTableMapAddr,\r
-                       &PrdTableMap\r
-                       );\r
-  if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
-    //\r
-    // If the data length actually mapped is not equal to the requested amount,\r
-    // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
-    // Can't handle this case.\r
-    //\r
-    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Allocate buffer for PRD table initialization.\r
+    //\r
+    PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    Status    = PciIo->AllocateBuffer (\r
+                         PciIo,\r
+                         AllocateAnyPages,\r
+                         EfiBootServicesData,\r
+                         PageCount,\r
+                         (VOID **)&PrdBaseAddr,\r
+                         0\r
+                         );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
-  ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
+    ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+    Status    = PciIo->Map (\r
+                         PciIo,\r
+                         EfiPciIoOperationBusMasterCommonBuffer,\r
+                         PrdBaseAddr,\r
+                         &ByteCount,\r
+                         &PrdTableMapAddr,\r
+                         &PrdTableMap\r
+                         );\r
+    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+      //\r
+      // If the data length actually mapped is not equal to the requested amount,\r
+      // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
+      // Can't handle this case.\r
+      //\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
-  //\r
-  // Map the host address of DataBuffer to DMA master address.\r
-  //\r
-  if (Read) {\r
-    PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
-  } else {\r
-    PciIoOperation = EfiPciIoOperationBusMasterRead;\r
-  }\r
+    ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
 \r
-  ByteCount = (UINTN)DataLength;\r
-  Status    = PciIo->Map (\r
-                       PciIo,\r
-                       PciIoOperation,\r
-                       DataBuffer,\r
-                       &ByteCount,\r
-                       &BufferMapAddress,\r
-                       &BufferMap\r
-                       );\r
-  if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
-    PciIo->Unmap (PciIo, PrdTableMap);\r
-    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Map the host address of DataBuffer to DMA master address.\r
+    //\r
+    if (Read) {\r
+      PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
+    } else {\r
+      PciIoOperation = EfiPciIoOperationBusMasterRead;\r
+    }\r
 \r
-  //\r
-  // According to Ata spec, it requires the buffer address and size to be even.\r
-  //\r
-  ASSERT ((BufferMapAddress & 0x1) == 0);\r
-  ASSERT ((ByteCount & 0x1) == 0);\r
+    ByteCount = (UINTN)DataLength;\r
+    Status    = PciIo->Map (\r
+                         PciIo,\r
+                         PciIoOperation,\r
+                         DataBuffer,\r
+                         &ByteCount,\r
+                         &BufferMapAddress,\r
+                         &BufferMap\r
+                         );\r
+    if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
+      PciIo->Unmap (PciIo, PrdTableMap);\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // According to Ata spec, it requires the buffer address and size to be even.\r
+    //\r
+    ASSERT ((BufferMapAddress & 0x1) == 0);\r
+    ASSERT ((ByteCount & 0x1) == 0);\r
+\r
+    //\r
+    // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
+    //\r
+    ByteRemaining = ByteCount;\r
+    while (ByteRemaining != 0) {\r
+      if (ByteRemaining <= 0x10000) {\r
+        PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
+        PrdBaseAddr->ByteCount      = (UINT16) ByteRemaining;\r
+        PrdBaseAddr->EndOfTable     = 0x8000;\r
+        break;\r
+      }\r
 \r
-  //\r
-  // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
-  //\r
-  ByteRemaining = ByteCount;\r
-  while (ByteRemaining != 0) {\r
-    if (ByteRemaining <= 0x10000) {\r
       PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
-      PrdBaseAddr->ByteCount      = (UINT16) ByteRemaining;\r
-      PrdBaseAddr->EndOfTable     = 0x8000;\r
-      break;\r
-    }\r
+      PrdBaseAddr->ByteCount      = (UINT16) 0x0;\r
 \r
-    PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
-    PrdBaseAddr->ByteCount      = (UINT16) 0x0;\r
+      ByteRemaining    -= 0x10000;\r
+      BufferMapAddress += 0x10000;\r
+      PrdBaseAddr++;\r
+    }\r
 \r
-    ByteRemaining    -= 0x10000;\r
-    BufferMapAddress += 0x10000;\r
-    PrdBaseAddr++;\r
-  }\r
+    //\r
+    // Start to enable the DMA operation\r
+    //\r
+    DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
+    AtaCommand = AtaCommandBlock->AtaCommand;\r
 \r
-  //\r
-  // Start to enable the DMA operation\r
-  //\r
-  DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
-  AtaCommand = AtaCommandBlock->AtaCommand;\r
+    IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
 \r
-  IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
+    //\r
+    // Enable interrupt to support UDMA\r
+    //\r
+    DeviceControl = 0;\r
+    IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
 \r
-  //\r
-  // Enable interrupt to support UDMA\r
-  //\r
-  DeviceControl = 0;\r
-  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+    //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+    IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
 \r
-  IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);\r
-  IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
-  IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);\r
+    //\r
+    // Set the base address to BMID register\r
+    //\r
+    IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
 \r
-  //\r
-  // Read BMIS register and clear ERROR and INTR bit\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
-  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+    //\r
+    // Set BMIC register to identify the operation direction\r
+    //\r
+    RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
+    if (Read) {\r
+      RegisterValue |= BMIC_NREAD;\r
+    } else {\r
+      RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+    }\r
+    IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
 \r
-  //\r
-  // Set the base address to BMID register\r
-  //\r
-  IdeWritePortDW(PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
+    //\r
+    // Issue ATA command\r
+    //\r
+    Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
 \r
-  //\r
-  // Set BMIC register to identify the operation direction\r
-  //\r
-  RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
-  if (Read) {\r
-    RegisterValue |= BMIC_NREAD;\r
-  } else {\r
-    RegisterValue &= ~((UINT8) BMIC_NREAD);\r
-  }\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
 \r
-  //\r
-  // Issue ATA command\r
-  //\r
-  Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
+    //\r
+    // Set START bit of BMIC register\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+    RegisterValue |= BMIC_START;\r
+    IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
+    if (Task != NULL) {\r
+      //\r
+      // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+      // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+      // So set the variable Count to 2000, for about 2 second Timeout time.\r
+      //\r
+      Task->RetryTimes     = 2000;\r
+      Task->Map            = BufferMap;\r
+      Task->TableMap       = PrdTableMap;\r
+      Task->MapBaseAddress = PrdBaseAddr;\r
+      Task->PageCount      = PageCount;\r
+      Task->IsStart        = TRUE;\r
+    }\r
   }\r
 \r
-  //\r
-  // Set START bit of BMIC register\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
-  RegisterValue |= BMIC_START;\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
-\r
   //\r
   // Check the INTERRUPT and ERROR bit of BMIS\r
   // Max transfer number of sectors for one command is 65536(32Mbyte),\r
   // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
   // So set the variable Count to 2000, for about 2 second Timeout time.\r
   //\r
-  Timeout = 2000;\r
-  while (TRUE) {\r
-    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
-\r
-    if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
-      DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
-      Status = EFI_DEVICE_ERROR;\r
-      break;\r
-    }\r
-\r
-    if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
-      Status = EFI_SUCCESS;\r
-      break;\r
-    }\r
-    //\r
-    // Stall for 1 milliseconds.\r
-    //\r
-    MicroSecondDelay (1000);\r
-    Timeout--;\r
+  if (Task != NULL) {\r
+    Status = AtaUdmStatusCheck (PciIo, Task, IoPortForBmis);\r
+  } else {\r
+    Status = AtaUdmStatusWait (PciIo, IoPortForBmis);\r
   }\r
 \r
   //\r
-  // Read BMIS register and clear ERROR and INTR bit\r
+  // For blocking mode, clear registers and free buffers.\r
+  // For non blocking mode, when the related registers have been set or time\r
+  // out, or a error has been happened, it needs to clear the register and free\r
+  // buffer.\r
   //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
-  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+  if ((Task == NULL) || Status != EFI_NOT_READY) {\r
+    //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    RegisterValue  = IdeReadPortB (PciIo, IoPortForBmis);\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+    IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
 \r
-  //\r
-  // Read Status Register of IDE device to clear interrupt\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
+    //\r
+    // Read Status Register of IDE device to clear interrupt\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
 \r
-  //\r
-  // Clear START bit of BMIC register\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
-  RegisterValue &= ~((UINT8) BMIC_START);\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+    //\r
+    // Clear START bit of BMIC register\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+    RegisterValue &= ~((UINT8) BMIC_START);\r
+    IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
 \r
-  //\r
-  // Disable interrupt of Select device\r
-  //\r
-  DeviceControl  = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
-  DeviceControl |= ATA_CTLREG_IEN_L;\r
-  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
-  //\r
-  // Stall for 10 milliseconds.\r
-  //\r
-  MicroSecondDelay (10000);\r
+    //\r
+    // Disable interrupt of Select device\r
+    //\r
+    DeviceControl  = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    DeviceControl |= ATA_CTLREG_IEN_L;\r
+    IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+    //\r
+    // Stall for 10 milliseconds.\r
+    //\r
+    MicroSecondDelay (10000);\r
+\r
+  }\r
 \r
 Exit:\r
   //\r
   // Free all allocated resource\r
   //\r
-  PciIo->Unmap (PciIo, PrdTableMap);\r
-  PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-  PciIo->Unmap (PciIo, BufferMap);\r
-\r
-  //\r
-  // Dump All Ide registers to ATA_STATUS_BLOCK\r
-  //\r
-  DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  if ((Task == NULL) || Status != EFI_NOT_READY) {\r
+    if (Task != NULL) {\r
+      PciIo->Unmap (PciIo, Task->TableMap);\r
+      PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress);\r
+      PciIo->Unmap (PciIo, Task->Map);\r
+    } else {\r
+      PciIo->Unmap (PciIo, PrdTableMap);\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->Unmap (PciIo, BufferMap);\r
+    }\r
 \r
+    //\r
+    // Dump All Ide registers to ATA_STATUS_BLOCK\r
+    //\r
+    DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  }\r
+  \r
   return Status;\r
 }\r
 \r
@@ -2021,7 +2180,8 @@ SetDeviceTransferMode (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2069,7 +2229,8 @@ SetDriveParameters (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   //\r
@@ -2084,7 +2245,8 @@ SetDriveParameters (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2132,7 +2294,8 @@ IdeAtaSmartReturnStatusCheck (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   if (EFI_ERROR (Status)) {\r
@@ -2212,7 +2375,8 @@ IdeAtaSmartSupport (
                  &Instance->IdeRegisters[Channel],\r
                  &AtaCommandBlock,\r
                  AtaStatusBlock,\r
-                 ATA_ATAPI_TIMEOUT\r
+                 ATA_ATAPI_TIMEOUT,\r
+                 NULL\r
                  );\r
 \r
       if (!EFI_ERROR (Status)) {\r
@@ -2233,7 +2397,8 @@ IdeAtaSmartSupport (
                    &Instance->IdeRegisters[Channel],\r
                    &AtaCommandBlock,\r
                    AtaStatusBlock,\r
-                   ATA_ATAPI_TIMEOUT\r
+                   ATA_ATAPI_TIMEOUT,\r
+                   NULL\r
                    );\r
         if (!EFI_ERROR (Status)) {\r
           Status = IdeAtaSmartReturnStatusCheck (\r
@@ -2254,6 +2419,7 @@ IdeAtaSmartSupport (
   return ;\r
 }\r
 \r
+\r
 /**\r
   Sends out an ATA Identify Command to the specified device.\r
 \r
@@ -2274,6 +2440,7 @@ IdeAtaSmartSupport (
   @retval EFI_SUCCESS          Identify ATA device successfully.\r
   @retval EFI_DEVICE_ERROR     ATA Identify Device Command failed or device is not ATA device.\r
   @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -2286,10 +2453,10 @@ AtaIdentify (
   )\r
 {\r
   EFI_STATUS             Status;\r
-  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;  \r
+  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;\r
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand    = ATA_CMD_IDENTIFY_DRIVE;\r
   AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
 \r
@@ -2301,7 +2468,8 @@ AtaIdentify (
              TRUE,\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2368,7 +2536,8 @@ AtaIdentifyPacket (
              TRUE,\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2425,7 +2594,7 @@ DetectAndConfigIdeDevice (
   IdeInit      = Instance->IdeControllerInit;\r
   PciIo        = Instance->PciIo;\r
 \r
-  for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {    \r
+  for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
     //\r
     // Send ATA Device Execut Diagnostic command.\r
     // This command should work no matter DRDY is ready or not\r
@@ -2483,7 +2652,7 @@ DetectAndConfigIdeDevice (
       if (EFI_ERROR (Status)) {\r
         DeviceType = EfiIdeHarddisk;\r
         Status     = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
-      } \r
+      }\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
@@ -2491,12 +2660,11 @@ DetectAndConfigIdeDevice (
       // No device is found at this port\r
       //\r
       continue;\r
-    } \r
-  \r
+    }\r
+\r
     DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n", \r
             (IdeChannel == 1) ? "secondary" : "primary  ", (IdeDevice == 1) ? "slave " : "master",\r
             DeviceType == EfiIdeCdrom ? "cdrom   " : "harddisk"));\r
-\r
     //\r
     // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
     //\r
@@ -2548,7 +2716,7 @@ DetectAndConfigIdeDevice (
         continue;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
     // be set together. Only one DMA mode can be set to a device. If setting\r
@@ -2559,7 +2727,7 @@ DetectAndConfigIdeDevice (
       TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
       TransferMode.ModeNumber   = (UINT8) (SupportedModes->UdmaMode.Mode);\r
       Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
-    \r
+\r
       if (EFI_ERROR (Status)) {\r
         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
         continue;\r
@@ -2568,13 +2736,13 @@ DetectAndConfigIdeDevice (
       TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
       TransferMode.ModeNumber   = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
       Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
-    \r
+\r
       if (EFI_ERROR (Status)) {\r
         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
         continue;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Set Parameters for the device:\r
     // 1) Init\r
@@ -2587,10 +2755,10 @@ DetectAndConfigIdeDevice (
       DriveParameters.Sector         = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;\r
       DriveParameters.Heads          = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);\r
       DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;\r
-    \r
+\r
       Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);\r
     }\r
-    \r
+\r
     //\r
     // Set IDE controller Timing Blocks in the PCI Configuration Space\r
     //\r