]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c
Code scrub for IdeBusDxe driver
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ata.c
index 87d466f9d07c8340952c8a446951e00113b8251b..98d9323ea7541612053318e63f23bb36eb5ebe7a 100644 (file)
@@ -1,4 +1,6 @@
 /** @file\r
+  This file contains all helper functions on the ATA command \r
+  \r
   Copyright (c) 2006 - 2008, 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
 **/\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->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
+  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
@@ -178,153 +402,71 @@ ATAIdentify (
   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->IdData == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
+    return ;\r
   }\r
 \r
-  Atapi6IdentifyStruct = IdeDev->IdData;\r
+  SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);\r
+  IdeDev->ModelName[40] = 0x00;\r
+}\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->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->IdData == NULL) {\r
-    return ;\r
-  }\r
-\r
-  SwapStringChars (IdeDev->ModelName, IdeDev->IdData->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
@@ -461,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
@@ -474,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
@@ -613,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
@@ -633,26 +771,26 @@ CheckErrorStatus (
 \r
   DEBUG_CODE_BEGIN ();\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
+  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) != 0) {\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) != 0) {\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) != 0) {\r
+    if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {\r
       DEBUG (\r
         (EFI_D_BLKIO,\r
         "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
@@ -712,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
@@ -830,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
@@ -933,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
@@ -946,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
@@ -1005,1015 +1119,1082 @@ 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
+  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] LBA\r
-  The starting logical block address to read from\r
-  on 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
-\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
-\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
+  Send ATA Ext command into device with NON_DATA protocol\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] StartLba\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
-  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
+    //\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
-  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
-  slow down writing performance by 100 times!)\r
+      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\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
+      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, 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
-}\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
-  This function is used to send out ATA commands conforms to the\r
-  PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
+    if ((RegisterValue & BMIS_ERROR) != 0) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
 \r
-  Comparing with ATA-3 data out 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
+       if (EFI_ERROR (Status)) {\r
+         break;\r
+       }\r
+    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
+    StartLba += NumberOfBlocks;\r
+  }\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
+  //\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
-  @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
+  return Status;\r
+}\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
+/**\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
-  @retval EFI_DEVICE_ERROR command sent failed.\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
-AtaPioDataOutExt (\r
+AtaUdmaReadExt (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  VOID            *Buffer,\r
-  IN  UINT32          ByteCount,\r
-  IN  UINT8           AtaCommand,\r
+  IN  VOID            *DataBuffer,\r
   IN  EFI_LBA         StartLba,\r
-  IN  UINT16          SectorCount\r
+  IN  UINTN           NumberOfBlocks\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
-  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\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
-\r
-  //\r
-  // Wait for DRDY singnal asserting.\r
-  //\r
-  Status = DRDYReady (IdeDev, ATATIMEOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_DEVICE_ERROR;\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
+  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
-  //\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
+  @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
-  SectorCount8 = (UINT8) SectorCount;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\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
-  //\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
+  @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
-  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
+  @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
-  // Send command via Command Register, invoking the processing of this command\r
+  // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol\r
   //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
-\r
-  Buffer16 = (UINT16 *) Buffer;\r
+  AtaCommand      = ATA_CMD_READ_SECTORS_EXT;\r
+  Buffer          = DataBuffer;\r
+  BlocksRemaining = NumberOfBlocks;\r
+  Lba64           = StartLba;\r
+  Status          = EFI_SUCCESS;\r
 \r
-  //\r
-  // According to PIO Data Out protocol, host can perform a series of writes to\r
-  // the data register after each time device set DRQ ready;\r
-  //\r
-  Increment = 256;\r
+  while (BlocksRemaining > 0) {\r
 \r
-  //\r
-  // used to record bytes of currently transfered data\r
-  //\r
-  WordCount = 0;\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
-  while (WordCount < ByteCount / 2) {\r
     //\r
-    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+    // ByteCount is the number of bytes that will be read\r
     //\r
-    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
-\r
-    Status = CheckErrorStatus (IdeDev);\r
-    if (EFI_ERROR (Status)) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
 \r
     //\r
-    // Write data into device by one series of writing to data register\r
+    // call AtaPioDataInExt() to send Read Sector Command and receive data read\r
     //\r
-    if ((WordCount + Increment) > ByteCount / 2) {\r
-      Increment = ByteCount / 2 - WordCount;\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
-    IDEWritePortWMultiple (\r
-      IdeDev->PciIo,\r
-      IdeDev->IoPort->Data,\r
-      Increment,\r
-      Buffer16\r
-      );\r
-\r
-    WordCount += Increment;\r
-    Buffer16 += Increment;\r
-\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\r
   }\r
-  //\r
-  // while\r
-  //\r
 \r
-  return CheckErrorStatus (IdeDev);\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
-/**\r
-  Enable SMART of the disk if supported\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
-  @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
+  @note If Read Block error because of device error, this function will call\r
+        AtaSoftReset() function to reset device.\r
 \r
 **/\r
