]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
Update the function's descriptions (which is in AtaBus, AtaAtapiPassThru, Partition...
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / AhciMode.c
index 71d58f6622c538649b97350bea7fba710eda353e..7acd96fa5026e87459d927c2e7aa1457d411f8a3 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
@@ -135,11 +135,11 @@ AhciOrReg (
 /**\r
   Wait for memory set to the test value.\r
     \r
-  @param  PciIo      The PCI IO protocol instance.\r
-  @param  Offset         The 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.\r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  Offset            The 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.\r
 \r
   @retval EFI_DEVICE_ERROR  The memory is not set.\r
   @retval EFI_TIMEOUT       The memory setting is time out.\r
@@ -184,12 +184,53 @@ 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 OUT 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
+  @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
@@ -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
@@ -347,15 +424,15 @@ AhciDisableFisReceive (
 /**\r
   Build the command list, command table and prepare the fis receiver.\r
     \r
-  @param    PciIo         The PCI IO protocol instance.\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    CommandFis      The control fis will be used for the transfer.\r
-  @param    CommandList     The command list will be used for the transfer.\r
-  @param    AtapiCommand      The atapi command will be used for the transfer.\r
-  @param    AtapiCommandLength  The length of the atapi command.\r
-  @param    CommandSlotNumber   The command slot will be used for the transfer.\r
+  @param    Port                  The number of port.\r
+  @param    PortMultiplier        The timeout value of stop.\r
+  @param    CommandFis            The control fis will be used for the transfer.\r
+  @param    CommandList           The command list will be used for the transfer.\r
+  @param    AtapiCommand          The atapi command will be used for the transfer.\r
+  @param    AtapiCommandLength    The length of the atapi command.\r
+  @param    CommandSlotNumber     The command slot will be used for the transfer.\r
   @param    DataPhysicalAddr      The pointer to the data buffer pci bus master address.\r
   @param    DataLength            The data count to be transferred.\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
@@ -425,12 +502,12 @@ AhciBuildCommand (
     AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
   }\r
   \r
-  RemainedData = DataLength;\r
+  RemainedData = (UINTN) DataLength;\r
   MemAddr      = (UINTN) DataPhysicalAddr;\r
   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
@@ -466,7 +543,7 @@ AhciBuildCommand (
 /**\r
   Buid a command FIS.\r
     \r
-  @param  CmdFis          A pointer to the EFI_AHCI_COMMAND_FIS data structure.\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
 **/\r
@@ -501,24 +578,27 @@ AhciBuildCommandFis (
   CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;\r
   CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
 \r
-  CmdFis->AhciCFisDevHead     = AtaCommandBlock->AtaDeviceHead | 0xE0;\r
+  CmdFis->AhciCFisDevHead     = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);\r
 }\r
 \r
 /**\r
   Start a PIO data transfer on specific port.\r
     \r
-  @param  PciIo             The PCI IO protocol instance.\r
-  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
-  @param  Port              The number of port.\r
-  @param  PortMultiplier    The timeout value of stop.\r
-  @param  AtapiCommand      The atapi command will be used for the transfer.\r
-  @param  AtapiCommandLength  The length of the atapi command.\r
-  @param  Read                The transfer direction.\r
-  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
-  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
-  @param  MemoryAddr          The pointer to the data buffer.\r
-  @param  DataCount           The data count to be transferred.\r
-  @param  Timeout             The timeout value of non data transfer.\r
+  @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
@@ -527,6 +607,7 @@ AhciBuildCommandFis (
 \r
 **/\r
 EFI_STATUS\r
