]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
MdeModulePkg: ATA performance tuning.
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AtaAtapiPassThru / IdeMode.c
index d3eb940839e7035442c7ebd46545d6aab210893a..0604a9d4c3cbd60774a25615cb2925b9ce90091a 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Header 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
@@ -17,7 +17,7 @@
 /**\r
   read a one-byte data from a IDE port.\r
 \r
-  @param  PciIo  The PCI IO protocol instance\r
+  @param  PciIo  A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port   The IDE Port number \r
 \r
   @return  the one-byte data read from IDE port\r
@@ -51,7 +51,7 @@ IdeReadPortB (
 /**\r
   write a 1-byte data to a specific IDE port.\r
 \r
-  @param  PciIo  The PCI IO protocol instance\r
+  @param  PciIo  A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port   The IDE port to be writen\r
   @param  Data   The data to write to the port\r
 **/\r
@@ -81,7 +81,7 @@ IdeWritePortB (
 /**\r
   write a 1-word data to a specific IDE port.\r
 \r
-  @param  PciIo  PCI IO protocol instance\r
+  @param  PciIo  A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port   The IDE port to be writen\r
   @param  Data   The data to write to the port\r
 **/\r
@@ -111,7 +111,7 @@ IdeWritePortW (
 /**\r
   write a 2-word data to a specific IDE port.\r
 \r
-  @param  PciIo  PCI IO protocol instance\r
+  @param  PciIo  A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port   The IDE port to be writen\r
   @param  Data   The data to write to the port\r
 **/\r
@@ -143,7 +143,7 @@ IdeWritePortDW (
   Call the IO abstraction once to do the complete read,\r
   not one word at a time\r
 \r
-  @param  PciIo      Pointer to the EFI_PCI_IO instance\r
+  @param  PciIo      A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port       IO port to read\r
   @param  Count      No. of UINT16's to read\r
   @param  Buffer     Pointer to the data buffer for read\r
@@ -180,7 +180,7 @@ IdeWritePortWMultiple (
   Call the IO abstraction once to do the complete read,\r
   not one word at a time\r
 \r
-  @param  PciIo    Pointer to the EFI_PCI_IO instance\r
+  @param  PciIo    A pointer to EFI_PCI_IO_PROTOCOL data structure\r
   @param  Port     IO port to read\r
   @param  Count    Number of UINT16's to read\r
   @param  Buffer   Pointer to the data buffer for read\r
@@ -217,7 +217,7 @@ IdeReadPortWMultiple (
   some debug information and if there is ERR bit set in the Status\r
   Register, the Error Register's value is also be parsed and print out.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
   @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
 \r
@@ -294,11 +294,10 @@ DumpAllIdeRegisters (
 }\r
 \r
 /**\r
-  This function is used to analyze the Status Register and print out\r
-  some debug information and if there is ERR bit set in the Status\r
-  Register, the Error Register's value is also be parsed and print out.\r
+  This function is used to analyze the Status Register at the condition that BSY is zero.\r
+  if there is ERR bit set in the Status Register, then return error.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
 \r
   @retval EFI_SUCCESS       No err information in the Status Register.\r
@@ -312,7 +311,6 @@ CheckStatusRegister (
   IN  EFI_IDE_REGISTERS        *IdeRegisters\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
   UINT8           StatusRegister;\r
 \r
   ASSERT (PciIo != NULL);\r
@@ -320,13 +318,14 @@ CheckStatusRegister (
 \r
   StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
 \r
-  if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
-    Status = EFI_SUCCESS;\r
-  } else {\r
-    Status = EFI_DEVICE_ERROR;\r
+  if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
+    if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
+      return EFI_SUCCESS;\r
+    } else {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
   }\r
-\r
-  return Status;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -334,9 +333,9 @@ CheckStatusRegister (
   Register. DRQ is cleared when the device is finished transferring data.\r
   So this function is called after data transfer is finished.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS     DRQ bit clear within the time out.\r
 \r
@@ -356,7 +355,6 @@ DRQClear (
 {\r
   UINT32  Delay;\r
   UINT8   StatusRegister;\r
-  UINT8   ErrorRegister;\r
 \r
   ASSERT (PciIo != NULL);\r
   ASSERT (IdeRegisters != NULL);\r
@@ -366,22 +364,18 @@ DRQClear (
     StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
 \r
     //\r
-    // wait for BSY == 0 and DRQ == 0\r
+    // Wait for BSY == 0, then judge if DRQ is clear\r
     //\r
-    if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
-      break;\r
-    }\r
-\r
-    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
-\r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+    if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
+        return EFI_DEVICE_ERROR;\r
+      } else {\r
+        return EFI_SUCCESS;\r
       }\r
     }\r
 \r
     //\r
-    //  Stall for 100 microseconds.\r
+    // Stall for 100 microseconds.\r
     //\r
     MicroSecondDelay (100);\r
 \r
@@ -389,11 +383,7 @@ DRQClear (
 \r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 /**\r
   This function is used to poll for the DRQ bit clear in the Alternate\r
@@ -401,9 +391,9 @@ DRQClear (
   transferring data. So this function is called after data transfer\r
   is finished.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS     DRQ bit clear within the time out.\r
 \r
@@ -421,7 +411,6 @@ DRQClear2 (
 {\r
   UINT32  Delay;\r
   UINT8   AltRegister;\r
-  UINT8   ErrorRegister;\r
 \r
   ASSERT (PciIo != NULL);\r
   ASSERT (IdeRegisters != NULL);\r
@@ -431,17 +420,13 @@ DRQClear2 (
     AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
 \r
     //\r
-    //  wait for BSY == 0 and DRQ == 0\r
+    // Wait for BSY == 0, then judge if DRQ is clear\r
     //\r
-    if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
-      break;\r
-    }\r
-\r
-    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
-\r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+    if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
+        return EFI_DEVICE_ERROR;\r
+      } else {\r
+        return EFI_SUCCESS;\r
       }\r
     }\r
 \r
@@ -454,11 +439,7 @@ DRQClear2 (
 \r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -468,9 +449,9 @@ DRQClear2 (
   is called after the command is sent to the device and before required\r
   data is transferred.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS          DRQ bit set within the time out.\r
   @retval EFI_TIMEOUT          DRQ bit not set within the time out.\r
@@ -497,22 +478,27 @@ DRQReady (
   Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
   do {\r
     //\r
-    //  read Status Register will clear interrupt\r
+    // Read Status Register will clear interrupt\r
     //\r
     StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
 \r
     //\r
-    //  BSY==0,DRQ==1\r
+    // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
     //\r
-    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
-      break;\r
-    }\r
+    if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+        ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
 \r
-    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+        if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+          return EFI_ABORTED;\r
+        }\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
 \r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+      if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        return EFI_NOT_READY;\r
       }\r
     }\r
 \r
@@ -524,20 +510,16 @@ DRQReady (
     Delay--;\r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 /**\r
   This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
   DRQ is set when the device is ready to transfer data. So this function is called after \r
   the command is sent to the device and before required data is transferred.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS           DRQ bit set within the time out.\r
   @retval EFI_TIMEOUT           DRQ bit not set within the time out.\r
@@ -564,21 +546,26 @@ DRQReady2 (
 \r
   do {\r
     //\r
-    //  Read Alternate Status Register will not clear interrupt status\r
+    // Read Alternate Status Register will not clear interrupt status\r
     //\r
     AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
     //\r
-    // BSY == 0 , DRQ == 1\r
+    // Wait for BSY == 0, then judge if DRQ is clear or ERR is set\r
     //\r
-    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
-      break;\r
-    }\r
+    if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+        ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
 \r
-    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+        if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+          return EFI_ABORTED;\r
+        }\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
 \r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+      if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        return EFI_NOT_READY;\r
       }\r
     }\r
 \r
@@ -590,11 +577,7 @@ DRQReady2 (
     Delay--;\r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -602,9 +585,9 @@ DRQReady2 (
   bit is set when the device is ready to accept command. Most ATA commands must be \r
   sent after DRDY set except the ATAPI Packet Command.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS         DRDY bit set within the time out.\r
   @retval EFI_TIMEOUT         DRDY bit not set within the time out.\r
@@ -630,17 +613,22 @@ DRDYReady (
   do {\r
     StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
     //\r
-    //  BSY == 0 , DRDY == 1\r
+    // Wait for BSY == 0, then judge if DRDY is set or ERR is set\r
     //\r
-    if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
-      break;\r
-    }\r
+    if ((StatusRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+        ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
 \r
-    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+        if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+          return EFI_ABORTED;\r
+        }\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
 \r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+      if ((StatusRegister & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        return EFI_DEVICE_ERROR;\r
       }\r
     }\r
 \r
@@ -652,11 +640,7 @@ DRDYReady (
     Delay--;\r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -664,9 +648,9 @@ DRDYReady (
   DRDY bit is set when the device is ready to accept command. Most ATA commands must \r
   be sent after DRDY set except the ATAPI Packet Command.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param PciIo            A pointer to EFI_PCI_IO_PROTOCOL data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS      DRDY bit set within the time out.\r
   @retval EFI_TIMEOUT      DRDY bit not set within the time out.\r
@@ -693,17 +677,22 @@ DRDYReady2 (
   do {\r
     AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
     //\r
-    //  BSY == 0 , DRDY == 1\r
+    // Wait for BSY == 0, then judge if DRDY is set or ERR is set\r
     //\r
-    if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
-      break;\r
-    }\r
+    if ((AltRegister & ATA_STSREG_BSY) == 0) {\r
+      if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+        ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
 \r
-    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
-      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+        if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+          return EFI_ABORTED;\r
+        }\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
 \r
-      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
-        return EFI_ABORTED;\r
+      if ((AltRegister & ATA_STSREG_DRDY) == ATA_STSREG_DRDY) {\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        return EFI_DEVICE_ERROR;\r
       }\r
     }\r
 \r
@@ -715,11 +704,7 @@ DRDYReady2 (
     Delay--;\r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -728,7 +713,7 @@ DRDYReady2 (
 \r
   @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS          BSY bit clear within the time out.\r
   @retval EFI_TIMEOUT          BSY bit not clear within the time out.\r
@@ -754,7 +739,7 @@ WaitForBSYClear (
     StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
 \r
     if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
-      break;\r
+      return EFI_SUCCESS;\r
     }\r
 \r
     //\r
@@ -766,11 +751,7 @@ WaitForBSYClear (
 \r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -779,7 +760,7 @@ WaitForBSYClear (
 \r
   @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS          BSY bit clear within the time out.\r
   @retval EFI_TIMEOUT          BSY bit not clear within the time out.\r
@@ -805,7 +786,7 @@ WaitForBSYClear2 (
     AltStatusRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
 \r
     if ((AltStatusRegister & ATA_STSREG_BSY) == 0x00) {\r
-      break;\r
+      return EFI_SUCCESS;\r
     }\r
 \r
     //\r
@@ -817,11 +798,7 @@ WaitForBSYClear2 (
 \r
   } while (Delay > 0);\r
 \r
-  if (Delay == 0) {\r
-    return EFI_TIMEOUT;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
+  return EFI_TIMEOUT;\r
 }\r
 \r
 /**\r
@@ -960,7 +937,7 @@ GetIdeRegisterIoAddr (
   IdeRegisters[EfiIdeSecondary].Head              = (UINT16) (CommandBlockBaseAddr + 0x06);\r
   IdeRegisters[EfiIdeSecondary].CmdOrStatus       = (UINT16) (CommandBlockBaseAddr + 0x07);\r
   IdeRegisters[EfiIdeSecondary].AltOrDev          = ControlBlockBaseAddr;\r
-  IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = BusMasterBaseAddr + 0x8;\r
+  IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = (UINT16) (BusMasterBaseAddr + 0x8);\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -978,7 +955,7 @@ GetIdeRegisterIoAddr (
 \r
   @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS       Soft reset completes successfully.\r
   @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.\r
@@ -1038,7 +1015,7 @@ AtaSoftReset (
   @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
   @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
   @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param Timeout          The time to complete the command, uses 100ns as a unit.\r
 \r
   @retval  EFI_SUCCESS Reading succeed\r
   @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
@@ -1123,16 +1100,20 @@ AtaIssueCommand (
 /**\r
   This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Buffer           A pointer to the source buffer for the data.\r
-  @param ByteCount        The length of  the data.\r
-  @param Read             Flag used to determine the data transfer direction.\r
-                          Read equals 1, means data transferred from device to host;\r
-                          Read equals 0, means data transferred from host to device.  \r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
+                                   structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in, out] Buffer           A pointer to the source buffer for the data.\r
+  @param[in]      ByteCount        The length of the data.\r
+  @param[in]      Read             Flag used to determine the data transfer direction.\r
+                                   Read equals 1, means data transferred from device\r
+                                   to host;Read equals 0, means data transferred\r
+                                   from host to device.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param[in, out] AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command, uses 100ns as a unit.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
   \r
   @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
@@ -1148,7 +1129,8 @@ AtaPioDataInOut (
   IN     BOOLEAN                   Read,\r
   IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     UINT64                    Timeout,\r
+  IN     ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   UINTN       WordCount;\r
@@ -1248,17 +1230,24 @@ Exit:
   //\r
   DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
 \r
+  //\r
+  // Not support the Non-blocking now,just do the blocking process.\r
+  //\r
   return Status;\r
 }\r
 \r
 /**\r
   Send ATA command into device with NON_DATA protocol\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE\r
+                                   data structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data\r
+                                   structure.\r
+  @param[in, out] AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command, uses 100ns as a unit.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
 \r
   @retval  EFI_SUCCESS Reading succeed\r
   @retval  EFI_ABORTED Command failed\r
@@ -1272,7 +1261,8 @@ AtaNonDataCommandIn (
   IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
   IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
   IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     UINT64                    Timeout,\r
+  IN     ATA_NONBLOCK_TASK         *Task\r
   )\r
 {\r
   EFI_STATUS  Status;\r
@@ -1310,24 +1300,137 @@ Exit:
   // Dump All Ide registers to ATA_STATUS_BLOCK\r
   //\r
   DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  \r
+  //\r
+  // Not support the Non-blocking now,just do the blocking process.\r
+  //\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for memory to be set.\r
+    \r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  IdeRegisters    A pointer to EFI_IDE_REGISTERS data structure.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmStatusWait (\r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters\r
+ ) \r
+{\r
+  UINT8                         RegisterValue;\r
+  EFI_STATUS                    Status;\r
+  UINT16                        IoPortForBmis;\r
+  UINT64                        Timeout;\r
+\r
+  Timeout = 2000;\r
+\r
+  while (TRUE) {\r
+    Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
+    RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
+    if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
+      DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+    //\r
+    // Stall for 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+    Timeout--;\r
+  }\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Check if the memory to be set.\r
+    \r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Task            Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                              used by non-blocking mode.\r
+  @param[in]  IdeRegisters    A pointer to EFI_IDE_REGISTERS data structure.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory setting met a issue.\r
+  @retval EFI_NOT_READY     The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaUdmStatusCheck (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     ATA_NONBLOCK_TASK          *Task,\r
+  IN     EFI_IDE_REGISTERS          *IdeRegisters\r
+ )\r
+{\r
+  UINT8          RegisterValue;\r
+  UINT16         IoPortForBmis;\r
+  EFI_STATUS     Status;\r
+\r
+  Task->RetryTimes--;\r
+\r
+  Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
+  RegisterValue = IdeReadPortB (PciIo, IoPortForBmis);\r
+\r
+  if ((RegisterValue & BMIS_ERROR) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (Task->RetryTimes == 0) {\r
+    return EFI_TIMEOUT;\r
+  } else {\r
+    //\r
+    // The memory is not set.\r
+    //\r
+    return EFI_NOT_READY;\r
+  }\r
+}\r
 \r
 /**\r
   Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
 \r
-  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
-  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
-  @param Read             Flag used to determine the data transfer direction.\r
-                          Read equals 1, means data transferred from device to host;\r
-                          Read equals 0, means data transferred from host to device.\r
-  @param DataBuffer       A pointer to the source buffer for the data.\r
-  @param DataLength       The length of  the data.\r
-  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
-  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
-  @param Timeout          The time to complete the command.\r
+  @param[in]      Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data\r
+                                   structure.\r
+  @param[in]      IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param[in]      Read             Flag used to determine the data transfer\r
+                                   direction. Read equals 1, means data transferred\r
+                                   from device to host;Read equals 0, means data\r
+                                   transferred from host to device.\r
+  @param[in]      DataBuffer       A pointer to the source buffer for the data.\r
+  @param[in]      DataLength       The length of  the data.\r
+  @param[in]      AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param[in, out] AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param[in]      Timeout          The time to complete the command, uses 100ns as a unit.\r
+  @param[in]      Task             Optional. Pointer to the ATA_NONBLOCK_TASK\r
+                                   used by non-blocking mode.\r
 \r
   @retval EFI_SUCCESS          the operation is successful.\r
   @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
@@ -1338,14 +1441,15 @@ Exit:
 EFI_STATUS\r
 EFIAPI\r
 AtaUdmaInOut (\r
-  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
-  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
-  IN     BOOLEAN                   Read,\r
-  IN     VOID                      *DataBuffer,\r
-  IN     UINT64                    DataLength,\r
-  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
-  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
-  IN     UINT64                    Timeout\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     EFI_IDE_REGISTERS             *IdeRegisters,\r
+  IN     BOOLEAN                       Read,\r
+  IN     VOID                          *DataBuffer,\r
+  IN     UINT64                        DataLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
+  IN     UINT64                        Timeout,\r
+  IN     ATA_NONBLOCK_TASK             *Task\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
@@ -1353,18 +1457,17 @@ AtaUdmaInOut (
   UINT16                        IoPortForBmis;\r
   UINT16                        IoPortForBmid;\r
 \r
-  UINT8                         RegisterValue;\r
-\r
-  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
-  UINTN                         PrdTableNum;\r
   UINTN                         PrdTableSize;\r
   EFI_PHYSICAL_ADDRESS          PrdTableMapAddr;\r
   VOID                          *PrdTableMap;\r
+  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
+  EFI_ATA_DMA_PRD               *TempPrdBaseAddr;\r
+  UINTN                         PrdTableNum;\r
 \r
+  UINT8                         RegisterValue;\r
   UINTN                         PageCount;\r
   UINTN                         ByteCount;\r
   UINTN                         ByteRemaining;\r
-\r
   UINT8                         DeviceControl;\r
 \r
   VOID                          *BufferMap;\r
@@ -1372,251 +1475,303 @@ AtaUdmaInOut (
   EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
 \r
   UINT8                         DeviceHead;\r
-  UINT8                         AtaCommand;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  EFI_TPL                       OldTpl;\r
 \r
-  Status      = EFI_SUCCESS;\r
-  PrdBaseAddr = NULL;\r
 \r
-  if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  Status        = EFI_SUCCESS;\r
+  PrdBaseAddr   = NULL;\r
+  PrdTableMap   = NULL;\r
+  BufferMap     = NULL;\r
+  PageCount     = 0;\r
+  PciIo         = Instance->PciIo;\r
 \r
-  //\r
-  // The data buffer should be even alignment\r
-  //\r
-  if (((UINTN)DataBuffer & 0x1) != 0) {\r
+  if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
-  // Calculate the number of PRD entry.\r
-  // Every entry in PRD table can specify a 64K memory region.\r
+  // Before starting the Blocking BlockIO operation, push to finish all non-blocking\r
+  // BlockIO tasks.\r
+  // Delay 1ms to simulate the blocking time out checking.\r
   //\r
-  PrdTableNum   = (UINTN)(RShiftU64(DataLength, 16) + 1);\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 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+  } \r
 \r
   //\r
-  // Make sure that the memory region of PRD table is not cross 64K boundary\r
+  // The data buffer should be even alignment\r
   //\r
-  PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
-  if (PrdTableSize > 0x10000) {\r
+  if (((UINTN)DataBuffer & 0x1) != 0) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   //\r
-  // Allocate buffer for PRD table initialization.\r
+  // Set relevant IO Port address.\r
   //\r
-  PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
-  Status    = PciIo->AllocateBuffer (\r
-                       PciIo,\r
-                       AllocateAnyPages,\r
-                       EfiBootServicesData,\r
-                       PageCount,\r
-                       &PrdBaseAddr,\r
-                       0\r
-                       );\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
-  ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
-  Status    = PciIo->Map (\r
-                       PciIo,\r
-                       EfiPciIoOperationBusMasterCommonBuffer,\r
-                       PrdBaseAddr,\r
-                       &ByteCount,\r
-                       &PrdTableMapAddr,\r
-                       &PrdTableMap\r
-                       );\r
-  if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
-    //\r
-    // If the data length actually mapped is not equal to the requested amount,\r
-    // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
-    // Can't handle this case.\r
-    //\r
-    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  IoPortForBmic = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET);\r
+  IoPortForBmis = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET);\r
+  IoPortForBmid = (UINT16) (IdeRegisters->BusMasterBaseAddr + BMID_OFFSET);\r
 \r
-  ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
-\r
-  //\r
-  // Map the host address of DataBuffer to DMA master address.\r
   //\r
-  if (Read) {\r
-    PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
-  } else {\r
-    PciIoOperation = EfiPciIoOperationBusMasterRead;\r
-  }\r
+  // For Blocking mode, start the command. \r
+  // For non-blocking mode, when the command is not started, start it, otherwise\r
+  // go to check the status.\r
+  //  \r
+  if (((Task != NULL) && (!Task->IsStart)) || (Task == NULL)) {\r
+    //\r
+    // Calculate the number of PRD entry.\r
+    // Every entry in PRD table can specify a 64K memory region.\r
+    //\r
+    PrdTableNum   = (UINTN)(RShiftU64(DataLength, 16) + 1);\r
 \r
-  ByteCount = DataLength;\r
-  Status    = PciIo->Map (\r
-                       PciIo,\r
-                       PciIoOperation,\r
-                       DataBuffer,\r
-                       &ByteCount,\r
-                       &BufferMapAddress,\r
-                       &BufferMap\r
-                       );\r
-  if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
-    PciIo->Unmap (PciIo, PrdTableMap);\r
-    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+    //\r
+    // Make sure that the memory region of PRD table is not cross 64K boundary\r
+    //\r
+    PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
+    if (PrdTableSize > 0x10000) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
-  //\r
-  // According to Ata spec, it requires the buffer address and size to be even.\r
-  //\r
-  ASSERT ((BufferMapAddress & 0x1) == 0);\r
-  ASSERT ((ByteCount & 0x1) == 0);\r
+    //\r
+    // Allocate buffer for PRD table initialization.\r
+    //\r
+    PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    Status    = PciIo->AllocateBuffer (\r
+                         PciIo,\r
+                         AllocateAnyPages,\r
+                         EfiBootServicesData,\r
+                         PageCount,\r
+                         (VOID **)&PrdBaseAddr,\r
+                         0\r
+                         );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
-  //\r
-  // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
-  //\r
-  ByteRemaining = ByteCount;\r
-  while (ByteRemaining != 0) {\r
-    if (ByteRemaining <= 0x10000) {\r
-      PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
-      PrdBaseAddr->ByteCount      = (UINT16) ByteRemaining;\r
-      PrdBaseAddr->EndOfTable     = 0x8000;\r
-      break;\r
+    ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+    Status    = PciIo->Map (\r
+                         PciIo,\r
+                         EfiPciIoOperationBusMasterCommonBuffer,\r
+                         PrdBaseAddr,\r
+                         &ByteCount,\r
+                         &PrdTableMapAddr,\r
+                         &PrdTableMap\r
+                         );\r
+    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+      //\r
+      // If the data length actually mapped is not equal to the requested amount,\r
+      // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
+      // Can't handle this case.\r
+      //\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
-    PrdBaseAddr->ByteCount      = (UINT16) 0x0;\r
+    ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
 \r
-    ByteRemaining    -= 0x10000;\r
-    BufferMapAddress += 0x10000;\r
-    PrdBaseAddr++;\r
-  }\r
+    //\r
+    // Map the host address of DataBuffer to DMA master address.\r
+    //\r
+    if (Read) {\r
+      PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
+    } else {\r
+      PciIoOperation = EfiPciIoOperationBusMasterRead;\r
+    }\r
 \r
-  //\r
-  // Start to enable the DMA operation\r
-  //\r
-  DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
-  AtaCommand = AtaCommandBlock->AtaCommand;\r
+    ByteCount = (UINTN)DataLength;\r
+    Status    = PciIo->Map (\r
+                         PciIo,\r
+                         PciIoOperation,\r
+                         DataBuffer,\r
+                         &ByteCount,\r
+                         &BufferMapAddress,\r
+                         &BufferMap\r
+                         );\r
+    if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
+      PciIo->Unmap (PciIo, PrdTableMap);\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // According to Ata spec, it requires the buffer address and size to be even.\r
+    //\r
+    ASSERT ((BufferMapAddress & 0x1) == 0);\r
+    ASSERT ((ByteCount & 0x1) == 0);\r
 \r
-  IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
+    //\r
+    // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
+    //\r
+    ByteRemaining   = ByteCount;\r
+    TempPrdBaseAddr = PrdBaseAddr;\r
+    while (ByteRemaining != 0) {\r
+      if (ByteRemaining <= 0x10000) {\r
+        TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
+        TempPrdBaseAddr->ByteCount      = (UINT16) ByteRemaining;\r
+        TempPrdBaseAddr->EndOfTable     = 0x8000;\r
+        break;\r
+      }\r
 \r
-  //\r
-  // Enable interrupt to support UDMA\r
-  //\r
-  DeviceControl = 0;\r
-  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+      TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
+      TempPrdBaseAddr->ByteCount      = (UINT16) 0x0;\r
 \r
-  IoPortForBmic = IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET;\r
-  IoPortForBmis = IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET;\r
-  IoPortForBmid = IdeRegisters->BusMasterBaseAddr + BMID_OFFSET;\r
+      ByteRemaining    -= 0x10000;\r
+      BufferMapAddress += 0x10000;\r
+      TempPrdBaseAddr++;\r
+    }\r
 \r
-  //\r
-  // Read BMIS register and clear ERROR and INTR bit\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
-  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+    //\r
+    // Start to enable the DMA operation\r
+    //\r
+    DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
 \r
-  //\r
-  // Set the base address to BMID register\r
-  //\r
-  IdeWritePortDW(PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
+    IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
 \r
-  //\r
-  // Set BMIC register to identify the operation direction\r
-  //\r
-  RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
-  if (Read) {\r
-    RegisterValue |= BMIC_NREAD;\r
-  } else {\r
-    RegisterValue &= ~((UINT8) BMIC_NREAD);\r
-  }\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+    //\r
+    // Enable interrupt to support UDMA\r
+    //\r
+    DeviceControl = 0;\r
+    IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
 \r
-  //\r
-  // Issue ATA command\r
-  //\r
-  Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
+    //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+    IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto Exit;\r
-  }\r
+    //\r
+    // Set the base address to BMID register\r
+    //\r
+    IdeWritePortDW (PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
 \r
-  //\r
-  // Set START bit of BMIC register\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
-  RegisterValue |= BMIC_START;\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+    //\r
+    // Set BMIC register to identify the operation direction\r
+    //\r
+    RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
+    if (Read) {\r
+      RegisterValue |= BMIC_NREAD;\r
+    } else {\r
+      RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+    }\r
+    IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
 \r
-  //\r
-  // Check the INTERRUPT and ERROR bit of BMIS\r
-  // Max transfer number of sectors for one command is 65536(32Mbyte),\r
-  // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
-  // So set the variable Count to 2000, for about 2 second Timeout time.\r
-  //\r
-  Timeout = 2000;\r
-  while (TRUE) {\r
-    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+    //\r
+    // Issue ATA command\r
+    //\r
+    Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
 \r
-    if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
-      DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+    if (EFI_ERROR (Status)) {\r
       Status = EFI_DEVICE_ERROR;\r
-      break;\r
+      goto Exit;\r
     }\r
 \r
-    if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
-      Status = EFI_SUCCESS;\r
-      break;\r
+    Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
     }\r
     //\r
-    // Stall for 1 milliseconds.\r
+    // Set START bit of BMIC register\r
     //\r
-    MicroSecondDelay (1000);\r
-    Timeout--;\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+    RegisterValue |= BMIC_START;\r
+    IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+\r
+    if (Task != NULL) {\r
+      //\r
+      // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+      // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+      // So set the variable Count to 2000, for about 2 second Timeout time.\r
+      //\r
+      Task->RetryTimes     = 2000;\r
+      Task->Map            = BufferMap;\r
+      Task->TableMap       = PrdTableMap;\r
+      Task->MapBaseAddress = PrdBaseAddr;\r
+      Task->PageCount      = PageCount;\r
+      Task->IsStart        = TRUE;\r
+    }\r
   }\r
 \r
   //\r
-  // Read BMIS register and clear ERROR and INTR bit\r
+  // Check the INTERRUPT and ERROR bit of BMIS\r
+  // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+  // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+  // So set the variable Count to 2000, for about 2 second Timeout time.\r
   //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
-  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+  if (Task != NULL) {\r
+    Status = AtaUdmStatusCheck (PciIo, Task, IdeRegisters);\r
+  } else {\r
+    Status = AtaUdmStatusWait (PciIo, IdeRegisters);\r
+  }\r
 \r
   //\r
-  // Read Status Register of IDE device to clear interrupt\r
+  // For blocking mode, clear registers and free buffers.\r
+  // For non blocking mode, when the related registers have been set or time\r
+  // out, or a error has been happened, it needs to clear the register and free\r
+  // buffer.\r
   //\r
-  RegisterValue  = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
+  if ((Task == NULL) || Status != EFI_NOT_READY) {\r
+    //\r
+    // Read BMIS register and clear ERROR and INTR bit\r
+    //\r
+    RegisterValue  = IdeReadPortB (PciIo, IoPortForBmis);\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+    IdeWritePortB (PciIo, IoPortForBmis, RegisterValue);\r
 \r
-  //\r
-  // Clear START bit of BMIC register\r
-  //\r
-  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
-  RegisterValue &= ~((UINT8) BMIC_START);\r
-  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+    //\r
+    // Read Status Register of IDE device to clear interrupt\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
 \r
-  //\r
-  // Disable interrupt of Select device\r
-  //\r
-  DeviceControl  = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
-  DeviceControl |= ATA_CTLREG_IEN_L;\r
-  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
-  //\r
-  // Stall for 10 milliseconds.\r
-  //\r
-  MicroSecondDelay (10000);\r
+    //\r
+    // Clear START bit of BMIC register\r
+    //\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+    RegisterValue &= ~((UINT8) BMIC_START);\r
+    IdeWritePortB (PciIo, IoPortForBmic, RegisterValue);\r
+\r
+    //\r
+    // Disable interrupt of Select device\r
+    //\r
+    DeviceControl  = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    DeviceControl |= ATA_CTLREG_IEN_L;\r
+    IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+    //\r
+    // Stall for 10 milliseconds.\r
+    //\r
+    MicroSecondDelay (10000);\r
+\r
+  }\r
 \r
 Exit:\r
   //\r
   // Free all allocated resource\r
   //\r
-  PciIo->Unmap (PciIo, PrdTableMap);\r
-  PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
-  PciIo->Unmap (PciIo, BufferMap);\r
-\r
-  //\r
-  // Dump All Ide registers to ATA_STATUS_BLOCK\r
-  //\r
-  DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  if ((Task == NULL) || Status != EFI_NOT_READY) {\r
+    if (Task != NULL) {\r
+      PciIo->Unmap (PciIo, Task->TableMap);\r
+      PciIo->FreeBuffer (PciIo, Task->PageCount, Task->MapBaseAddress);\r
+      PciIo->Unmap (PciIo, Task->Map);\r
+    } else {\r
+      PciIo->Unmap (PciIo, PrdTableMap);\r
+      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->Unmap (PciIo, BufferMap);\r
+    }\r
 \r
+    //\r
+    // Dump All Ide registers to ATA_STATUS_BLOCK\r
+    //\r
+    DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+  }\r
+  \r
   return Status;\r
 }\r
 \r
@@ -1672,7 +1827,8 @@ AtaPacketReadPendingData (
   @param Read          Flag used to determine the data transfer direction.\r
                        Read equals 1, means data transferred from device to host;\r
                        Read equals 0, means data transferred from host to device.\r
-  @param Timeout       Timeout value for wait DRQ ready before each data stream's transfer.\r
+  @param Timeout       Timeout value for wait DRQ ready before each data stream's transfer\r
+                       , uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS      data is transferred successfully.\r
   @retval EFI_DEVICE_ERROR the device failed to transfer data.\r
@@ -1715,8 +1871,7 @@ AtaPacketReadWrite (
     //\r
     Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
     if (EFI_ERROR (Status)) {\r
-      CheckStatusRegister (PciIo, IdeRegisters);\r
-      return EFI_DEVICE_ERROR;\r
+      return CheckStatusRegister (PciIo, IdeRegisters);\r
     }\r
 \r
     //\r
@@ -1777,7 +1932,7 @@ AtaPacketReadWrite (
   //\r
   // After data transfer is completed, normally, DRQ bit should clear.\r
   //\r
-  Status = DRQClear2 (PciIo, IdeRegisters, Timeout);\r
+  Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -1795,7 +1950,7 @@ AtaPacketReadWrite (
   @param[in] Device          The device number of device.\r
   @param[in] SenseData       A pointer to store sense data.\r
   @param[in] SenseDataLength The sense data length.\r
-  @param[in] Timeout         The timeout value to execute this cmd.\r
+  @param[in] Timeout         The timeout value to execute this cmd, uses 100ns as a unit.\r
 \r
   @retval EFI_SUCCESS        Send out the ATAPI packet command successfully.\r
   @retval EFI_DEVICE_ERROR   The device failed to send data.\r
@@ -1890,7 +2045,7 @@ AtaPacketCommandExecute (
   //\r
   AtaCommandBlock.AtaCylinderLow  = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
   AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
-  AtaCommandBlock.AtaDeviceHead   = Device << 0x4;\r
+  AtaCommandBlock.AtaDeviceHead   = (UINT8) (Device << 0x4);\r
   AtaCommandBlock.AtaCommand      = ATA_CMD_PACKET;\r
 \r
   IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | (Device << 0x4)));\r
@@ -2022,7 +2177,8 @@ SetDeviceTransferMode (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2050,7 +2206,6 @@ SetDriveParameters (
   IN     UINT8                         Device,\r
   IN     EFI_ATA_DRIVE_PARMS           *DriveParameters,\r
   IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock\r
-  \r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -2070,7 +2225,8 @@ SetDriveParameters (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   //\r
@@ -2085,12 +2241,181 @@ SetDriveParameters (
              &Instance->IdeRegisters[Channel],\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT, \r
+             NULL\r
              );\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Send SMART Return Status command to check if the execution of SMART cmd is successful or not.\r
+\r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\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
+IdeAtaSmartReturnStatusCheck (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\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
+\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
+  AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+  //\r
+  // Send S.M.A.R.T Read Return Status command to device\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\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
+  LBAMid  = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderLsb);\r
+  LBAHigh = IdeReadPortB (Instance->PciIo, Instance->IdeRegisters[Channel].CylinderMsb);\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
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Enable SMART command of the disk if supported.\r
+\r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\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
+IdeAtaSmartSupport (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\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 [%a] channel [%a] device!\n", \r
+            (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
+  } else {\r
+    //\r
+    // Check if the feature is enabled. If not, then enable S.M.A.R.T.\r
+    //\r
+    if ((IdentifyData->AtaData.command_set_feature_enb_85 & 0x0001) != 0x0001) {\r
+\r
+      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
+      AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+      //\r
+      // Send S.M.A.R.T Enable command to device\r
+      //\r
+      Status = AtaNonDataCommandIn (\r
+                 Instance->PciIo,\r
+                 &Instance->IdeRegisters[Channel],\r
+                 &AtaCommandBlock,\r
+                 AtaStatusBlock,\r
+                 ATA_ATAPI_TIMEOUT,\r
+                 NULL\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
+        AtaCommandBlock.AtaDeviceHead   = (UINT8) ((Device << 0x4) | 0xe0);\r
+\r
+        Status = AtaNonDataCommandIn (\r
+                   Instance->PciIo,\r
+                   &Instance->IdeRegisters[Channel],\r
+                   &AtaCommandBlock,\r
+                   AtaStatusBlock,\r
+                   ATA_ATAPI_TIMEOUT,\r
+                   NULL\r
+                   );\r
+        if (!EFI_ERROR (Status)) {\r
+          Status = IdeAtaSmartReturnStatusCheck (\r
+                     Instance,\r
+                     Channel,\r
+                     Device,\r
+                     AtaStatusBlock\r
+                     );\r
+        }\r
+      }\r
+    }\r
+\r
+    DEBUG ((EFI_D_INFO, "Enabled S.M.A.R.T feature at [%a] channel [%a] device!\n", \r
+           (Channel == 1) ? "secondary" : "primary", (Device == 1) ? "slave" : "master"));\r
+\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+\r
 /**\r
   Sends out an ATA Identify Command to the specified device.\r
 \r
@@ -2111,6 +2436,7 @@ SetDriveParameters (
   @retval EFI_SUCCESS          Identify ATA device successfully.\r
   @retval EFI_DEVICE_ERROR     ATA Identify Device Command failed or device is not ATA device.\r
   @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -2123,10 +2449,10 @@ AtaIdentify (
   )\r
 {\r
   EFI_STATUS             Status;\r
-  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;  \r
+  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;\r
 \r
   ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
-  \r
+\r
   AtaCommandBlock.AtaCommand    = ATA_CMD_IDENTIFY_DRIVE;\r
   AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
 \r
@@ -2138,7 +2464,8 @@ AtaIdentify (
              TRUE,\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2205,7 +2532,8 @@ AtaIdentifyPacket (
              TRUE,\r
              &AtaCommandBlock,\r
              AtaStatusBlock,\r
-             ATA_ATAPI_TIMEOUT\r
+             ATA_ATAPI_TIMEOUT,\r
+             NULL\r
              );\r
 \r
   return Status;\r
@@ -2247,7 +2575,7 @@ DetectAndConfigIdeDevice (
   UINT8                             LBAMidReg;\r
   UINT8                             LBAHighReg;\r
   EFI_ATA_DEVICE_TYPE               DeviceType;\r
-  EFI_IDE_DEVICE                    IdeDevice;\r
+  UINT8                             IdeDevice;\r
   EFI_IDE_REGISTERS                 *IdeRegisters;\r
   EFI_IDENTIFY_DATA                 Buffer;\r
 \r
@@ -2262,7 +2590,7 @@ DetectAndConfigIdeDevice (
   IdeInit      = Instance->IdeControllerInit;\r
   PciIo        = Instance->PciIo;\r
 \r
-  for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {    \r
+  for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {\r
     //\r
     // Send ATA Device Execut Diagnostic command.\r
     // This command should work no matter DRDY is ready or not\r
@@ -2309,6 +2637,8 @@ DetectAndConfigIdeDevice (
       // if identifying ata device is failure, then try to send identify packet cmd.\r
       //\r
       if (EFI_ERROR (Status)) {\r
+        REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_EC_NOT_DETECTED));\r
+\r
         DeviceType = EfiIdeCdrom;\r
         Status     = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
       }\r
@@ -2320,7 +2650,7 @@ DetectAndConfigIdeDevice (
       if (EFI_ERROR (Status)) {\r
         DeviceType = EfiIdeHarddisk;\r
         Status     = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
-      } \r
+      }\r
     }\r
 \r
     if (EFI_ERROR (Status)) {\r
@@ -2328,11 +2658,23 @@ DetectAndConfigIdeDevice (
       // No device is found at this port\r
       //\r
       continue;\r
-    } \r
-  \r
+    }\r
+\r
     DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n", \r
             (IdeChannel == 1) ? "secondary" : "primary  ", (IdeDevice == 1) ? "slave " : "master",\r
             DeviceType == EfiIdeCdrom ? "cdrom   " : "harddisk"));\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
+      IdeAtaSmartSupport (\r
+        Instance,\r
+        IdeChannel,\r
+        IdeDevice,\r
+        &Buffer,\r
+        NULL\r
+        );\r
+    }\r
 \r
     //\r
     // Submit identify data to IDE controller init driver\r
@@ -2372,7 +2714,7 @@ DetectAndConfigIdeDevice (
         continue;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
     // be set together. Only one DMA mode can be set to a device. If setting\r
@@ -2383,7 +2725,7 @@ DetectAndConfigIdeDevice (
       TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
       TransferMode.ModeNumber   = (UINT8) (SupportedModes->UdmaMode.Mode);\r
       Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
-    \r
+\r
       if (EFI_ERROR (Status)) {\r
         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
         continue;\r
@@ -2392,13 +2734,13 @@ DetectAndConfigIdeDevice (
       TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
       TransferMode.ModeNumber   = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
       Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
-    \r
+\r
       if (EFI_ERROR (Status)) {\r
         DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
         continue;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Set Parameters for the device:\r
     // 1) Init\r
@@ -2409,12 +2751,12 @@ DetectAndConfigIdeDevice (
       // Init driver parameters\r
       //\r
       DriveParameters.Sector         = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;\r
-      DriveParameters.Heads          = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1;\r
+      DriveParameters.Heads          = (UINT8) (((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1);\r
       DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;\r
-    \r
+\r
       Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);\r
     }\r
-    \r
+\r
     //\r
     // Set IDE controller Timing Blocks in the PCI Configuration Space\r
     //\r
@@ -2428,6 +2770,10 @@ DetectAndConfigIdeDevice (
     if (EFI_ERROR (Status)) {\r
       continue;\r
     }\r
+\r
+    if (DeviceType == EfiIdeHarddisk) {\r
+      REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_PERIPHERAL_FIXED_MEDIA | EFI_P_PC_ENABLE));\r
+    }\r
   }\r
   return EFI_SUCCESS;\r
 }\r
@@ -2447,7 +2793,6 @@ IdeModeInitialization (
   IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance\r
   )\r
 {\r
-  BOOLEAN                           EnumAll;\r
   EFI_STATUS                        Status;\r
   EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeInit;\r
   EFI_PCI_IO_PROTOCOL               *PciIo;\r
@@ -2458,7 +2803,6 @@ IdeModeInitialization (
 \r
   IdeInit = Instance->IdeControllerInit;\r
   PciIo   = Instance->PciIo;\r
-  EnumAll = IdeInit->EnumAll;\r
   Channel = IdeInit->ChannelCount;\r
 \r
   //\r