-VOID\r
-AtaSMARTSupport (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\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_STATUS        Status;\r
-  BOOLEAN           SMARTSupported;\r
-  UINT8             Device;\r
-  EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;\r
-  UINT8             DeviceSelect;\r
-  UINT8             LBAMid;\r
-  UINT8             LBAHigh;\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
-  // Detect if the device supports S.M.A.R.T.\r
+  //  Get the intrinsic block size\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
+  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 (!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
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\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
+  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
-    // Detect if this feature is enabled\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\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
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
-\r
+  } else {\r
     //\r
-    // Check if the feature is enabled\r
+    // For ATA-3 compatible device, use ATA-3 read block mechanism\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
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\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
+      Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
+  }\r
 \r
-    gBS->FreePool (TmpAtaIdentifyPointer);\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
-  return ;\r
-}\r
+  return EFI_SUCCESS;\r
 \r
+}\r
 /**\r
-  Enable Long Physical Sector Feature for ATA device.\r
+  This function is used to send out ATA commands conforms to the\r
+  PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
 \r
-  @param   IdeDev  The IDE device data\r
+  Comparing with ATA-3 data out 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
+\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
+  @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
-  @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
+AtaPioDataOutExt (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  VOID            *Buffer,\r
+  IN  UINT32          ByteCount,\r
+  IN  UINT8           AtaCommand,\r
+  IN  EFI_LBA         StartLba,\r
+  IN  UINT16          SectorCount\r
   )\r
 {\r
-  EFI_ATA_IDENTIFY_DATA  *AtaIdentifyData;\r
-  UINT16                 PhyLogicSectorSupport;\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
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-  ASSERT (IdeDev->IdData != NULL);\r
   //\r
-  // Only valid for ATA device\r
+  // Select device. Set bit6 as 1 to indicate LBA mode is used\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
+  DevSel = (UINT8) (IdeDev->Device << 4);\r
+  DevSel |= 0x40;\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    DevSel\r
+    );\r
+\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
-\r
-/**\r
-  Send ATA Ext command into device with NON_DATA protocol\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
-\r
-  @retval  EFI_SUCCESS Reading succeed\r
-  @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
-\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
-  )\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
-\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
+  // Wait for DRDY singnal asserting.\r
   //\r
   Status = DRDYReady (IdeDev, ATATIMEOUT);\r
   if (EFI_ERROR (Status)) {\r
@@ -2021,18 +2202,11 @@ AtaCommandIssueExt (
   }\r
 \r
   //\r
-  // Pass parameter into device register block\r
-  //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
-  //\r
-  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  // Fill feature register if needed\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
+  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
@@ -2046,685 +2220,579 @@ AtaCommandIssueExt (
   //\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
+  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
-\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
-  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
-  //\r
-  // Work around for Segate 160G disk writing\r
-  //\r
-  gBS->Stall (1800);\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\r
+  // Send command via Command Register, invoking the processing of this command\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
-  Send ATA Ext command into device with NON_DATA protocol\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
-\r
-  @retval  EFI_SUCCESS Reading succeed\r
-  @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
-\r
-**/\r
-EFI_STATUS\r
-AtaCommandIssue (\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       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
-  // 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
-  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
+  Buffer16 = (UINT16 *) Buffer;\r
 \r
   //\r
-  // Pass parameter into device register block\r
+  // According to PIO Data Out protocol, host can perform a series of writes to\r
+  // the data register after each time device set DRQ ready;\r
   //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+  Increment = 256;\r
 \r
   //\r
-  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  // used to record bytes of currently transfered data\r
   //\r
-  Feature8 = (UINT8) Feature;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
+  WordCount = 0;\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
+  while (WordCount < ByteCount / 2) {\r
+    //\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.\r
+    //\r
+    Status = DRQReady2 (IdeDev, ATATIMEOUT);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
 \r
-  //\r
-  // Fill the start LBA registers, which are also two-byte FIFO\r
-  //\r
+    Status = CheckErrorStatus (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\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
+    //\r
+    // Write data into device by one series of writing to data register\r
+    //\r
+    if ((WordCount + Increment) > ByteCount / 2) {\r
+      Increment = ByteCount / 2 - WordCount;\r
+    }\r
 \r
-  //\r
-  // Send command via Command Register\r
-  //\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+    IDEWritePortWMultiple (\r
+      IdeDev->PciIo,\r
+      IdeDev->IoPort->Data,\r
+      Increment,\r
+      Buffer16\r
+      );\r
 \r
-  //\r
-  // Stall at least 400ns\r
-  //\r
-  gBS->Stall (100);\r
+    WordCount += Increment;\r
+    Buffer16 += Increment;\r
 \r
-  return EFI_SUCCESS;\r
+  }\r
+  return CheckErrorStatus (IdeDev);\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
+  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 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
+  @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 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
+  @return status depends on the function DoAtaUdma() returns.\r
 **/\r
 EFI_STATUS\r
-AtaUdmaReadExt (\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, AtaUdmaReadExtOp);\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\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
+  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
-AtaUdmaRead (\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, AtaUdmaReadOp);\r
+  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\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
+  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[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
+  @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 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
+  @return status is fully dependent on the return status of AtaPioDataOutExt() function.\r
 **/\r
 EFI_STATUS\r
-AtaUdmaWriteExt (\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
-  return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\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
-  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
+  // 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
-  @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
+  while (BlocksRemaining > 0) {\r
 \r
-  @param[in] *DataBuffer\r
-  A pointer to the source buffer for the data.\r
+    if (BlocksRemaining >= 0x10000) {\r
+      //\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
+      SectorCount = 0xffff;\r
+    } else {\r
+      SectorCount = (UINT16) BlocksRemaining;\r
+    }\r
 \r
-  @param[in] StartLba\r
-  The starting logical block address to write to\r
-  on the device media.\r
+    //\r
+    // ByteCount is the number of bytes that will be written\r
+    //\r
+    ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);\r
 \r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\r
+    //\r
+    // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command\r
+    //\r
+    Status = AtaPioDataOutExt (\r
+              IdeDev,\r
+              Buffer,\r
+              ByteCount,\r
+              AtaCommand,\r
+              Lba64,\r
+              SectorCount\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
 \r
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\r
+    Lba64 += SectorCount;\r
+    Buffer = ((UINT8 *) Buffer + ByteCount);\r
+    BlocksRemaining -= SectorCount;\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
-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
+  return Status;\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
+  This function is the ATA implementation for WriteBlocks in the\r
+  Block I/O Protocol interface.\r
 \r
-  @param[in] NumberOfBlocks\r
-  The number of transfer data blocks.\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
-  @param[in] UdmaOp\r
-  The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
-  AtaUdmaWriteOp, AtaUdmaWriteExOp\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
-  @return The device status of UDMA operation. If the operation is\r
-  successful, return EFI_SUCCESS.\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
-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
+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
-  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
+  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
-  //\r
-  // Select device\r
-  //\r
-  Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
 \r
   //\r
-  // Enable interrupt to support UDMA\r
+  // Get the intrinsic block size\r
   //\r
-  DeviceControl = 0;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
+  Media           = IdeBlkIoDevice->BlkIo.Media;\r
+  BlockSize       = Media->BlockSize;\r
+  NumberOfBlocks  = BufferSize / BlockSize;\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
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\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
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
 \r
-  Status = EFI_SUCCESS;\r
-  \r
-  RemainBlockNum = NumberOfBlocks;\r
-  while (RemainBlockNum > 0) {\r
+  if (LBA > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\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
+  if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\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
+  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
-    // Build PRD table\r
+    // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\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
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     } else {\r
-      if ((UINTN) PrdAddr & 0x03) {\r
-        UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
-      } else {\r
-        UsedPrdAddr = PrdAddr;\r
-      }\r
+      Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
-\r
+  } else {\r
     //\r
-    // Build the PRD table\r
+    // For ATA-3 compatible device, use ATA-3 write block mechanism\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
+    if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+      Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    } else {\r
+      Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
-    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);\r
-    TempPrdAddr = UsedPrdAddr;\r
-    while (TRUE) {\r
+  }\r
 \r
-      ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
+  if (EFI_ERROR (Status)) {\r
+    AtaSoftReset (IdeBlkIoDevice);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-      if (ByteCount <= ByteAvailable) {\r
-        TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
-        TempPrdAddr->ByteCount      = (UINT16) ByteCount;\r
-        TempPrdAddr->EndOfTable     = 0x8000;\r
-        break;\r
-      }\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  Enable Long Physical Sector Feature for ATA device.\r
 \r
-      TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
-      TempPrdAddr->ByteCount      = (UINT16) ByteAvailable;\r
+  @param   IdeDev  The IDE device data\r
 \r
-      ByteCount -= ByteAvailable;\r
-      PrdBuffer += ByteAvailable;\r
-      TempPrdAddr++;\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
+  // 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
-    // Set the base address to BMID register\r
+    // Check whether one physical block contains multiple physical blocks\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
+    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
-    // Set BMIC register to identify the operation direction\r
+    // Check logical block size\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
+    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
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\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  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
-    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
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error.\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
+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
-    //\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
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
 \r
-    RegisterValue |= BMIC_START;\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
-    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
+  // 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
-    // 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
+  // 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
-      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
+  // Send command via Command Register\r
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
 \r
-      gBS->Stall (1000);\r
-      Count --;\r
-    }\r
+  //\r
+  // Wait for command completion\r
+  // For ATAPI_SMART_CMD, we may need more timeout to let device\r
+  // adjust internal states.\r
+  //\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
-    IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
-    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
+  StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
+  if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
     //\r
-    // Read BMIS register and clear ERROR and INTR bit\r
+    // Failed to execute command, abort operation\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
+    return EFI_ABORTED;\r
+  }\r
 \r
-    RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+  return EFI_SUCCESS;\r
+}\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
+  Send ATA Ext command into device with NON_DATA protocol\r
 \r
-    RegisterValue &= ~((UINT8) BMIC_START);\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
-    IdeDev->PciIo->Io.Write (\r
-                        IdeDev->PciIo,\r
-                        EfiPciIoWidthUint8,\r
-                        EFI_PCI_IO_PASS_THROUGH_BAR,\r
-                        IoPortForBmic,\r
-                        1,\r
-                        &RegisterValue\r
-                        );\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error.\r
 \r
-    if ((RegisterValue & BMIS_ERROR) != 0) {\r
-      return EFI_DEVICE_ERROR;\r
-    }\r
+**/\r
+EFI_STATUS\r
+AtaNonDataCommandInExt (\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       StatusRegister;\r
+  UINT8       SectorCount8;\r
+  UINT8       Feature8;\r
+  UINT8       LbaLow;\r
+  UINT8       LbaMid;\r
+  UINT8       LbaHigh;\r
 \r
-       if (EFI_ERROR (Status)) {\r
-         break;\r
-       }\r
-    DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
-    StartLba += NumberOfBlocks;\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
   }\r
 \r
   //\r
-  // Disable interrupt of Select device\r
+  // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\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
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
+    );\r
 \r
-  return Status;\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
+\r
+  //\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
+  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
+  //\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
+\r
+  //\r
+  // Wait for command completion\r
+  //\r
+  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\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
 \r
+\r
+\r