]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
EFI_FVB2_ALIGNMNET_512K should be EFI_FVB2_ALIGNMENT_512K.
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index a36d03e827a9512e6c658214cdd8950505b5c65a..a9b126acfa7fa92221667800d5b2d9fbd8ef1345 100644 (file)
@@ -133,24 +133,23 @@ AhciOrReg (
 }\r
 \r
 /**\r
-  Wait for memory set to the test value.\r
+  Wait for the value of the specified MMIO register set to the test value.\r
     \r
   @param  PciIo             The PCI IO protocol instance.\r
-  @param  Offset            The memory address to test.\r
+  @param  Offset            The MMIO address to test.\r
   @param  MaskValue         The mask value of memory.\r
   @param  TestValue         The test value of memory.\r
-  @param  Timeout           The time out value for wait memory set.\r
+  @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.\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
+  @retval EFI_TIMEOUT       The MMIO setting is time out.\r
+  @retval EFI_SUCCESS       The MMIO is correct set.\r
 \r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-AhciWaitMemSet (\r
+AhciWaitMmioSet (\r
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN  UINT32                    Offset,\r
+  IN  UINT                    Offset,\r
   IN  UINT32                    MaskValue,\r
   IN  UINT32                    TestValue,\r
   IN  UINT64                    Timeout\r
@@ -159,10 +158,13 @@ AhciWaitMemSet (
   UINT32     Value;  \r
   UINT32     Delay;\r
 \r
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
 \r
   do {\r
-    Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+    //\r
+    // Access PCI MMIO space to see if the value is the tested one.\r
+    //\r
+    Value = AhciReadReg (PciIo, (UINT32) Offset) & MaskValue;\r
 \r
     if (Value == TestValue) {\r
       return EFI_SUCCESS;\r
@@ -177,21 +179,70 @@ AhciWaitMemSet (
 \r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified system memory set to the test value.\r
+    \r
+  @param  Address           The system memory address to test.\r
+  @param  MaskValue         The mask value of memory.\r
+  @param  TestValue         The test value of memory.\r
+  @param  Timeout           The time out value for wait memory set, uses 100ns as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The system memory setting is time out.\r
+  @retval EFI_SUCCESS       The system memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMemSet (\r
+  IN  EFI_PHYSICAL_ADDRESS      Address,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;  \r
+  UINT32     Delay;\r
+\r
+  Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+\r
+  do {\r
+    //\r
+    // Access sytem memory to see if the value is the tested one.\r
+    //\r
+    // The system memory pointed by Address will be updated by the\r
+    // SATA Host Controller, "volatile" is introduced to prevent\r
+    // compiler from optimizing the access to the memory address\r
+    // to only read once.\r
+    //\r
+    Value  = *(volatile UINT32 *) (UINTN) Address;\r
+    Value &= MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
 \r
-  return EFI_DEVICE_ERROR;\r
+  } while (Delay > 0);\r
+\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
   Check the memory status to the test value.\r
     \r
-  @param[in]       PciIo             The PCI IO protocol instance.\r
-  @param[in]       Offset            The memory address to test.\r
+  @param[in]       Address           The memory address to test.\r
   @param[in]       MaskValue         The mask value of memory.\r
   @param[in]       TestValue         The test value of memory.\r
-  @param[in, out]  RetryTimes        The retry times value for waitting memory set.\r
+  @param[in, out]  RetryTimes        The retry times value for waitting memory set. If 0, then just try once.\r
 \r
   @retval EFI_NOTREADY      The memory is not set.\r
   @retval EFI_TIMEOUT       The memory setting retry times out.\r
@@ -201,24 +252,26 @@ AhciWaitMemSet (
 EFI_STATUS\r
 EFIAPI\r
 AhciCheckMemSet (\r
-  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN     UINT32                    Offset,\r
+  IN     UINTN                     Address,\r
   IN     UINT32                    MaskValue,\r
   IN     UINT32                    TestValue,\r
-  IN OUT UINTN                     *RetryTimes\r
+  IN OUT UINTN                     *RetryTimes OPTIONAL\r
   )\r
 {\r
   UINT32     Value;\r
 \r
-  (*RetryTimes) --;\r
-  \r
-  Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+  if (RetryTimes != NULL) {\r
+    (*RetryTimes)--;\r
+  }\r
\r
+  Value  = *(volatile UINT32 *) Address;\r
+  Value &= MaskValue;\r
 \r
   if (Value == TestValue) {\r
     return EFI_SUCCESS;\r
   }\r
 \r
-  if ((*RetryTimes) == 0) {\r
+  if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\r
     return EFI_TIMEOUT;\r
   } else {\r
     return EFI_NOT_READY;\r
@@ -338,7 +391,7 @@ AhciDumpPortStatus (
     \r
   @param      PciIo          The PCI IO protocol instance.\r
   @param      Port           The number of port.\r
-  @param      Timeout        The timeout value of enabling FIS.\r
+  @param      Timeout        The timeout value of enabling FIS, uses 100ns as a unit.\r
 \r
   @retval EFI_DEVICE_ERROR   The FIS enable setting fails.\r
   @retval EFI_TIMEOUT        The FIS enable setting is time out.\r
@@ -358,7 +411,7 @@ AhciEnableFisReceive (
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
 \r
-  return AhciWaitMemSet (\r
+  return AhciWaitMmioSet (\r
            PciIo, \r
            Offset,\r
            EFI_AHCI_PORT_CMD_FR,\r
@@ -372,7 +425,7 @@ AhciEnableFisReceive (
 \r
   @param      PciIo          The PCI IO protocol instance.\r
   @param      Port           The number of port.\r
-  @param      Timeout        The timeout value of disabling FIS.\r
+  @param      Timeout        The timeout value of disabling FIS, uses 100ns as a unit.\r
 \r
   @retval EFI_DEVICE_ERROR   The FIS disable setting fails.\r
   @retval EFI_TIMEOUT        The FIS disable setting is time out.\r
@@ -410,7 +463,7 @@ AhciDisableFisReceive (
 \r
   AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
 \r
-  return AhciWaitMemSet (\r
+  return AhciWaitMmioSet (\r
            PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_FR,\r
@@ -596,7 +649,7 @@ AhciBuildCommandFis (
   @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
   @param[in, out]  MemoryAddr          The pointer to the data buffer.\r
   @param[in]       DataCount           The data count to be transferred.\r
-  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Timeout             The timeout value of non data transfer, uses 100ns as a unit.\r
   @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
                                        used by non-blocking mode.\r
 \r
@@ -626,15 +679,16 @@ AhciPioTransfer (
 {\r
   EFI_STATUS                    Status;\r
   UINTN                         FisBaseAddr;\r
-  UINT32                        Offset;\r
-  UINT32                        Value;\r
+  UINTN                         Offset;\r
   EFI_PHYSICAL_ADDRESS          PhyAddr;\r
   VOID                          *Map;\r
   UINTN                         MapLength;\r
   EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
   UINT32                        Delay;\r
   EFI_AHCI_COMMAND_FIS          CFis;\r
-  EFI_AHCI_COMMAND_LIST         CmdList;\r
+  EFI_AHCI_COMMAND_LIST         CmdList; \r
+  UINT32                        PortTfd;\r
+  UINT32                        PrdCount;\r
 \r
   if (Read) {\r
     Flag = EfiPciIoOperationBusMasterWrite;\r
@@ -656,7 +710,7 @@ AhciPioTransfer (
                     );\r
 \r
   if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    return EFI_BAD_BUFFER_SIZE;\r
   }\r
   \r
   //\r
@@ -697,56 +751,66 @@ AhciPioTransfer (
   // Check the status and wait the driver sending data\r
   //\r
   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
-  //\r
-  // Wait device sends the PIO setup fis before data transfer\r
-  //\r
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
-  do {\r
-    Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);\r
-\r
-    if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_PIO_SETUP) {\r
-      break;\r
-    }\r
 \r
+  if (Read && (AtapiCommand == 0)) {\r
     //\r
-    // Stall for 100 microseconds.\r
+    // Wait device sends the PIO setup fis before data transfer\r
     //\r
-    MicroSecondDelay(100);\r
+    Status = EFI_TIMEOUT;\r
+    Delay  = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+    do {\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+      PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
 \r
-    Delay--;\r
-  } while (Delay > 0);\r
+      if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        break;\r
+      }\r
+      Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
 \r
-  if (Delay == 0) {\r
-    Status = EFI_TIMEOUT;\r
-    goto Exit;\r
-  }\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\r
+      if (!EFI_ERROR (Status)) {\r
+        PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
+        if (PrdCount == DataCount) {\r
+          break;\r
+        }\r
+      }\r
 \r
-  //\r
-  // Wait for command compelte\r
-  //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             0xFFFFFFFF,\r
-             0,\r
-             Timeout\r
-             );\r
+      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        break;\r
+      }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\r
-  }\r
+      //\r
+      // Stall for 100 microseconds.\r
+      //\r
+      MicroSecondDelay(100);\r
 \r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             EFI_AHCI_PORT_IS_PSS,\r
-             EFI_AHCI_PORT_IS_PSS,\r
-             Timeout\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\r
+      Delay--;\r
+    } while (Delay > 0);\r
+  } else {\r
+    //\r
+    // Wait for D2H Fis is received\r
+    //\r
+    Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+    Status = AhciWaitMemSet (\r
+               Offset,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
+               Timeout\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+    PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+    if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
   }\r
 \r
 Exit:\r
@@ -787,7 +851,7 @@ Exit:
   @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
   @param[in, out]  MemoryAddr          The pointer to the data buffer.\r
   @param[in]       DataCount           The data count to be transferred.\r
-  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Timeout             The timeout value of non data transfer, uses 100ns as a unit.\r
   @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
                                        used by non-blocking mode.\r
 \r
@@ -810,22 +874,24 @@ AhciDmaTransfer (
   IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
   IN OUT VOID                       *MemoryAddr,\r
-  IN     UINT                     DataCount,\r
+  IN     UINT32                     DataCount,\r
   IN     UINT64                     Timeout,\r
   IN     ATA_NONBLOCK_TASK          *Task\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
-  UINT32                        Offset;\r
+  UINT                        Offset;\r
   EFI_PHYSICAL_ADDRESS          PhyAddr;\r
   VOID                          *Map;\r
   UINTN                         MapLength;\r
   EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
   EFI_AHCI_COMMAND_FIS          CFis;\r
   EFI_AHCI_COMMAND_LIST         CmdList;\r
+  UINTN                         FisBaseAddr;\r
+  UINT32                        PortTfd;\r
 \r
-  EFI_PCI_IO_PROTOCOL          *PciIo;\r
-  EFI_TPL                      OldTpl;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  EFI_TPL                       OldTpl;\r
 \r
   Map   = NULL;\r
   PciIo = Instance->PciIo;\r
@@ -877,7 +943,7 @@ AhciDmaTransfer (
                       );\r
 \r
     if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
-      return EFI_OUT_OF_RESOURCES;\r
+      return EFI_BAD_BUFFER_SIZE;\r
     }\r
 \r
     if (Task != NULL) {\r
@@ -916,45 +982,28 @@ AhciDmaTransfer (
     if (EFI_ERROR (Status)) {\r
       goto Exit;\r
     }\r
-\r
-    //\r
-    // Wait device PRD processed\r
-    //\r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-    Status = AhciWaitMemSet (\r
-               PciIo,\r
-               Offset,\r
-               EFI_AHCI_PORT_IS_DPS,\r
-               EFI_AHCI_PORT_IS_DPS,\r
-               Timeout\r
-               );\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      goto Exit;\r
-    }\r
   }\r
 \r
   //\r
   // Wait for command compelte\r
   //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+  Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
   if (Task != NULL) {\r
     //\r
     // For Non-blocking\r
     //\r
     Status = AhciCheckMemSet (\r
-               PciIo,\r
                Offset,\r
-               0xFFFFFFFF,\r
-               0,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
                (UINTN *) (&Task->RetryTimes)\r
                );\r
   } else {\r
     Status = AhciWaitMemSet (\r
-               PciIo,\r
                Offset,\r
-               0xFFFFFFFF,\r
-               0,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
                Timeout\r
                );\r
   }\r
@@ -963,31 +1012,10 @@ AhciDmaTransfer (
     goto Exit;\r
   }\r
 \r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-\r
-  if (Task != NULL) {\r
-    //\r
-    // For Non-blocking\r
-    //\r
-    Status = AhciCheckMemSet (\r
-               PciIo,\r
-               Offset,\r
-               EFI_AHCI_PORT_IS_DHRS,\r
-               EFI_AHCI_PORT_IS_DHRS,\r
-               (UINTN *) (&Task->RetryTimes)\r
-             );\r
-  } else {\r
-    Status = AhciWaitMemSet (\r
-               PciIo,\r
-               Offset,\r
-               EFI_AHCI_PORT_IS_DHRS,\r
-               EFI_AHCI_PORT_IS_DHRS,\r
-               Timeout\r
-               );\r
-  }\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+  PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+  if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
   }\r
 \r
 Exit:\r
@@ -1039,7 +1067,7 @@ Exit:
   @param[in]       AtapiCommandLength  The length of the atapi command.\r
   @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
   @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Timeout             The timeout value of non data transfer, uses 100ns as a unit.\r
   @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
                                        used by non-blocking mode.\r
 \r
@@ -1066,10 +1094,8 @@ AhciNonDataTransfer (
 {\r
   EFI_STATUS                   Status;\r
   UINTN                        FisBaseAddr;\r
-  UINT32                       Offset;\r
-  UINT32                       Value;\r
-  UINT32                       Delay;\r
-\r
+  UINTN                        Offset;\r
+  UINT32                       PortTfd;\r
   EFI_AHCI_COMMAND_FIS         CFis;\r
   EFI_AHCI_COMMAND_LIST        CmdList;\r
 \r
@@ -1110,39 +1136,23 @@ AhciNonDataTransfer (
   // Wait device sends the Response Fis\r
   //\r
   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
-  //\r
-  // Wait device sends the PIO setup fis before data transfer\r
-  //\r
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
-  do {\r
-    Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+  Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+  Status      = AhciWaitMemSet (\r
+                  Offset,\r
+                  EFI_AHCI_FIS_TYPE_MASK,\r
+                  EFI_AHCI_FIS_REGISTER_D2H,\r
+                  Timeout\r
+                  );\r
 \r
-    if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
-      break;\r
-    }\r
-\r
-    //\r
-    // Stall for 100 microseconds.\r
-    //\r
-    MicroSecondDelay(100);\r
-\r
-    Delay --;\r
-  } while (Delay > 0);\r
-\r
-  if (Delay == 0) {\r
-    Status = EFI_TIMEOUT;\r
+  if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
 \r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
-\r
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             0xFFFFFFFF,\r
-             0,\r
-             Timeout\r
-             );\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+  PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+  if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
 \r
 Exit:\r
   AhciStopCommand (\r
@@ -1167,7 +1177,7 @@ Exit:
     \r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
-  @param  Timeout            The timeout value of stop.\r
+  @param  Timeout            The timeout value of stop, uses 100ns as a unit.\r
    \r
   @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.\r
   @retval EFI_TIMEOUT        The operation is time out.\r
@@ -1196,7 +1206,7 @@ AhciStopCommand (
     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
   }\r
 \r
-  return AhciWaitMemSet (\r
+  return AhciWaitMmioSet (\r
            PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_CR,\r
@@ -1211,7 +1221,7 @@ AhciStopCommand (
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
   @param  CommandSlot        The number of Command Slot.\r
-  @param  Timeout            The timeout value of start.\r
+  @param  Timeout            The timeout value of start, uses 100ns as a unit.\r
 \r
   @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
   @retval EFI_TIMEOUT        The operation is time out.\r
@@ -1273,12 +1283,12 @@ AhciStartCommand (
   if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
     if ((Capability & BIT24) != 0) {\r
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
-      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
 \r
-      AhciWaitMemSet (\r
+      AhciWaitMmioSet (\r
         PciIo,\r
         Offset,\r
-        EFI_AHCI_PORT_CMD_COL,\r
+        EFI_AHCI_PORT_CMD_CLO,\r
         0,\r
         Timeout\r
         );\r
@@ -1307,7 +1317,7 @@ AhciStartCommand (
 \r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
-  @param  Timeout            The timeout value of reset.\r
+  @param  Timeout            The timeout value of reset, uses 100ns as a unit.\r
    \r
   @retval EFI_DEVICE_ERROR   The port reset unsuccessfully\r
   @retval EFI_TIMEOUT        The reset operation is time out.\r
@@ -1353,7 +1363,7 @@ AhciPortReset (
   // Wait for communication to be re-established\r
   //\r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-  Status = AhciWaitMemSet (\r
+  Status = AhciWaitMmioSet (\r
              PciIo,\r
              Offset,\r
              EFI_AHCI_PORT_SSTS_DET_MASK,\r
@@ -1375,7 +1385,7 @@ AhciPortReset (
   Do AHCI HBA reset.\r
 \r
   @param  PciIo              The PCI IO protocol instance.\r
-  @param  Timeout            The timeout value of reset.\r
+  @param  Timeout            The timeout value of reset, uses 100ns as a unit.\r
 \r
   @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.\r
   @retval EFI_TIMEOUT        The reset operation is time out.\r
@@ -1389,7 +1399,6 @@ AhciReset (
   IN  UINT64                    Timeout\r
   )    \r
 {\r
-  EFI_STATUS             Status;\r
   UINT32                 Delay;\r
   UINT32                 Value;\r
 \r
@@ -1397,8 +1406,6 @@ AhciReset (
 \r
   AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
 \r
-  Status  = EFI_TIMEOUT;\r
-\r
   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
 \r
   do {\r
@@ -1816,7 +1823,6 @@ AhciPacketCommandExecute (
   EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
   EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
   BOOLEAN                      Read;\r
-  UINT8                        Retry;\r
 \r
   if (Packet == NULL || Packet->Cdb == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -1860,35 +1866,21 @@ AhciPacketCommandExecute (
                NULL\r
                );\r
   } else {\r
-    //\r
-    // READ_CAPACITY cmd may execute failure. Retry 5 times\r
-    //\r
-    if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
-      Retry = 5;\r
-    } else {\r
-      Retry = 1;\r
-    }\r
-    do {\r
-      Status = AhciPioTransfer (\r
-                 PciIo,\r
-                 AhciRegisters,\r
-                 Port,\r
-                 PortMultiplier,\r
-                 Packet->Cdb,\r
-                 Packet->CdbLength,\r
-                 Read,\r
-                 &AtaCommandBlock,\r
-                 &AtaStatusBlock,\r
-                 Buffer,\r
-                 Length,\r
-                 Packet->Timeout, \r
-                 NULL\r
-                 );\r
-      if (!EFI_ERROR (Status)) {\r
-        break;\r
-      }\r
-      Retry--;\r
-    } while (Retry != 0);\r
+    Status = AhciPioTransfer (\r
+               PciIo,\r
+               AhciRegisters,\r
+               Port,\r
+               PortMultiplier,\r
+               Packet->Cdb,\r
+               Packet->CdbLength,\r
+               Read,\r
+               &AtaCommandBlock,\r
+               &AtaStatusBlock,\r
+               Buffer,\r
+               Length,\r
+               Packet->Timeout, \r
+               NULL\r
+               );\r
   }\r
   return Status;\r
 }\r
@@ -2152,8 +2144,6 @@ AhciModeInitialization (
   UINT32                           Capability;\r
   UINT8                            MaxPortNumber;\r
   UINT32                           PortImplementBitMap;\r
-  UINT8                            MaxCommandSlotNumber;\r
-  BOOLEAN                          Support64Bit;\r
 \r
   EFI_AHCI_REGISTERS               *AhciRegisters;\r
 \r
@@ -2165,7 +2155,8 @@ AhciModeInitialization (
   EFI_ATA_DEVICE_TYPE              DeviceType;\r
   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
   EFI_ATA_TRANSFER_MODE            TransferMode;\r
-  \r
+  UINT32                           PhyDetectDelay;\r
+\r
   if (Instance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -2173,7 +2164,7 @@ AhciModeInitialization (
   PciIo   = Instance->PciIo;\r
   IdeInit = Instance->IdeControllerInit;\r
 \r
-  Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
+  Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT); \r
 \r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
@@ -2192,15 +2183,13 @@ AhciModeInitialization (
   //\r
   // Get the number of command slots per port supported by this HBA.\r
   //\r
-  MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
-  Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
+  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
 \r
   //\r
   // Get the bit map of those ports exposed by this HBA.\r
   // It indicates which ports that the HBA supports are available for software to use. \r
   //\r
   PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
-  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
   \r
   AhciRegisters = &Instance->AhciRegisters;\r
   Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
@@ -2210,191 +2199,227 @@ AhciModeInitialization (
   }\r
 \r
   for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
-    Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
-  \r
-    //\r
-    // Single task envrionment, we only use one command table for all port\r
-    //\r
-    Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
-    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
-  \r
     if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+      IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
+\r
+      //\r
+      // Initialize FIS Base Address Register and Command List Base Address Register for use.\r
+      //\r
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
+      Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+      AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+\r
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
-  \r
-      if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
-        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
-      }\r
       Data = AhciReadReg (PciIo, Offset);\r
       if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
         AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
       }\r
-  \r
-      AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
-    }\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
-    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
\r
-    AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
-    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
-  \r
-    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
-    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
-    AhciAndReg (PciIo, Offset, 0);\r
-  \r
-    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
-    AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
-  }\r
 \r
-  //\r
-  // Stall for 100 milliseconds.\r
-  //\r
-  MicroSecondDelay(100000);\r
-  \r
-  IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
-  \r
-  for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
-    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
-    \r
-      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-      Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+      if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
+        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
+      }\r
+\r
+      //\r
+      // Disable aggressive power management.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);\r
+      //\r
+      // Disable the reporting of the corresponding interrupt to system software.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+      AhciAndReg (PciIo, Offset, 0);\r
 \r
-      if (Data == 0) {\r
+      //\r
+      // Now inform the IDE Controller Init Module.\r
+      //\r
+      IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+\r
+      //\r
+      // Enable FIS Receive DMA engine for the first D2H FIS.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
+      Status = AhciWaitMmioSet (\r
+                 PciIo, \r
+                 Offset,\r
+                 EFI_AHCI_PORT_CMD_FR,\r
+                 EFI_AHCI_PORT_CMD_FR,\r
+                 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
         continue;\r
       }\r
+\r
       //\r
-      // Found device in the port\r
+      // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
+      // It's the requirment from SATA1.0a spec section 5.2.\r
       //\r
-      if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
-        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
-\r
-        Status = AhciWaitMemSet (\r
-                   PciIo, \r
-                   Offset,\r
-                   0x0000FFFF,\r
-                   0x00000101,\r
-                   ATA_ATAPI_TIMEOUT\r
-                   );\r
-        if (EFI_ERROR (Status)) {\r
-          continue;\r
+      PhyDetectDelay = EFI_AHCI_BUS_PHY_DETECT_TIMEOUT;\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
+      do {\r
+        Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+        if ((Data == EFI_AHCI_PORT_SSTS_DET_PCE) || (Data == EFI_AHCI_PORT_SSTS_DET)) {\r
+          break;\r
         }\r
 \r
+        MicroSecondDelay (1000);\r
+        PhyDetectDelay--;\r
+      } while (PhyDetectDelay > 0);\r
+\r
+      if (PhyDetectDelay == 0) {\r
         //\r
-        // Now inform the IDE Controller Init Module.\r
+        // No device detected at this port.\r
         //\r
-        IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+        continue;\r
+      }\r
 \r
-        Data = AhciReadReg (PciIo, Offset);\r
+      //\r
+      // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ\r
+      // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.\r
+      //\r
+      PhyDetectDelay = 16 * 1000;\r
+      do {\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+        if (AhciReadReg(PciIo, Offset) != 0) {\r
+          AhciWriteReg (PciIo, Offset, AhciReadReg(PciIo, Offset));\r
+        }\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
 \r
-        if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
-          Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+        Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_TFD_MASK;\r
+        if (Data == 0) {\r
+          break;\r
+        }\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            continue;\r
-          }\r
+        MicroSecondDelay (1000);\r
+        PhyDetectDelay--;\r
+      } while (PhyDetectDelay > 0);\r
+      \r
+      if (PhyDetectDelay == 0) {\r
+        continue;\r
+      }\r
 \r
-          DeviceType = EfiIdeCdrom;\r
-        } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
-          Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+      //\r
+      // When the first D2H register FIS is received, the content of PxSIG register is updated.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+      Status = AhciWaitMmioSet (\r
+                 PciIo, \r
+                 Offset,\r
+                 0x0000FFFF,\r
+                 0x00000101,\r
+                 EFI_TIMER_PERIOD_SECONDS(16)\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
 \r
-          if (EFI_ERROR (Status)) {\r
-            REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
-            continue;\r
-          }\r
+      Data = AhciReadReg (PciIo, Offset);\r
+      if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
+        Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
 \r
-          DeviceType = EfiIdeHarddisk;\r
-        } else {\r
+        if (EFI_ERROR (Status)) {\r
           continue;\r
         }\r
 \r
-        DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
-            Port, 0, 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
-        if (DeviceType == EfiIdeHarddisk) {\r
-          AhciAtaSmartSupport (\r
-            PciIo,\r
-            AhciRegisters,\r
-            Port,\r
-            0,\r
-            &Buffer,\r
-            NULL\r
-            );\r
-        }\r
-\r
-        //\r
-        // Submit identify data to IDE controller init driver\r
-        //\r
-        IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
+        DeviceType = EfiIdeCdrom;\r
+      } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
+        Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
 \r
-        //\r
-        // Now start to config ide device parameter and transfer mode.\r
-        //\r
-        Status = IdeInit->CalculateMode (\r
-                            IdeInit,\r
-                            Port,\r
-                            0,\r
-                            &SupportedModes\r
-                            );\r
         if (EFI_ERROR (Status)) {\r
-          DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
           continue;\r
         }\r
 \r
-        //\r
-        // Set best supported PIO mode on this IDE device\r
-        //\r
-        if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
-        } else {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
-        }\r
+        DeviceType = EfiIdeHarddisk;\r
+      } else {\r
+        continue;\r
+      }\r
+      DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
+              Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
 \r
-        TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\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
-        // DMA mode operation fails, we can continue moving on because we only use\r
-        // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
-        //\r
-        if (SupportedModes->UdmaMode.Valid) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
-          TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
-        } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
-          TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
-          TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  \r
-        }\r
+      //\r
+      // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
+      //\r
+      if (DeviceType == EfiIdeHarddisk) {\r
+        AhciAtaSmartSupport (\r
+          PciIo,\r
+          AhciRegisters,\r
+          Port,\r
+          0,\r
+          &Buffer,\r
+          NULL\r
+          );\r
+      }\r
 \r
-        Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+      //\r
+      // Submit identify data to IDE controller init driver\r
+      //\r
+      IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
 \r
-        if (EFI_ERROR (Status)) {\r
-          DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
-          continue;\r
-        }\r
-        //\r
-        // Found a ATA or ATAPI device, add it into the device list.\r
-        //\r
-        CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
-        if (DeviceType == EfiIdeHarddisk) {\r
-          REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
-        }\r
+      //\r
+      // Now start to config ide device parameter and transfer mode.\r
+      //\r
+      Status = IdeInit->CalculateMode (\r
+                          IdeInit,\r
+                          Port,\r
+                          0,\r
+                          &SupportedModes\r
+                          );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Set best supported PIO mode on this IDE device\r
+      //\r
+      if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
+      } else {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
+      }\r
+\r
+      TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\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
+      // DMA mode operation fails, we can continue moving on because we only use\r
+      // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
+      //\r
+      if (SupportedModes->UdmaMode.Valid) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
+        TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
+      } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
+        TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
+        TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  \r
+      }\r
+\r
+      Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Found a ATA or ATAPI device, add it into the device list.\r
+      //\r
+      CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+      if (DeviceType == EfiIdeHarddisk) {\r
+        REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
       }\r
     }\r
   }\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r