]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c
Update in IdeBus to solve the non-backward compatibility issue by the MdePkg updates...
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ata.c
index 72941e93d4691ec025e062804eb1117e4810563c..c22f7a3b303e48347c077fe897ada72d61059208 100644 (file)
@@ -1,5 +1,7 @@
 /** @file\r
-  Copyright (c) 2006 - 2008, Intel Corporation.<BR>\r
+  This file contains all helper functions on the ATA command \r
+  \r
+  Copyright (c) 2006 - 2010, Intel Corporation.<BR>\r
   All rights reserved. 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
 **/\r
 \r
 #include "IdeBus.h"\r
+/**\r
+  This function is called by ATAIdentify() to identity whether this disk\r
+  supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
+\r
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+                all the information of the IDE device.\r
+\r
+  @retval EFI_SUCCESS       The disk specified by IdeDev is a Atapi6 supported one and \r
+                            48-bit addressing must be used\r
+  @retval EFI_UNSUPPORTED   The disk dosn't not support Atapi6 or it supports but the \r
+                            capacity is below 120G, 48bit addressing is not needed\r
+  @retval  EFI_DEVICE_ERROR      The identify data in IdeDev is incorrect\r
+  @retval  EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.\r
+\r
+  @note  This function must be called after DEVICE_IDENTITY command has been\r
+          successfully returned\r
+\r
+**/\r
+EFI_STATUS\r
+AtaAtapi6Identify (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  UINT8             Index;\r
+  EFI_LBA           TmpLba;\r
+  EFI_LBA           Capacity;\r
+  EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
+\r
+  if (IdeDev->IdData == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Atapi6IdentifyStruct = IdeDev->IdData;\r
+\r
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r
+    //\r
+    // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r
+    //\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r
+    //\r
+    // The device dosn't support 48 bit addressing\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // 48 bit address feature set is supported, get maximum capacity\r
+  //\r
+  Capacity = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[0];\r
+  for (Index = 1; Index < 4; Index++) {\r
+    //\r
+    // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
+    //\r
+    TmpLba = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[Index];\r
+    Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
+  }\r
+\r
+  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
+    //\r
+    // Capacity exceeds 120GB. 48-bit addressing is really needed\r
+    //\r
+    IdeDev->Type = Ide48bitAddressingHardDisk;\r
+\r
+    //\r
+    // Fill block media information:Media->LogicalPartition ,\r
+    // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
+    //\r
+    IdeDev->BlkIo.Media->IoAlign        = 4;\r
+    IdeDev->BlkIo.Media->MediaId        = 1;\r
+    IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
+    IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
+    IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
+    IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
+    IdeDev->BlkIo.Media->LastBlock      = Capacity - 1;\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+/**\r
+  Enable SMART of the disk if supported\r
+\r
+  @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r
+                all the information of the IDE device.\r
+**/\r
+VOID\r
+AtaSMARTSupport (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  BOOLEAN           SMARTSupported;\r
+  UINT8             Device;\r
+  EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
+  UINT8             DeviceSelect;\r
+  UINT8             LBAMid;\r
+  UINT8             LBAHigh;\r
+\r
+  //\r
+  // Detect if the device supports S.M.A.R.T.\r
+  //\r
+  if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
+    //\r
+    // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
+    //\r
+    return ;\r
+  } else {\r
+    if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+      //\r
+      // S.M.A.R.T is not supported by the device\r
+      //\r
+      SMARTSupported = FALSE;\r
+    } else {\r
+      SMARTSupported = TRUE;\r
+    }\r
+  }\r
+\r
+  if (!SMARTSupported) {\r
+    //\r
+    // Report nonsupport status code\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
+      );\r
+  } else {\r
+    //\r
+    // Enable this feature\r
+    //\r
+    REPORT_STATUS_CODE (\r
+      EFI_PROGRESS_CODE,\r
+      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
+      );\r
+\r
+    Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+    Status = AtaNonDataCommandIn (\r
+              IdeDev,\r
+              ATA_CMD_SMART,\r
+              Device,\r
+              ATA_SMART_ENABLE_OPERATION,\r
+              0,\r
+              0,\r
+              ATA_CONSTANT_4F,\r
+              ATA_CONSTANT_C2\r
+              );\r
+    //\r
+    // Detect if this feature is enabled\r
+    //\r
+    TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+    if (TmpAtaIdentifyPointer == NULL) {\r
+      return;\r
+    }\r
+\r
+    DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);\r
+    Status = AtaPioDataIn (\r
+              IdeDev,\r
+              (VOID *) TmpAtaIdentifyPointer,\r
+              sizeof (EFI_IDENTIFY_DATA),\r
+              ATA_CMD_IDENTIFY_DRIVE,\r
+              DeviceSelect,\r
+              0,\r
+              0,\r
+              0,\r
+              0\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      gBS->FreePool (TmpAtaIdentifyPointer);\r
+      return ;\r
+    }\r
+\r
+    //\r
+    // Check if the feature is enabled\r
+    //\r
+    if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
+      //\r
+      // Read status data\r
+      //\r
+      AtaNonDataCommandIn (\r
+        IdeDev,\r
+        ATA_CMD_SMART,\r
+        Device,\r
+        ATA_SMART_RETURN_STATUS,\r
+        0,\r
+        0,\r
+        ATA_CONSTANT_4F,\r
+        ATA_CONSTANT_C2\r
+        );\r
+      LBAMid  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
+      LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
+\r
+      if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
+        //\r
+        // The threshold exceeded condition is not detected by the device\r
+        //\r
+        REPORT_STATUS_CODE (\r
+              EFI_PROGRESS_CODE,\r
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
+              );\r
+\r
+      } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
+        //\r
+        // The threshold exceeded condition is  detected by the device\r
+        //\r
+        REPORT_STATUS_CODE (\r
+              EFI_PROGRESS_CODE,\r
+              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
+              );\r
+      }\r
+\r
+    } else {\r
+      //\r
+      // Report disabled status code\r
+      //\r
+      REPORT_STATUS_CODE (\r
+            EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
+            (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
+            );\r
+    }\r
 \r
+    gBS->FreePool (TmpAtaIdentifyPointer);\r
+  }\r
+\r
+  return ;\r
+}\r
 /**\r
   Sends out an ATA Identify Command to the specified device.\r
 \r
   information it needs to fill the IDE_BLK_IO_DEV data structure,\r
   including device type, media block size, media capacity, and etc.\r
 \r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
-  to record all the information of the IDE device.\r
-\r
-  @retval EFI_SUCCESS Identify ATA device successfully.\r
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure,used to record \r
+                 all the information of the IDE device.\r
 \r
-  @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or\r
-  device is not ATA device.\r
-\r
-  @note\r
-  parameter IdeDev will be updated in this function.\r
+  @retval EFI_SUCCESS      Identify ATA device successfully.\r
+  @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.\r
+  @note  parameter IdeDev will be updated in this function.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -63,6 +287,9 @@ ATAIdentify (
   //  the ATA Identify command\r
   //\r
   AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
+  if (AtaIdentifyPointer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
 \r
   //\r
   //  use ATA PIO Data In protocol to send ATA Identify command\r
@@ -93,7 +320,7 @@ ATAIdentify (
     //\r
     if (!EFI_ERROR (Status)) {\r
 \r
-      IdeDev->pIdData = AtaIdentifyPointer;\r
+      IdeDev->IdData = AtaIdentifyPointer;\r
 \r
       //\r
       // Print ATA Module Name\r
@@ -170,158 +397,76 @@ ATAIdentify (
   //\r
   // Make sure the pIdData will not be freed again.\r
   //\r
-  IdeDev->pIdData = NULL;\r
+  IdeDev->IdData = NULL;\r
 \r
   return EFI_DEVICE_ERROR;\r
 }\r
 \r
-\r
 /**\r
-  This function is called by ATAIdentify() to identity whether this disk\r
-  supports ATA/ATAPI6 48bit addressing, ie support >120G capacity\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @retval  EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one\r
-  and 48-bit addressing must be used\r
-\r
-  @retval  EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
-  the capacity is below 120G, 48bit addressing is not needed\r
+  This function is a helper function used to change the char order in a string. It\r
+  is designed specially for the PrintAtaModuleName() function. After the IDE device \r
+  is detected, the IDE driver gets the device module name by sending ATA command \r
+  called ATA Identify Command or ATAPI Identify Command to the specified IDE device.\r
+  The module name returned is a string of ASCII characters: the first character is bit8--bit15\r
+  of the first word, the second character is BIT0--bit7 of the first word and so on. Thus\r
+  the string can not be print directly before it is preprocessed by this func to change \r
+  the order of characters in each word in the string.\r
+\r
+  @param Destination Indicates the destination string.\r
+  @param Source      Indicates the source string.\r
+  @param Size         the length of the string\r
+**/\r
+VOID\r
+SwapStringChars (\r
+  IN CHAR8  *Destination,\r
+  IN CHAR8  *Source,\r
+  IN UINT32 Size\r
+  )\r
+{\r
+  UINT32  Index;\r
+  CHAR8   Temp;\r
 \r
-  @retval  EFI_DEVICE_ERROR The identify data in IdeDev is incorrect\r
-  \r
-  @retval  EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.\r
+  for (Index = 0; Index < Size; Index += 2) {\r
 \r
-  @note\r
-  This function must be called after DEVICE_IDENTITY command has been\r
-  successfully returned\r
+    Temp                    = Source[Index + 1];\r
+    Destination[Index + 1]  = Source[Index];\r
+    Destination[Index]      = Temp;\r
+  }\r
+}\r
+/**\r
+  This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.\r
 \r
+  @param  IdeDev   pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+                   all the information of the IDE device.\r
 **/\r
