]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg/AtaAtapiPassThru: Ensure GHC.AE bit is always set in Ahci
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 06b280a001af3f48506388228f29c4f557629822..4d01c1dd7fca2c70d97250e9bace7840135e4d09 100644 (file)
@@ -1,14 +1,15 @@
 /** @file\r
   The file for AHCI mode of ATA host controller.\r
-  \r
-  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials                          \r
-  are licensed and made available under the terms and conditions of the BSD License         \r
-  which accompanies this distribution.  The full text of the license may be found at        \r
-  http://opensource.org/licenses/bsd-license.php                                            \r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+  Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
 \r
@@ -33,7 +34,7 @@ AhciReadReg (
   UINT32                  Data;\r
 \r
   ASSERT (PciIo != NULL);\r
-  \r
+\r
   Data = 0;\r
 \r
   PciIo->Mem.Read (\r
@@ -95,7 +96,7 @@ AhciAndReg (
   )\r
 {\r
   UINT32 Data;\r
-  \r
+\r
   ASSERT (PciIo != NULL);\r
 \r
   Data  = AhciReadReg (PciIo, Offset);\r
@@ -133,36 +134,45 @@ AhciOrReg (
 }\r
 \r
 /**\r
-  Wait for memory set to the test value.\r
-    \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
   )\r
 {\r
-  UINT32     Value;  \r
-  UINT32     Delay;\r
+  UINT32     Value;\r
+  UINT64     Delay;\r
+  BOOLEAN    InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
 \r
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  Delay = 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
@@ -175,23 +185,123 @@ AhciWaitMemSet (
 \r
     Delay--;\r
 \r
-  } while (Delay > 0);\r
+  } while (InfiniteWait || (Delay > 0));\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\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
+  UINT64     Delay;\r
+  BOOLEAN    InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  Delay =  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
+  } while (InfiniteWait || (Delay > 0));\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Check the memory status to the test value.\r
+\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]  Task              Optional. Pointer to the ATA_NONBLOCK_TASK used by\r
+                                     non-blocking mode. If NULL, 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
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCheckMemSet (\r
+  IN     UINTN                     Address,\r
+  IN     UINT32                    MaskValue,\r
+  IN     UINT32                    TestValue,\r
+  IN OUT ATA_NONBLOCK_TASK         *Task\r
+  )\r
+{\r
+  UINT32     Value;\r
+\r
+  if (Task != NULL) {\r
+    Task->RetryTimes--;\r
+  }\r
+\r
+  Value  = *(volatile UINT32 *) Address;\r
+  Value &= MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
   }\r
 \r
-  return EFI_DEVICE_ERROR;\r
+  if ((Task != NULL) && !Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    return EFI_NOT_READY;\r
+  }\r
 }\r
 \r
 /**\r
-  Check if the device is still on port. It also checks if the AHCI controller \r
-  supports the address and data count will be transfered.\r
+  Check if the device is still on port. It also checks if the AHCI controller\r
+  supports the address and data count will be transferred.\r
 \r
   @param  PciIo            The PCI IO protocol instance.\r
   @param  Port             The number of port.\r
 \r
-  @retval EFI_SUCCESS      The device is attached to port and the transfer data is \r
+  @retval EFI_SUCCESS      The device is attached to port and the transfer data is\r
                            supported by AHCI controller.\r
   @retval EFI_UNSUPPORTED  The transfer address and count is not supported by AHCI\r
                            controller.\r
@@ -206,7 +316,7 @@ AhciCheckDeviceStatus (
   IN  UINT8                  Port\r
   )\r
 {\r
-  UINT32      Data; \r
+  UINT32      Data;\r
   UINT32      Offset;\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
@@ -214,7 +324,7 @@ AhciCheckDeviceStatus (
   Data   = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
 \r
   if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
-    return EFI_SUCCESS;      \r
+    return EFI_SUCCESS;\r
   }\r
 \r
   return EFI_NOT_READY;\r
@@ -224,23 +334,23 @@ AhciCheckDeviceStatus (
 \r
   Clear the port interrupt and error status. It will also clear\r
   HBA interrupt status.\r
-    \r
+\r
   @param      PciIo          The PCI IO protocol instance.\r
   @param      Port           The number of port.\r
-     \r
-**/ \r
+\r
+**/\r
 VOID\r
 EFIAPI\r
 AhciClearPortStatus (\r
   IN  EFI_PCI_IO_PROTOCOL    *PciIo,\r
   IN  UINT8                  Port\r
-  )  \r
+  )\r
 {\r
   UINT32 Offset;\r
 \r
   //\r
   // Clear any error status\r
-  //  \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
@@ -256,12 +366,67 @@ AhciClearPortStatus (
   AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
 }\r
 \r
+/**\r
+  This function is used to dump the Status Registers and if there is ERR bit set\r
+  in the Status Register, the Error Register's value is also be dumped.\r
+\r
+  @param  PciIo            The PCI IO protocol instance.\r
+  @param  AhciRegisters    The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port             The number of port.\r
+  @param  AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciDumpPortStatus (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock\r
+  )\r
+{\r
+  UINTN                Offset;\r
+  UINT32               Data;\r
+  UINTN                FisBaseAddr;\r
+  EFI_STATUS           Status;\r
+\r
+  ASSERT (PciIo != NULL);\r
+\r
+  if (AtaStatusBlock != NULL) {\r
+    ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+\r
+    FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+    Offset      = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+\r
+    Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // If D2H FIS is received, update StatusBlock with its content.\r
+      //\r
+      CopyMem (AtaStatusBlock, (UINT8 *)Offset, sizeof (EFI_ATA_STATUS_BLOCK));\r
+    } else {\r
+      //\r
+      // If D2H FIS is not received, only update Status & Error field through PxTFD\r
+      // as there is no other way to get the content of the Shadow Register Block.\r
+      //\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+      Data   = AhciReadReg (PciIo, (UINT32)Offset);\r
+\r
+      AtaStatusBlock->AtaStatus  = (UINT8)Data;\r
+      if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
+        AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
 /**\r
   Enable the FIS running for giving port.\r
-    \r
+\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
@@ -274,20 +439,14 @@ AhciEnableFisReceive (
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN  UINT8                     Port,\r
   IN  UINT64                    Timeout\r
-  )     \r
-{ \r
+  )\r
+{\r
   UINT32 Offset;\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
 \r
-  return AhciWaitMemSet (\r
-           PciIo, \r
-           Offset,\r
-           EFI_AHCI_PORT_CMD_FR,\r
-           EFI_AHCI_PORT_CMD_FR,\r
-           Timeout\r
-           );\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -295,7 +454,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
@@ -309,7 +468,7 @@ AhciDisableFisReceive (
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN  UINT8                     Port,\r
   IN  UINT64                    Timeout\r
-  )  \r
+  )\r
 {\r
   UINT32 Offset;\r
   UINT32 Data;\r
@@ -323,7 +482,7 @@ AhciDisableFisReceive (
   if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
     return EFI_UNSUPPORTED;\r
   }\r
-  \r
+\r
   //\r
   // Check if the Fis receive DMA engine for the port is running.\r
   //\r
@@ -333,20 +492,20 @@ AhciDisableFisReceive (
 \r
   AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
 \r
-  return AhciWaitMemSet (\r
-           PciIo, \r
+  return AhciWaitMmioSet (\r
+           PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_FR,\r
            0,\r
            Timeout\r
-           ); \r
+           );\r
 }\r
 \r
 \r
 \r
 /**\r
   Build the command list, command table and prepare the fis receiver.\r
-    \r
+\r
   @param    PciIo                 The PCI IO protocol instance.\r
   @param    AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
   @param    Port                  The number of port.\r
@@ -359,7 +518,7 @@ AhciDisableFisReceive (
   @param    DataPhysicalAddr      The pointer to the data buffer pci bus master address.\r
   @param    DataLength            The data count to be transferred.\r
 \r
-**/  \r
+**/\r
 VOID\r
 EFIAPI\r
 AhciBuildCommand (\r
@@ -373,12 +532,12 @@ AhciBuildCommand (
   IN     UINT8                      AtapiCommandLength,\r
   IN     UINT8                      CommandSlotNumber,\r
   IN OUT VOID                       *DataPhysicalAddr,\r
-  IN     UINT64                     DataLength\r
-  )   \r
+  IN     UINT32                     DataLength\r
+  )\r
 {\r
-  UINT64     BaseAddr; \r
-  UINT64     PrdtNumber;\r
-  UINT64     PrdtIndex;\r
+  UINT64     BaseAddr;\r
+  UINT32     PrdtNumber;\r
+  UINT32     PrdtIndex;\r
   UINTN      RemainedData;\r
   UINTN      MemAddr;\r
   DATA_64    Data64;\r
@@ -386,8 +545,8 @@ AhciBuildCommand (
 \r
   //\r
   // Filling the PRDT\r
-  //  \r
-  PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
+  //\r
+  PrdtNumber = (UINT32)DivU64x32 (((UINT64)DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1), EFI_AHCI_MAX_DATA_PER_PRDT);\r
 \r
   //\r
   // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
@@ -399,13 +558,13 @@ AhciBuildCommand (
   Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
 \r
   BaseAddr = Data64.Uint64;\r
-  \r
-  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));  \r
-    \r
+\r
+  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
+\r
   ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
 \r
   CommandFis->AhciCFisPmNum = PortMultiplier;\r
-  \r
+\r
   CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
@@ -418,19 +577,18 @@ AhciBuildCommand (
 \r
     CommandList->AhciCmdA = 1;\r
     CommandList->AhciCmdP = 1;\r
-    CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;\r
 \r
     AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
   } else {\r
     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
   }\r
-  \r
+\r
   RemainedData = (UINTN) DataLength;\r
   MemAddr      = (UINTN) DataPhysicalAddr;\r
-  CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
-  \r
+  CommandList->AhciCmdPrdtl = PrdtNumber;\r
+\r
   for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
-    if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {     \r
+    if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
     } else {\r
       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
@@ -439,7 +597,7 @@ AhciBuildCommand (
     Data64.Uint64 = (UINT64)MemAddr;\r
     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba  = Data64.Uint32.Lower32;\r
     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
-    RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;    \r
+    RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;\r
     MemAddr      += EFI_AHCI_MAX_DATA_PER_PRDT;\r
   }\r
 \r
@@ -454,7 +612,7 @@ AhciBuildCommand (
     (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
     CommandList,\r
     sizeof (EFI_AHCI_COMMAND_LIST)\r
-    );  \r
+    );\r
 \r
   Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
   AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;\r
@@ -465,7 +623,7 @@ AhciBuildCommand (
 \r
 /**\r
   Buid a command FIS.\r
-    \r
+\r
   @param  CmdFis            A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
   @param  AtaCommandBlock   A pointer to the AhciBuildCommandFis data structure.\r
 \r
@@ -483,7 +641,7 @@ AhciBuildCommandFis (
   //\r
   // Indicator it's a command\r
   //\r
-  CmdFis->AhciCFisCmdInd      = 0x1; \r
+  CmdFis->AhciCFisCmdInd      = 0x1;\r
   CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;\r
 \r
   CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;\r
@@ -506,19 +664,22 @@ AhciBuildCommandFis (
 \r
 /**\r
   Start a PIO data transfer on specific port.\r
-    \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  Read                The transfer direction.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  MemoryAddr          The pointer to the data buffer.\r
-  @param  DataCount           The data count to be transferred.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+\r
+  @param[in]       PciIo               The PCI IO protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @param[in]       AtapiCommandLength  The length of the atapi command.\r
+  @param[in]       Read                The transfer direction.\r
+  @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @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, uses 100ns as a unit.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The PIO data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -534,26 +695,37 @@ AhciPioTransfer (
   IN     UINT8                      Port,\r
   IN     UINT8                      PortMultiplier,\r
   IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
-  IN     UINT8                      AtapiCommandLength,  \r
-  IN     BOOLEAN                    Read,  \r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     BOOLEAN                    Read,\r
   IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
   IN OUT VOID                       *MemoryAddr,\r
   IN     UINT32                     DataCount,\r
-  IN     UINT64                     Timeout \r
+  IN     UINT64                     Timeout,\r
+  IN     ATA_NONBLOCK_TASK          *Task\r
   )\r
 {\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
+  UINT64                        Delay;\r
   EFI_AHCI_COMMAND_FIS          CFis;\r
   EFI_AHCI_COMMAND_LIST         CmdList;\r
+  UINT32                        PortTfd;\r
+  UINT32                        PrdCount;\r
+  BOOLEAN                       InfiniteWait;\r
+  BOOLEAN                       PioFisReceived;\r
+  BOOLEAN                       D2hFisReceived;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
 \r
   if (Read) {\r
     Flag = EfiPciIoOperationBusMasterWrite;\r
@@ -575,9 +747,9 @@ 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
   //\r
   // Package read needed\r
   //\r
@@ -600,83 +772,110 @@ AhciPioTransfer (
     0,\r
     (VOID *)(UINTN)PhyAddr,\r
     DataCount\r
-    );    \r
-  \r
+    );\r
+\r
   Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
+             PciIo,\r
+             Port,\r
              0,\r
              Timeout\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
-  \r
+\r
   //\r
-  // Checking the status and wait the driver sending data\r
+  // 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 = *(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  = DivU64x32 (Timeout, 1000) + 1;\r
+    do {\r
+      PioFisReceived = FALSE;\r
+      D2hFisReceived = FALSE;\r
+      Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, NULL);\r
+      if (!EFI_ERROR (Status)) {\r
+        PioFisReceived = TRUE;\r
+      }\r
+      //\r
+      // According to SATA 2.6 spec section 11.7, D2h FIS means an error encountered.\r
+      // But Qemu and Marvel 9230 sata controller may just receive a D2h FIS from device\r
+      // after the transaction is finished successfully.\r
+      // To get better device compatibilities, we further check if the PxTFD's ERR bit is set.\r
+      // By this way, we can know if there is a real error happened.\r
+      //\r
+      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
+      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, NULL);\r
+      if (!EFI_ERROR (Status)) {\r
+        D2hFisReceived = TRUE;\r
+      }\r
 \r
-    Delay--;    \r
-  } while (Delay > 0);\r
+      if (PioFisReceived || D2hFisReceived) {\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+        PortTfd = AhciReadReg (PciIo, (UINT32) Offset);\r
+        //\r
+        // PxTFD will be updated if there is a D2H or SetupFIS received. \r
+        //\r
+        if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {\r
+          Status = EFI_DEVICE_ERROR;\r
+          break;\r
+        }\r
 \r
-  if (Delay == 0) {\r
-    Status = EFI_TIMEOUT;\r
-    goto Exit;\r
-  }\r
+        PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
+        if (PrdCount == DataCount) {\r
+          Status = EFI_SUCCESS;\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
+      //\r
+      // Stall for 100 microseconds.\r
+      //\r
+      MicroSecondDelay(100);\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;   \r
-  }\r
+      Delay--;\r
+      if (Delay == 0) {\r
+        Status = EFI_TIMEOUT;\r
+      }\r
+    } while (InfiniteWait || (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
-  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
+    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
+Exit:\r
   AhciStopCommand (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
-  \r
+\r
   AhciDisableFisReceive (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
@@ -686,197 +885,251 @@ Exit:
     Map\r
     );\r
 \r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
+\r
   return Status;\r
 }\r
 \r
 /**\r
   Start a DMA data transfer on specific port\r
 \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  Read                The transfer direction.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  MemoryAddr          The pointer to the data buffer.\r
-  @param  DataCount           The data count to be transferred.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+  @param[in]       Instance            The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @param[in]       AtapiCommandLength  The length of the atapi command.\r
+  @param[in]       Read                The transfer direction.\r
+  @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @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, uses 100ns as a unit.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The DMA data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
   @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
   @retval EFI_SUCCESS         The DMA data transfer executes successfully.\r
-   \r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 AhciDmaTransfer (\r
-  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
   IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
   IN     UINT8                      Port,\r
   IN     UINT8                      PortMultiplier,\r
   IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
   IN     UINT8                      AtapiCommandLength,\r
-  IN     BOOLEAN                    Read,  \r
+  IN     BOOLEAN                    Read,\r
   IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
   IN OUT VOID                       *MemoryAddr,\r
-  IN     UINTN                      DataCount,\r
-  IN     UINT64                     Timeout\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
-  if (Read) {\r
-    Flag = EfiPciIoOperationBusMasterWrite;\r
-  } else {\r
-    Flag = EfiPciIoOperationBusMasterRead;\r
-  }\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  EFI_TPL                       OldTpl;\r
 \r
-  //\r
-  // construct command list and command table with pci bus address\r
-  //\r
-  MapLength = DataCount;\r
-  Status = PciIo->Map (\r
-                    PciIo,\r
-                    Flag,\r
-                    MemoryAddr,\r
-                    &MapLength,\r
-                    &PhyAddr,\r
-                    &Map\r
-                    );\r
+  Map   = NULL;\r
+  PciIo = Instance->PciIo;\r
 \r
-  if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+  if (PciIo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
-  // Package read needed\r
+  // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
+  // BlockIO tasks.\r
+  // Delay 100us to simulate the blocking time out checking.\r
   //\r
-  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
-\r
-  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+  while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
+    AsyncNonBlockingTransferRoutine (NULL, Instance);\r
+    //\r
+    // Stall for 100us.\r
+    //\r
+    MicroSecondDelay (100);\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
-  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
-  CmdList.AhciCmdW   = Read ? 0 : 1;\r
+  if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\r
+    //\r
+    // Mark the Task to indicate that it has been started.\r
+    //\r
+    if (Task != NULL) {\r
+      Task->IsStart      = TRUE;\r
+    }\r
+    if (Read) {\r
+      Flag = EfiPciIoOperationBusMasterWrite;\r
+    } else {\r
+      Flag = EfiPciIoOperationBusMasterRead;\r
+    }\r
 \r
-  AhciBuildCommand (\r
-    PciIo,\r
-    AhciRegisters,\r
-    Port,\r
-    PortMultiplier,\r
-    &CFis,\r
-    &CmdList,\r
-    AtapiCommand,\r
-    AtapiCommandLength,\r
-    0,\r
-    (VOID *)(UINTN)PhyAddr,\r
-    DataCount\r
-    ); \r
-  \r
-  Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
-             0,\r
-             Timeout\r
-             );\r
-  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
+    // Construct command list and command table with pci bus address.\r
+    //\r
+    MapLength = DataCount;\r
+    Status = PciIo->Map (\r
+                      PciIo,\r
+                      Flag,\r
+                      MemoryAddr,\r
+                      &MapLength,\r
+                      &PhyAddr,\r
+                      &Map\r
+                      );\r
+\r
+    if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
+      return EFI_BAD_BUFFER_SIZE;\r
+    }\r
+\r
+    if (Task != NULL) {\r
+      Task->Map = Map;\r
+    }\r
+    //\r
+    // Package read needed\r
+    //\r
+    AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+    ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+    CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+    CmdList.AhciCmdW   = Read ? 0 : 1;\r
+\r
+    AhciBuildCommand (\r
+      PciIo,\r
+      AhciRegisters,\r
+      Port,\r
+      PortMultiplier,\r
+      &CFis,\r
+      &CmdList,\r
+      AtapiCommand,\r
+      AtapiCommandLength,\r
+      0,\r
+      (VOID *)(UINTN)PhyAddr,\r
+      DataCount\r
+      );\r
+\r
+    Status = AhciStartCommand (\r
+               PciIo,\r
+               Port,\r
+               0,\r
+               Timeout\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
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             0xFFFFFFFF,\r
-             0,\r
-             Timeout\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\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
+               Offset,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
+               Task\r
+               );\r
+  } else {\r
+    Status = AhciWaitMemSet (\r
+               Offset,\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
+               Timeout\r
+               );\r
   }\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_DHRS,\r
-             EFI_AHCI_PORT_IS_DHRS,\r
-             Timeout\r
-             );  \r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
 \r
-Exit: \r
-  AhciStopCommand (\r
-    PciIo, \r
-    Port,\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
-  AhciDisableFisReceive (\r
-    PciIo, \r
-    Port,\r
-    Timeout\r
-    );\r
+Exit:\r
+  //\r
+  // For Blocking mode, the command should be stopped, the Fis should be disabled\r
+  // and the PciIo should be unmapped.\r
+  // For non-blocking mode, only when a error is happened (if the return status is\r
+  // EFI_NOT_READY that means the command doesn't finished, try again.), first do the\r
+  // context cleanup, then set the packet's Asb status.\r
+  //\r
+  if (Task == NULL ||\r
+      ((Task != NULL) && (Status != EFI_NOT_READY))\r
+     ) {\r
+    AhciStopCommand (\r
+      PciIo,\r
+      Port,\r
+      Timeout\r
+      );\r
 \r
-  PciIo->Unmap (\r
-           PciIo,\r
-           Map\r
-           );  \r
-  \r
+    AhciDisableFisReceive (\r
+      PciIo,\r
+      Port,\r
+      Timeout\r
+      );\r
+\r
+    PciIo->Unmap (\r
+             PciIo,\r
+             (Task != NULL) ? Task->Map : Map\r
+             );\r
+\r
+    if (Task != NULL) {\r
+      Task->Packet->Asb->AtaStatus = 0x01;\r
+    }\r
+  }\r
+\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
   return Status;\r
 }\r
 \r
 /**\r
   Start a non data transfer on specific port.\r
-    \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+\r
+  @param[in]       PciIo               The PCI IO protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @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, uses 100ns as a unit.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The non data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
   @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
   @retval EFI_SUCCESS         The non data transfer executes successfully.\r
 \r
-**/ \r
+**/\r
 EFI_STATUS\r
 EFIAPI\r
 AhciNonDataTransfer (\r
@@ -888,15 +1141,14 @@ AhciNonDataTransfer (
   IN     UINT8                         AtapiCommandLength,\r
   IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
-  IN     UINT64                        Timeout\r
-  ) \r
+  IN     UINT64                        Timeout,\r
+  IN     ATA_NONBLOCK_TASK             *Task\r
+  )\r
 {\r
-  EFI_STATUS                   Status;  \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
@@ -921,79 +1173,65 @@ AhciNonDataTransfer (
     0,\r
     NULL,\r
     0\r
-    ); \r
-  \r
+    );\r
+\r
   Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
+             PciIo,\r
+             Port,\r
              0,\r
              Timeout\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
-  \r
+\r
   //\r
   // 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 = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\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
+  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
-    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
+  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
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             0xFFFFFFFF,\r
-             0,\r
-             Timeout\r
-             );  \r
-  \r
-Exit:  \r
+Exit:\r
   AhciStopCommand (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
 \r
   AhciDisableFisReceive (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
 \r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
+\r
   return Status;\r
 }\r
 \r
 /**\r
   Stop command running for giving port\r
-    \r
+\r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
-  @param  Timeout            The timeout value of stop.\r
-   \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
   @retval EFI_SUCCESS        The command stop successfully.\r
@@ -1014,30 +1252,30 @@ AhciStopCommand (
   Data   = AhciReadReg (PciIo, Offset);\r
 \r
   if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {\r
-    return EFI_SUCCESS;    \r
+    return EFI_SUCCESS;\r
   }\r
 \r
   if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
   }\r
 \r
-  return AhciWaitMemSet (\r
-           PciIo, \r
+  return AhciWaitMmioSet (\r
+           PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_CR,\r
            0,\r
            Timeout\r
-           ); \r
+           );\r
 }\r
 \r
 /**\r
   Start command for give slot on specific port.\r
-    \r
+\r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
-  @param  CommandSlot        The number of CommandSlot.\r
-  @param  Timeout            The timeout value of start.\r
-   \r
+  @param  CommandSlot        The number of Command Slot.\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
   @retval EFI_SUCCESS        The command start successfully.\r
@@ -1073,29 +1311,18 @@ AhciStartCommand (
     );\r
 \r
   Status = AhciEnableFisReceive (\r
-             PciIo, \r
+             PciIo,\r
              Port,\r
              Timeout\r
              );\r
-  \r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  //\r
-  // Setting the command\r
-  //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
-  AhciAndReg (PciIo, Offset, 0);\r
-  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
-  AhciAndReg (PciIo, Offset, 0);\r
-  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
-\r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
   PortStatus = AhciReadReg (PciIo, Offset);\r
-  \r
+\r
   StartCmd = 0;\r
   if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
     StartCmd = AhciReadReg (PciIo, Offset);\r
@@ -1109,21 +1336,28 @@ 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
-        PciIo, \r
+      AhciWaitMmioSet (\r
+        PciIo,\r
         Offset,\r
-        EFI_AHCI_PORT_CMD_COL,\r
+        EFI_AHCI_PORT_CMD_CLO,\r
         0,\r
         Timeout\r
-        ); \r
+        );\r
     }\r
   }\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_ST | StartCmd);\r
 \r
+  //\r
+  // Setting the command\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  AhciAndReg (PciIo, Offset, 0);\r
+  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1132,8 +1366,8 @@ 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
-   \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
   @retval EFI_SUCCESS        The port reset successfully.\r
@@ -1148,8 +1382,8 @@ AhciPortReset (
   )\r
 {\r
   EFI_STATUS      Status;\r
-  UINT32          Offset;  \r
-  \r
+  UINT32          Offset;\r
+\r
   AhciClearPortStatus (PciIo, Port);\r
 \r
   AhciStopCommand (PciIo, Port, Timeout);\r
@@ -1163,14 +1397,14 @@ AhciPortReset (
   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
 \r
   //\r
-  // wait 5 milliseceond before de-assert DET  \r
+  // wait 5 millisecond before de-assert DET\r
   //\r
   MicroSecondDelay (5000);\r
 \r
   AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
 \r
   //\r
-  // wait 5 milliseceond before de-assert DET  \r
+  // wait 5 millisecond before de-assert DET\r
   //\r
   MicroSecondDelay (5000);\r
 \r
@@ -1178,15 +1412,16 @@ 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
              EFI_AHCI_PORT_SSTS_DET_PCE,\r
              Timeout\r
-             ); \r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Port %d COMRESET failed: %r\n", Port, Status));\r
     return Status;\r
   }\r
 \r
@@ -1198,11 +1433,10 @@ AhciPortReset (
 \r
 /**\r
   Do AHCI HBA reset.\r
-    \r
+\r
   @param  PciIo              The PCI IO protocol instance.\r
-  @param  Timeout            The timeout value of reset.\r
\r
-   \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
   @retval EFI_SUCCESS        AHCI controller is reset successfully.\r
@@ -1213,19 +1447,23 @@ EFIAPI
 AhciReset (\r
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN  UINT64                    Timeout\r
-  )    \r
+  )\r
 {\r
-  EFI_STATUS             Status;\r
-  UINT32                 Delay;\r
+  UINT64                 Delay;\r
   UINT32                 Value;\r
 \r
-  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  //\r
+  // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
+  //\r
+  Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
 \r
-  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
+  if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+    AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
 \r
-  Status  = EFI_TIMEOUT;\r
+  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
 \r
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  Delay = DivU64x32(Timeout, 1000) + 1;\r
 \r
   do {\r
     Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
@@ -1249,13 +1487,227 @@ AhciReset (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The port multiplier port number.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS     Successfully get the return status of S.M.A.R.T command execution.\r
+  @retval Others          Fail to get return status data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAtaSmartReturnStatusCheck (\r
+  IN EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN EFI_AHCI_REGISTERS          *AhciRegisters,\r
+  IN UINT8                       Port,\r
+  IN UINT8                       PortMultiplier,\r
+  IN OUT EFI_ATA_STATUS_BLOCK    *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;\r
+  UINT8                   LBAMid;\r
+  UINT8                   LBAHigh;\r
+  UINTN                   FisBaseAddr;\r
+  UINT32                  Value;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+  AtaCommandBlock.AtaFeatures     = ATA_SMART_RETURN_STATUS;\r
+  AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+  AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+  //\r
+  // Send S.M.A.R.T Read Return Status command to device\r
+  //\r
+  Status = AhciNonDataTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             (UINT8)Port,\r
+             (UINT8)PortMultiplier,\r
+             NULL,\r
+             0,\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+      );\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  REPORT_STATUS_CODE (\r
+    EFI_PROGRESS_CODE,\r
+    (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+    );\r
+\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+\r
+  Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
+    LBAMid  = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
+    LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
+\r
+    if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+      //\r
+      // The threshold exceeded condition is not detected by the device\r
+      //\r
+      DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
+      REPORT_STATUS_CODE (\r
+            EFI_PROGRESS_CODE,\r
+            (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+            );\r
+    } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+      //\r
+      // The threshold exceeded condition is detected by the device\r
+      //\r
+      DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is detected\n"));\r
+      REPORT_STATUS_CODE (\r
+           EFI_PROGRESS_CODE,\r
+           (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+           );\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable SMART command of the disk if supported.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The port multiplier port number.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAtaSmartSupport (\r
+  IN EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN UINT8                         Port,\r
+  IN UINT8                         PortMultiplier,\r
+  IN EFI_IDENTIFY_DATA             *IdentifyData,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;\r
+\r
+  //\r
+  // Detect if the device supports S.M.A.R.T.\r
+  //\r
+  if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+    //\r
+    // S.M.A.R.T is not supported by the device\r
+    //\r
+    DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n",\r
+            Port, PortMultiplier));\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+      );\r
+  } else {\r
+    //\r
+    // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
+    //\r
+    if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
+\r
+      REPORT_STATUS_CODE (\r
+        EFI_PROGRESS_CODE,\r
+        (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLE)\r
+        );\r
+\r
+      ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+      AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+      AtaCommandBlock.AtaFeatures     = ATA_SMART_ENABLE_OPERATION;\r
+      AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+      AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+      //\r
+      // Send S.M.A.R.T Enable command to device\r
+      //\r
+      Status = AhciNonDataTransfer (\r
+                 PciIo,\r
+                 AhciRegisters,\r
+                 (UINT8)Port,\r
+                 (UINT8)PortMultiplier,\r
+                 NULL,\r
+                 0,\r
+                 &AtaCommandBlock,\r
+                 AtaStatusBlock,\r
+                 ATA_ATAPI_TIMEOUT,\r
+                 NULL\r
+                 );\r
+\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Send S.M.A.R.T AutoSave command to device\r
+        //\r
+        ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+        AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+        AtaCommandBlock.AtaFeatures     = 0xD2;\r
+        AtaCommandBlock.AtaSectorCount  = 0xF1;\r
+        AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+        AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+        Status = AhciNonDataTransfer (\r
+                   PciIo,\r
+                   AhciRegisters,\r
+                   (UINT8)Port,\r
+                   (UINT8)PortMultiplier,\r
+                   NULL,\r
+                   0,\r
+                   &AtaCommandBlock,\r
+                   AtaStatusBlock,\r
+                   ATA_ATAPI_TIMEOUT,\r
+                   NULL\r
+                   );\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = AhciAtaSmartReturnStatusCheck (\r
+                     PciIo,\r
+                     AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplier,\r
+                     AtaStatusBlock\r
+                     );\r
+        }\r
+      }\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
+            Port, PortMultiplier));\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   Send Buffer cmd to specific device.\r
-    \r
+\r
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
@@ -1271,7 +1723,7 @@ AhciIdentify (
   IN EFI_AHCI_REGISTERS       *AhciRegisters,\r
   IN UINT8                    Port,\r
   IN UINT8                    PortMultiplier,\r
-  IN OUT EFI_IDENTIFY_DATA    *Buffer  \r
+  IN OUT EFI_IDENTIFY_DATA    *Buffer\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
@@ -1284,7 +1736,7 @@ AhciIdentify (
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;\r
   AtaCommandBlock.AtaSectorCount = 1;\r
 \r
@@ -1300,7 +1752,8 @@ AhciIdentify (
              &AtaStatusBlock,\r
              Buffer,\r
              sizeof (EFI_IDENTIFY_DATA),\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -1308,11 +1761,11 @@ AhciIdentify (
 \r
 /**\r
   Send Buffer cmd to specific device.\r
-    \r
+\r
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
@@ -1328,7 +1781,7 @@ AhciIdentifyPacket (
   IN EFI_AHCI_REGISTERS       *AhciRegisters,\r
   IN UINT8                    Port,\r
   IN UINT8                    PortMultiplier,\r
-  IN OUT EFI_IDENTIFY_DATA    *Buffer  \r
+  IN OUT EFI_IDENTIFY_DATA    *Buffer\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
@@ -1338,7 +1791,7 @@ AhciIdentifyPacket (
   if (PciIo == NULL || AhciRegisters == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
 \r
@@ -1357,7 +1810,8 @@ AhciIdentifyPacket (
              &AtaStatusBlock,\r
              Buffer,\r
              sizeof (EFI_IDENTIFY_DATA),\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -1365,11 +1819,11 @@ AhciIdentifyPacket (
 \r
 /**\r
   Send SET FEATURE cmd on specific device.\r
-    \r
+\r
   @param  PciIo               The PCI IO protocol instance.\r
   @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
   @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
+  @param  PortMultiplier      The port multiplier port number.\r
   @param  Feature             The data to send Feature register.\r
   @param  FeatureSpecificData The specific data for SET FEATURE cmd.\r
 \r
@@ -1396,7 +1850,7 @@ AhciDeviceSetFeature (
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand      = ATA_CMD_SET_FEATURES;\r
   AtaCommandBlock.AtaFeatures     = (UINT8) Feature;\r
   AtaCommandBlock.AtaFeaturesExp  = (UINT8) (Feature >> 8);\r
@@ -1414,19 +1868,20 @@ AhciDeviceSetFeature (
              0,\r
              &AtaCommandBlock,\r
              &AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
 }\r
 \r
 /**\r
-  This function is used to send out ATAPI commands conforms to the Packet Command \r
+  This function is used to send out ATAPI commands conforms to the Packet Command\r
   with PIO Protocol.\r
 \r
   @param PciIo              The PCI IO protocol instance.\r
   @param AhciRegisters      The pointer to the EFI_AHCI_REGISTERS.\r
-  @param Port               The number of port.     \r
+  @param Port               The number of port.\r
   @param PortMultiplier     The number of port multiplier.\r
   @param Packet             A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
 \r
@@ -1451,7 +1906,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
@@ -1481,7 +1935,7 @@ AhciPacketCommandExecute (
     Read = FALSE;\r
   }\r
 \r
-  if (Length == 0) {    \r
+  if (Length == 0) {\r
     Status = AhciNonDataTransfer (\r
                PciIo,\r
                AhciRegisters,\r
@@ -1491,44 +1945,32 @@ AhciPacketCommandExecute (
                Packet->CdbLength,\r
                &AtaCommandBlock,\r
                &AtaStatusBlock,\r
-               Packet->Timeout\r
+               Packet->Timeout,\r
+               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
-                 );\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
 \r
 /**\r
   Allocate transfer-related data struct which is used at AHCI mode.\r
-  \r
+\r
   @param  PciIo                 The PCI IO protocol instance.\r
   @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
 \r
@@ -1545,31 +1987,43 @@ AhciCreateTransferDescriptor (
   VOID                  *Buffer;\r
 \r
   UINT32                Capability;\r
+  UINT32                PortImplementBitMap;\r
   UINT8                 MaxPortNumber;\r
   UINT8                 MaxCommandSlotNumber;\r
   BOOLEAN               Support64Bit;\r
   UINT64                MaxReceiveFisSize;\r
   UINT64                MaxCommandListSize;\r
   UINT64                MaxCommandTableSize;\r
+  EFI_PHYSICAL_ADDRESS  AhciRFisPciAddr;\r
+  EFI_PHYSICAL_ADDRESS  AhciCmdListPciAddr;\r
+  EFI_PHYSICAL_ADDRESS  AhciCommandTablePciAddr;\r
 \r
   Buffer = NULL;\r
   //\r
   // Collect AHCI controller information\r
   //\r
   Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
-  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
   //\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
+  \r
+  PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
+  //\r
+  // Get the highest bit of implemented ports which decides how many bytes are allocated for recived FIS.\r
+  //\r
+  MaxPortNumber        = (UINT8)(UINTN)(HighBitSet32(PortImplementBitMap) + 1);\r
+  if (MaxPortNumber == 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
   MaxReceiveFisSize    = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
   Status = PciIo->AllocateBuffer (\r
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1589,25 +2043,26 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *) &AhciRegisters->AhciRFisPciAddr,\r
+                    &AhciRFisPciAddr,\r
                     &AhciRegisters->MapRFis\r
                     );\r
 \r
   if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
     //\r
-    // Map error or unable to map the whole RFis buffer into a contiguous region. \r
+    // Map error or unable to map the whole RFis buffer into a contiguous region.\r
     //\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Error6;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciRFisPciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error5;\r
   }\r
+  AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
 \r
   //\r
   // Allocate memory for command list\r
@@ -1619,14 +2074,14 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
                     &Buffer,\r
                     0\r
                     );\r
 \r
   if (EFI_ERROR (Status)) {\r
     //\r
-    // Free mapped resource. \r
+    // Free mapped resource.\r
     //\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Error5;\r
@@ -1643,7 +2098,7 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCmdListPciAddr,\r
+                    &AhciCmdListPciAddr,\r
                     &AhciRegisters->MapCmdList\r
                     );\r
 \r
@@ -1655,13 +2110,14 @@ AhciCreateTransferDescriptor (
     goto Error4;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCmdListPciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error3;\r
   }\r
+  AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
 \r
   //\r
   // Allocate memory for command table\r
@@ -1674,14 +2130,14 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
                     &Buffer,\r
                     0\r
                     );\r
 \r
   if (EFI_ERROR (Status)) {\r
     //\r
-    // Free mapped resource. \r
+    // Free mapped resource.\r
     //\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto Error3;\r
@@ -1698,7 +2154,7 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCommandTablePciAddr,\r
+                    &AhciCommandTablePciAddr,\r
                     &AhciRegisters->MapCommandTable\r
                     );\r
 \r
@@ -1710,17 +2166,18 @@ AhciCreateTransferDescriptor (
     goto Error2;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCommandTablePciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error1;\r
   }\r
+  AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
 \r
   return EFI_SUCCESS;\r
   //\r
-  // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
+  // Map error or unable to map the whole CmdList buffer into a contiguous region.\r
   //\r
 Error1:\r
   PciIo->Unmap (\r
@@ -1730,7 +2187,7 @@ Error1:
 Error2:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
            AhciRegisters->AhciCommandTable\r
            );\r
 Error3:\r
@@ -1741,7 +2198,7 @@ Error3:
 Error4:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
            AhciRegisters->AhciCmdList\r
            );\r
 Error5:\r
@@ -1752,7 +2209,7 @@ Error5:
 Error6:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
            AhciRegisters->AhciRFis\r
            );\r
 \r
@@ -1762,8 +2219,8 @@ Error6:
 /**\r
   Initialize ATA host controller at AHCI mode.\r
 \r
-  The function is designed to initialize ATA host controller. \r
-  \r
+  The function is designed to initialize ATA host controller.\r
+\r
   @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
 \r
 **/\r
@@ -1779,8 +2236,6 @@ AhciModeInitialization (
   UINT32                           Capability;\r
   UINT8                            MaxPortNumber;\r
   UINT32                           PortImplementBitMap;\r
-  UINT8                            MaxCommandSlotNumber;\r
-  BOOLEAN                          Support64Bit;\r
 \r
   EFI_AHCI_REGISTERS               *AhciRegisters;\r
 \r
@@ -1792,7 +2247,9 @@ AhciModeInitialization (
   EFI_ATA_DEVICE_TYPE              DeviceType;\r
   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
   EFI_ATA_TRANSFER_MODE            TransferMode;\r
-  \r
+  UINT32                           PhyDetectDelay;\r
+  UINT32                           Value;\r
+\r
   if (Instance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -1800,35 +2257,55 @@ 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
   }\r
 \r
   //\r
-  // Enable AE before accessing any AHCI registers\r
+  // Collect AHCI controller information\r
   //\r
-  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  Capability = AhciReadReg (PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
 \r
   //\r
-  // Collect AHCI controller information\r
+  // Make sure that GHC.AE bit is set before accessing any AHCI registers.\r
   //\r
-  Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+  Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+    AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
+\r
+  //\r
+  // Enable 64-bit DMA support in the PCI layer if this controller\r
+  // supports it.\r
+  //\r
+  if ((Capability & EFI_AHCI_CAP_S64A) != 0) {\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
+                      NULL\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_WARN,\r
+        "AhciModeInitialization: failed to enable 64-bit DMA on 64-bit capable controller (%r)\n",\r
+        Status));\r
+    }\r
+  }\r
 \r
   //\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
+  // 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
+\r
   AhciRegisters = &Instance->AhciRegisters;\r
   Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
 \r
@@ -1836,174 +2313,233 @@ AhciModeInitialization (
     return EFI_OUT_OF_RESOURCES;\r
   }\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
+  for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
     if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\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
+      // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
+      //\r
+      if ((MaxPortNumber--) == 0) {\r
+        //\r
+        // Should never be here.\r
+        //\r
+        ASSERT (FALSE);\r
+        return EFI_SUCCESS;\r
       }\r
+\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
       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
-\r
-      if (Data == 0) {\r
-        continue;\r
+      if ((Capability & EFI_AHCI_CAP_SSS) != 0) {\r
+        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
       }\r
+\r
       //\r
-      // Found device in the port\r
+      // Disable aggressive power management.\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
+      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
+      //\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
+\r
+      //\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
+      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
+        // Clear PxCMD.SUD for those ports at which there are no device present.\r
         //\r
-        IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+        AhciAndReg (PciIo, Offset, (UINT32) ~(EFI_AHCI_PORT_CMD_SUD));\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
-          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
+      if (PhyDetectDelay == 0) {\r
+        DEBUG ((EFI_D_ERROR, "Port %d Device presence detected but phy not ready (TFD=0x%X)\n", Port, Data));\r
+        continue;\r
+      }\r
+\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
-            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
-        // 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) && PcdGetBool (PcdAtaSmartEnable)) {\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
+      //\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, 0xFFFF, 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