]> 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 0bc54abbf7255512837cf0f71e30cd1f52fe50a4..4d01c1dd7fca2c70d97250e9bace7840135e4d09 100644 (file)
@@ -1,14 +1,15 @@
 /** @file\r
   The file for AHCI mode of ATA host controller.\r
-  \r
-  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials                          \r
-  are licensed and made available under the terms and conditions of the BSD License         \r
-  which accompanies this distribution.  The full text of the license may be found at        \r
-  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
-  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\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,80 @@ 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
-  return EFI_DEVICE_ERROR;\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]       PciIo             The PCI IO protocol instance.\r
-  @param[in]       Offset            The memory address to test.\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]  RetryTimes        The retry times value for waitting memory set.\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
@@ -201,24 +268,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 ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   UINT32     Value;\r
 \r
-  (*RetryTimes) --;\r
-  \r
-  Value = AhciReadReg (PciIo, Offset) & MaskValue;\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
-  if ((*RetryTimes) == 0) {\r
+  if ((Task != NULL) && !Task->InfiniteWait && (Task->RetryTimes == 0)) {\r
     return EFI_TIMEOUT;\r
   } else {\r
     return EFI_NOT_READY;\r
@@ -226,13 +295,13 @@ AhciCheckMemSet (
 }\r
 \r
 /**\r
-  Check if the device is still on port. It also checks if the AHCI controller \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
@@ -265,17 +334,17 @@ 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
@@ -302,6 +371,7 @@ AhciClearPortStatus (
   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
@@ -310,24 +380,42 @@ VOID
 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
-  UINT32               Offset;\r
+  UINT               Offset;\r
   UINT32               Data;\r
+  UINTN                FisBaseAddr;\r
+  EFI_STATUS           Status;\r
 \r
   ASSERT (PciIo != NULL);\r
 \r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
-  Data   = AhciReadReg (PciIo, Offset);\r
-\r
   if (AtaStatusBlock != NULL) {\r
     ZeroMem (AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
 \r
-    AtaStatusBlock->AtaStatus  = (UINT8)Data;\r
-    if ((AtaStatusBlock->AtaStatus & BIT0) != 0) {\r
-      AtaStatusBlock->AtaError = (UINT8)(Data >> 8);\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
@@ -335,10 +423,10 @@ AhciDumpPortStatus (
 \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
@@ -358,13 +446,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
-           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
@@ -372,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
@@ -386,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
@@ -400,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
@@ -410,7 +492,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
@@ -423,7 +505,7 @@ AhciDisableFisReceive (
 \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
@@ -436,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
@@ -450,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
+  UINT32     PrdtNumber;\r
+  UINT32     PrdtIndex;\r
   UINTN      RemainedData;\r
   UINTN      MemAddr;\r
   DATA_64    Data64;\r
@@ -463,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
@@ -476,13 +558,13 @@ AhciBuildCommand (
   Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
 \r
   BaseAddr = Data64.Uint64;\r
-  \r
+\r
   ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
-    \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
@@ -495,17 +577,16 @@ 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
       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
@@ -531,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
@@ -542,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
@@ -560,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
@@ -583,7 +664,7 @@ AhciBuildCommandFis (
 \r
 /**\r
   Start a PIO data transfer on specific port.\r
-    \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
@@ -596,7 +677,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
@@ -614,8 +695,8 @@ 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
@@ -626,15 +707,25 @@ 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
+  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
@@ -658,7 +749,7 @@ AhciPioTransfer (
   if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
-  \r
+\r
   //\r
   // Package read needed\r
   //\r
@@ -681,8 +772,8 @@ AhciPioTransfer (
     0,\r
     (VOID *)(UINTN)PhyAddr,\r
     DataCount\r
-    );    \r
-  \r
+    );\r
+\r
   Status = AhciStartCommand (\r
              PciIo,\r
              Port,\r
@@ -697,56 +788,83 @@ 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  = 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
@@ -755,7 +873,7 @@ Exit:
     Port,\r
     Timeout\r
     );\r
-  \r
+\r
   AhciDisableFisReceive (\r
     PciIo,\r
     Port,\r
@@ -767,7 +885,7 @@ Exit:
     Map\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
 \r
   return Status;\r
 }\r
@@ -787,7 +905,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
@@ -806,26 +924,28 @@ AhciDmaTransfer (
   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     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
@@ -839,15 +959,15 @@ AhciDmaTransfer (
   // BlockIO tasks.\r
   // Delay 100us to simulate the blocking time out checking.\r
   //\r
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
   while ((Task == NULL) && (!IsListEmpty (&Instance->NonBlockingTaskList))) {\r
-    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
     AsyncNonBlockingTransferRoutine (NULL, Instance);\r
-    gBS->RestoreTPL (OldTpl);  \r
     //\r
     // Stall for 100us.\r
     //\r
     MicroSecondDelay (100);\r
   }\r
+  gBS->RestoreTPL (OldTpl);\r
 \r
   if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\r
     //\r
@@ -855,7 +975,6 @@ AhciDmaTransfer (
     //\r
     if (Task != NULL) {\r
       Task->IsStart      = TRUE;\r
-      Task->RetryTimes   = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
     }\r
     if (Read) {\r
       Flag = EfiPciIoOperationBusMasterWrite;\r
@@ -916,45 +1035,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
-               (UINTN *) (&Task->RetryTimes)\r
+               EFI_AHCI_FIS_TYPE_MASK,\r
+               EFI_AHCI_FIS_REGISTER_D2H,\r
+               Task\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,52 +1065,31 @@ 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
   //\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
+  // 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
+      PciIo,\r
       Port,\r
       Timeout\r
       );\r
 \r
     AhciDisableFisReceive (\r
-      PciIo, \r
+      PciIo,\r
       Port,\r
       Timeout\r
       );\r
@@ -1023,13 +1104,13 @@ Exit:
     }\r
   }\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
   return Status;\r
 }\r
 \r
 /**\r
   Start a non data transfer on specific port.\r
-    \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
@@ -1039,7 +1120,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
@@ -1048,7 +1129,7 @@ Exit:
   @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
@@ -1066,10 +1147,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 +1189,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
@@ -1157,18 +1220,18 @@ Exit:
     Timeout\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\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
@@ -1196,7 +1259,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 +1274,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
@@ -1248,7 +1311,7 @@ AhciStartCommand (
     );\r
 \r
   Status = AhciEnableFisReceive (\r
-             PciIo, \r
+             PciIo,\r
              Port,\r
              Timeout\r
              );\r
@@ -1275,7 +1338,7 @@ AhciStartCommand (
       Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_CLO);\r
 \r
-      AhciWaitMemSet (\r
+      AhciWaitMmioSet (\r
         PciIo,\r
         Offset,\r
         EFI_AHCI_PORT_CMD_CLO,\r
@@ -1291,10 +1354,6 @@ AhciStartCommand (
   //\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
@@ -1307,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
@@ -1353,7 +1412,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
@@ -1362,6 +1421,7 @@ AhciPortReset (
              );\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
@@ -1375,7 +1435,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
@@ -1387,16 +1447,23 @@ EFIAPI
 AhciReset (\r
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN  UINT64                    Timeout\r
-  )    \r
+  )\r
 {\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
+  if ((Value & EFI_AHCI_GHC_ENABLE) == 0) {\r
+    AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+  }\r
 \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
@@ -1426,7 +1493,7 @@ AhciReset (
   @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  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
@@ -1474,9 +1541,18 @@ AhciAtaSmartReturnStatusCheck (
              );\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
@@ -1490,12 +1566,19 @@ AhciAtaSmartReturnStatusCheck (
       // 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
-\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
@@ -1508,7 +1591,7 @@ AhciAtaSmartReturnStatusCheck (
   @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  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
@@ -1534,13 +1617,23 @@ AhciAtaSmartSupport (
     //\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
+    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
@@ -1610,11 +1703,11 @@ AhciAtaSmartSupport (
 \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
@@ -1630,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
@@ -1659,7 +1752,7 @@ AhciIdentify (
              &AtaStatusBlock,\r
              Buffer,\r
              sizeof (EFI_IDENTIFY_DATA),\r
-             ATA_ATAPI_TIMEOUT, \r
+             ATA_ATAPI_TIMEOUT,\r
              NULL\r
              );\r
 \r
@@ -1668,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
@@ -1688,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
@@ -1726,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
@@ -1775,7 +1868,7 @@ AhciDeviceSetFeature (
              0,\r
              &AtaCommandBlock,\r
              &AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT, \r
+             ATA_ATAPI_TIMEOUT,\r
              NULL\r
              );\r
 \r
@@ -1783,12 +1876,12 @@ AhciDeviceSetFeature (
 }\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
@@ -1852,7 +1945,7 @@ AhciPacketCommandExecute (
                Packet->CdbLength,\r
                &AtaCommandBlock,\r
                &AtaStatusBlock,\r
-               Packet->Timeout, \r
+               Packet->Timeout,\r
                NULL\r
                );\r
   } else {\r
@@ -1868,7 +1961,7 @@ AhciPacketCommandExecute (
                &AtaStatusBlock,\r
                Buffer,\r
                Length,\r
-               Packet->Timeout, \r
+               Packet->Timeout,\r
                NULL\r
                );\r
   }\r
@@ -1877,7 +1970,7 @@ AhciPacketCommandExecute (
 \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
@@ -1894,6 +1987,7 @@ AhciCreateTransferDescriptor (
   VOID                  *Buffer;\r
 \r
   UINT32                Capability;\r
+  UINT32                PortImplementBitMap;\r
   UINT8                 MaxPortNumber;\r
   UINT8                 MaxCommandSlotNumber;\r
   BOOLEAN               Support64Bit;\r
@@ -1909,12 +2003,20 @@ AhciCreateTransferDescriptor (
   // 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
@@ -1947,7 +2049,7 @@ AhciCreateTransferDescriptor (
 \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
@@ -1979,7 +2081,7 @@ AhciCreateTransferDescriptor (
 \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
@@ -2035,7 +2137,7 @@ AhciCreateTransferDescriptor (
 \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
@@ -2075,7 +2177,7 @@ AhciCreateTransferDescriptor (
 \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
@@ -2117,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
@@ -2146,6 +2248,7 @@ AhciModeInitialization (
   EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
   EFI_ATA_TRANSFER_MODE            TransferMode;\r
   UINT32                           PhyDetectDelay;\r
+  UINT32                           Value;\r
 \r
   if (Instance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2154,21 +2257,43 @@ AhciModeInitialization (
   PciIo   = Instance->PciIo;\r
   IdeInit = Instance->IdeControllerInit;\r
 \r
-  Status = AhciReset (PciIo, EFI_AHCI_BUS_RESET_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
@@ -2177,10 +2302,10 @@ AhciModeInitialization (
 \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
-  \r
+\r
   AhciRegisters = &Instance->AhciRegisters;\r
   Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
 \r
@@ -2188,8 +2313,19 @@ AhciModeInitialization (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
+  for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
     if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\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
@@ -2238,16 +2374,6 @@ AhciModeInitialization (
       //\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 = AhciWaitMemSet (\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
       // Wait no longer than 10 ms to wait the Phy to detect the presence of a device.\r
@@ -2268,7 +2394,10 @@ AhciModeInitialization (
       if (PhyDetectDelay == 0) {\r
         //\r
         // No device detected at this port.\r
+        // Clear PxCMD.SUD for those ports at which there are no device present.\r
         //\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
@@ -2292,8 +2421,9 @@ AhciModeInitialization (
         MicroSecondDelay (1000);\r
         PhyDetectDelay--;\r
       } while (PhyDetectDelay > 0);\r
-      \r
+\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
@@ -2301,8 +2431,8 @@ AhciModeInitialization (
       // 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 = AhciWaitMemSet (\r
-                 PciIo, \r
+      Status = AhciWaitMmioSet (\r
+                 PciIo,\r
                  Offset,\r
                  0x0000FFFF,\r
                  0x00000101,\r
@@ -2333,13 +2463,13 @@ AhciModeInitialization (
       } else {\r
         continue;\r
       }\r
-      DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \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
+      if ((DeviceType == EfiIdeHarddisk) && PcdGetBool (PcdAtaSmartEnable)) {\r
         AhciAtaSmartSupport (\r
           PciIo,\r
           AhciRegisters,\r
@@ -2391,7 +2521,7 @@ AhciModeInitialization (
         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
+        TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
       }\r
 \r
       Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
@@ -2403,7 +2533,7 @@ AhciModeInitialization (
       //\r
       // Found a ATA or ATAPI device, add it into the device list.\r
       //\r
-      CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\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