+EFIAPI\r
 AhciPioTransfer (\r
   IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
   IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
@@ -539,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
@@ -602,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
@@ -620,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
@@ -631,7 +713,7 @@ AhciPioTransfer (
     //\r
     MicroSecondDelay(100);\r
 \r
-    Delay--;    \r
+    Delay--;\r
   } while (Delay > 0);\r
 \r
   if (Delay == 0) {\r
@@ -652,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
@@ -685,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
-\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
+  @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
 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
@@ -724,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
@@ -736,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
@@ -887,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
@@ -920,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
@@ -941,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
@@ -952,7 +1126,7 @@ AhciNonDataTransfer (
     //\r
     MicroSecondDelay(100);\r
 \r
-    Delay --;    \r
+    Delay --;\r
   } while (Delay > 0);\r
 \r
   if (Delay == 0) {\r
@@ -968,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
@@ -1013,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
@@ -1021,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
@@ -1076,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
@@ -1111,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
@@ -1147,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
@@ -1162,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
@@ -1183,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
@@ -1197,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
@@ -1248,14 +1423,202 @@ 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
-  @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  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    Buffer                The data buffer to store IDENTIFY PACKET data.\r
+  @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -1283,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
@@ -1299,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
@@ -1308,11 +1672,11 @@ AhciIdentify (
 /**\r
   Send Buffer cmd to specific 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  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    Buffer                The data buffer to store IDENTIFY PACKET data.\r
+  @param  Buffer              The data buffer to store IDENTIFY PACKET data.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -1337,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
@@ -1356,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
@@ -1365,12 +1730,12 @@ AhciIdentifyPacket (
 /**\r
   Send SET FEATURE cmd on specific 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  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    Feature               The data to send Feature register.\r
-  @param  FeatureSpecificData   The specific data for SET FEATURE cmd.\r
+  @param  Feature             The data to send Feature register.\r
+  @param  FeatureSpecificData The specific data for SET FEATURE cmd.\r
 \r
   @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
   @retval EFI_TIMEOUT         The operation is time out.\r
@@ -1395,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
@@ -1413,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
@@ -1480,7 +1846,7 @@ AhciPacketCommandExecute (
     Read = FALSE;\r
   }\r
 \r
-  if (Length == 0) {    \r
+  if (Length == 0) {\r
     Status = AhciNonDataTransfer (\r
                PciIo,\r
                AhciRegisters,\r
@@ -1490,7 +1856,8 @@ AhciPacketCommandExecute (
                Packet->CdbLength,\r
                &AtaCommandBlock,\r
                &AtaStatusBlock,\r
-               Packet->Timeout\r
+               Packet->Timeout, \r
+               NULL\r
                );\r
   } else {\r
     //\r
@@ -1514,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
@@ -1550,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
@@ -1561,14 +1932,14 @@ AhciCreateTransferDescriptor (
   // Get the number of command slots per port supported by this HBA.\r
   //\r
   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
-  Support64Bit         = ((Capability & BIT31) != 0) ? TRUE : FALSE;\r
+  Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
 \r
   MaxReceiveFisSize    = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
   Status = PciIo->AllocateBuffer (\r
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1577,18 +1948,18 @@ AhciCreateTransferDescriptor (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  ZeroMem (Buffer, MaxReceiveFisSize);\r
+  ZeroMem (Buffer, (UINTN)MaxReceiveFisSize);\r
 \r
   AhciRegisters->AhciRFis          = Buffer;\r
   AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
-  Bytes  = MaxReceiveFisSize;\r
+  Bytes  = (UINTN)MaxReceiveFisSize;\r
 \r
   Status = PciIo->Map (\r
                     PciIo,\r
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciRFisPciAddr,\r
+                    &AhciRFisPciAddr,\r
                     &AhciRegisters->MapRFis\r
                     );\r
 \r
@@ -1600,13 +1971,14 @@ AhciCreateTransferDescriptor (
     goto Error6;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciRFisPciAddr > 0x100000000UL)) {\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
@@ -1618,7 +1990,7 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1631,18 +2003,18 @@ AhciCreateTransferDescriptor (
     goto Error5;\r
   }\r
 \r
-  ZeroMem (Buffer, MaxCommandListSize);\r
+  ZeroMem (Buffer, (UINTN)MaxCommandListSize);\r
 \r
   AhciRegisters->AhciCmdList        = Buffer;\r
   AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
-  Bytes  = MaxCommandListSize;\r
+  Bytes  = (UINTN)MaxCommandListSize;\r
 \r
   Status = PciIo->Map (\r
                     PciIo,\r
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCmdListPciAddr,\r
+                    &AhciCmdListPciAddr,\r
                     &AhciRegisters->MapCmdList\r
                     );\r
 \r
@@ -1654,13 +2026,14 @@ AhciCreateTransferDescriptor (
     goto Error4;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCmdListPciAddr > 0x100000000UL)) {\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
@@ -1673,7 +2046,7 @@ AhciCreateTransferDescriptor (
                     PciIo,\r
                     AllocateAnyPages,\r
                     EfiBootServicesData,\r
-                    EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+                    EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
                     &Buffer,\r
                     0\r
                     );\r
@@ -1686,18 +2059,18 @@ AhciCreateTransferDescriptor (
     goto Error3;\r
   }\r
 \r
-  ZeroMem (Buffer, MaxCommandTableSize);\r
+  ZeroMem (Buffer, (UINTN)MaxCommandTableSize);\r
 \r
   AhciRegisters->AhciCommandTable    = Buffer;\r
   AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
-  Bytes  = MaxCommandTableSize;\r
+  Bytes  = (UINTN)MaxCommandTableSize;\r
 \r
   Status = PciIo->Map (\r
                     PciIo,\r
                     EfiPciIoOperationBusMasterCommonBuffer,\r
                     Buffer,\r
                     &Bytes,\r
-                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCommandTablePciAddr,\r
+                    &AhciCommandTablePciAddr,\r
                     &AhciRegisters->MapCommandTable\r
                     );\r
 \r
@@ -1709,13 +2082,14 @@ AhciCreateTransferDescriptor (
     goto Error2;\r
   }\r
 \r
-  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCommandTablePciAddr > 0x100000000UL)) {\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
@@ -1729,7 +2103,7 @@ Error1:
 Error2:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandTableSize),\r
            AhciRegisters->AhciCommandTable\r
            );\r
 Error3:\r
@@ -1740,7 +2114,7 @@ Error3:
 Error4:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxCommandListSize),\r
            AhciRegisters->AhciCmdList\r
            );\r
 Error5:\r
@@ -1751,7 +2125,7 @@ Error5:
 Error6:\r
   PciIo->FreeBuffer (\r
            PciIo,\r
-           EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+           EFI_SIZE_TO_PAGES ((UINTN) MaxReceiveFisSize),\r
            AhciRegisters->AhciRFis\r
            );\r
 \r
@@ -1819,7 +2193,7 @@ AhciModeInitialization (
   // Get the number of command slots per port supported by this HBA.\r
   //\r
   MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
-  Support64Bit         = ((Capability & BIT31) != 0) ? TRUE : FALSE;\r
+  Support64Bit         = (BOOLEAN) (((Capability & BIT31) != 0) ? TRUE : FALSE);\r
 \r
   //\r
   // Get the bit map of those ports exposed by this HBA.\r
@@ -1942,10 +2316,24 @@ AhciModeInitialization (
         } else {\r
           continue;\r
         }\r
-    \r
+\r
         DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
             Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
 \r
+        //\r
+        // If the device is a hard disk, then try to enable S.M.A.R.T feature\r
+        //\r
+        if (DeviceType == EfiIdeHarddisk) {\r
+          AhciAtaSmartSupport (\r
+            PciIo,\r
+            AhciRegisters,\r
+            Port,\r
+            0,\r
+            &Buffer,\r
+            NULL\r
+            );\r
+        }\r
+\r
         //\r
         // Submit identify data to IDE controller init driver\r
         //\r
@@ -1991,7 +2379,7 @@ AhciModeInitialization (
         }\r
 \r
         Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
-    \r
+\r
         if (EFI_ERROR (Status)) {\r
           DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
           continue;\r
@@ -2006,5 +2394,3 @@ AhciModeInitialization (
   return EFI_SUCCESS;\r
 }\r
 \r
-\r
-\r