]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
Add BlockIO2 Protocol.
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 06b280a001af3f48506388228f29c4f557629822..7765bfc75c892ba5acf0064aea10f5b7ff456c7a 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   The file for AHCI mode of ATA host controller.\r
   \r
-  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials                          \r
   are licensed and made available under the terms and conditions of the BSD License         \r
   which accompanies this distribution.  The full text of the license may be found at        \r
@@ -184,9 +184,50 @@ AhciWaitMemSet (
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
+/**\r
+  Check the memory status to the test value.\r
+    \r
+  @param[in]       PciIo             The PCI IO protocol instance.\r
+  @param[in]       Offset            The memory address to test.\r
+  @param[in]       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
+\r
+  @retval EFI_NOTREADY      The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting retry times out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCheckMemSet (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINTN                     *RetryTimes\r
+  )\r
+{\r
+  UINT32     Value;\r
+\r
+  (*RetryTimes) --;\r
+  \r
+  Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((*RetryTimes) == 0) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    return EFI_NOT_READY;\r
+  }\r
+}\r
+\r
 /**\r
   Check if the device is still on port. It also checks if the AHCI controller \r
-  supports the address and data count will be transfered.\r
+  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
@@ -206,7 +247,7 @@ AhciCheckDeviceStatus (
   IN  UINT8                  Port\r
   )\r
 {\r
-  UINT32      Data; \r
+  UINT32      Data;\r
   UINT32      Offset;\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
@@ -214,7 +255,7 @@ AhciCheckDeviceStatus (
   Data   = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
 \r
   if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
-    return EFI_SUCCESS;      \r
+    return EFI_SUCCESS;\r
   }\r
 \r
   return EFI_NOT_READY;\r
@@ -240,7 +281,7 @@ AhciClearPortStatus (
 \r
   //\r
   // Clear any error status\r
-  //  \r
+  //\r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
   AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
 \r
@@ -256,6 +297,42 @@ AhciClearPortStatus (
   AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
 }\r
 \r
+/**\r
+  This function is used to dump the Status Registers and if there is ERR bit set\r
+  in the Status Register, the Error Register's value is also be dumped.\r
+\r
+  @param  PciIo            The PCI IO protocol instance.\r
+  @param  Port             The number of port.\r
+  @param  AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciDumpPortStatus (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     UINT8                      Port,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock\r
+  )\r
+{\r
+  UINT32               Offset;\r
+  UINT32               Data;\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
+    }\r
+  }\r
+}\r
+\r
+\r
 /**\r
   Enable the FIS running for giving port.\r
     \r
@@ -274,8 +351,8 @@ AhciEnableFisReceive (
   IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
   IN  UINT8                     Port,\r
   IN  UINT64                    Timeout\r
-  )     \r
-{ \r
+  )\r
+{\r
   UINT32 Offset;\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
@@ -334,12 +411,12 @@ AhciDisableFisReceive (
   AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
 \r
   return AhciWaitMemSet (\r
-           PciIo, \r
+           PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_FR,\r
            0,\r
            Timeout\r
-           ); \r
+           );\r
 }\r
 \r
 \r
@@ -376,7 +453,7 @@ AhciBuildCommand (
   IN     UINT64                     DataLength\r
   )   \r
 {\r
-  UINT64     BaseAddr; \r
+  UINT64     BaseAddr;\r
   UINT64     PrdtNumber;\r
   UINT64     PrdtIndex;\r
   UINTN      RemainedData;\r
@@ -400,7 +477,7 @@ AhciBuildCommand (
 \r
   BaseAddr = Data64.Uint64;\r
   \r
-  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));  \r
+  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));\r
     \r
   ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
 \r
@@ -430,7 +507,7 @@ AhciBuildCommand (
   CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
   \r
   for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
-    if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {     \r
+    if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {\r
       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
     } else {\r
       AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
@@ -439,7 +516,7 @@ AhciBuildCommand (
     Data64.Uint64 = (UINT64)MemAddr;\r
     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba  = Data64.Uint32.Lower32;\r
     AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
-    RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;    \r
+    RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;\r
     MemAddr      += EFI_AHCI_MAX_DATA_PER_PRDT;\r
   }\r
 \r
@@ -507,18 +584,21 @@ AhciBuildCommandFis (
 /**\r
   Start a PIO data transfer on specific port.\r
     \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  Read                The transfer direction.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  MemoryAddr          The pointer to the data buffer.\r
-  @param  DataCount           The data count to be transferred.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+  @param[in]       PciIo               The PCI IO protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @param[in]       AtapiCommandLength  The length of the atapi command.\r
+  @param[in]       Read                The transfer direction.\r
+  @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
+  @param[in, out]  MemoryAddr          The pointer to the data buffer.\r
+  @param[in]       DataCount           The data count to be transferred.\r
+  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The PIO data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -540,7 +620,8 @@ AhciPioTransfer (
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
   IN OUT VOID                       *MemoryAddr,\r
   IN     UINT32                     DataCount,\r
-  IN     UINT64                     Timeout \r
+  IN     UINT64                     Timeout,\r
+  IN     ATA_NONBLOCK_TASK          *Task\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
@@ -603,17 +684,17 @@ AhciPioTransfer (
     );    \r
   \r
   Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
+             PciIo,\r
+             Port,\r
              0,\r
              Timeout\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
-  \r
+\r
   //\r
-  // Checking the status and wait the driver sending data\r
+  // Check the status and wait the driver sending data\r
   //\r
   FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
   //\r
@@ -621,7 +702,7 @@ AhciPioTransfer (
   //\r
   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
   do {\r
-    Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);\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
@@ -632,7 +713,7 @@ AhciPioTransfer (
     //\r
     MicroSecondDelay(100);\r
 \r
-    Delay--;    \r
+    Delay--;\r
   } while (Delay > 0);\r
 \r
   if (Delay == 0) {\r
@@ -653,30 +734,30 @@ AhciPioTransfer (
              );\r
 \r
   if (EFI_ERROR (Status)) {\r
-    goto Exit;   \r
+    goto Exit;\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
+             Offset,\r
              EFI_AHCI_PORT_IS_PSS,\r
              EFI_AHCI_PORT_IS_PSS,\r
              Timeout\r
-             );  \r
+             );\r
   if (EFI_ERROR (Status)) {\r
-    goto Exit;  \r
+    goto Exit;\r
   }\r
 \r
-Exit: \r
+Exit:\r
   AhciStopCommand (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
   \r
   AhciDisableFisReceive (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
@@ -686,35 +767,40 @@ Exit:
     Map\r
     );\r
 \r
+  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+\r
   return Status;\r
 }\r
 \r
 /**\r
   Start a DMA data transfer on specific port\r
 \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  Read                The transfer direction.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  MemoryAddr          The pointer to the data buffer.\r
-  @param  DataCount           The data count to be transferred.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+  @param[in]       Instance            The ATA_ATAPI_PASS_THRU_INSTANCE protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @param[in]       AtapiCommandLength  The length of the atapi command.\r
+  @param[in]       Read                The transfer direction.\r
+  @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
+  @param[in, out]  MemoryAddr          The pointer to the data buffer.\r
+  @param[in]       DataCount           The data count to be transferred.\r
+  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The DMA data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
   @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
   @retval EFI_SUCCESS         The DMA data transfer executes successfully.\r
-   \r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 AhciDmaTransfer (\r
-  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE *Instance,\r
   IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
   IN     UINT8                      Port,\r
   IN     UINT8                      PortMultiplier,\r
@@ -725,7 +811,8 @@ AhciDmaTransfer (
   IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
   IN OUT VOID                       *MemoryAddr,\r
   IN     UINTN                      DataCount,\r
-  IN     UINT64                     Timeout\r
+  IN     UINT64                     Timeout,\r
+  IN     ATA_NONBLOCK_TASK          *Task\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
@@ -737,139 +824,224 @@ AhciDmaTransfer (
   EFI_AHCI_COMMAND_FIS          CFis;\r
   EFI_AHCI_COMMAND_LIST         CmdList;\r
 \r
-  if (Read) {\r
-    Flag = EfiPciIoOperationBusMasterWrite;\r
-  } else {\r
-    Flag = EfiPciIoOperationBusMasterRead;\r
-  }\r
+  EFI_PCI_IO_PROTOCOL          *PciIo;\r
+  EFI_TPL                      OldTpl;\r
 \r
-  //\r
-  // construct command list and command table with pci bus address\r
-  //\r
-  MapLength = DataCount;\r
-  Status = PciIo->Map (\r
-                    PciIo,\r
-                    Flag,\r
-                    MemoryAddr,\r
-                    &MapLength,\r
-                    &PhyAddr,\r
-                    &Map\r
-                    );\r
+  Map   = NULL;\r
+  PciIo = Instance->PciIo;\r
 \r
-  if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+  if (PciIo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
-  // Package read needed\r
+  // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
+  // BlockIO tasks.\r
+  // Delay 100us to simulate the blocking time out checking.\r
   //\r
-  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+  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
 \r
-  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+  if ((Task == NULL) || ((Task != NULL) && (!Task->IsStart))) {\r
+    //\r
+    // Mark the Task to indicate that it has been started.\r
+    //\r
+    if (Task != NULL) {\r
+      Task->IsStart      = TRUE;\r
+      Task->RetryTimes   = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+    }\r
+    if (Read) {\r
+      Flag = EfiPciIoOperationBusMasterWrite;\r
+    } else {\r
+      Flag = EfiPciIoOperationBusMasterRead;\r
+    }\r
 \r
-  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
-  CmdList.AhciCmdW   = Read ? 0 : 1;\r
+    //\r
+    // Construct command list and command table with pci bus address.\r
+    //\r
+    MapLength = DataCount;\r
+    Status = PciIo->Map (\r
+                      PciIo,\r
+                      Flag,\r
+                      MemoryAddr,\r
+                      &MapLength,\r
+                      &PhyAddr,\r
+                      &Map\r
+                      );\r
+\r
+    if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
-  AhciBuildCommand (\r
-    PciIo,\r
-    AhciRegisters,\r
-    Port,\r
-    PortMultiplier,\r
-    &CFis,\r
-    &CmdList,\r
-    AtapiCommand,\r
-    AtapiCommandLength,\r
-    0,\r
-    (VOID *)(UINTN)PhyAddr,\r
-    DataCount\r
-    ); \r
-  \r
-  Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
-             0,\r
-             Timeout\r
-             );\r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\r
-  }\r
-  \r
-  //\r
-  // Wait device PRD processed\r
-  //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             EFI_AHCI_PORT_IS_DPS,\r
-             EFI_AHCI_PORT_IS_DPS,\r
-             Timeout\r
-             ); \r
-  \r
-  if (EFI_ERROR (Status)) {\r
-    goto Exit;\r
+    if (Task != NULL) {\r
+      Task->Map = Map;\r
+    }\r
+    //\r
+    // Package read needed\r
+    //\r
+    AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+    ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+    CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+    CmdList.AhciCmdW   = Read ? 0 : 1;\r
+\r
+    AhciBuildCommand (\r
+      PciIo,\r
+      AhciRegisters,\r
+      Port,\r
+      PortMultiplier,\r
+      &CFis,\r
+      &CmdList,\r
+      AtapiCommand,\r
+      AtapiCommandLength,\r
+      0,\r
+      (VOID *)(UINTN)PhyAddr,\r
+      DataCount\r
+      );\r
+\r
+    Status = AhciStartCommand (\r
+               PciIo,\r
+               Port,\r
+               0,\r
+               Timeout\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // 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
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             0xFFFFFFFF,\r
-             0,\r
-             Timeout\r
-             );\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
+               );\r
+  } else {\r
+    Status = AhciWaitMemSet (\r
+               PciIo,\r
+               Offset,\r
+               0xFFFFFFFF,\r
+               0,\r
+               Timeout\r
+               );\r
+  }\r
+\r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
-  Status = AhciWaitMemSet (\r
-             PciIo,\r
-             Offset,\r
-             EFI_AHCI_PORT_IS_DHRS,\r
-             EFI_AHCI_PORT_IS_DHRS,\r
-             Timeout\r
-             );  \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
   }\r
 \r
-Exit: \r
-  AhciStopCommand (\r
-    PciIo, \r
-    Port,\r
-    Timeout\r
-    );\r
+Exit:\r
+  //\r
+  // For Blocking mode, the command should be stopped, the Fis should be disabled\r
+  // and the PciIo should be unmapped.\r
+  // For non-blocking mode, only when a error is happened (if the return status is \r
+  // EFI_NOT_READY that means the command doesn't finished, try again.), first do the \r
+  // context cleanup, then set the packet's Asb status.\r
+  //\r
+  if (Task == NULL ||\r
+      ((Task != NULL) && (Status != EFI_NOT_READY))\r
+     ) {\r
+    AhciStopCommand (\r
+      PciIo, \r
+      Port,\r
+      Timeout\r
+      );\r
 \r
-  AhciDisableFisReceive (\r
-    PciIo, \r
-    Port,\r
-    Timeout\r
-    );\r
+    AhciDisableFisReceive (\r
+      PciIo, \r
+      Port,\r
+      Timeout\r
+      );\r
 \r
-  PciIo->Unmap (\r
-           PciIo,\r
-           Map\r
-           );  \r
-  \r
+    PciIo->Unmap (\r
+             PciIo,\r
+             (Task != NULL) ? Task->Map : Map\r
+             );\r
+\r
+    if (Task != NULL) {\r
+      Task->Packet->Asb->AtaStatus = 0x01;\r
+    }\r
+  }\r
+\r
+  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
   return Status;\r
 }\r
 \r
 /**\r
   Start a non data transfer on specific port.\r
     \r
-  @param  PciIo               The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port                The number of port.\r
-  @param  PortMultiplier      The timeout value of stop.\r
-  @param  AtapiCommand        The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+  @param[in]       PciIo               The PCI IO protocol instance.\r
+  @param[in]       AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param[in]       Port                The number of port.\r
+  @param[in]       PortMultiplier      The timeout value of stop.\r
+  @param[in]       AtapiCommand        The atapi command will be used for the\r
+                                       transfer.\r
+  @param[in]       AtapiCommandLength  The length of the atapi command.\r
+  @param[in]       AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @param[in, out]  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
+  @param[in]       Timeout             The timeout value of non data transfer.\r
+  @param[in]       Task                Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                       used by non-blocking mode.\r
 \r
   @retval EFI_DEVICE_ERROR    The non data transfer abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -888,15 +1060,16 @@ AhciNonDataTransfer (
   IN     UINT8                         AtapiCommandLength,\r
   IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
-  IN     UINT64                        Timeout\r
-  ) \r
+  IN     UINT64                        Timeout,\r
+  IN     ATA_NONBLOCK_TASK             *Task\r
+  )\r
 {\r
-  EFI_STATUS                   Status;  \r
+  EFI_STATUS                   Status;\r
   UINTN                        FisBaseAddr;\r
   UINT32                       Offset;\r
   UINT32                       Value;\r
   UINT32                       Delay;\r
-  \r
+\r
   EFI_AHCI_COMMAND_FIS         CFis;\r
   EFI_AHCI_COMMAND_LIST        CmdList;\r
 \r
@@ -921,18 +1094,18 @@ AhciNonDataTransfer (
     0,\r
     NULL,\r
     0\r
-    ); \r
-  \r
+    );\r
+\r
   Status = AhciStartCommand (\r
-             PciIo, \r
-             Port, \r
+             PciIo,\r
+             Port,\r
              0,\r
              Timeout\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto Exit;\r
   }\r
-  \r
+\r
   //\r
   // Wait device sends the Response Fis\r
   //\r
@@ -942,7 +1115,7 @@ AhciNonDataTransfer (
   //\r
   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
   do {\r
-    Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+    Value = *(volatile UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
 \r
     if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
       break;\r
@@ -953,7 +1126,7 @@ AhciNonDataTransfer (
     //\r
     MicroSecondDelay(100);\r
 \r
-    Delay --;    \r
+    Delay --;\r
   } while (Delay > 0);\r
 \r
   if (Delay == 0) {\r
@@ -969,21 +1142,23 @@ AhciNonDataTransfer (
              0xFFFFFFFF,\r
              0,\r
              Timeout\r
-             );  \r
-  \r
-Exit:  \r
+             );\r
+\r
+Exit:\r
   AhciStopCommand (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
 \r
   AhciDisableFisReceive (\r
-    PciIo, \r
+    PciIo,\r
     Port,\r
     Timeout\r
     );\r
 \r
+  AhciDumpPortStatus (PciIo, Port, AtaStatusBlock);\r
+\r
   return Status;\r
 }\r
 \r
@@ -1014,7 +1189,7 @@ AhciStopCommand (
   Data   = AhciReadReg (PciIo, Offset);\r
 \r
   if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {\r
-    return EFI_SUCCESS;    \r
+    return EFI_SUCCESS;\r
   }\r
 \r
   if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
@@ -1022,22 +1197,22 @@ AhciStopCommand (
   }\r
 \r
   return AhciWaitMemSet (\r
-           PciIo, \r
+           PciIo,\r
            Offset,\r
            EFI_AHCI_PORT_CMD_CR,\r
            0,\r
            Timeout\r
-           ); \r
+           );\r
 }\r
 \r
 /**\r
   Start command for give slot on specific port.\r
-    \r
+\r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Port               The number of port.\r
-  @param  CommandSlot        The number of CommandSlot.\r
+  @param  CommandSlot        The number of Command Slot.\r
   @param  Timeout            The timeout value of start.\r
-   \r
+\r
   @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
   @retval EFI_TIMEOUT        The operation is time out.\r
   @retval EFI_SUCCESS        The command start successfully.\r
@@ -1077,25 +1252,14 @@ AhciStartCommand (
              Port,\r
              Timeout\r
              );\r
-  \r
+\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  //\r
-  // Setting the command\r
-  //\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
-  AhciAndReg (PciIo, Offset, 0);\r
-  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
-\r
-  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
-  AhciAndReg (PciIo, Offset, 0);\r
-  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
-\r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
   PortStatus = AhciReadReg (PciIo, Offset);\r
-  \r
+\r
   StartCmd = 0;\r
   if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
     StartCmd = AhciReadReg (PciIo, Offset);\r
@@ -1112,18 +1276,29 @@ AhciStartCommand (
       AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
 \r
       AhciWaitMemSet (\r
-        PciIo, \r
+        PciIo,\r
         Offset,\r
         EFI_AHCI_PORT_CMD_COL,\r
         0,\r
         Timeout\r
-        ); \r
+        );\r
     }\r
   }\r
 \r
   Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
 \r
+  //\r
+  // Setting the command\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
+  AhciAndReg (PciIo, Offset, 0);\r
+  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  AhciAndReg (PciIo, Offset, 0);\r
+  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1148,8 +1323,8 @@ AhciPortReset (
   )\r
 {\r
   EFI_STATUS      Status;\r
-  UINT32          Offset;  \r
-  \r
+  UINT32          Offset;\r
+\r
   AhciClearPortStatus (PciIo, Port);\r
 \r
   AhciStopCommand (PciIo, Port, Timeout);\r
@@ -1163,14 +1338,14 @@ AhciPortReset (
   AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
 \r
   //\r
-  // wait 5 milliseceond before de-assert DET  \r
+  // wait 5 millisecond before de-assert DET\r
   //\r
   MicroSecondDelay (5000);\r
 \r
   AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
 \r
   //\r
-  // wait 5 milliseceond before de-assert DET  \r
+  // wait 5 millisecond before de-assert DET\r
   //\r
   MicroSecondDelay (5000);\r
 \r
@@ -1184,7 +1359,7 @@ AhciPortReset (
              EFI_AHCI_PORT_SSTS_DET_MASK,\r
              EFI_AHCI_PORT_SSTS_DET_PCE,\r
              Timeout\r
-             ); \r
+             );\r
 \r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -1198,11 +1373,10 @@ AhciPortReset (
 \r
 /**\r
   Do AHCI HBA reset.\r
-    \r
+\r
   @param  PciIo              The PCI IO protocol instance.\r
   @param  Timeout            The timeout value of reset.\r
\r
-   \r
+\r
   @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.\r
   @retval EFI_TIMEOUT        The reset operation is time out.\r
   @retval EFI_SUCCESS        AHCI controller is reset successfully.\r
@@ -1249,6 +1423,194 @@ AhciReset (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS     Successfully get the return status of S.M.A.R.T command execution.\r
+  @retval Others          Fail to get return status data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciAtaSmartReturnStatusCheck (\r
+  IN EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN EFI_AHCI_REGISTERS          *AhciRegisters,\r
+  IN UINT8                       Port,\r
+  IN UINT8                       PortMultiplier,\r
+  IN OUT EFI_ATA_STATUS_BLOCK    *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;\r
+  UINT8                   LBAMid;\r
+  UINT8                   LBAHigh;\r
+  UINTN                   FisBaseAddr;\r
+  UINT32                  Value;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+  AtaCommandBlock.AtaFeatures     = ATA_SMART_RETURN_STATUS;\r
+  AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+  AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+  //\r
+  // Send S.M.A.R.T Read Return Status command to device\r
+  //\r
+  Status = AhciNonDataTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             (UINT8)Port,\r
+             (UINT8)PortMultiplier,\r
+             NULL,\r
+             0,\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+\r
+  Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+\r
+  if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
+    LBAMid  = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[5];\r
+    LBAHigh = ((UINT8 *)(UINTN)(FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET))[6];\r
+\r
+    if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+      //\r
+      // The threshold exceeded condition is not detected by the device\r
+      //\r
+      DEBUG ((EFI_D_INFO, "The S.M.A.R.T threshold exceeded condition is not detected\n"));\r
+\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
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable SMART command of the disk if supported.\r
+\r
+  @param  PciIo               The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port                The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  IdentifyData        A pointer to data buffer which is used to contain IDENTIFY data.\r
+  @param  AtaStatusBlock      A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAtaSmartSupport (\r
+  IN EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN UINT8                         Port,\r
+  IN UINT8                         PortMultiplier,\r
+  IN EFI_IDENTIFY_DATA             *IdentifyData,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;\r
+\r
+  //\r
+  // Detect if the device supports S.M.A.R.T.\r
+  //\r
+  if ((IdentifyData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+    //\r
+    // S.M.A.R.T is not supported by the device\r
+    //\r
+    DEBUG ((EFI_D_INFO, "S.M.A.R.T feature is not supported at port [%d] PortMultiplier [%d]!\n", \r
+            Port, PortMultiplier));\r
+  } 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
+      ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+      AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+      AtaCommandBlock.AtaFeatures     = ATA_SMART_ENABLE_OPERATION;\r
+      AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+      AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+      //\r
+      // Send S.M.A.R.T Enable command to device\r
+      //\r
+      Status = AhciNonDataTransfer (\r
+                 PciIo,\r
+                 AhciRegisters,\r
+                 (UINT8)Port,\r
+                 (UINT8)PortMultiplier,\r
+                 NULL,\r
+                 0,\r
+                 &AtaCommandBlock,\r
+                 AtaStatusBlock,\r
+                 ATA_ATAPI_TIMEOUT,\r
+                 NULL\r
+                 );\r
+\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Send S.M.A.R.T AutoSave command to device\r
+        //\r
+        ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+        AtaCommandBlock.AtaCommand      = ATA_CMD_SMART;\r
+        AtaCommandBlock.AtaFeatures     = 0xD2;\r
+        AtaCommandBlock.AtaSectorCount  = 0xF1;\r
+        AtaCommandBlock.AtaCylinderLow  = ATA_CONSTANT_4F;\r
+        AtaCommandBlock.AtaCylinderHigh = ATA_CONSTANT_C2;\r
+\r
+        Status = AhciNonDataTransfer (\r
+                   PciIo,\r
+                   AhciRegisters,\r
+                   (UINT8)Port,\r
+                   (UINT8)PortMultiplier,\r
+                   NULL,\r
+                   0,\r
+                   &AtaCommandBlock,\r
+                   AtaStatusBlock,\r
+                   ATA_ATAPI_TIMEOUT,\r
+                   NULL\r
+                   );\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = AhciAtaSmartReturnStatusCheck (\r
+                     PciIo,\r
+                     AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplier,\r
+                     AtaStatusBlock\r
+                     );\r
+        }\r
+      }\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at port [%d] PortMultiplier [%d]!\n",\r
+            Port, PortMultiplier));\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
 /**\r
   Send Buffer cmd to specific device.\r
     \r
@@ -1284,7 +1646,7 @@ AhciIdentify (
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;\r
   AtaCommandBlock.AtaSectorCount = 1;\r
 \r
@@ -1300,7 +1662,8 @@ AhciIdentify (
              &AtaStatusBlock,\r
              Buffer,\r
              sizeof (EFI_IDENTIFY_DATA),\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -1338,7 +1701,7 @@ AhciIdentifyPacket (
   if (PciIo == NULL || AhciRegisters == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  \r
+\r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
 \r
@@ -1357,7 +1720,8 @@ AhciIdentifyPacket (
              &AtaStatusBlock,\r
              Buffer,\r
              sizeof (EFI_IDENTIFY_DATA),\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -1396,7 +1760,7 @@ AhciDeviceSetFeature (
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
   ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand      = ATA_CMD_SET_FEATURES;\r
   AtaCommandBlock.AtaFeatures     = (UINT8) Feature;\r
   AtaCommandBlock.AtaFeaturesExp  = (UINT8) (Feature >> 8);\r
@@ -1414,7 +1778,8 @@ AhciDeviceSetFeature (
              0,\r
              &AtaCommandBlock,\r
              &AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -1481,7 +1846,7 @@ AhciPacketCommandExecute (
     Read = FALSE;\r
   }\r
 \r
-  if (Length == 0) {    \r
+  if (Length == 0) {\r
     Status = AhciNonDataTransfer (\r
                PciIo,\r
                AhciRegisters,\r
@@ -1491,7 +1856,8 @@ AhciPacketCommandExecute (
                Packet->CdbLength,\r
                &AtaCommandBlock,\r
                &AtaStatusBlock,\r
-               Packet->Timeout\r
+               Packet->Timeout, \r
+               NULL\r
                );\r
   } else {\r
     //\r
@@ -1515,7 +1881,8 @@ AhciPacketCommandExecute (
                  &AtaStatusBlock,\r
                  Buffer,\r
                  Length,\r
-                 Packet->Timeout\r
+                 Packet->Timeout, \r
+                 NULL\r
                  );\r
       if (!EFI_ERROR (Status)) {\r
         break;\r
@@ -1551,6 +1918,9 @@ AhciCreateTransferDescriptor (
   UINT64                MaxReceiveFisSize;\r
   UINT64                MaxCommandListSize;\r
   UINT64                MaxCommandTableSize;\r
+  EFI_PHYSICAL_ADDRESS  AhciRFisPciAddr;\r
+  EFI_PHYSICAL_ADDRESS  AhciCmdListPciAddr;\r
+  EFI_PHYSICAL_ADDRESS  AhciCommandTablePciAddr;\r
 \r
   Buffer = NULL;\r
   //\r
@@ -1569,7 +1939,7 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1589,7 +1959,7 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *) &AhciRegisters->AhciRFisPciAddr,\r
+                    &AhciRFisPciAddr,\r
                     &AhciRegisters->MapRFis\r
                     );\r
 \r
@@ -1601,13 +1971,14 @@ AhciCreateTransferDescriptor (
     goto Error6;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciRFisPciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciRFisPciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error5;\r
   }\r
+  AhciRegisters->AhciRFisPciAddr = (EFI_AHCI_RECEIVED_FIS *)(UINTN)AhciRFisPciAddr;\r
 \r
   //\r
   // Allocate memory for command list\r
@@ -1619,7 +1990,7 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1643,7 +2014,7 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCmdListPciAddr,\r
+                    &AhciCmdListPciAddr,\r
                     &AhciRegisters->MapCmdList\r
                     );\r
 \r
@@ -1655,13 +2026,14 @@ AhciCreateTransferDescriptor (
     goto Error4;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCmdListPciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciCmdListPciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error3;\r
   }\r
+  AhciRegisters->AhciCmdListPciAddr = (EFI_AHCI_COMMAND_LIST *)(UINTN)AhciCmdListPciAddr;\r
 \r
   //\r
   // Allocate memory for command table\r
@@ -1674,7 +2046,7 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1698,7 +2070,7 @@ AhciCreateTransferDescriptor (
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    (EFI_PHYSICAL_ADDRESS *)&AhciRegisters->AhciCommandTablePciAddr,\r
+                    &AhciCommandTablePciAddr,\r
                     &AhciRegisters->MapCommandTable\r
                     );\r
 \r
@@ -1710,13 +2082,14 @@ AhciCreateTransferDescriptor (
     goto Error2;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)(UINTN)AhciRegisters->AhciCommandTablePciAddr > 0x100000000ULL)) {\r
+  if ((!Support64Bit) && (AhciCommandTablePciAddr > 0x100000000ULL)) {\r
     //\r
     // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
     //\r
     Status = EFI_DEVICE_ERROR;\r
     goto Error1;\r
   }\r
+  AhciRegisters->AhciCommandTablePciAddr = (EFI_AHCI_COMMAND_TABLE *)(UINTN)AhciCommandTablePciAddr;\r
 \r
   return EFI_SUCCESS;\r
   //\r
@@ -1730,7 +2103,7 @@ Error1:
 Error2:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
            AhciRegisters->AhciCommandTable\r
            );\r
 Error3:\r
@@ -1741,7 +2114,7 @@ Error3:
 Error4:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
            AhciRegisters->AhciCmdList\r
            );\r
 Error5:\r
@@ -1752,7 +2125,7 @@ Error5:
 Error6:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           (UINTN)EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
            AhciRegisters->AhciRFis\r
            );\r
 \r
@@ -1947,6 +2320,20 @@ AhciModeInitialization (
         DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
             Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
 \r
+        //\r
+        // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
+        //\r
+        if (DeviceType == EfiIdeHarddisk) {\r
+          AhciAtaSmartSupport (\r
+            PciIo,\r
+            AhciRegisters,\r
+            Port,\r
+            0,\r
+            &Buffer,\r
+            NULL\r
+            );\r
+        }\r
+\r
         //\r
         // Submit identify data to IDE controller init driver\r
         //\r