-EFI_STATUS\r
-AtaAtapi6Identify (\r
+VOID\r
+PrintAtaModuleName (\r
   IN  IDE_BLK_IO_DEV  *IdeDev\r
   )\r
 {\r
-  UINT8             Index;\r
-  EFI_LBA           TmpLba;\r
-  EFI_LBA           Capacity;\r
-  EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;\r
-\r
-  if (IdeDev->pIdData == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  if (IdeDev->IdData == NULL) {\r
+    return ;\r
   }\r
 \r
-  Atapi6IdentifyStruct = IdeDev->pIdData;\r
-\r
-  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {\r
-    //\r
-    // Per ATA-6 spec, word83: bit15 is zero and bit14 is one\r
-    //\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+  SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);\r
+  IdeDev->ModelName[40] = 0x00;\r
+}\r
 \r
-  if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {\r
-    //\r
-    // The device dosn't support 48 bit addressing\r
-    //\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // 48 bit address feature set is supported, get maximum capacity\r
-  //\r
-  Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];\r
-  for (Index = 1; Index < 4; Index++) {\r
-    //\r
-    // Lower byte goes first: word[100] is the lowest word, word[103] is highest\r
-    //\r
-    TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];\r
-    Capacity |= LShiftU64 (TmpLba, 16 * Index);\r
-  }\r
-\r
-  if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {\r
-    //\r
-    // Capacity exceeds 120GB. 48-bit addressing is really needed\r
-    //\r
-    IdeDev->Type = Ide48bitAddressingHardDisk;\r
-\r
-    //\r
-    // Fill block media information:Media->LogicalPartition ,\r
-    // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.\r
-    //\r
-    IdeDev->BlkIo.Media->IoAlign        = 4;\r
-    IdeDev->BlkIo.Media->MediaId        = 1;\r
-    IdeDev->BlkIo.Media->RemovableMedia = FALSE;\r
-    IdeDev->BlkIo.Media->MediaPresent   = TRUE;\r
-    IdeDev->BlkIo.Media->ReadOnly       = FALSE;\r
-    IdeDev->BlkIo.Media->BlockSize      = 0x200;\r
-    IdeDev->BlkIo.Media->LastBlock      = Capacity - 1;\r
-\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
-  return EFI_UNSUPPORTED;\r
-}\r
-\r
-/**\r
-  This function is called by ATAIdentify() or ATAPIIdentify()\r
-  to print device's module name.\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-**/\r
-VOID\r
-PrintAtaModuleName (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
-  )\r
-{\r
-  if (IdeDev->pIdData == NULL) {\r
-    return ;\r
-  }\r
-\r
-  SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);\r
-  IdeDev->ModelName[40] = 0x00;\r
-}\r
-\r
-/**\r
-  This function is used to send out ATA commands conforms to the\r
-  PIO Data In Protocol.\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *Buffer\r
-  buffer contained data transferred from device to host.\r
-\r
-  @param[in] ByteCount\r
-  data size in byte unit of the buffer.\r
-\r
-  @param[in] AtaCommand\r
-  value of the Command Register\r
-\r
-  @param[in] Head\r
-  value of the Head/Device Register\r
-\r
-  @param[in] SectorCount\r
-  value of the Sector Count Register\r
-\r
-  @param[in] SectorNumber\r
-  value of the Sector Number Register\r
-\r
-  @param[in] CylinderLsb\r
-  value of the low byte of the Cylinder Register\r
-\r
-  @param[in] CylinderMsb\r
-  value of the high byte of the Cylinder Register\r
-\r
-  @retval EFI_SUCCESS send out the ATA command and device send required\r
-  data successfully.\r
+/**\r
+  This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
 \r
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+                      all the information of the IDE device.\r
+  @param Buffer       buffer contained data transferred from device to host.\r
+  @param ByteCount    data size in byte unit of the buffer.\r
+  @param AtaCommand   value of the Command Register\r
+  @param Head         value of the Head/Device Register\r
+  @param SectorCount  value of the Sector Count Register\r
+  @param SectorNumber value of the Sector Number Register\r
+  @param CylinderLsb  value of the low byte of the Cylinder Register\r
+  @param CylinderMsb  value of the high byte of the Cylinder Register\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
 \r
 **/\r
@@ -458,10 +603,8 @@ AtaPioDataIn (
   This function is used to send out ATA commands conforms to the\r
   PIO Data Out Protocol.\r
 \r
-  @param *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                      to record all the information of the IDE device.\r
   @param *Buffer      buffer contained data transferred from host to device.\r
   @param ByteCount    data size in byte unit of the buffer.\r
   @param AtaCommand   value of the Command Register\r
@@ -471,9 +614,8 @@ AtaPioDataIn (
   @param CylinderLsb  value of the low byte of the Cylinder Register\r
   @param CylinderMsb  value of the high byte of the Cylinder Register\r
 \r
-  @retval EFI_SUCCESS send out the ATA command and device received required\r
-  data successfully.\r
-\r
+  @retval EFI_SUCCESS      send out the ATA command and device received required\r
+                           data successfully.\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -610,9 +752,8 @@ AtaPioDataOut (
   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[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to \r
+                 record all the information of the IDE device.\r
 \r
   @retval EFI_SUCCESS       No err information in the Status Register.\r
   @retval EFI_DEVICE_ERROR  Any err information in the Status Register.\r
@@ -630,26 +771,26 @@ CheckErrorStatus (
 \r
   DEBUG_CODE_BEGIN ();\r
 \r
-    if (StatusRegister & ATA_STSREG_DWF) {\r
-      DEBUG (\r
-        (EFI_D_BLKIO,\r
-        "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
-        StatusRegister)\r
-        );\r
-    }\r
+  if ((StatusRegister & ATA_STSREG_DWF) != 0) {\r
+    DEBUG (\r
+      (EFI_D_BLKIO,\r
+      "CheckErrorStatus()-- %02x : Error : Write Fault\n",\r
+      StatusRegister)\r
+      );\r
+  }\r
 \r
-    if (StatusRegister & ATA_STSREG_CORR) {\r
-      DEBUG (\r
-        (EFI_D_BLKIO,\r
-        "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
-        StatusRegister)\r
-        );\r
-    }\r
+  if ((StatusRegister & ATA_STSREG_CORR) != 0) {\r
+    DEBUG (\r
+      (EFI_D_BLKIO,\r
+      "CheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
+      StatusRegister)\r
+      );\r
+   }\r
 \r
-    if (StatusRegister & ATA_STSREG_ERR) {\r
-      ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+  if ((StatusRegister & ATA_STSREG_ERR) != 0) {\r
+    ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
 \r
-      if (ErrorRegister & ATA_ERRREG_BBK) {\r
+    if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {\r
       DEBUG (\r
         (EFI_D_BLKIO,\r
         "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
@@ -657,7 +798,7 @@ CheckErrorStatus (
         );\r
       }\r
 \r
-      if (ErrorRegister & ATA_ERRREG_UNC) {\r
+      if ((ErrorRegister & ATA_ERRREG_UNC) != 0) {\r
         DEBUG (\r
           (EFI_D_BLKIO,\r
           "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
@@ -665,7 +806,7 @@ CheckErrorStatus (
           );\r
       }\r
 \r
-      if (ErrorRegister & ATA_ERRREG_MC) {\r
+      if ((ErrorRegister & ATA_ERRREG_MC) != 0) {\r
         DEBUG (\r
           (EFI_D_BLKIO,\r
           "CheckErrorStatus()-- %02x : Error : Media Change\n",\r
@@ -673,7 +814,7 @@ CheckErrorStatus (
           );\r
       }\r
 \r
-      if (ErrorRegister & ATA_ERRREG_ABRT) {\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) != 0) {\r
         DEBUG (\r
           (EFI_D_BLKIO,\r
           "CheckErrorStatus()-- %02x : Error : Abort\n",\r
@@ -681,7 +822,7 @@ CheckErrorStatus (
           );\r
       }\r
 \r
-      if (ErrorRegister & ATA_ERRREG_TK0NF) {\r
+      if ((ErrorRegister & ATA_ERRREG_TK0NF) != 0) {\r
         DEBUG (\r
           (EFI_D_BLKIO,\r
           "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
@@ -689,7 +830,7 @@ CheckErrorStatus (
           );\r
       }\r
 \r
-      if (ErrorRegister & ATA_ERRREG_AMNF) {\r
+      if ((ErrorRegister & ATA_ERRREG_AMNF) != 0) {\r
         DEBUG (\r
           (EFI_D_BLKIO,\r
           "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
@@ -709,25 +850,16 @@ CheckErrorStatus (
 }\r
 \r
 /**\r
-  This function is called by the AtaBlkIoReadBlocks() to perform\r
-  reading from media in block unit.\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer\r
-  A pointer to the destination buffer for the data.\r
-\r
-  @param[in] Lba\r
-  The starting logical block address to read from\r
-  on the device media.\r
-\r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
-\r
-  @return return status is fully dependent on the return status\r
-  of AtaPioDataIn() function.\r
+  This function is called by the AtaBlkIoReadBlocks() to perform reading from \r
+  media in block unit.\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+                        all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the destination buffer for the data.\r
+  @param Lba            The starting logical block address to read from on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+  \r
+  @return status is fully dependent on the return status of AtaPioDataIn() function.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -827,25 +959,16 @@ AtaReadSectors (
 }\r
 \r
 /**\r
-  This function is called by the AtaBlkIoWriteBlocks() to perform\r
-  writing onto media in block unit.\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *BufferData\r
-  A pointer to the source buffer for the data.\r
-\r
-  @param[in] Lba\r
-  The starting logical block address to write onto\r
-  the device media.\r
-\r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
-\r
-  @return return status is fully dependent on the return status\r
-  of AtaPioDataOut() function.\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform writing onto \r
+  media in block unit.\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure,used to record\r
+                        all the information of the IDE device.\r
+  @param BufferData     A pointer to the source buffer for the data.\r
+  @param Lba            The starting logical block address to write onto the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+  \r
+  @return status is fully dependent on the return status of AtaPioDataIn() function.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -930,12 +1053,10 @@ AtaWriteSectors (
 \r
   return Status;\r
 }\r
-\r
 /**\r
-  This function is used to implement the Soft Reset on the specified\r
-  device. But, the ATA Soft Reset mechanism is so strong a reset method\r
-  that it will force resetting on both devices connected to the\r
-  same cable.\r
+  This function is used to implement the Soft Reset on the specified device. But,\r
+  the ATA Soft Reset mechanism is so strong a reset method that it will force \r
+  resetting on both devices connected to the same cable.\r
 \r
   It is called by IdeBlkIoReset(), a interface function of Block\r
   I/O protocol.\r
@@ -943,17 +1064,13 @@ AtaWriteSectors (
   This function can also be used by the ATAPI device to perform reset when\r
   ATAPI Reset command is failed.\r
 \r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
+  @param IdeDev  pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+                 all the information of the IDE device.\r
   @retval EFI_SUCCESS       Soft reset completes successfully.\r
   @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.\r
 \r
-  @note\r
-  The registers initial values after ATA soft reset are different\r
-  to the ATA device and ATAPI device.\r
-\r
+  @note  The registers initial values after ATA soft reset are different\r
+         to the ATA device and ATAPI device.\r
 **/\r
 EFI_STATUS\r
 AtaSoftReset (\r
@@ -1002,594 +1119,1020 @@ AtaSoftReset (
 \r
   return EFI_SUCCESS;\r
 }\r
-\r
 /**\r
-  This function is the ATA implementation for ReadBlocks in the\r
-  Block I/O Protocol interface.\r
-\r
-  @param[in] *IdeBlkIoDevice\r
-  Indicates the calling context.\r
-\r
-  @param[in] MediaId\r
-  The media id that the read request is for.\r
-\r
-  @param[in] LBA\r
-  The starting logical block address to read from\r
-  on the device.\r
+  This function is used to send out ATA commands conforms to the PIO Data In \r
+  Protocol, supporting ATA/ATAPI-6 standard\r
 \r
-  @param[in] BufferSize\r
-  The size of the Buffer in bytes. This must be a\r
-  multiple of the intrinsic block size of the device.\r
-\r
-  @param[out] *Buffer\r
-  A pointer to the destination buffer for the data.\r
-  The caller is responsible for either having implicit\r
-  or explicit ownership of the memory that data is read into.\r
-\r
-  @retval EFI_SUCCESS       Read Blocks successfully.\r
-  @retval EFI_DEVICE_ERROR  Read Blocks failed.\r
-  @retval EFI_NO_MEDIA      There is no media in the device.\r
-  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
+  Comparing with ATA-3 data in protocol, we have two differents here:\r
+  1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
+  wait will frequently fail... cause writing function return error)\r
 \r
-  @retval EFI_BAD_BUFFER_SIZE\r
-  The BufferSize parameter is not a multiple of the\r
-  intrinsic block size of the device.\r
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
+  slow down writing performance by 100 times!)\r
 \r
-  @retval EFI_INVALID_PARAMETER\r
-  The read request contains LBAs that are not valid,\r
-  or the data buffer is not valid.\r
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                      to record all the information of the IDE device.\r
+  @param Buffer       buffer contained data transferred from device to host.\r
+  @param ByteCount    data size in byte unit of the buffer.\r
+  @param AtaCommand   value of the Command Register\r
+  @param StartLba     the start LBA of this transaction\r
+  @param SectorCount  the count of sectors to be transfered\r
 \r
-  @note\r
-  If Read Block error because of device error, this function will call\r
-  AtaSoftReset() function to reset device.\r
+  @retval EFI_SUCCESS      send out the ATA command and device send required data successfully.\r
+  @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
 EFI_STATUS\r
-AtaBlkIoReadBlocks (\r
-  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
-  IN UINT32           MediaId,\r
-  IN EFI_LBA          LBA,\r
-  IN UINTN            BufferSize,\r
-  OUT VOID            *Buffer\r
+AtaPioDataInExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  OUT VOID        *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINT16          SectorCount\r
   )\r
 {\r
-  EFI_BLOCK_IO_MEDIA  *Media;\r
-  UINTN               BlockSize;\r
-  UINTN               NumberOfBlocks;\r
-  EFI_STATUS          Status;\r
+  UINT8       DevSel;\r
+  UINT8       SectorCount8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
 \r
-  if (Buffer == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  if (BufferSize == 0) {\r
-    return EFI_SUCCESS;\r
+  //\r
+  // Select device, set bit6 as 1 to indicate LBA mode is used\r
+  //\r
+  DevSel = (UINT8) (IdeDev->Device << 4);\r
+  DevSel |= 0x40;\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    DevSel\r
+    );\r
+\r
+  //\r
+  // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
+  //\r
+  if ( (IdeDev->Type == IdeHardDisk)  ||\r
+        (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+\r
+    Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
   }\r
 \r
-  Status = EFI_SUCCESS;\r
+  //\r
+  // Fill feature register if needed\r
+  //\r
+  if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
+    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
+  }\r
 \r
   //\r
-  //  Get the intrinsic block size\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
   //\r
-  Media           = IdeBlkIoDevice->BlkIo.Media;\r
-  BlockSize       = Media->BlockSize;\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
-  NumberOfBlocks  = BufferSize / BlockSize;\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
-  if (MediaId != Media->MediaId) {\r
-    return EFI_MEDIA_CHANGED;\r
-  }\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
-  if (BufferSize % BlockSize != 0) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\r
+  LbaLow  = (UINT8) StartLba;\r
+  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);\r
+  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
-  if (!(Media->MediaPresent)) {\r
-    return EFI_NO_MEDIA;\r
-  }\r
+  //\r
+  // Send command via Command Register, invoking the processing of this command\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
 \r
-  if (LBA > Media->LastBlock) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  Buffer16 = (UINT16 *) Buffer;\r
 \r
-  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  //\r
+  // According to PIO data in protocol, host can perform a series of reads to\r
+  // the data register after each time device set DRQ ready;\r
+  //\r
 \r
-  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  //\r
+  // 256 words\r
+  //\r
+  Increment = 256;\r
 \r
-  Status = EFI_SUCCESS;\r
-  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+  //\r
+  // used to record bytes of currently transfered data\r
+  //\r
+  WordCount = 0;\r
+\r
+  while (WordCount < ByteCount / 2) {\r
     //\r
-    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
     //\r
-    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
-      Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    } else {\r
-      Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
     }\r
-  } else {\r
+\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
     //\r
-    // For ATA-3 compatible device, use ATA-3 read block mechanism\r
+    // Get the byte count for one series of read\r
     //\r
-    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
-      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    } else {\r
-      Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
     }\r
-  }\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    AtaSoftReset (IdeBlkIoDevice);\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+    IDEReadPortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
 \r
-  return EFI_SUCCESS;\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
 \r
-}\r
+  }\r
 \r
+  return CheckErrorStatus (IdeDev);\r
+}\r
 /**\r
-  This function is the ATA implementation for WriteBlocks in the\r
-  Block I/O Protocol interface.\r
-\r
-  @param[in] *IdeBlkIoDevice\r
-  Indicates the calling context.\r
-\r
-  @param[in] MediaId\r
-  The media id that the write request is for.\r
-\r
-  @param[in] LBA\r
-  The starting logical block address to write onto\r
-  the device.\r
-\r
-  @param[in] BufferSize\r
-  The size of the Buffer in bytes. This must be a\r
-  multiple of the intrinsic block size of the device.\r
+  Send ATA Ext command into device with NON_DATA protocol.\r
 \r
-  @param[out] *Buffer\r
-  A pointer to the source buffer for the data.\r
-  The caller is responsible for either having implicit\r
-  or explicit ownership of the memory that data is\r
-  written from.\r
-\r
-  @retval EFI_SUCCESS       Write Blocks successfully.\r
-  @retval EFI_DEVICE_ERROR  Write Blocks failed.\r
-  @retval EFI_NO_MEDIA      There is no media in the device.\r
-  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
-\r
-  @retval EFI_BAD_BUFFER_SIZE\r
-  The BufferSize parameter is not a multiple of the\r
-  intrinsic block size of the device.\r
-\r
-  @retval EFI_INVALID_PARAMETER\r
-  The write request contains LBAs that are not valid,\r
-  or the data buffer is not valid.\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaAddress The LBA address in 48-bit mode\r
 \r
-  @note\r
-  If Write Block error because of device error, this function will call\r
-  AtaSoftReset() function to reset device.\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
 \r
 **/\r
 EFI_STATUS\r
-AtaBlkIoWriteBlocks (\r
-  IN  IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
-  IN  UINT32           MediaId,\r
-  IN  EFI_LBA          LBA,\r
-  IN  UINTN            BufferSize,\r
-  OUT VOID             *Buffer\r
+AtaCommandIssueExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
   )\r
 {\r
+  EFI_STATUS  Status;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
 \r
-  EFI_BLOCK_IO_MEDIA  *Media;\r
-  UINTN               BlockSize;\r
-  UINTN               NumberOfBlocks;\r
-  EFI_STATUS          Status;\r
-\r
-  if (Buffer == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  if (BufferSize == 0) {\r
-    return EFI_SUCCESS;\r
+  //\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  Status = EFI_SUCCESS;\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
 \r
   //\r
-  // Get the intrinsic block size\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
   //\r
-  Media           = IdeBlkIoDevice->BlkIo.Media;\r
-  BlockSize       = Media->BlockSize;\r
-  NumberOfBlocks  = BufferSize / BlockSize;\r
+  Feature8 = (UINT8) (Feature >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
 \r
-  if (MediaId != Media->MediaId) {\r
-    return EFI_MEDIA_CHANGED;\r
-  }\r
+  Feature8 = (UINT8) Feature;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
 \r
-  if (BufferSize % BlockSize != 0) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
-  if (LBA > Media->LastBlock) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
-  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  LbaLow = (UINT8) LbaAddress;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
 \r
-  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
 \r
-  Status = EFI_SUCCESS;\r
-  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
-    //\r
-    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
-    //\r
-    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
-      Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    } else {\r
-      Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    }\r
-  } else {\r
-    //\r
-    // For ATA-3 compatible device, use ATA-3 write block mechanism\r
-    //\r
-    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
-      Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    } else {\r
-      Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    }\r
-  }\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
-  if (EFI_ERROR (Status)) {\r
-    AtaSoftReset (IdeBlkIoDevice);\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+  //\r
+  // Work around for Segate 160G disk writing\r
+  //\r
+  gBS->Stall (1800);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Stall at least 400ns\r
+  //\r
+  gBS->Stall (100);\r
 \r
   return EFI_SUCCESS;\r
 }\r
-\r
 /**\r
-  This function is called by the AtaBlkIoReadBlocks() to perform\r
-  reading from media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
+  Send ATA Ext command into device with NON_DATA protocol\r
 \r
-  @param[in] *DataBuffer    A pointer to the destination buffer for the data.\r
-  @param[in] StartLba       The starting logical block address to read from\r
-  on the device media.\r
-  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaAddress The LBA address in 48-bit mode\r
 \r
-  @return return status is fully dependent on the return status\r
-  of AtaPioDataInExt() function.\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
 \r
 **/\r
 EFI_STATUS\r
-AtaReadSectorsExt (\r
+AtaCommandIssue (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT16          Feature,\r
+  IN  UINT16          SectorCount,\r
+  IN  EFI_LBA         LbaAddress\r
   )\r
 {\r
   EFI_STATUS  Status;\r
-  UINTN       BlocksRemaining;\r
-  EFI_LBA     Lba64;\r
-  UINT8       AtaCommand;\r
-  UINT16      SectorCount;\r
-  UINT32      ByteCount;\r
-  VOID        *Buffer;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       Lba0;\r
+  UINT8       Lba1;\r
+  UINT8       Lba2;\r
+  UINT8       Lba3;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
   //\r
-  // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
   //\r
-  AtaCommand      = ATA_CMD_READ_SECTORS_EXT;\r
-  Buffer          = DataBuffer;\r
-  BlocksRemaining = NumberOfBlocks;\r
-  Lba64           = StartLba;\r
-  Status          = EFI_SUCCESS;\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
 \r
-  while (BlocksRemaining > 0) {\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-    if (BlocksRemaining >= 0x10000) {\r
-      //\r
-      //  SectorCount is used to record the number of sectors to be read\r
-      //  Max 65536 sectors can be transfered at a time.\r
-      //\r
-      SectorCount = 0xffff;\r
-    } else {\r
-      SectorCount = (UINT16) BlocksRemaining;\r
-    }\r
+  Lba0  = (UINT8) LbaAddress;\r
+  Lba1  = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  Lba2  = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  Lba3  = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  Device = (UINT8) (Device | Lba3);\r
 \r
-    //\r
-    // ByteCount is the number of bytes that will be read\r
-    //\r
-    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
 \r
-    //\r
-    // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
-    //\r
-    Status = AtaPioDataInExt (\r
-              IdeDev,\r
-              Buffer,\r
-              ByteCount,\r
-              AtaCommand,\r
-              Lba64,\r
-              SectorCount\r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
+  //\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  Feature8 = (UINT8) Feature;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
 \r
-    Lba64 += SectorCount;\r
-    Buffer = ((UINT8 *) Buffer + ByteCount);\r
-    BlocksRemaining -= SectorCount;\r
-  }\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  SectorCount8 = (UINT8) SectorCount;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
-  return Status;\r
-}\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
 \r
-/**\r
-  This function is called by the AtaBlkIoWriteBlocks() to perform\r
-  writing onto media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
 \r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
-  to record all the information of the IDE device.\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
 \r
-  @param[in] *DataBuffer\r
-  A pointer to the source buffer for the data.\r
+  //\r
+  // Stall at least 400ns\r
+  //\r
+  gBS->Stall (100);\r
 \r
-  @param[in] Lba\r
-  The starting logical block address to write onto\r
-  the device media.\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
 \r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                        to record all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the source buffer for the data.\r
+  @param StartLba       The starting logical block address to write to\r
+                        on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+  @param UdmaOp         The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+                        AtaUdmaWriteOp, AtaUdmaWriteExOp\r
 \r
-  @return status is fully dependent on the return status\r
-  of AtaPioDataOutExt() function.\r
+  @retval EFI_SUCCESS          the operation is successful.\r
+  @retval EFI_OUT_OF_RESOURCES Build PRD table failed\r
+  @retval EFI_UNSUPPORTED      Unknown channel or operations command\r
+  @retval EFI_DEVICE_ERROR     Ata command execute failed\r
 \r
 **/\r
 EFI_STATUS\r
-AtaWriteSectorsExt (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
+DoAtaUdma (\r
+  IN  IDE_BLK_IO_DEV      *IdeDev,\r
+  IN  VOID                *DataBuffer,\r
+  IN  EFI_LBA             StartLba,\r
+  IN  UINTN               NumberOfBlocks,\r
+  IN  ATA_UDMA_OPERATION  UdmaOp\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  EFI_LBA     Lba64;\r
-  UINTN       BlocksRemaining;\r
-  UINT8       AtaCommand;\r
-  UINT16      SectorCount;\r
-  UINT32      ByteCount;\r
-  VOID        *Buffer;\r
+  IDE_DMA_PRD                   *PrdAddr;\r
+  IDE_DMA_PRD                   *UsedPrdAddr;\r
+  IDE_DMA_PRD                   *TempPrdAddr;\r
+  UINT8                         RegisterValue;\r
+  UINT8                         Device;\r
+  UINT64                        IoPortForBmic;\r
+  UINT64                        IoPortForBmis;\r
+  UINT64                        IoPortForBmid;\r
+  EFI_STATUS                    Status;\r
+  UINTN                         PrdTableNum;\r
+  UINTN                         ByteCount;\r
+  UINTN                         ByteAvailable;\r
+  UINT8                         *PrdBuffer;\r
+  UINTN                         RemainBlockNum;\r
+  UINT8                         DeviceControl;\r
+  UINT32                        Count;\r
+  UINTN                         PageCount;\r
+  VOID                          *Map;\r
+  VOID                          *MemPage;\r
+  EFI_PHYSICAL_ADDRESS          DeviceAddress;\r
+  UINTN                         MaxDmaCommandSectors;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
+  UINT8                         AtaCommand;\r
+\r
+  switch (UdmaOp) {\r
+  case AtaUdmaReadOp:\r
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
+    AtaCommand           = ATA_CMD_READ_DMA;\r
+    break;\r
+  case AtaUdmaReadExtOp:\r
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
+    AtaCommand           = ATA_CMD_READ_DMA_EXT;\r
+    break;\r
+  case AtaUdmaWriteOp:\r
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
+    AtaCommand           = ATA_CMD_WRITE_DMA;\r
+    break;\r
+  case AtaUdmaWriteExtOp:\r
+    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
+    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
+    AtaCommand           = ATA_CMD_WRITE_DMA_EXT;\r
+    break;\r
+  default:\r
+    return EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
 \r
   //\r
-  // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+  // Select device\r
   //\r
-  AtaCommand      = ATA_CMD_WRITE_SECTORS_EXT;\r
-  Lba64           = StartLba;\r
-  Buffer          = DataBuffer;\r
-  BlocksRemaining = NumberOfBlocks;\r
+  Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
 \r
-  Status          = EFI_SUCCESS;\r
+  //\r
+  // Enable interrupt to support UDMA\r
+  //\r
+  DeviceControl = 0;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
-  while (BlocksRemaining > 0) {\r
+  if (IdePrimary == IdeDev->Channel) {\r
+    IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+    IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
+  } else {\r
+    if (IdeSecondary == IdeDev->Channel) {\r
+      IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+      IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
+    } else {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  }\r
 \r
-    if (BlocksRemaining >= 0x10000) {\r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  IdeDev->PciIo->Io.Read (\r
+                                         IdeDev->PciIo,\r
+                                         EfiPciIoWidthUint8,\r
+                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                         IoPortForBmis,\r
+                                         1,\r
+                                         &RegisterValue\r
+                                         );\r
+  \r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+  \r
+  IdeDev->PciIo->Io.Write (\r
+                                         IdeDev->PciIo,\r
+                                         EfiPciIoWidthUint8,\r
+                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                                         IoPortForBmis,\r
+                                         1,\r
+                                         &RegisterValue\r
+                                         );\r
+\r
+  Status = EFI_SUCCESS;\r
+  \r
+  RemainBlockNum = NumberOfBlocks;\r
+  while (RemainBlockNum > 0) {\r
+\r
+    if (RemainBlockNum >= MaxDmaCommandSectors) {\r
       //\r
-      //  SectorCount is used to record the number of sectors to be written.\r
+      //  SectorCount is used to record the number of sectors to be read\r
       //  Max 65536 sectors can be transfered at a time.\r
       //\r
-      SectorCount = 0xffff;\r
+      NumberOfBlocks = MaxDmaCommandSectors;\r
+      RemainBlockNum -= MaxDmaCommandSectors;\r
     } else {\r
-      SectorCount = (UINT16) BlocksRemaining;\r
+      NumberOfBlocks  = (UINT16) RemainBlockNum;\r
+      RemainBlockNum  = 0;\r
     }\r
 \r
     //\r
-    // ByteCount is the number of bytes that will be written\r
+    // Calculate the number of PRD table to make sure the memory region\r
+    // not cross 64K boundary\r
     //\r
-    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+    ByteCount   = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+    PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
 \r
     //\r
-    // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+    // Build PRD table\r
     //\r
-    Status = AtaPioDataOutExt (\r
-              IdeDev,\r
-              Buffer,\r
-              ByteCount,\r
-              AtaCommand,\r
-              Lba64,\r
-              SectorCount\r
-              );\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = IdeDev->PciIo->AllocateBuffer (\r
+                    IdeDev->PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage,\r
+                    0\r
+                    );\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      return EFI_OUT_OF_RESOURCES;\r
     }\r
+    ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
 \r
-    Lba64 += SectorCount;\r
-    Buffer = ((UINT8 *) Buffer + ByteCount);\r
-    BlocksRemaining -= SectorCount;\r
-  }\r
-\r
-  return Status;\r
-}\r
+    PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
+    //\r
+    // To make sure PRD is allocated in one 64K page\r
+    //\r
+    if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
+      UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
+    } else {\r
+      if ((UINTN) PrdAddr & 0x03) {\r
+        UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
+      } else {\r
+        UsedPrdAddr = PrdAddr;\r
+      }\r
+    }\r
 \r
-/**\r
-  This function is used to send out ATA commands conforms to the\r
-  PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
+    //\r
+    // Build the PRD table\r
+    //\r
+    Status = IdeDev->PciIo->Map (\r
+                       IdeDev->PciIo,\r
+                       PciIoProtocolOp,\r
+                       DataBuffer,\r
+                       &ByteCount,\r
+                       &DeviceAddress,\r
+                       &Map\r
+                       );\r
+    if (EFI_ERROR (Status)) {\r
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);\r
+    TempPrdAddr = UsedPrdAddr;\r
+    while (TRUE) {\r
 \r
-  Comparing with ATA-3 data in protocol, we have two differents here:<BR>\r
-  1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
-  wait will frequently fail... cause writing function return error)\r
+      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
 \r
-  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
-  slow down writing performance by 100 times!)\r
+      if (ByteCount <= ByteAvailable) {\r
+        TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+        TempPrdAddr->ByteCount      = (UINT16) ByteCount;\r
+        TempPrdAddr->EndOfTable     = 0x8000;\r
+        break;\r
+      }\r
 \r
-  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in,out] *Buffer  buffer contained data transferred from device to host.\r
-  @param[in] ByteCount    data size in byte unit of the buffer.\r
-  @param[in] AtaCommand   value of the Command Register\r
-  @param[in] StartLba     the start LBA of this transaction\r
-  @param[in] SectorCount  the count of sectors to be transfered\r
+      TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
+      TempPrdAddr->ByteCount      = (UINT16) ByteAvailable;\r
 \r
-  @retval EFI_SUCCESS send out the ATA command and device send required\r
-  data successfully.\r
+      ByteCount -= ByteAvailable;\r
+      PrdBuffer += ByteAvailable;\r
+      TempPrdAddr++;\r
+    }\r
 \r
-  @retval EFI_DEVICE_ERROR command sent failed.\r
+    //\r
+    // Set the base address to BMID register\r
+    //\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint32,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmid,\r
+                        1,\r
+                        &UsedPrdAddr\r
+                        );\r
 \r
-**/\r
-EFI_STATUS\r
-AtaPioDataInExt (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  OUT VOID        *Buffer,\r
-  IN  UINT32          ByteCount,\r
-  IN  UINT8           AtaCommand,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINT16          SectorCount\r
-  )\r
-{\r
-  UINT8       DevSel;\r
-  UINT8       SectorCount8;\r
-  UINT8       LbaLow;\r
-  UINT8       LbaMid;\r
-  UINT8       LbaHigh;\r
-  UINTN       WordCount;\r
-  UINTN       Increment;\r
-  UINT16      *Buffer16;\r
-  EFI_STATUS  Status;\r
+    //\r
+    // Set BMIC register to identify the operation direction\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+    if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
+      RegisterValue |= BMIC_NREAD;\r
+    } else {\r
+      RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+    }\r
 \r
-  //\r
-  // Select device, set bit6 as 1 to indicate LBA mode is used\r
-  //\r
-  DevSel = (UINT8) (IdeDev->Device << 4);\r
-  DevSel |= 0x40;\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    DevSel\r
-    );\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-  //\r
-  // Wait for DRDY singnal asserting. ATAPI device needn't wait\r
-  //\r
-  if ( (IdeDev->Type == IdeHardDisk)  ||\r
-        (IdeDev->Type == Ide48bitAddressingHardDisk)) {\r
+    if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
+      Status = AtaCommandIssueExt (\r
+                 IdeDev,\r
+                 AtaCommand,\r
+                 Device,\r
+                 0,\r
+                 (UINT16) NumberOfBlocks,\r
+                 StartLba\r
+                 );\r
+    } else {\r
+      Status = AtaCommandIssue (\r
+                 IdeDev,\r
+                 AtaCommand,\r
+                 Device,\r
+                 0,\r
+                 (UINT16) NumberOfBlocks,\r
+                 StartLba\r
+                 );\r
+    }\r
 \r
-    Status = DRDYReady (IdeDev, ATATIMEOUT);\r
     if (EFI_ERROR (Status)) {\r
+      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
       return EFI_DEVICE_ERROR;\r
     }\r
-  }\r
-\r
-  //\r
-  // Fill feature register if needed\r
-  //\r
-  if (AtaCommand == ATA_CMD_SET_FEATURES) {\r
-    IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);\r
-  }\r
-\r
-  //\r
-  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
-  //\r
-  SectorCount8 = (UINT8) (SectorCount >> 8);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
-  SectorCount8 = (UINT8) SectorCount;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
-\r
-  //\r
-  // Fill the start LBA registers, which are also two-byte FIFO\r
-  //\r
-  LbaLow  = (UINT8) RShiftU64 (StartLba, 24);\r
-  LbaMid  = (UINT8) RShiftU64 (StartLba, 32);\r
-  LbaHigh = (UINT8) RShiftU64 (StartLba, 40);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-\r
-  LbaLow  = (UINT8) StartLba;\r
-  LbaMid  = (UINT8) RShiftU64 (StartLba, 8);\r
-  LbaHigh = (UINT8) RShiftU64 (StartLba, 16);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
-  //\r
-  // Send command via Command Register, invoking the processing of this command\r
-  //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
-  Buffer16 = (UINT16 *) Buffer;\r
-\r
-  //\r
-  // According to PIO data in protocol, host can perform a series of reads to\r
-  // the data register after each time device set DRQ ready;\r
-  //\r
+    //\r
+    // Set START bit of BMIC register\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-  //\r
-  // 256 words\r
-  //\r
-  Increment = 256;\r
+    RegisterValue |= BMIC_START;\r
 \r
-  //\r
-  // used to record bytes of currently transfered data\r
-  //\r
-  WordCount = 0;\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-  while (WordCount < ByteCount / 2) {\r
     //\r
-    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\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
-    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
+    Status = EFI_SUCCESS;\r
+    Count = 2000;\r
+    while (TRUE) {\r
 \r
-    Status = CheckErrorStatus (IdeDev);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_DEVICE_ERROR;\r
+      IdeDev->PciIo->Io.Read (\r
+                          IdeDev->PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                          IoPortForBmis,\r
+                          1,\r
+                          &RegisterValue\r
+                          );\r
+      if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {\r
+        if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {\r
+                 Status = EFI_DEVICE_ERROR;\r
+                 break;\r
+        }\r
+        break;\r
+      }\r
+\r
+      gBS->Stall (1000);\r
+      Count --;\r
     }\r
 \r
+    IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
     //\r
-    // Get the byte count for one series of read\r
+    // Read BMIS register and clear ERROR and INTR bit\r
     //\r
-    if ((WordCount + Increment) > ByteCount / 2) {\r
-      Increment = ByteCount / 2 - WordCount;\r
-    }\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-    IDEReadPortWMultiple (\r
-      IdeDev->PciIo,\r
-      IdeDev->IoPort->Data,\r
-      Increment,\r
-      Buffer16\r
-      );\r
+    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
 \r
-    WordCount += Increment;\r
-    Buffer16 += Increment;\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmis,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+       //\r
+    // Read Status Register of IDE device to clear interrupt\r
+    //\r
+    RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
+    //\r
+    // Clear START bit of BMIC register\r
+    //\r
+    IdeDev->PciIo->Io.Read (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
 \r
-  }\r
+    RegisterValue &= ~((UINT8) BMIC_START);\r
 \r
-  return CheckErrorStatus (IdeDev);\r
+    IdeDev->PciIo->Io.Write (\r
+                        IdeDev->PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                        IoPortForBmic,\r
+                        1,\r
+                        &RegisterValue\r
+                        );\r
+\r
+    if ((RegisterValue & BMIS_ERROR) != 0) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+       if (EFI_ERROR (Status)) {\r
+         break;\r
+       }\r
+    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+    StartLba += NumberOfBlocks;\r
+  }\r
+\r
+  //\r
+  // Disable interrupt of Select device\r
+  //\r
+  IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
+  DeviceControl |= ATA_CTLREG_IEN_L;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform reading from\r
+  media in block unit. The function has been enhanced to support >120GB access \r
+  and transfer at most 65536 blocks per command\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
+                        all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the destination buffer for the data.\r
+  @param StartLba       The starting logical block address to read from on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return status depends on the function DoAtaUdma() returns.\r
+**/\r
+EFI_STATUS\r
+AtaUdmaReadExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+}\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+                        all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the destination buffer for the data.\r
+  @param StartLba       The starting logical block address to read from\r
+                        on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+  \r
+  @return status depends on the function DoAtaUdma() returns.\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+}\r
+\r
+/**\r
+  This function is called by the AtaBlkIoReadBlocks() to perform\r
+  reading from media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used to record\r
+                        all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the destination buffer for the data.\r
+  @param StartLba       The starting logical block address to read from on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return status is fully dependent on the return status of AtaPioDataInExt() function.\r
+**/\r
+EFI_STATUS\r
+AtaReadSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       BlocksRemaining;\r
+  EFI_LBA     Lba64;\r
+  UINT8       AtaCommand;\r
+  UINT16      SectorCount;\r
+  UINT32      ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  //\r
+  // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
+  //\r
+  AtaCommand      = ATA_CMD_READ_SECTORS_EXT;\r
+  Buffer          = DataBuffer;\r
+  BlocksRemaining = NumberOfBlocks;\r
+  Lba64           = StartLba;\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining >= 0x10000) {\r
+      //\r
+      //  SectorCount is used to record the number of sectors to be read\r
+      //  Max 65536 sectors can be transfered at a time.\r
+      //\r
+      SectorCount = 0xffff;\r
+    } else {\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    }\r
+\r
+    //\r
+    // ByteCount is the number of bytes that will be read\r
+    //\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
+\r
+    //\r
+    // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
+    //\r
+    Status = AtaPioDataInExt (\r
+              IdeDev,\r
+              Buffer,\r
+              ByteCount,\r
+              AtaCommand,\r
+              Lba64,\r
+              SectorCount\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
+  }\r
+\r
+  return Status;\r
 }\r
+/**\r
+  This function is the ATA implementation for ReadBlocks in the\r
+  Block I/O Protocol interface.\r
+\r
+  @param IdeBlkIoDevice Indicates the calling context.\r
+  @param MediaId        The media id that the read request is for.\r
+  @param Lba            The starting logical block address to read from on the device.\r
+  @param BufferSize     The size of the Buffer in bytes. This must be a  multiple\r
+                        of the intrinsic block size of the device.\r
+\r
+  @param Buffer         A pointer to the destination buffer for the data. The caller\r
+                        is responsible for either having implicit or explicit ownership\r
+                        of the memory that data is read into.\r
+\r
+  @retval EFI_SUCCESS          Read Blocks successfully.\r
+  @retval EFI_DEVICE_ERROR     Read Blocks failed.\r
+  @retval EFI_NO_MEDIA         There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGE     The MediaId is not for the current media.\r
+  @retval EFI_BAD_BUFFER_SIZE  The BufferSize parameter is not a multiple of the\r
+                               intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER  The read request contains LBAs that are not valid,\r
+                                 or the data buffer is not valid.\r
+\r
+  @note If Read Block error because of device error, this function will call\r
+        AtaSoftReset() function to reset device.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaBlkIoReadBlocks (\r
+  IN IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN UINT32           MediaId,\r
+  IN EFI_LBA          Lba,\r
+  IN UINTN            BufferSize,\r
+  OUT VOID            *Buffer\r
+  )\r
+{\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
+\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Get the intrinsic block size\r
+  //\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (!(Media->MediaPresent)) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+    //\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    }\r
+  } else {\r
+    //\r
+    // For ATA-3 compatible device, use ATA-3 read block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
+  return EFI_SUCCESS;\r
+\r
+}\r
 /**\r
   This function is used to send out ATA commands conforms to the\r
   PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
@@ -1601,19 +2144,16 @@ AtaPioDataInExt (
   2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
   slow down writing performance by 100 times!)\r
 \r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *Buffer      buffer contained data transferred from host to device.\r
-  @param[in] ByteCount    data size in byte unit of the buffer.\r
-  @param[in] AtaCommand   value of the Command Register\r
-  @param[in] StartLba     the start LBA of this transaction\r
-  @param[in] SectorCount  the count of sectors to be transfered\r
-\r
-  @retval EFI_SUCCESS send out the ATA command and device receive required\r
-  data successfully.\r
+  @param IdeDev       pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                       to record all the information of the IDE device.\r
+  @param Buffer       buffer contained data transferred from host to device.\r
+  @param ByteCount    data size in byte unit of the buffer.\r
+  @param AtaCommand   value of the Command Register\r
+  @param StartLba     the start LBA of this transaction\r
+  @param SectorCount  the count of sectors to be transfered\r
 \r
+  @retval EFI_SUCCESS      send out the ATA command and device receive required\r
+                           data successfully.\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -1744,257 +2284,366 @@ AtaPioDataOutExt (
     Buffer16 += Increment;\r
 \r
   }\r
-  //\r
-  // while\r
-  //\r
-\r
   return CheckErrorStatus (IdeDev);\r
 }\r
-\r
-\r
 /**\r
-  Enable SMART of the disk if supported\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing to media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
 \r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure,used\r
-  to record all the information of the IDE device.\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                        to record all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the source buffer for the data.\r
+  @param StartLba       The starting logical block address to write to\r
+                        on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
 \r
+  @return status depends on the function DoAtaUdma() returns.\r
 **/\r
-VOID\r
-AtaSMARTSupport (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
   )\r
 {\r
-  EFI_STATUS        Status;\r
-  BOOLEAN           SMARTSupported;\r
-  UINT8             Device;\r
-  EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
-  UINT8             DeviceSelect;\r
-  UINT8             LBAMid;\r
-  UINT8             LBAHigh;\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
+}\r
 \r
-  //\r
-  // Detect if the device supports S.M.A.R.T.\r
-  //\r
-  if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {\r
-    //\r
-    // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)\r
-    //\r
-    return ;\r
-  } else {\r
-    if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing to media in block unit. \r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                        to record all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the source buffer for the data.\r
+  @param StartLba       The starting logical block address to write to\r
+                        on the device media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+  \r
+  @return status depends on the function DoAtaUdma() returns.\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
+}\r
+/**\r
+  This function is called by the AtaBlkIoWriteBlocks() to perform\r
+  writing onto media in block unit. The function has been enhanced to\r
+  support >120GB access and transfer at most 65536 blocks per command\r
+\r
+  @param IdeDev         pointer pointing to IDE_BLK_IO_DEV data structure,used\r
+                        to record all the information of the IDE device.\r
+  @param DataBuffer     A pointer to the source buffer for the data.\r
+  @param StartLba       The starting logical block address to write onto the device \r
+                        media.\r
+  @param NumberOfBlocks The number of transfer data blocks.\r
+\r
+  @return status is fully dependent on the return status of AtaPioDataOutExt() function.\r
+**/\r
+EFI_STATUS\r
+AtaWriteSectorsExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *DataBuffer,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINTN           NumberOfBlocks\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  EFI_LBA     Lba64;\r
+  UINTN       BlocksRemaining;\r
+  UINT8       AtaCommand;\r
+  UINT16      SectorCount;\r
+  UINT32      ByteCount;\r
+  VOID        *Buffer;\r
+\r
+  //\r
+  // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol\r
+  //\r
+  AtaCommand      = ATA_CMD_WRITE_SECTORS_EXT;\r
+  Lba64           = StartLba;\r
+  Buffer          = DataBuffer;\r
+  BlocksRemaining = NumberOfBlocks;\r
+\r
+  Status          = EFI_SUCCESS;\r
+\r
+  while (BlocksRemaining > 0) {\r
+\r
+    if (BlocksRemaining >= 0x10000) {\r
       //\r
-      // S.M.A.R.T is not supported by the device\r
+      //  SectorCount is used to record the number of sectors to be written.\r
+      //  Max 65536 sectors can be transfered at a time.\r
       //\r
-      SMARTSupported = FALSE;\r
+      SectorCount = 0xffff;\r
     } else {\r
-      SMARTSupported = TRUE;\r
+      SectorCount = (UINT16) BlocksRemaining;\r
     }\r
-  }\r
 \r
-  if (!SMARTSupported) {\r
-    //\r
-    // Report nonsupport status code\r
-    //\r
-    REPORT_STATUS_CODE (\r
-      EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)\r
-      );\r
-  } else {\r
     //\r
-    // Enable this feature\r
+    // ByteCount is the number of bytes that will be written\r
     //\r
-    REPORT_STATUS_CODE (\r
-      EFI_PROGRESS_CODE,\r
-      (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)\r
-      );\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
 \r
-    Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-    Status = AtaNonDataCommandIn (\r
-              IdeDev,\r
-              ATA_CMD_SMART,\r
-              Device,\r
-              ATA_SMART_ENABLE_OPERATION,\r
-              0,\r
-              0,\r
-              ATA_CONSTANT_4F,\r
-              ATA_CONSTANT_C2\r
-              );\r
     //\r
-    // Detect if this feature is enabled\r
+    // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
     //\r
-    TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));\r
-\r
-    DeviceSelect          = (UINT8) ((IdeDev->Device) << 4);\r
-    Status = AtaPioDataIn (\r
+    Status = AtaPioDataOutExt (\r
               IdeDev,\r
-              (VOID *) TmpAtaIdentifyPointer,\r
-              sizeof (EFI_IDENTIFY_DATA),\r
-              ATA_CMD_IDENTIFY_DRIVE,\r
-              DeviceSelect,\r
-              0,\r
-              0,\r
-              0,\r
-              0\r
+              Buffer,\r
+              ByteCount,\r
+              AtaCommand,\r
+              Lba64,\r
+              SectorCount\r
               );\r
     if (EFI_ERROR (Status)) {\r
-      gBS->FreePool (TmpAtaIdentifyPointer);\r
-      return ;\r
-    }\r
-\r
-    //\r
-    // Check if the feature is enabled\r
-    //\r
-    if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {\r
-      //\r
-      // Read status data\r
-      //\r
-      AtaNonDataCommandIn (\r
-        IdeDev,\r
-        ATA_CMD_SMART,\r
-        Device,\r
-        ATA_SMART_RETURN_STATUS,\r
-        0,\r
-        0,\r
-        ATA_CONSTANT_4F,\r
-        ATA_CONSTANT_C2\r
-        );\r
-      LBAMid  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);\r
-      LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);\r
-\r
-      if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {\r
-        //\r
-        // The threshold exceeded condition is not detected by the device\r
-        //\r
-        REPORT_STATUS_CODE (\r
-              EFI_PROGRESS_CODE,\r
-              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)\r
-              );\r
-\r
-      } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {\r
-        //\r
-        // The threshold exceeded condition is  detected by the device\r
-        //\r
-        REPORT_STATUS_CODE (\r
-              EFI_PROGRESS_CODE,\r
-              (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)\r
-              );\r
-      }\r
-\r
-    } else {\r
-      //\r
-      // Report disabled status code\r
-      //\r
-      REPORT_STATUS_CODE (\r
-            EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
-            (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)\r
-            );\r
+      return Status;\r
     }\r
 \r
-    gBS->FreePool (TmpAtaIdentifyPointer);\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
   }\r
 \r
-  return ;\r
+  return Status;\r
 }\r
-\r
 /**\r
-  Send ATA Ext command into device with NON_DATA protocol\r
+  This function is the ATA implementation for WriteBlocks in the\r
+  Block I/O Protocol interface.\r
 \r
-  @param  IdeDev Standard IDE device private data structure\r
-  @param  AtaCommand The ATA command to be sent\r
-  @param  Device The value in Device register\r
-  @param  Feature The value in Feature register\r
-  @param  SectorCount The value in SectorCount register\r
-  @param  LbaAddress The LBA address in 48-bit mode\r
+  @param IdeBlkIoDevice  Indicates the calling context.\r
+  @param MediaId         The media id that the write request is for.\r
+  @param Lba             The starting logical block address to write onto the device.\r
+  @param BufferSize      The size of the Buffer in bytes. This must be a multiple\r
+                         of the intrinsic block size of the device.\r
+  @param Buffer          A pointer to the source buffer for the data.The caller\r
+                         is responsible for either having implicit or explicit \r
+                         ownership of the memory that data is written from.\r
 \r
-  @retval  EFI_SUCCESS Reading succeed\r
-  @retval  EFI_DEVICE_ERROR Error executing commands on this device\r
+  @retval EFI_SUCCESS       Write Blocks successfully.\r
+  @retval EFI_DEVICE_ERROR  Write Blocks failed.\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
 \r
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the\r
+                                intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the data buffer is not valid.\r
+\r
+  @note If Write Block error because of device error, this function will call\r
+        AtaSoftReset() function to reset device.\r
 **/\r
 EFI_STATUS\r
-AtaCommandIssueExt (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINT8           AtaCommand,\r
-  IN  UINT8           Device,\r
-  IN  UINT16          Feature,\r
-  IN  UINT16          SectorCount,\r
-  IN  EFI_LBA         LbaAddress\r
+AtaBlkIoWriteBlocks (\r
+  IN  IDE_BLK_IO_DEV   *IdeBlkIoDevice,\r
+  IN  UINT32           MediaId,\r
+  IN  EFI_LBA          Lba,\r
+  IN  UINTN            BufferSize,\r
+  OUT VOID             *Buffer\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  UINT8       SectorCount8;\r
-  UINT8       Feature8;\r
-  UINT8       LbaLow;\r
-  UINT8       LbaMid;\r
-  UINT8       LbaHigh;\r
 \r
-  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
+  EFI_BLOCK_IO_MEDIA  *Media;\r
+  UINTN               BlockSize;\r
+  UINTN               NumberOfBlocks;\r
+  EFI_STATUS          Status;\r
 \r
-  //\r
-  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
-  //\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
-    );\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
-  //\r
-  // ATA commands for ATA device must be issued when DRDY is set\r
-  //\r
-  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
   }\r
 \r
-  //\r
-  // Pass parameter into device register block\r
-  //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+  Status = EFI_SUCCESS;\r
 \r
   //\r
-  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  // Get the intrinsic block size\r
   //\r
-  Feature8 = (UINT8) (Feature >> 8);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+  NumberOfBlocks  = BufferSize / BlockSize;\r
 \r
-  Feature8 = (UINT8) Feature;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
 \r
-  //\r
-  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
-  //\r
-  SectorCount8 = (UINT8) (SectorCount >> 8);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
 \r
-  SectorCount8 = (UINT8) SectorCount;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+  if (Lba > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
+  if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+  if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
+    //\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    }\r
+  } else {\r
+    //\r
+    // For ATA-3 compatible device, use ATA-3 write block mechanism\r
+    //\r
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  Enable Long Physical Sector Feature for ATA device.\r
+\r
+  @param   IdeDev  The IDE device data\r
+\r
+  @retval  EFI_SUCCESS      The ATA device supports Long Physical Sector feature\r
+                            and corresponding fields in BlockIo structure is updated.\r
+  @retval  EFI_UNSUPPORTED  The device is not ATA device or Long Physical Sector\r
+                            feature is not supported.\r
+**/\r
+EFI_STATUS\r
+AtaEnableLongPhysicalSector (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
+{\r
+  EFI_ATA_IDENTIFY_DATA  *AtaIdentifyData;\r
+  UINT16                 PhyLogicSectorSupport;\r
+\r
+  ASSERT (IdeDev->IdData != NULL);\r
   //\r
-  // Fill the start LBA registers, which are also two-byte FIFO\r
-  //\r
-  LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
-  LbaLow = (UINT8) LbaAddress;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  // Only valid for ATA device\r
+  //\r
+  AtaIdentifyData       = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;\r
+  if ((AtaIdentifyData->config & 0x8000) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;\r
+  //\r
+  // Check whether Long Physical Sector Feature is supported\r
+  //\r
+  if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {\r
+    IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
+    IdeDev->BlkIo.Media->LowestAlignedLba              = 0;\r
+    //\r
+    // Check whether one physical block contains multiple physical blocks\r
+    //\r
+    if ((PhyLogicSectorSupport & 0x2000) != 0) {\r
+      IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =\r
+        (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));\r
+      //\r
+      // Check lowest alignment of logical blocks within physical block\r
+      //\r
+      if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {\r
+        IdeDev->BlkIo.Media->LowestAlignedLba =\r
+          (EFI_LBA) (AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff);\r
+      }\r
+    }\r
+    //\r
+    // Check logical block size\r
+    //\r
+    IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+    if ((PhyLogicSectorSupport & 0x1000) != 0) {\r
+      IdeDev->BlkIo.Media->BlockSize = (UINT32) (\r
+        ((AtaIdentifyData->logic_sector_size_hi << 16) |\r
+         AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)\r
+        );\r
+    }\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+}\r
+/**\r
+  Send ATA command into device with NON_DATA protocol\r
 \r
-  LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
-  LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  @param  IdeDev Standard IDE device private data structure\r
+  @param  AtaCommand The ATA command to be sent\r
+  @param  Device The value in Device register\r
+  @param  Feature The value in Feature register\r
+  @param  SectorCount The value in SectorCount register\r
+  @param  LbaLow The value in LBA_LOW register\r
+  @param  LbaMiddle The value in LBA_MIDDLE register\r
+  @param  LbaHigh The value in LBA_HIGH register\r
 \r
-  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
-  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandIn (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINT8           AtaCommand,\r
+  IN  UINT8           Device,\r
+  IN  UINT8           Feature,\r
+  IN  UINT8           SectorCount,\r
+  IN  UINT8           LbaLow,\r
+  IN  UINT8           LbaMiddle,\r
+  IN  UINT8           LbaHigh\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       StatusRegister;\r
+\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
   //\r
-  // Work around for Segate 160G disk writing\r
+  // Select device (bit4), set Lba mode(bit6) (use 0xe0 for compatibility)\r
   //\r
-  gBS->Stall (1800);\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
+\r
+  //\r
+  // ATA commands for ATA device must be issued when DRDY is set\r
+  //\r
+  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Pass parameter into device register block\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
   //\r
   // Send command via Command Register\r
@@ -2002,9 +2651,26 @@ AtaCommandIssueExt (
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
 \r
   //\r
-  // Stall at least 400ns\r
+  // Wait for command completion\r
+  // For ATAPI_SMART_CMD, we may need more timeout to let device\r
+  // adjust internal states.\r
   //\r
-  gBS->Stall (100);\r
+  if (AtaCommand == ATA_CMD_SMART) {\r
+    Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+  } else {\r
+    Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+  if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+    //\r
+    // Failed to execute command, abort operation\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -2020,11 +2686,12 @@ AtaCommandIssueExt (
   @param  LbaAddress The LBA address in 48-bit mode\r
 \r
   @retval  EFI_SUCCESS Reading succeed\r
-  @retval  EFI_DEVICE_ERROR Error executing commands on this device\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error.\r
 \r
 **/\r
 EFI_STATUS\r
-AtaCommandIssue (\r
+AtaNonDataCommandInExt (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
   IN  UINT8           AtaCommand,\r
   IN  UINT8           Device,\r
@@ -2034,12 +2701,12 @@ AtaCommandIssue (
   )\r
 {\r
   EFI_STATUS  Status;\r
+  UINT8       StatusRegister;\r
   UINT8       SectorCount8;\r
   UINT8       Feature8;\r
-  UINT8       Lba0;\r
-  UINT8       Lba1;\r
-  UINT8       Lba2;\r
-  UINT8       Lba3;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
 \r
   Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
   if (EFI_ERROR (Status)) {\r
@@ -2063,12 +2730,6 @@ AtaCommandIssue (
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  Lba0  = (UINT8) LbaAddress;\r
-  Lba1  = (UINT8) RShiftU64 (LbaAddress, 8);\r
-  Lba2  = (UINT8) RShiftU64 (LbaAddress, 16);\r
-  Lba3  = (UINT8) RShiftU64 (LbaAddress, 24);\r
-  Device = (UINT8) (Device | Lba3);\r
-\r
   //\r
   // Pass parameter into device register block\r
   //\r
@@ -2077,22 +2738,37 @@ AtaCommandIssue (
   //\r
   // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
   //\r
+  Feature8 = (UINT8) (Feature >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+\r
   Feature8 = (UINT8) Feature;\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
 \r
   //\r
   // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
   //\r
+  SectorCount8 = (UINT8) (SectorCount >> 8);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
+\r
   SectorCount8 = (UINT8) SectorCount;\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
 \r
   //\r
   // Fill the start LBA registers, which are also two-byte FIFO\r
   //\r
+  LbaLow  = (UINT8) RShiftU64 (LbaAddress, 24);\r
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 32);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
+  LbaLow  = (UINT8) LbaAddress;\r
+  LbaMid  = (UINT8) RShiftU64 (LbaAddress, 8);\r
+  LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
 \r
   //\r
   // Send command via Command Register\r
@@ -2100,561 +2776,23 @@ AtaCommandIssue (
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
 \r
   //\r
-  // Stall at least 400ns\r
+  // Wait for command completion\r
   //\r
-  gBS->Stall (100);\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  This function is called by the AtaBlkIoReadBlocks() to perform\r
-  reading from media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
-\r
-  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
-\r
-  @param[in] StartLba The starting logical block address to read from\r
-  on the device media.\r
-\r
-  @param[in] NumberOfBlocks The number of transfer data blocks.\r
-\r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
-\r
-  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaReadExt (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
-  )\r
-{\r
-  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
-}\r
-\r
-/**\r
-  This function is called by the AtaBlkIoReadBlocks() to perform\r
-  reading from media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer    A pointer to the destination buffer for the data.\r
-  @param[in] StartLba       The starting logical block address to read from\r
-  on the device media.\r
-  @param[in] NumberOfBlocks The number of transfer data blocks.\r
-\r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
-\r
-  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaRead (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
-  )\r
-{\r
-  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
-}\r
-\r
-/**\r
-  This function is called by the AtaBlkIoWriteBlocks() to perform\r
-  writing to media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
-\r
-  @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer A pointer to the source buffer for the data.\r
-\r
-  @param[in] StartLba The starting logical block address to write to\r
-  on the device media.\r
-\r
-  @param[in] NumberOfBlocks The number of transfer data blocks.\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+  if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
+    //\r
+    // Failed to execute command, abort operation\r
+    //\r
+    return EFI_ABORTED;\r
+  }\r
 \r
-  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaWriteExt (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
-  )\r
-{\r
-  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
+  return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  This function is called by the AtaBlkIoWriteBlocks() to perform\r
-  writing to media in block unit. The function has been enhanced to\r
-  support >120GB access and transfer at most 65536 blocks per command\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer\r
-  A pointer to the source buffer for the data.\r
-\r
-  @param[in] StartLba\r
-  The starting logical block address to write to\r
-  on the device media.\r
-\r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
 \r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
-\r
-  TODO:    EFI_UNSUPPORTED - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-  TODO:    EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaWrite (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *DataBuffer,\r
-  IN  EFI_LBA         StartLba,\r
-  IN  UINTN           NumberOfBlocks\r
-  )\r
-{\r
-  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
-}\r
-\r
-/**\r
-  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
-\r
-  @param[in] *IdeDev\r
-  pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-  to record all the information of the IDE device.\r
-\r
-  @param[in] *DataBuffer\r
-  A pointer to the source buffer for the data.\r
-\r
-  @param[in] StartLba\r
-  The starting logical block address to write to\r
-  on the device media.\r
-\r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
-\r
-  @param[in] UdmaOp\r
-  The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
-  AtaUdmaWriteOp, AtaUdmaWriteExOp\r
-\r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
-\r
-**/\r
-EFI_STATUS\r
-DoAtaUdma (\r
-  IN  IDE_BLK_IO_DEV      *IdeDev,\r
-  IN  VOID                *DataBuffer,\r
-  IN  EFI_LBA             StartLba,\r
-  IN  UINTN               NumberOfBlocks,\r
-  IN  ATA_UDMA_OPERATION  UdmaOp\r
-  )\r
-{\r
-  IDE_DMA_PRD                   *PrdAddr;\r
-  IDE_DMA_PRD                   *UsedPrdAddr;\r
-  IDE_DMA_PRD                   *TempPrdAddr;\r
-  UINT8                         RegisterValue;\r
-  UINT8                         Device;\r
-  UINT64                        IoPortForBmic;\r
-  UINT64                        IoPortForBmis;\r
-  UINT64                        IoPortForBmid;\r
-  EFI_STATUS                    Status;\r
-  UINTN                         PrdTableNum;\r
-  UINTN                         ByteCount;\r
-  UINTN                         ByteAvailable;\r
-  UINT8                         *PrdBuffer;\r
-  UINTN                         RemainBlockNum;\r
-  UINT8                         DeviceControl;\r
-  UINT32                        Count;\r
-  UINTN                         PageCount;\r
-  VOID                          *Map;\r
-  VOID                          *MemPage;\r
-  EFI_PHYSICAL_ADDRESS          DeviceAddress;\r
-  UINTN                         MaxDmaCommandSectors;\r
-  EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
-  UINT8                         AtaCommand;\r
-\r
-  switch (UdmaOp) {\r
-  case AtaUdmaReadOp:\r
-    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
-    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
-    AtaCommand           = ATA_CMD_READ_DMA;\r
-    break;\r
-  case AtaUdmaReadExtOp:\r
-    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
-    PciIoProtocolOp      = EfiPciIoOperationBusMasterWrite;\r
-    AtaCommand           = ATA_CMD_READ_DMA_EXT;\r
-    break;\r
-  case AtaUdmaWriteOp:\r
-    MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;\r
-    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
-    AtaCommand           = ATA_CMD_WRITE_DMA;\r
-    break;\r
-  case AtaUdmaWriteExtOp:\r
-    MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;\r
-    PciIoProtocolOp      = EfiPciIoOperationBusMasterRead;\r
-    AtaCommand           = ATA_CMD_WRITE_DMA_EXT;\r
-    break;\r
-  default:\r
-    return EFI_UNSUPPORTED;\r
-    break;\r
-  }\r
-\r
-  //\r
-  // Select device\r
-  //\r
-  Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
-  //\r
-  // Enable interrupt to support UDMA\r
-  //\r
-  DeviceControl = 0;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
-  if (IdePrimary == IdeDev->Channel) {\r
-    IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
-    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
-    IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
-  } else {\r
-    if (IdeSecondary == IdeDev->Channel) {\r
-      IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
-      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
-      IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
-    } else {\r
-      return EFI_UNSUPPORTED;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Read BMIS register and clear ERROR and INTR bit\r
-  //\r
-  IdeDev->PciIo->Io.Read (\r
-                                         IdeDev->PciIo,\r
-                                         EfiPciIoWidthUint8,\r
-                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                                         IoPortForBmis,\r
-                                         1,\r
-                                         &RegisterValue\r
-                                         );\r
-  \r
-  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-  \r
-  IdeDev->PciIo->Io.Write (\r
-                                         IdeDev->PciIo,\r
-                                         EfiPciIoWidthUint8,\r
-                                         EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                                         IoPortForBmis,\r
-                                         1,\r
-                                         &RegisterValue\r
-                                         );\r
-\r
-  Status = EFI_SUCCESS;\r
-  \r
-  RemainBlockNum = NumberOfBlocks;\r
-  while (RemainBlockNum > 0) {\r
-\r
-    if (RemainBlockNum >= MaxDmaCommandSectors) {\r
-      //\r
-      //  SectorCount is used to record the number of sectors to be read\r
-      //  Max 65536 sectors can be transfered at a time.\r
-      //\r
-      NumberOfBlocks = MaxDmaCommandSectors;\r
-      RemainBlockNum -= MaxDmaCommandSectors;\r
-    } else {\r
-      NumberOfBlocks  = (UINT16) RemainBlockNum;\r
-      RemainBlockNum  = 0;\r
-    }\r
-\r
-    //\r
-    // Calculate the number of PRD table to make sure the memory region\r
-    // not cross 64K boundary\r
-    //\r
-    ByteCount   = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
-    PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
-\r
-    //\r
-    // Build PRD table\r
-    //\r
-    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
-    Status = IdeDev->PciIo->AllocateBuffer (\r
-                    IdeDev->PciIo,\r
-                    AllocateAnyPages,\r
-                    EfiBootServicesData,\r
-                    PageCount,\r
-                    &MemPage,\r
-                    0\r
-                    );\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-    ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
-    PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
-    //\r
-    // To make sure PRD is allocated in one 64K page\r
-    //\r
-    if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
-      UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
-    } else {\r
-      if ((UINTN) PrdAddr & 0x03) {\r
-        UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
-      } else {\r
-        UsedPrdAddr = PrdAddr;\r
-      }\r
-    }\r
-\r
-    //\r
-    // Build the PRD table\r
-    //\r
-    Status = IdeDev->PciIo->Map (\r
-                       IdeDev->PciIo,\r
-                       PciIoProtocolOp,\r
-                       DataBuffer,\r
-                       &ByteCount,\r
-                       &DeviceAddress,\r
-                       &Map\r
-                       );\r
-    if (EFI_ERROR (Status)) {\r
-      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);\r
-    TempPrdAddr = UsedPrdAddr;\r
-    while (TRUE) {\r
-\r
-      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
-\r
-      if (ByteCount <= ByteAvailable) {\r
-        TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
-        TempPrdAddr->ByteCount      = (UINT16) ByteCount;\r
-        TempPrdAddr->EndOfTable     = 0x8000;\r
-        break;\r
-      }\r
-\r
-      TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
-      TempPrdAddr->ByteCount      = (UINT16) ByteAvailable;\r
-\r
-      ByteCount -= ByteAvailable;\r
-      PrdBuffer += ByteAvailable;\r
-      TempPrdAddr++;\r
-    }\r
-\r
-    //\r
-    // Set the base address to BMID register\r
-    //\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint32,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmid,\r
-                        1,\r
-                        &UsedPrdAddr\r
-                        );\r
-\r
-    //\r
-    // Set BMIC register to identify the operation direction\r
-    //\r
-    IdeDev->PciIo->Io.Read (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
-      RegisterValue |= BMIC_nREAD;\r
-    } else {\r
-      RegisterValue &= ~((UINT8) BMIC_nREAD);\r
-    }\r
-\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
-      Status = AtaCommandIssueExt (\r
-                 IdeDev,\r
-                 AtaCommand,\r
-                 Device,\r
-                 0,\r
-                 (UINT16) NumberOfBlocks,\r
-                 StartLba\r
-                 );\r
-    } else {\r
-      Status = AtaCommandIssue (\r
-                 IdeDev,\r
-                 AtaCommand,\r
-                 Device,\r
-                 0,\r
-                 (UINT16) NumberOfBlocks,\r
-                 StartLba\r
-                 );\r
-    }\r
-\r
-    if (EFI_ERROR (Status)) {\r
-      IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
-      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
-\r
-    //\r
-    // Set START bit of BMIC register\r
-    //\r
-    IdeDev->PciIo->Io.Read (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    RegisterValue |= BMIC_START;\r
-\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\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
-    Status = EFI_SUCCESS;\r
-    Count = 2000;\r
-    while (TRUE) {\r
-\r
-      IdeDev->PciIo->Io.Read (\r
-                          IdeDev->PciIo,\r
-                          EfiPciIoWidthUint8,\r
-                          EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                          IoPortForBmis,\r
-                          1,\r
-                          &RegisterValue\r
-                          );\r
-      if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
-        if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
-                 Status = EFI_DEVICE_ERROR;\r
-                 break;\r
-        }\r
-        break;\r
-      }\r
-\r
-      gBS->Stall (1000);\r
-      Count --;\r
-    }\r
-\r
-    IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
-    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
-    //\r
-    // Read BMIS register and clear ERROR and INTR bit\r
-    //\r
-    IdeDev->PciIo->Io.Read (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmis,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmis,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-       //\r
-    // Read Status Register of IDE device to clear interrupt\r
-    //\r
-    RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
-    //\r
-    // Clear START bit of BMIC register\r
-    //\r
-    IdeDev->PciIo->Io.Read (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    RegisterValue &= ~((UINT8) BMIC_START);\r
-\r
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
-\r
-    if (RegisterValue & BMIS_ERROR) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
-\r
-       if (EFI_ERROR (Status)) {\r
-         break;\r
-       }\r
-    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
-    StartLba += NumberOfBlocks;\r
-  }\r
-\r
-  //\r
-  // Disable interrupt of Select device\r
-  //\r
-  IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
-  DeviceControl |= ATA_CTLREG_IEN_L;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
-  return Status;\r
-}\r
 \r