]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 2001175fe723559056ea578b39f78922c5fd167b..00aa7e686c34c6c57ea208541b2600001daa7304 100644 (file)
@@ -1,14 +1,9 @@
 /** @file\r
   The file for AHCI mode of ATA host controller.\r
 \r
-  Copyright (c) 2010 - 2012, 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 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -156,9 +151,16 @@ AhciWaitMmioSet (
   )\r
 {\r
   UINT32     Value;\r
-  UINT32     Delay;\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
     //\r
@@ -177,7 +179,7 @@ AhciWaitMmioSet (
 \r
     Delay--;\r
 \r
-  } while (Delay > 0);\r
+  } while (InfiniteWait || (Delay > 0));\r
 \r
   return EFI_TIMEOUT;\r
 }\r
@@ -204,9 +206,16 @@ AhciWaitMemSet (
   )\r
 {\r
   UINT32     Value;\r
-  UINT32     Delay;\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
     //\r
@@ -231,7 +240,7 @@ AhciWaitMemSet (
 \r
     Delay--;\r
 \r
-  } while (Delay > 0);\r
+  } while (InfiniteWait || (Delay > 0));\r
 \r
   return EFI_TIMEOUT;\r
 }\r
@@ -242,7 +251,8 @@ AhciWaitMemSet (
   @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. If 0, then just try once.\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
@@ -255,13 +265,13 @@ AhciCheckMemSet (
   IN     UINTN                     Address,\r
   IN     UINT32                    MaskValue,\r
   IN     UINT32                    TestValue,\r
-  IN OUT UINTN                     *RetryTimes OPTIONAL\r
+  IN OUT ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   UINT32     Value;\r
 \r
-  if (RetryTimes != NULL) {\r
-    (*RetryTimes)--;\r
+  if (Task != NULL) {\r
+    Task->RetryTimes--;\r
   }\r
 \r
   Value  = *(volatile UINT32 *) Address;\r
@@ -271,48 +281,13 @@ AhciCheckMemSet (
     return EFI_SUCCESS;\r
   }\r
 \r
-  if ((RetryTimes != NULL) && (*RetryTimes == 0)) {\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 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
-                           supported by AHCI controller.\r
-  @retval EFI_UNSUPPORTED  The transfer address and count is not supported by AHCI\r
-                           controller.\r
-  @retval EFI_NOT_READY    The physical communication between AHCI controller and device\r
-                           is not ready.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciCheckDeviceStatus (\r
-  IN  EFI_PCI_IO_PROTOCOL    *PciIo,\r
-  IN  UINT8                  Port\r
-  )\r
-{\r
-  UINT32      Data;\r
-  UINT32      Offset;\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
-\r
-  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
-  }\r
-\r
-  return EFI_NOT_READY;\r
-}\r
 \r
 /**\r
 \r
@@ -355,6 +330,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
@@ -363,24 +339,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
@@ -411,13 +405,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 AhciWaitMmioSet (\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
@@ -517,7 +505,7 @@ AhciBuildCommand (
   //\r
   // Filling the PRDT\r
   //\r
-  PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\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
@@ -683,11 +671,20 @@ AhciPioTransfer (
   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
@@ -756,17 +753,33 @@ AhciPioTransfer (
     // Wait device sends the PIO setup fis before data transfer\r
     //\r
     Status = EFI_TIMEOUT;\r
-    Delay  = (UINT32) (DivU64x32 (Timeout, 1000) + 1);\r
+    Delay  = DivU64x32 (Timeout, 1000) + 1;\r
     do {\r
+      PioFisReceived = FALSE;\r
+      D2hFisReceived = FALSE;\r
       Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;\r
-\r
-      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);\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
+      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
-        // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.\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
@@ -775,24 +788,21 @@ AhciPioTransfer (
 \r
         PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));\r
         if (PrdCount == DataCount) {\r
+          Status = EFI_SUCCESS;\r
           break;\r
         }\r
       }\r
 \r
-      Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;\r
-      Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);\r
-      if (!EFI_ERROR (Status)) {\r
-        Status = EFI_DEVICE_ERROR;\r
-        break;\r
-      }\r
-\r
       //\r
       // Stall for 100 microseconds.\r
       //\r
       MicroSecondDelay(100);\r
 \r
       Delay--;\r
-    } while (Delay > 0);\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
@@ -834,7 +844,7 @@ Exit:
     Map\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
 \r
   return Status;\r
 }\r
@@ -924,7 +934,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
@@ -1000,7 +1009,7 @@ AhciDmaTransfer (
                Offset,\r
                EFI_AHCI_FIS_TYPE_MASK,\r
                EFI_AHCI_FIS_REGISTER_D2H,\r
-               (UINTN *) (&Task->RetryTimes)\r
+               Task\r
                );\r
   } else {\r
     Status = AhciWaitMemSet (\r
@@ -1054,7 +1063,7 @@ Exit:
     }\r
   }\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
   return Status;\r
 }\r
 \r
@@ -1170,7 +1179,7 @@ Exit:
     Timeout\r
     );\r
 \r
-  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+  AhciDumpPortStatus (PciIo, AhciRegisters, Port, AtaStatusBlock);\r
 \r
   return Status;\r
 }\r
@@ -1304,10 +1313,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
@@ -1315,74 +1320,6 @@ AhciStartCommand (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Do AHCI port reset.\r
-\r
-  @param  PciIo              The PCI IO protocol instance.\r
-  @param  Port               The number of port.\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
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-AhciPortReset (\r
-  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN  UINT8                     Port,\r
-  IN  UINT64                    Timeout\r
-  )\r
-{\r
-  EFI_STATUS      Status;\r
-  UINT32          Offset;\r
-\r
-  AhciClearPortStatus (PciIo, Port);\r
-\r
-  AhciStopCommand (PciIo, Port, Timeout);\r
-\r
-  AhciDisableFisReceive (PciIo, Port, Timeout);\r
-\r
-  AhciEnableFisReceive (PciIo, Port, Timeout);\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
-\r
-  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
-\r
-  //\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 millisecond before de-assert DET\r
-  //\r
-  MicroSecondDelay (5000);\r
-\r
-  //\r
-  // 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 = AhciWaitMmioSet (\r
-             PciIo,\r
-             Offset,\r
-             EFI_AHCI_PORT_SSTS_DET_MASK,\r
-             EFI_AHCI_PORT_SSTS_DET_PCE,\r
-             Timeout\r
-             );\r
-\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
-  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
-\r
-  return EFI_SUCCESS;\r
-}\r
 \r
 /**\r
   Do AHCI HBA reset.\r
@@ -1402,14 +1339,21 @@ AhciReset (
   IN  UINT64                    Timeout\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
@@ -1439,7 +1383,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
@@ -1487,9 +1431,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
@@ -1503,12 +1456,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
@@ -1521,7 +1481,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
@@ -1549,11 +1509,21 @@ AhciAtaSmartSupport (
     //\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
@@ -1627,7 +1597,7 @@ AhciAtaSmartSupport (
   @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
@@ -1685,7 +1655,7 @@ AhciIdentify (
   @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
@@ -1743,9 +1713,10 @@ AhciIdentifyPacket (
   @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
+  @param  Timeout             The timeout value of SET FEATURE cmd, uses 100ns as a unit.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -1761,7 +1732,8 @@ AhciDeviceSetFeature (
   IN UINT8                  Port,\r
   IN UINT8                  PortMultiplier,\r
   IN UINT16                 Feature,\r
-  IN UINT32                 FeatureSpecificData\r
+  IN UINT32                 FeatureSpecificData,\r
+  IN UINT64                 Timeout\r
   )\r
 {\r
   EFI_STATUS               Status;\r
@@ -1788,7 +1760,7 @@ AhciDeviceSetFeature (
              0,\r
              &AtaCommandBlock,\r
              &AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT,\r
+             Timeout,\r
              NULL\r
              );\r
 \r
@@ -1928,7 +1900,7 @@ AhciCreateTransferDescriptor (
   //\r
   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
   Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
-  \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
@@ -2136,6 +2108,343 @@ Error6:
   return Status;\r
 }\r
 \r
+/**\r
+  Read logs from SATA device.\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 multiplier of port.\r
+  @param  Buffer              The data buffer to store SATA logs.\r
+  @param  LogNumber           The address of the log.\r
+  @param  PageNumber          The page number of the log.\r
+\r
+  @retval EFI_INVALID_PARAMETER  PciIo, AhciRegisters or Buffer is NULL.\r
+  @retval others                 Return status of AhciPioTransfer().\r
+**/\r
+EFI_STATUS\r
+AhciReadLogExt (\r
+  IN EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN EFI_AHCI_REGISTERS        *AhciRegisters,\r
+  IN UINT8                     Port,\r
+  IN UINT8                     PortMultiplier,\r
+  IN OUT UINT8                 *Buffer,\r
+  IN UINT8                     LogNumber,\r
+  IN UINT8                     PageNumber\r
+  )\r
+{\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
+\r
+  if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ///\r
+  /// Read log from device\r
+  ///\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  ZeroMem (Buffer, 512);\r
+\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_READ_LOG_EXT;\r
+  AtaCommandBlock.AtaSectorCount  = 1;\r
+  AtaCommandBlock.AtaSectorNumber = LogNumber;\r
+  AtaCommandBlock.AtaCylinderLow  = PageNumber;\r
+\r
+  return AhciPioTransfer (\r
+           PciIo,\r
+           AhciRegisters,\r
+           Port,\r
+           PortMultiplier,\r
+           NULL,\r
+           0,\r
+           TRUE,\r
+           &AtaCommandBlock,\r
+           &AtaStatusBlock,\r
+           Buffer,\r
+           512,\r
+           ATA_ATAPI_TIMEOUT,\r
+           NULL\r
+           );\r
+}\r
+\r
+/**\r
+  Enable DEVSLP 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 multiplier of port.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+  @retval EFI_SUCCESS         The DEVSLP is enabled per policy successfully.\r
+  @retval EFI_UNSUPPORTED     The DEVSLP isn't supported by the controller/device and policy requires to enable it.\r
+**/\r
+EFI_STATUS\r
+AhciEnableDevSlp (\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
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  UINT32                   Offset;\r
+  UINT32                   Capability2;\r
+  UINT8                    LogData[512];\r
+  DEVSLP_TIMING_VARIABLES  DevSlpTiming;\r
+  UINT32                   PortCmd;\r
+  UINT32                   PortDevSlp;\r
+\r
+  if (mAtaAtapiPolicy->DeviceSleepEnable != 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if DevSlp is not supported.\r
+  //\r
+  Capability2 = AhciReadReg (PciIo, AHCI_CAPABILITY2_OFFSET);\r
+  DEBUG ((DEBUG_INFO, "AHCI CAPABILITY2 = %08x\n", Capability2));\r
+  if ((Capability2 & AHCI_CAP2_SDS) == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if DevSlp is not present\r
+  // Do not enable DevSlp if Hot Plug or Mechanical Presence Switch is supported\r
+  //\r
+  Offset     = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH;\r
+  PortCmd    = AhciReadReg (PciIo, Offset + EFI_AHCI_PORT_CMD);\r
+  PortDevSlp = AhciReadReg (PciIo, Offset + AHCI_PORT_DEVSLP);\r
+  DEBUG ((DEBUG_INFO, "Port CMD/DEVSLP = %08x / %08x\n", PortCmd, PortDevSlp));\r
+  if (((PortDevSlp & AHCI_PORT_DEVSLP_DSP) == 0) ||\r
+      ((PortCmd & (EFI_AHCI_PORT_CMD_HPCP | EFI_AHCI_PORT_CMD_MPSP)) != 0)\r
+     ) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Do not enable DevSlp if the device doesn't support DevSlp\r
+  //\r
+  DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [77] = %04x, [78] = %04x, [79] = %04x\n",\r
+          IdentifyData->AtaData.reserved_77,\r
+          IdentifyData->AtaData.serial_ata_features_supported, IdentifyData->AtaData.serial_ata_features_enabled));\r
+  if ((IdentifyData->AtaData.serial_ata_features_supported & BIT8) == 0) {\r
+    DEBUG ((DEBUG_INFO, "DevSlp feature is not supported for device at port [%d] PortMultiplier [%d]!\n",\r
+            Port, PortMultiplier));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Enable DevSlp when it is not enabled.\r
+  //\r
+  if ((IdentifyData->AtaData.serial_ata_features_enabled & BIT8) != 0) {\r
+    Status = AhciDeviceSetFeature (\r
+      PciIo, AhciRegisters, Port, 0, ATA_SUB_CMD_ENABLE_SATA_FEATURE, 0x09, ATA_ATAPI_TIMEOUT\r
+    );\r
+    DEBUG ((DEBUG_INFO, "DevSlp set feature for device at port [%d] PortMultiplier [%d] - %r\n",\r
+            Port, PortMultiplier, Status));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = AhciReadLogExt(PciIo, AhciRegisters, Port, PortMultiplier, LogData, 0x30, 0x08);\r
+\r
+  //\r
+  // Clear PxCMD.ST and PxDEVSLP.ADSE before updating PxDEVSLP.DITO and PxDEVSLP.MDAT.\r
+  //\r
+  AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd & ~EFI_AHCI_PORT_CMD_ST);\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_ADSE;\r
+  AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+  //\r
+  // Set PxDEVSLP.DETO and PxDEVSLP.MDAT to 0.\r
+  //\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_DETO_MASK;\r
+  PortDevSlp &= ~AHCI_PORT_DEVSLP_MDAT_MASK;\r
+  AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+  DEBUG ((DEBUG_INFO, "Read Log Ext at port [%d] PortMultiplier [%d] - %r\n", Port, PortMultiplier, Status));\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Assume DEVSLP TIMING VARIABLES is not supported if the Identify Device Data log (30h, 8) fails\r
+    //\r
+    ZeroMem (&DevSlpTiming, sizeof (DevSlpTiming));\r
+  } else {\r
+    CopyMem (&DevSlpTiming, &LogData[48], sizeof (DevSlpTiming));\r
+    DEBUG ((DEBUG_INFO, "DevSlpTiming: Supported(%d), Deto(%d), Madt(%d)\n",\r
+            DevSlpTiming.Supported, DevSlpTiming.Deto, DevSlpTiming.Madt));\r
+  }\r
+\r
+  //\r
+  // Use 20ms as default DETO when DEVSLP TIMING VARIABLES is not supported or the DETO is 0.\r
+  //\r
+  if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Deto == 0)) {\r
+    DevSlpTiming.Deto = 20;\r
+  }\r
+\r
+  //\r
+  // Use 10ms as default MADT when DEVSLP TIMING VARIABLES is not supported or the MADT is 0.\r
+  //\r
+  if ((DevSlpTiming.Supported == 0) || (DevSlpTiming.Madt == 0)) {\r
+    DevSlpTiming.Madt = 10;\r
+  }\r
+\r
+  PortDevSlp |= DevSlpTiming.Deto << 2;\r
+  PortDevSlp |= DevSlpTiming.Madt << 10;\r
+  AhciOrReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+  if (mAtaAtapiPolicy->AggressiveDeviceSleepEnable == 1) {\r
+    if ((Capability2 & AHCI_CAP2_SADM) != 0) {\r
+      PortDevSlp &= ~AHCI_PORT_DEVSLP_DITO_MASK;\r
+      PortDevSlp |= (625 << 15);\r
+      AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+\r
+      PortDevSlp |= AHCI_PORT_DEVSLP_ADSE;\r
+      AhciWriteReg (PciIo, Offset + AHCI_PORT_DEVSLP, PortDevSlp);\r
+    }\r
+  }\r
+\r
+\r
+  AhciWriteReg (PciIo, Offset + EFI_AHCI_PORT_CMD, PortCmd);\r
+\r
+  DEBUG ((DEBUG_INFO, "Enabled DevSlp feature at port [%d] PortMultiplier [%d], Port CMD/DEVSLP = %08x / %08x\n",\r
+          Port, PortMultiplier, PortCmd, PortDevSlp));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Spin-up disk if IDD was incomplete or PUIS feature is enabled\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 multiplier of port.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciSpinUpDisk (\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_IDENTIFY_DATA         *IdentifyData\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK     AtaStatusBlock;\r
+  UINT8                    Buffer[512];\r
+\r
+  if (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_REQUIRED_IDD_INCOMPLETE) {\r
+    //\r
+    // Use SET_FEATURE subcommand to spin up the device.\r
+    //\r
+    Status = AhciDeviceSetFeature (\r
+               PciIo, AhciRegisters, Port, PortMultiplier,\r
+               ATA_SUB_CMD_PUIS_SET_DEVICE_SPINUP, 0x00, ATA_SPINUP_TIMEOUT\r
+               );\r
+    DEBUG ((DEBUG_INFO, "CMD_PUIS_SET_DEVICE_SPINUP for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+            Port, PortMultiplier, Status));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    ASSERT (IdentifyData->AtaData.specific_config == ATA_SPINUP_CFG_NOT_REQUIRED_IDD_INCOMPLETE);\r
+\r
+    //\r
+    // Use READ_SECTORS to spin up the device if SpinUp SET FEATURE subcommand is not supported\r
+    //\r
+    ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+    ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+    //\r
+    // Perform READ SECTORS PIO Data-In command to Read LBA 0\r
+    //\r
+    AtaCommandBlock.AtaCommand      = ATA_CMD_READ_SECTORS;\r
+    AtaCommandBlock.AtaSectorCount  = 0x1;\r
+\r
+    Status = AhciPioTransfer (\r
+               PciIo,\r
+               AhciRegisters,\r
+               Port,\r
+               PortMultiplier,\r
+               NULL,\r
+               0,\r
+               TRUE,\r
+               &AtaCommandBlock,\r
+               &AtaStatusBlock,\r
+               &Buffer,\r
+               sizeof (Buffer),\r
+               ATA_SPINUP_TIMEOUT,\r
+               NULL\r
+               );\r
+    DEBUG ((DEBUG_INFO, "Read LBA 0 for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+            Port, PortMultiplier, Status));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Read the complete IDENTIFY DEVICE data.\r
+  //\r
+  ZeroMem (IdentifyData, sizeof (*IdentifyData));\r
+  Status = AhciIdentify (PciIo, AhciRegisters, Port, PortMultiplier, IdentifyData);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Read IDD failed for device at port [%d] PortMultiplier [%d] - %r!\n",\r
+            Port, PortMultiplier, Status));\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+          IdentifyData->AtaData.config, IdentifyData->AtaData.specific_config,\r
+          IdentifyData->AtaData.command_set_supported_83, IdentifyData->AtaData.command_set_feature_enb_86));\r
+  //\r
+  // Check if IDD is incomplete\r
+  //\r
+  if ((IdentifyData->AtaData.config & BIT2) != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable/disable/skip PUIS of the disk according to policy.\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 multiplier of port.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciPuisEnable (\r
+  IN EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN UINT8                         Port,\r
+  IN UINT8                         PortMultiplier\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (mAtaAtapiPolicy->PuisEnable == 0) {\r
+    Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_DISABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
+  } else if (mAtaAtapiPolicy->PuisEnable == 1) {\r
+    Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, PortMultiplier, ATA_SUB_CMD_ENABLE_PUIS, 0x00, ATA_ATAPI_TIMEOUT);\r
+  }\r
+  DEBUG ((DEBUG_INFO, "%a PUIS feature at port [%d] PortMultiplier [%d] - %r!\n",\r
+    (mAtaAtapiPolicy->PuisEnable == 0) ? "Disable" : (\r
+    (mAtaAtapiPolicy->PuisEnable == 1) ? "Enable" : "Skip"\r
+      ), Port, PortMultiplier, Status));\r
+  return Status;\r
+}\r
+\r
 /**\r
   Initialize ATA host controller at AHCI mode.\r
 \r
@@ -2168,6 +2477,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
@@ -2183,14 +2493,36 @@ AhciModeInitialization (
   }\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
@@ -2211,7 +2543,7 @@ AhciModeInitialization (
   }\r
 \r
   for (Port = 0; Port < EFI_AHCI_MAX_PORTS; Port ++) {\r
-    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+    if ((PortImplementBitMap & (((UINT32)BIT0) << Port)) != 0) {\r
       //\r
       // According to AHCI spec, MaxPortNumber should be equal or greater than the number of implemented ports.\r
       //\r
@@ -2271,20 +2603,9 @@ 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 = AhciWaitMmioSet (\r
-                 PciIo,\r
-                 Offset,\r
-                 EFI_AHCI_PORT_CMD_FR,\r
-                 EFI_AHCI_PORT_CMD_FR,\r
-                 EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT\r
-                 );\r
-      if (EFI_ERROR (Status)) {\r
-        continue;\r
-      }\r
 \r
       //\r
-      // 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
+      // Wait for the Phy to detect the presence of a device.\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
@@ -2330,6 +2651,7 @@ AhciModeInitialization (
       } while (PhyDetectDelay > 0);\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
@@ -2365,6 +2687,28 @@ AhciModeInitialization (
           continue;\r
         }\r
 \r
+        DEBUG ((\r
+          DEBUG_INFO, "IDENTIFY DEVICE: [0] = %016x, [2] = %016x, [83] = %016x, [86] = %016x\n",\r
+          Buffer.AtaData.config, Buffer.AtaData.specific_config,\r
+          Buffer.AtaData.command_set_supported_83, Buffer.AtaData.command_set_feature_enb_86\r
+          ));\r
+        if ((Buffer.AtaData.config & BIT2) != 0) {\r
+          //\r
+          // SpinUp disk if device reported incomplete IDENTIFY DEVICE.\r
+          //\r
+          Status = AhciSpinUpDisk (\r
+                     PciIo,\r
+                     AhciRegisters,\r
+                     Port,\r
+                     0,\r
+                     &Buffer\r
+                     );\r
+          if (EFI_ERROR (Status)) {\r
+            DEBUG ((DEBUG_ERROR, "Spin up standby device failed - %r\n", Status));\r
+            continue;\r
+          }\r
+        }\r
+\r
         DeviceType = EfiIdeHarddisk;\r
       } else {\r
         continue;\r
@@ -2430,7 +2774,7 @@ AhciModeInitialization (
         TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
       }\r
 \r
-      Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+      Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode), ATA_ATAPI_TIMEOUT);\r
       if (EFI_ERROR (Status)) {\r
         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
         continue;\r
@@ -2439,9 +2783,32 @@ 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
+        AhciEnableDevSlp (\r
+          PciIo,\r
+          AhciRegisters,\r
+          Port,\r
+          0,\r
+          &Buffer\r
+          );\r
+      }\r
+\r
+      //\r
+      // Enable/disable PUIS according to policy setting if PUIS is capable (Word[83].BIT5 is set).\r
+      //\r
+      if ((Buffer.AtaData.command_set_supported_83 & BIT5) != 0) {\r
+        Status = AhciPuisEnable (\r
+                   PciIo,\r
+                   AhciRegisters,\r
+                   Port,\r
+                   0\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((DEBUG_ERROR, "PUIS enable/disable failed, Status = %r\n", Status));\r
+          continue;\r
+        }\r
       }\r
     }\r
   }\r