]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c
In IdeBus driver block I/O read/write interface, it will always try to use UDMA mode...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / IdeBus / Dxe / ide.c
index d318fd23df98c4188be7f8ae3b85c9abd1ff97e3..4b4a8ef0a355cfe798d31b2dfba5eba993bd3f28 100644 (file)
@@ -1,50 +1,37 @@
-/*++\r
+/** @file\r
+  Copyright (c) 2006, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
 \r
-Copyright (c) 2006, Intel Corporation                                                         \r
-All rights reserved. This program and the accompanying materials                          \r
-are licensed and made available under the terms and conditions of the BSD License         \r
-which accompanies this distribution.  The full text of the license may be found at        \r
-http://opensource.org/licenses/bsd-license.php                                            \r
-                                                                                          \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
-Module Name:\r
+**/\r
 \r
-    ide.c\r
-    \r
-Abstract: \r
-    \r
+#include "idebus.h"\r
 \r
-Revision History\r
---*/\r
+BOOLEAN ChannelDeviceDetected = FALSE;\r
+BOOLEAN SlaveDeviceExist      = FALSE;\r
+UINT8   SlaveDeviceType       = INVALID_DEVICE_TYPE;\r
+BOOLEAN MasterDeviceExist     = FALSE;\r
+UINT8   MasterDeviceType      = INVALID_DEVICE_TYPE;\r
 \r
-#include "idebus.h"\r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
 \r
-BOOLEAN SlaveDeviceExist  = FALSE;\r
-BOOLEAN MasterDeviceExist = FALSE;\r
+  TODO: add return values\r
 \r
+**/\r
 UINT8\r
 IDEReadPortB (\r
   IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
   IN  UINT16                Port\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  PciIo - TODO: add argument description\r
-  Port  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   UINT8 Data;\r
 \r
@@ -63,6 +50,17 @@ Returns:
   return Data;\r
 }\r
 \r
+/**\r
+  Reads multiple words of data from the IDE data port.\r
+  Call the IO abstraction once to do the complete read,\r
+  not one word at a time\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO instance\r
+  @param  Port IO port to read\r
+  @param  Count No. of UINT16's to read\r
+  @param  Buffer Pointer to the data buffer for read\r
+\r
+**/\r
 VOID\r
 IDEReadPortWMultiple (\r
   IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
@@ -70,23 +68,6 @@ IDEReadPortWMultiple (
   IN  UINTN                 Count,\r
   IN  VOID                  *Buffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Reads multiple words of data from the IDE data port. \r
-  Call the IO abstraction once to do the complete read,\r
-  not one word at a time\r
-  \r
-\r
-Arguments:\r
-  PciIo   - Pointer to the EFI_PCI_IO instance\r
-  Port    - IO port to read\r
-  Count   - No. of UINT16's to read\r
-  Buffer  - Pointer to the data buffer for read\r
-\r
-++*/\r
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Returns:'\r
 {\r
   UINT16  *AlignedBuffer;\r
   UINT16  *WorkingBuffer;\r
@@ -127,29 +108,22 @@ Arguments:
   gBS->FreePool (WorkingBuffer);\r
 }\r
 \r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
 VOID\r
 IDEWritePortB (\r
   IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
   IN  UINT16                Port,\r
   IN  UINT8                 Data\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  PciIo - TODO: add argument description\r
-  Port  - TODO: add argument description\r
-  Data  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   //\r
   // perform 1-byte data write to register\r
@@ -165,29 +139,22 @@ Returns:
 \r
 }\r
 \r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  PciIo TODO: add argument description\r
+  @param  Port TODO: add argument description\r
+  @param  Data TODO: add argument description\r
+\r
+  TODO: add return values\r
+\r
+**/\r
 VOID\r
 IDEWritePortW (\r
   IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
   IN  UINT16                Port,\r
   IN  UINT16                Data\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  PciIo - TODO: add argument description\r
-  Port  - TODO: add argument description\r
-  Data  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
 {\r
   //\r
   // perform 1-word data write to register\r
@@ -202,6 +169,17 @@ Returns:
               );\r
 }\r
 \r
+/**\r
+  Write multiple words of data to the IDE data port.\r
+  Call the IO abstraction once to do the complete read,\r
+  not one word at a time\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO instance\r
+  @param  Port IO port to read\r
+  @param  Count No. of UINT16's to read\r
+  @param  Buffer Pointer to the data buffer for read\r
+\r
+**/\r
 VOID\r
 IDEWritePortWMultiple (\r
   IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
@@ -209,23 +187,6 @@ IDEWritePortWMultiple (
   IN  UINTN                 Count,\r
   IN  VOID                  *Buffer\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  Write multiple words of data to the IDE data port. \r
-  Call the IO abstraction once to do the complete read,\r
-  not one word at a time\r
-  \r
-\r
-Arguments:\r
-  PciIo   - Pointer to the EFI_PCI_IO instance\r
-  Port    - IO port to read\r
-  Count   - No. of UINT16's to read\r
-  Buffer  - Pointer to the data buffer for read\r
-\r
-++*/\r
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Returns:'\r
 {\r
   UINT16  *AlignedBuffer;\r
   UINT32  *WorkingBuffer;\r
@@ -267,137 +228,65 @@ Arguments:
   gBS->FreePool (WorkingBuffer);\r
 }\r
 \r
-BOOLEAN\r
-BadIdeDeviceCheck (\r
-  IN IDE_BLK_IO_DEV *IdeDev\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  TODO: Add function description\r
-\r
-Arguments:\r
-\r
-  IdeDev  - TODO: add argument description\r
-\r
-Returns:\r
-\r
-  TODO: add return values\r
-\r
---*/\r
-{\r
-  //\r
-  //  check whether all registers return 0xff,\r
-  //  if so, deem the channel is disabled.\r
-  //\r
-#ifdef EFI_DEBUG\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) {\r
-    return FALSE;\r
-  }\r
-\r
-  return TRUE;\r
-\r
-#else\r
-\r
-  return FALSE;\r
-\r
-#endif\r
-}\r
-\r
 //\r
 // GetIdeRegistersBaseAddr\r
 //\r
-EFI_STATUS\r
-GetIdeRegistersBaseAddr (\r
-  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
-  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr\r
-  )\r
-/*++\r
-\r
-Routine Description:\r
+/**\r
   Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
   use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
   the PCI IDE controller's Configuration Space.\r
-  \r
-  The steps to get IDE IO port registers' base addresses for each channel \r
+\r
+  The steps to get IDE IO port registers' base addresses for each channel\r
   as follows:\r
 \r
-  1. Examine the Programming Interface byte of the Class Code fields in PCI IDE \r
-     controller's Configuration Space to determine the operating mode.\r
-     \r
+  1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
+  controller's Configuration Space to determine the operating mode.\r
+\r
   2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
-                 ___________________________________________\r
-                |           | Command Block | Control Block |\r
-                |  Channel  |   Registers   |   Registers   |\r
-                |___________|_______________|_______________|\r
-                |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |\r
-                |___________|_______________|_______________|\r
-                | Secondary |  170h - 177h  |  376h - 377h  |\r
-                |___________|_______________|_______________|\r
-        \r
-                  Table 1. Compatibility resource mappings\r
-        \r
-     b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
-        in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
-               ___________________________________________________\r
-              |           |   Command Block   |   Control Block   |\r
-              |  Channel  |     Registers     |     Registers     |\r
-              |___________|___________________|___________________|\r
-              |  Primary  | BAR at offset 0x10| BAR at offset 0x14|\r
-              |___________|___________________|___________________|\r
-              | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
-              |___________|___________________|___________________|\r
-      \r
-                        Table 2. BARs for Register Mapping\r
-        Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for \r
-              primary, 0374h for secondary. So 2 bytes extra offset should be \r
-              added to the base addresses read from BARs.\r
-  \r
-  For more details, please refer to PCI IDE Controller Specification and Intel \r
+  <pre>\r
+  ___________________________________________\r
+  |           | Command Block | Control Block |\r
+  |  Channel  |   Registers   |   Registers   |\r
+  |___________|_______________|_______________|\r
+  |  Primary  |  1F0h - 1F7h  |  3F6h - 3F7h  |\r
+  |___________|_______________|_______________|\r
+  | Secondary |  170h - 177h  |  376h - 377h  |\r
+  |___________|_______________|_______________|\r
+\r
+  Table 1. Compatibility resource mappings\r
+  </pre>\r
+\r
+  b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
+  in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
+  <pre>\r
+  ___________________________________________________\r
+  |           |   Command Block   |   Control Block   |\r
+  |  Channel  |     Registers     |     Registers     |\r
+  |___________|___________________|___________________|\r
+  |  Primary  | BAR at offset 0x10| BAR at offset 0x14|\r
+  |___________|___________________|___________________|\r
+  | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
+  |___________|___________________|___________________|\r
+\r
+  Table 2. BARs for Register Mapping\r
+  </pre>\r
+  @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
+  primary, 0374h for secondary. So 2 bytes extra offset should be\r
+  added to the base addresses read from BARs.\r
+\r
+  For more details, please refer to PCI IDE Controller Specification and Intel\r
   ICH4 Datasheet.\r
-  \r
-Arguments:\r
-  PciIo             - Pointer to the EFI_PCI_IO_PROTOCOL instance\r
-  IdeRegsBaseAddr   - Pointer to IDE_REGISTERS_BASE_ADDR to \r
-                      receive IDE IO port registers' base addresses\r
-                      \r
-Returns:\r
-    \r
---*/\r
+\r
+  @param  PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param  IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
+  receive IDE IO port registers' base addresses\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdeRegistersBaseAddr (\r
+  IN  EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr\r
+  )\r
 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
 // TODO:    EFI_SUCCESS - add return value to function comment\r
@@ -420,13 +309,13 @@ Returns:
   if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
     IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr  = 0x1f0;\r
     IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr  = 0x3f6;\r
-    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     = \r
+    IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr     =\r
     (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
   } else {\r
     //\r
     // The BARs should be of IO type\r
     //\r
-    if ((PciData.Device.Bar[0] & bit0) == 0 || \r
+    if ((PciData.Device.Bar[0] & bit0) == 0 ||\r
         (PciData.Device.Bar[1] & bit0) == 0) {\r
       return EFI_UNSUPPORTED;\r
     }\r
@@ -464,24 +353,19 @@ Returns:
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This function is used to requery IDE resources. The IDE controller will\r
+  probably switch between native and legacy modes during the EFI->CSM->OS\r
+  transfer. We do this everytime before an BlkIo operation to ensure its\r
+  succeess.\r
+\r
+  @param  IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
 EFI_STATUS\r
 ReassignIdeResources (\r
   IN  IDE_BLK_IO_DEV  *IdeDev\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-  This function is used to requery IDE resources. The IDE controller will \r
-  probably switch between native and legacy modes during the EFI->CSM->OS \r
-  transfer. We do this everytime before an BlkIo operation to ensure its\r
-  succeess.\r
-  \r
-Arguments:\r
-  IdeDev - The BLK_IO private data which specifies the IDE device\r
-  \r
-++*/\r
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Returns:'\r
 // TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_STATUS              Status;\r
@@ -519,125 +403,85 @@ Arguments:
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-CheckPowerMode (\r
-  IDE_BLK_IO_DEV    *IdeDev\r
-  )\r
-/*++\r
- Routine Description:\r
\r
-  Read SATA registers to detect SATA disks\r
-\r
- Arguments:\r
-\r
-  IdeDev - The BLK_IO private data which specifies the IDE device\r
-  \r
-++*/\r
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Returns:'\r
-// TODO:    EFI_NOT_FOUND - add return value to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
-// TODO:    EFI_NOT_FOUND - add return value to function comment\r
-{\r
-  UINT8       ErrorRegister;\r
-  EFI_STATUS  Status;\r
-\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
-    );\r
-\r
-  //\r
-  // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists\r
-  // a device (initial state). Normally, BSY is also in clear state if there is\r
-  // no device\r
-  //\r
-  Status = WaitForBSYClear (IdeDev, 31000);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  //\r
-  // select device, read error register\r
-  //\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
-    );\r
-  Status        = DRDYReady (IdeDev, 200);\r
-\r
-  ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
-  if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) {\r
-    return EFI_SUCCESS;\r
-  } else {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-}\r
-\r
 //\r
 // DiscoverIdeDevice\r
 //\r
+/**\r
+  Detect if there is disk connected to this port\r
+\r
+  @param  IdeDev The BLK_IO private data which specifies the IDE device\r
+\r
+**/\r
 EFI_STATUS\r
 DiscoverIdeDevice (\r
   IN IDE_BLK_IO_DEV *IdeDev\r
   )\r
-/*++\r
- Routine Description:\r
\r
-  Detect if there is disk connected to this port\r
-\r
- Arguments:\r
-\r
-  IdeDev - The BLK_IO private data which specifies the IDE device\r
-  \r
-++*/\r
-// TODO: function comment should end with '--*/'\r
-// TODO: function comment is missing 'Returns:'\r
 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
 // TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_STATUS  Status;\r
-  BOOLEAN     SataFlag;\r
 \r
-  SataFlag = FALSE;\r
-  //\r
-  // This extra detection is for SATA disks\r
-  //\r
-  Status = CheckPowerMode (IdeDev);\r
-  if (Status == EFI_SUCCESS) {\r
-    SataFlag = TRUE;\r
-  }\r
-    \r
   //\r
   // If a channel has not been checked, check it now. Then set it to "checked" state\r
   // After this step, all devices in this channel have been checked.\r
   //\r
-  Status = DetectIDEController (IdeDev);\r
-\r
-  if ((EFI_ERROR (Status)) && !SataFlag) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-  \r
-  //\r
-  // Device exists. test if it is an ATA device\r
-  //\r
-  Status = ATAIdentify (IdeDev);\r
-  if (EFI_ERROR (Status)) {\r
-    //\r
-    // if not ATA device, test if it is an ATAPI device\r
-    //\r
-    Status = ATAPIIdentify (IdeDev);\r
+  if (ChannelDeviceDetected == FALSE) {\r
+    Status = DetectIDEController (IdeDev);\r
     if (EFI_ERROR (Status)) {\r
-      //\r
-      // if not ATAPI device either, return error.\r
-      //\r
       return EFI_NOT_FOUND;\r
     }\r
   }\r
 \r
+  Status = EFI_NOT_FOUND;\r
+\r
+  //\r
+  // Device exists. test if it is an ATA device.\r
+  // Prefer the result from DetectIDEController,\r
+  // if failed, try another device type to handle\r
+  // devices that not follow the spec.\r
+  //\r
+  if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
+    if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
+    if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
   //\r
   // Init Block I/O interface\r
   //\r
@@ -662,82 +506,71 @@ DiscoverIdeDevice (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This interface is used to initialize all state data related to the detection of one\r
+  channel.\r
+\r
+  @retval EFI_SUCCESS Completed Successfully.\r
+\r
+**/\r
 EFI_STATUS\r
-DetectIDEController (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+InitializeIDEChannelData (\r
+  VOID\r
   )\r
-/*++\r
-  \r
-  Name: DetectIDEController\r
-\r
+{\r
+  ChannelDeviceDetected = FALSE;\r
+  MasterDeviceExist = FALSE;\r
+  MasterDeviceType  = 0xff;\r
+  SlaveDeviceExist  = FALSE;\r
+  SlaveDeviceType   = 0xff;\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-  Purpose: \r
-      This function is called by DiscoverIdeDevice(). It is used for detect \r
-      whether the IDE device exists in the specified Channel as the specified \r
-      Device Number.\r
+/**\r
+  This function is called by DiscoverIdeDevice(). It is used for detect\r
+  whether the IDE device exists in the specified Channel as the specified\r
+  Device Number.\r
 \r
-      There is two IDE channels: one is Primary Channel, the other is \r
-      Secondary Channel.(Channel is the logical name for the physical "Cable".) \r
-      Different channel has different register group.\r
+  There is two IDE channels: one is Primary Channel, the other is\r
+  Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
+  Different channel has different register group.\r
 \r
-      On each IDE channel, at most two IDE devices attach, \r
-      one is called Device 0 (Master device), the other is called Device 1 \r
-      (Slave device). The devices on the same channel co-use the same register \r
-      group, so before sending out a command for a specified device via command \r
-      register, it is a must to select the current device to accept the command \r
-      by set the device number in the Head/Device Register.\r
\r
-            \r
-  Parameters:\r
-      IDE_BLK_IO_DEV  IN    *IdeDev\r
-            pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-            to record all the information of the IDE device.\r
+  On each IDE channel, at most two IDE devices attach,\r
+  one is called Device 0 (Master device), the other is called Device 1\r
+  (Slave device). The devices on the same channel co-use the same register\r
+  group, so before sending out a command for a specified device via command\r
+  register, it is a must to select the current device to accept the command\r
+  by set the device number in the Head/Device Register.\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
-  Returns:    \r
-      TRUE      \r
-            successfully detects device.\r
+  @retval TRUE\r
+  successfully detects device.\r
 \r
-      FALSE\r
-            any failure during detection process will return this\r
-            value.\r
+  @retval FALSE\r
+  any failure during detection process will return this\r
+  value.\r
 \r
+  @note\r
+  TODO:    EFI_SUCCESS - add return value to function comment\r
+  TODO:    EFI_NOT_FOUND - add return value to function comment\r
 \r
-  Notes:\r
---*/\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO:    IdeDev - add argument and description to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
-// TODO:    EFI_NOT_FOUND - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+DetectIDEController (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  )\r
 {\r
   EFI_STATUS  Status;\r
-  UINT8       ErrorReg;\r
-  UINT8       StatusReg;\r
+  UINT8       SectorCountReg;\r
+  UINT8       LBALowReg;\r
+  UINT8       LBAMidReg;\r
+  UINT8       LBAHighReg;\r
   UINT8       InitStatusReg;\r
-  EFI_STATUS  DeviceStatus;\r
-\r
-  //\r
-  // Slave device has been detected with master device.\r
-  //\r
-  if ((IdeDev->Device) == 1) {\r
-    if (SlaveDeviceExist) {\r
-      //\r
-      // If master not exists but slave exists, slave have to wait a while\r
-      //\r
-      if (!MasterDeviceExist) {\r
-        //\r
-        // if single slave can't be detected, add delay 4s here.\r
-        //\r
-        gBS->Stall (4000000);\r
-      }\r
+  UINT8       StatusReg;\r
 \r
-      return EFI_SUCCESS;\r
-    } else {\r
-      return EFI_NOT_FOUND;\r
-    }\r
-  }\r
-      \r
   //\r
   // Select slave device\r
   //\r
@@ -754,7 +587,7 @@ DetectIDEController (
   InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
 \r
   //\r
-  // Select master back\r
+  // Select Master back\r
   //\r
   IDEWritePortB (\r
     IdeDev->PciIo,\r
@@ -762,6 +595,7 @@ DetectIDEController (
     (UINT8) ((0 << 4) | 0xe0)\r
     );\r
   gBS->Stall (100);\r
+\r
   //\r
   // Send ATA Device Execut Diagnostic command.\r
   // This command should work no matter DRDY is ready or not\r
@@ -769,117 +603,153 @@ DetectIDEController (
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
 \r
   Status    = WaitForBSYClear (IdeDev, 3500);\r
-\r
-  ErrorReg  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
-\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+    return Status;\r
+  }\r
   //\r
-  // Master Error register is 0x01. D0 passed, D1 passed or not present.\r
-  // Master Error register is 0x81. D0 passed, D1 failed. Return.\r
-  // Master Error register is other value. D0 failed, D1 passed or not present..\r
+  // Read device signature\r
   //\r
-  if (ErrorReg == 0x01) {\r
-    MasterDeviceExist = TRUE;\r
-    DeviceStatus      = EFI_SUCCESS;\r
-  } else if (ErrorReg == 0x81) {\r
-\r
+  //\r
+  // Select Master\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((0 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorNumber\r
+                     );\r
+  LBAMidReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderLsb\r
+                     );\r
+  LBAHighReg     = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderMsb\r
+                     );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
     MasterDeviceExist = TRUE;\r
-    DeviceStatus      = EFI_SUCCESS;\r
-    SlaveDeviceExist  = FALSE;\r
-\r
-    return DeviceStatus;\r
+    MasterDeviceType  = ATA_DEVICE_TYPE;\r
   } else {\r
-    MasterDeviceExist = FALSE;\r
-    DeviceStatus      = EFI_NOT_FOUND;\r
+    if ((LBAMidReg      == 0x14) &&\r
+        (LBAHighReg     == 0xeb)) {\r
+      MasterDeviceExist = TRUE;\r
+      MasterDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
   }\r
-    \r
+\r
   //\r
-  // Master Error register is not 0x81, Go on check Slave\r
+  // For some Hard Drive, it takes some time to get\r
+  // the right signature when operating in single slave mode.\r
+  // We stall 20ms to work around this.\r
   //\r
+  if (!MasterDeviceExist) {\r
+    gBS->Stall (20000);\r
+  }\r
 \r
   //\r
-  // select slave\r
+  // Select Slave\r
   //\r
   IDEWritePortB (\r
     IdeDev->PciIo,\r
     IdeDev->IoPort->Head,\r
     (UINT8) ((1 << 4) | 0xe0)\r
     );\r
-\r
-  gBS->Stall (300);\r
-  ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->SectorNumber\r
+                 );\r
+  LBAMidReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderLsb\r
+                 );\r
+  LBAHighReg = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderMsb\r
+                 );\r
+  StatusReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->Reg.Status\r
+                 );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
+    SlaveDeviceExist = TRUE;\r
+    SlaveDeviceType  = ATA_DEVICE_TYPE;\r
+  } else {\r
+    if ((LBAMidReg     == 0x14) &&\r
+        (LBAHighReg    == 0xeb)) {\r
+      SlaveDeviceExist = TRUE;\r
+      SlaveDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
+  }\r
 \r
   //\r
-  // Slave Error register is not 0x01, D1 failed. Return.\r
+  // When single master is plugged, slave device\r
+  // will be wrongly detected. Here's the workaround\r
+  // for ATA devices by detecting DRY bit in status\r
+  // register.\r
+  // NOTE: This workaround doesn't apply to ATAPI.\r
   //\r
-  if (ErrorReg != 0x01) {\r
+  if (MasterDeviceExist && SlaveDeviceExist &&\r
+      (StatusReg & DRDY) == 0               &&\r
+      (InitStatusReg & DRDY) == 0           &&\r
+      MasterDeviceType == SlaveDeviceType   &&\r
+      SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
     SlaveDeviceExist = FALSE;\r
-    return DeviceStatus;\r
   }\r
 \r
-  StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
-\r
   //\r
-  // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate\r
-  //   "ATAPI TEST UNIT READY" command\r
+  // Indicate this channel has been detected\r
   //\r
-  if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) {\r
-    Status = AtapiTestUnitReady (IdeDev);\r
+  ChannelDeviceDetected = TRUE;\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-    //\r
-    // Still fail, Slave doesn't exist.\r
-    //\r
-    if (EFI_ERROR (Status)) {\r
-      SlaveDeviceExist = FALSE;\r
-      return DeviceStatus;\r
-    }\r
-  }\r
+/**\r
+  This function is used to poll for the DRQ bit clear in the Status\r
+  Register. DRQ is cleared when the device is finished transferring data.\r
+  So this function is called after data transfer is finished.\r
 \r
-  //\r
-  // Error reg is 0x01 and DRDY is ready,\r
-  //  or ATAPI test unit ready success,\r
-  //  or  init Slave status DRDY is ready\r
-  // Slave exists.\r
-  //\r
-  SlaveDeviceExist = TRUE;\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
-  return DeviceStatus;\r
+  @param[in] TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ clear.\r
 \r
-}\r
+  @retval EFI_SUCCESS\r
+  DRQ bit clear within the time out.\r
 \r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not clear within the time out.\r
+\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
+\r
+**/\r
 EFI_STATUS\r
 DRQClear (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
   IN  UINTN           TimeoutInMilliSeconds\r
   )\r
-/*++\r
-  Name:   DRQClear\r
-\r
-\r
-  Purpose: \r
-        This function is used to poll for the DRQ bit clear in the Status \r
-        Register. DRQ is cleared when the device is finished transferring data. \r
-        So this function is called after data transfer is finished.\r
-\r
-\r
-  Parameters:\r
-        IDE_BLK_IO_DEV  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
-        UINTN     IN    TimeoutInMilliSeconds\r
-            used to designate the timeout for the DRQ clear.\r
-\r
-  Returns:  \r
-        EFI_SUCCESS\r
-            DRQ bit clear within the time out.\r
-\r
-        EFI_TIMEOUT\r
-            DRQ bit not clear within the time out. \r
-\r
-\r
-  Notes:\r
-        Read Status Register will clear interrupt status.\r
---*/\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -926,41 +796,34 @@ DRQClear (
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-DRQClear2 (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           TimeoutInMilliSeconds\r
-  )\r
-/*++\r
-  Name:   DRQClear2\r
+/**\r
+  This function is used to poll for the DRQ bit clear in the Alternate\r
+  Status Register. DRQ is cleared when the device is finished\r
+  transferring data. So this function is called after data transfer\r
+  is finished.\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
-  Purpose: \r
-        This function is used to poll for the DRQ bit clear in the Alternate \r
-        Status Register. DRQ is cleared when the device is finished \r
-        transferring data. So this function is called after data transfer\r
-        is finished.\r
+  @param[in] TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ clear.\r
 \r
+  @retval EFI_SUCCESS\r
+  DRQ bit clear within the time out.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  IN    *IdeDev\r
-          pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-          to record all the information of the IDE device.\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not clear within the time out.\r
 \r
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ clear.\r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          DRQ bit clear within the time out.\r
-\r
-        EFI_TIMEOUT\r
-          DRQ bit not clear within the time out. \r
-\r
-\r
-  Notes:\r
-        Read Alternate Status Register will not clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+DRQClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1007,46 +870,38 @@ DRQClear2 (
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-DRQReady (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           TimeoutInMilliSeconds\r
-  )\r
-/*++\r
-  Name:   DRQReady\r
-\r
-  \r
-  Purpose: \r
-        This function is used to poll for the DRQ bit set in the \r
-        Status Register.\r
-        DRQ is set when the device is ready to transfer data. So this function\r
-        is called after the command is sent to the device and before required \r
-        data is transferred.\r
-\r
+/**\r
+  This function is used to poll for the DRQ bit set in the\r
+  Status Register.\r
+  DRQ is set when the device is ready to transfer data. So this function\r
+  is called after the command is sent to the device and before required\r
+  data is transferred.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  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[in] IDE_BLK_IO_DEV  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
-        UINTN     IN    TimeoutInMilliSeconds\r
-            used to designate the timeout for the DRQ ready.\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
+  @retval EFI_SUCCESS\r
+  DRQ bit set within the time out.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-            DRQ bit set within the time out.\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not set within the time out.\r
 \r
-        EFI_TIMEOUT\r
-            DRQ bit not set within the time out.\r
-            \r
-        EFI_ABORTED\r
-            DRQ bit not set caused by the command abort.\r
+  @retval EFI_ABORTED\r
+  DRQ bit not set caused by the command abort.\r
 \r
-  Notes:\r
-        Read Status Register will clear interrupt status.\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
 \r
---*/\r
+**/\r
+EFI_STATUS\r
+DRQReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1093,43 +948,37 @@ DRQReady (
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-DRQReady2 (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           TimeoutInMilliSeconds\r
-  )\r
-/*++\r
-  Name:   DRQReady2\r
-\r
+/**\r
+  This function is used to poll for the DRQ bit set in the\r
+  Alternate Status Register. DRQ is set when the device is ready to\r
+  transfer data. So this function is called after the command\r
+  is sent to the device and before required data is transferred.\r
 \r
-  Purpose: \r
-        This function is used to poll for the DRQ bit set in the \r
-        Alternate Status Register. DRQ is set when the device is ready to \r
-        transfer data. So this function is called after the command \r
-        is sent to the device and before required data is transferred.\r
+  @param[in] IDE_BLK_IO_DEV  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] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  IN    *IdeDev\r
-          pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-          to record all the information of the IDE device.\r
+  @retval EFI_SUCCESS\r
+  DRQ bit set within the time out.\r
 \r
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ ready.\r
+  @retval EFI_TIMEOUT\r
+  DRQ bit not set within the time out.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          DRQ bit set within the time out.\r
+  @retval EFI_ABORTED\r
+  DRQ bit not set caused by the command abort.\r
 \r
-        EFI_TIMEOUT\r
-          DRQ bit not set within the time out. \r
-        \r
-        EFI_ABORTED\r
-            DRQ bit not set caused by the command abort.\r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
 \r
-  Notes:\r
-        Read Alternate Status Register will not clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+DRQReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1176,41 +1025,33 @@ DRQReady2 (
   return EFI_SUCCESS;\r
 }\r
 \r
-EFI_STATUS\r
-WaitForBSYClear (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           TimeoutInMilliSeconds\r
-  )\r
-/*++\r
-  Name:\r
-        WaitForBSYClear\r
-\r
+/**\r
+  This function is used to poll for the BSY bit clear in the\r
+  Status Register. BSY is clear when the device is not busy.\r
+  Every command must be sent after device is not busy.\r
 \r
-  Purpose: \r
-        This function is used to poll for the BSY bit clear in the \r
-        Status Register. BSY is clear when the device is not busy.\r
-        Every command must be sent after device is not busy.\r
+  @param[in] IDE_BLK_IO_DEV  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] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  IN    *IdeDev\r
-          pointer pointing to IDE_BLK_IO_DEV data structure, used\r
-          to record all the information of the IDE device.\r
+  @retval EFI_SUCCESS\r
+  BSY bit clear within the time out.\r
 \r
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ ready.\r
+  @retval EFI_TIMEOUT\r
+  BSY bit not clear within the time out.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          BSY bit clear within the time out.\r
+  @note\r
+  Read Status Register will clear interrupt status.\r
 \r
-        EFI_TIMEOUT\r
-          BSY bit not clear within the time out. \r
-\r
-\r
-  Notes:\r
-        Read Status Register will clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1245,41 +1086,33 @@ WaitForBSYClear (
 //\r
 // WaitForBSYClear2\r
 //\r
-EFI_STATUS\r
-WaitForBSYClear2 (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           TimeoutInMilliSeconds\r
-  )\r
-/*++\r
-  Name:\r
-        WaitForBSYClear2\r
-\r
-\r
-  Purpose: \r
-        This function is used to poll for the BSY bit clear in the \r
-        Alternate Status Register. BSY is clear when the device is not busy.\r
-        Every command must be sent after device is not busy.\r
-\r
+/**\r
+  This function is used to poll for the BSY bit clear in the\r
+  Alternate Status Register. BSY is clear when the device is not busy.\r
+  Every command must be sent after device is not busy.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  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[in] IDE_BLK_IO_DEV  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
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ ready.\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          BSY bit clear within the time out.\r
+  @retval EFI_SUCCESS\r
+  BSY bit clear within the time out.\r
 \r
-        EFI_TIMEOUT\r
-          BSY bit not clear within the time out. \r
+  @retval EFI_TIMEOUT\r
+  BSY bit not clear within the time out.\r
 \r
+  @note\r
+  Read Alternate Status Register will not clear interrupt status.\r
 \r
-  Notes:\r
-        Read Alternate Status Register will not clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+WaitForBSYClear2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           TimeoutInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1311,42 +1144,34 @@ WaitForBSYClear2 (
 //\r
 // DRDYReady\r
 //\r
-EFI_STATUS\r
-DRDYReady (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           DelayInMilliSeconds\r
-  )\r
-/*++\r
-  Name:\r
-        DRDYReady\r
-\r
-\r
-  Purpose: \r
-        This function is used to poll for the DRDY bit set in the \r
-        Status Register. DRDY bit is set when the device is ready \r
-        to accept command. Most ATA commands must be sent after \r
-        DRDY set except the ATAPI Packet Command.\r
+/**\r
+  This function is used to poll for the DRDY bit set in the\r
+  Status Register. DRDY bit is set when the device is ready\r
+  to accept command. Most ATA commands must be sent after\r
+  DRDY set except the ATAPI Packet Command.\r
 \r
+  @param[in] IDE_BLK_IO_DEV  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
-  Parameters:\r
-        IDE_BLK_IO_DEV  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[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ ready.\r
+  @retval EFI_SUCCESS\r
+  DRDY bit set within the time out.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          DRDY bit set within the time out.\r
+  @retval EFI_TIMEOUT\r
+  DRDY bit not set within the time out.\r
 \r
-        EFI_TIMEOUT\r
-          DRDY bit not set within the time out. \r
+  @note\r
+  Read Status Register will clear interrupt status.\r
 \r
-\r
-  Notes:\r
-        Read Status Register will clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+DRDYReady (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1375,7 +1200,7 @@ DRDYReady (
       }\r
     }\r
 \r
-    gBS->Stall (15);\r
+    gBS->Stall (30);\r
 \r
     Delay--;\r
   } while (Delay);\r
@@ -1390,42 +1215,34 @@ DRDYReady (
 //\r
 // DRDYReady2\r
 //\r
-EFI_STATUS\r
-DRDYReady2 (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev,\r
-  IN  UINTN           DelayInMilliSeconds\r
-  )\r
-/*++\r
-  Name:\r
-        DRDYReady2\r
-\r
-\r
-  Purpose: \r
-        This function is used to poll for the DRDY bit set in the \r
-        Alternate Status Register. DRDY bit is set when the device is ready \r
-        to accept command. Most ATA commands must be sent after \r
-        DRDY set except the ATAPI Packet Command.\r
-\r
+/**\r
+  This function is used to poll for the DRDY bit set in the\r
+  Alternate Status Register. DRDY bit is set when the device is ready\r
+  to accept command. Most ATA commands must be sent after\r
+  DRDY set except the ATAPI Packet Command.\r
 \r
-  Parameters:\r
-        IDE_BLK_IO_DEV  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[in] IDE_BLK_IO_DEV  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
-        UINTN     IN    TimeoutInMilliSeconds\r
-          used to designate the timeout for the DRQ ready.\r
+  @param[in] UINTN     IN    TimeoutInMilliSeconds\r
+  used to designate the timeout for the DRQ ready.\r
 \r
-  Returns:  \r
-        EFI_SUCCESS\r
-          DRDY bit set within the time out.\r
+  @retval EFI_SUCCESS\r
+  DRDY bit set within the time out.\r
 \r
-        EFI_TIMEOUT\r
-          DRDY bit not set within the time out. \r
+  @retval EFI_TIMEOUT\r
+  DRDY bit not set within the time out.\r
 \r
+  @note\r
+  Read Alternate Status Register will clear interrupt status.\r
 \r
-  Notes:\r
-        Read Alternate Status Register will clear interrupt status.\r
---*/\r
+**/\r
+EFI_STATUS\r
+DRDYReady2 (\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  IN  UINTN           DelayInMilliSeconds\r
+  )\r
 // TODO: function comment is missing 'Routine Description:'\r
 // TODO: function comment is missing 'Arguments:'\r
 // TODO:    IdeDev - add argument and description to function comment\r
@@ -1469,52 +1286,34 @@ DRDYReady2 (
 //\r
 // SwapStringChars\r
 //\r
+/**\r
+  This function is a helper function used to change the char order in a\r
+  string. It is designed specially for the PrintAtaModuleName() function.\r
+  After the IDE device is detected, the IDE driver gets the device module\r
+  name by sending ATA command called ATA Identify Command or ATAPI\r
+  Identify Command to the specified IDE device. The module name returned\r
+  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\r
+  and so on. Thus the string can not be print directly before it is\r
+  preprocessed by this func to change the order of characters in\r
+  each word in the string.\r
+\r
+  @param[in] CHAR8 IN    *Destination\r
+  Indicates the destination string.\r
+\r
+  @param[in] CHAR8 IN    *Source\r
+  Indicates the source string.\r
+\r
+  @param[in] UINT8 IN    Size\r
+  the length of the string\r
+\r
+**/\r
 VOID\r
 SwapStringChars (\r
   IN CHAR8  *Destination,\r
   IN CHAR8  *Source,\r
   IN UINT32 Size\r
   )\r
-/*++\r
-  Name:\r
-        SwapStringChars\r
-\r
-\r
-  Purpose: \r
-        This function is a helper function used to change the char order in a \r
-        string. It is designed specially for the PrintAtaModuleName() function.\r
-        After the IDE device is detected, the IDE driver gets the device module\r
-        name by sending ATA command called ATA Identify Command or ATAPI \r
-        Identify Command to the specified IDE device. The module name returned \r
-        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 \r
-        and so on. Thus the string can not be print directly before it is \r
-        preprocessed by this func to change the order of characters in \r
-        each word in the string.\r
-\r
-\r
-  Parameters:\r
-        CHAR8 IN    *Destination\r
-          Indicates the destination string.\r
-\r
-        CHAR8 IN    *Source\r
-          Indicates the source string.\r
-\r
-        UINT8 IN    Size\r
-          the length of the string\r
-\r
-\r
-  Returns:  \r
-        none\r
-\r
-  Notes:\r
-\r
---*/\r
-// TODO: function comment is missing 'Routine Description:'\r
-// TODO: function comment is missing 'Arguments:'\r
-// TODO:    Destination - add argument and description to function comment\r
-// TODO:    Source - add argument and description to function comment\r
-// TODO:    Size - add argument and description to function comment\r
 {\r
   UINT32  Index;\r
   CHAR8   Temp;\r
@@ -1530,26 +1329,16 @@ SwapStringChars (
 //\r
 // ReleaseIdeResources\r
 //\r
+/**\r
+  Release resources of an IDE device before stopping it.\r
+\r
+  @param[in] *IdeBlkIoDevice  Standard IDE device private data structure\r
+\r
+**/\r
 VOID\r
 ReleaseIdeResources (\r
   IN  IDE_BLK_IO_DEV  *IdeBlkIoDevice\r
   )\r
-/*++\r
-Routing Description:\r
-\r
-  Release resources of an IDE device before stopping it.\r
-\r
-Arguments:\r
-\r
-  IdeBlkIoDevice  --  Standard IDE device private data structure\r
-\r
-\r
-Returns:\r
-\r
-    NONE\r
-    \r
----*/\r
-// TODO: function comment is missing 'Routine Description:'\r
 {\r
   if (IdeBlkIoDevice == NULL) {\r
     return ;\r
@@ -1558,7 +1347,7 @@ Returns:
   //\r
   // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
   //\r
-  \r
+\r
   if (IdeBlkIoDevice->SenseData != NULL) {\r
     gBS->FreePool (IdeBlkIoDevice->SenseData);\r
     IdeBlkIoDevice->SenseData = NULL;\r
@@ -1592,6 +1381,11 @@ Returns:
     gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
   }\r
 \r
+  if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
+    IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
+  }\r
+\r
   gBS->FreePool (IdeBlkIoDevice);\r
   IdeBlkIoDevice = NULL;\r
 \r
@@ -1601,26 +1395,20 @@ Returns:
 //\r
 // SetDeviceTransferMode\r
 //\r
+/**\r
+  Set the calculated Best transfer mode to a detected device\r
+\r
+  @param[in] *IdeDev       Standard IDE device private data structure\r
+  @param[in] *TransferMode The device transfer mode to be set\r
+\r
+  @return Set transfer mode Command execute status\r
+\r
+**/\r
 EFI_STATUS\r
 SetDeviceTransferMode (\r
   IN IDE_BLK_IO_DEV       *IdeDev,\r
   IN ATA_TRANSFER_MODE    *TransferMode\r
   )\r
-/*++\r
-Routing Description:\r
-\r
-  Set the calculated Best transfer mode to a detected device\r
-\r
-Arguments:\r
-\r
-  IdeDev       --  Standard IDE device private data structure\r
-  TransferMode --  The device transfer mode to be set\r
-\r
-Returns:\r
-\r
-    Set transfer mode Command execute status\r
-    \r
----*/\r
 // TODO: function comment is missing 'Routine Description:'\r
 {\r
   EFI_STATUS  Status;\r
@@ -1648,6 +1436,23 @@ Returns:
   return Status;\r
 }\r
 \r
+/**\r
+  Send ATA 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  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
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
 EFI_STATUS\r
 AtaNonDataCommandIn (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
@@ -1659,30 +1464,6 @@ AtaNonDataCommandIn (
   IN  UINT8           LbaMiddle,\r
   IN  UINT8           LbaHigh\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Send ATA command into device with NON_DATA protocol\r
-\r
-Arguments:\r
-\r
-  IdeDev      - Standard IDE device private data structure\r
-  AtaCommand  - The ATA command to be sent\r
-  Device      - The value in Device register\r
-  Feature     - The value in Feature register\r
-  SectorCount - The value in SectorCount register \r
-  LbaLow      - The value in LBA_LOW register\r
-  LbaMiddle   - The value in LBA_MIDDLE register\r
-  LbaHigh     - The value in LBA_HIGH register\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS      - Reading succeed\r
-  EFI_ABORTED      - Command failed\r
-  EFI_DEVICE_ERROR - Device status error\r
-\r
---*/\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       StatusRegister;\r
@@ -1726,8 +1507,14 @@ Returns:
 \r
   //\r
   // Wait for command completion\r
+  // For ATA_SMART_CMD, we may need more timeout to let device\r
+  // adjust internal states.\r
   //\r
-  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (AtaCommand == ATA_SMART_CMD) {\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
@@ -1743,6 +1530,21 @@ Returns:
   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_ABORTED Command failed\r
+  @retval  EFI_DEVICE_ERROR Device status error\r
+\r
+**/\r
 EFI_STATUS\r
 AtaNonDataCommandInExt (\r
   IN  IDE_BLK_IO_DEV  *IdeDev,\r
@@ -1752,28 +1554,6 @@ AtaNonDataCommandInExt (
   IN  UINT16          SectorCount,\r
   IN  EFI_LBA         LbaAddress\r
   )\r
-/*++\r
-\r
-Routine Description:\r
-\r
-  Send ATA Ext command into device with NON_DATA protocol\r
-\r
-Arguments:\r
-\r
-  IdeDev      - Standard IDE device private data structure\r
-  AtaCommand  - The ATA command to be sent\r
-  Device      - The value in Device register\r
-  Feature     - The value in Feature register\r
-  SectorCount - The value in SectorCount register \r
-  LbaAddress - The LBA address in 48-bit mode\r
-\r
-Returns:\r
-\r
-  EFI_SUCCESS      - Reading succeed\r
-  EFI_ABORTED      - Command failed\r
-  EFI_DEVICE_ERROR - Device status error\r
-\r
---*/\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       StatusRegister;\r
@@ -1872,26 +1652,20 @@ Returns:
 //\r
 // SetDriveParameters\r
 //\r
+/**\r
+  Set drive parameters for devices not support PACKETS command\r
+\r
+  @param[in] IdeDev       Standard IDE device private data structure\r
+  @param[in] DriveParameters The device parameters to be set into the disk\r
+\r
+  @return SetParameters Command execute status\r
+\r
+**/\r
 EFI_STATUS\r
 SetDriveParameters (\r
   IN IDE_BLK_IO_DEV       *IdeDev,\r
   IN ATA_DRIVE_PARMS      *DriveParameters\r
   )\r
-/*++\r
-Routine Description: \r
-\r
-  Set drive parameters for devices not support PACKETS command\r
-\r
-Arguments:\r
-\r
-  IdeDev       --  Standard IDE device private data structure\r
-  DriveParameters --  The device parameters to be set into the disk\r
-\r
-Returns:\r
-\r
-  SetParameters Command execute status\r
-    \r
---*/\r
 {\r
   EFI_STATUS  Status;\r
   UINT8       DeviceSelect;\r
@@ -1902,12 +1676,11 @@ Returns:
   //\r
   // Send Init drive parameters\r
   //\r
-  Status = AtaPioDataIn (\r
+  Status = AtaNonDataCommandIn (\r
             IdeDev,\r
-            NULL,\r
-            0,\r
             INIT_DRIVE_PARAM_CMD,\r
             (UINT8) (DeviceSelect + DriveParameters->Heads),\r
+            0,\r
             DriveParameters->Sector,\r
             0,\r
             0,\r
@@ -1917,48 +1690,135 @@ Returns:
   //\r
   // Send Set Multiple parameters\r
   //\r
-  Status = AtaPioDataIn (\r
+  Status = AtaNonDataCommandIn (\r
             IdeDev,\r
-            NULL,\r
-            0,\r
             SET_MULTIPLE_MODE_CMD,\r
             DeviceSelect,\r
+            0,\r
             DriveParameters->MultipleSector,\r
             0,\r
             0,\r
             0\r
             );\r
-\r
   return Status;\r
 }\r
 \r
+/**\r
+  TODO: Add function description\r
+\r
+  @param  IdeDev TODO: add argument description\r
+\r
+  @retval  EFI_SUCCESS TODO: Add description for return value\r
+\r
+**/\r
 EFI_STATUS\r
 EnableInterrupt (\r
   IN IDE_BLK_IO_DEV       *IdeDev\r
   )\r
-/*++\r
+{\r
+  UINT8 DeviceControl;\r
 \r
-Routine Description:\r
+  //\r
+  // Enable interrupt for DMA operation\r
+  //\r
+  DeviceControl = 0;\r
+  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
-  TODO: Add function description\r
+  return EFI_SUCCESS;\r
+}\r
 \r
-Arguments:\r
+/**\r
+  Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
 \r
-  IdeDev  - TODO: add argument description\r
+  @param[in]  Event   Pointer to this event\r
+  @param[in]  Context Event hanlder private data\r
 \r
-Returns:\r
+**/\r
+VOID\r
+EFIAPI\r
+ClearInterrupt (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINT64          IoPortForBmis;\r
+  UINT8           RegisterValue;\r
+  IDE_BLK_IO_DEV  *IdeDev;\r
 \r
-  EFI_SUCCESS - TODO: Add description for return value\r
+  //\r
+  // Get our context\r
+  //\r
+  IdeDev = (IDE_BLK_IO_DEV *) Context;\r
 \r
---*/\r
-{\r
-  UINT8 DeviceControl;\r
+  //\r
+  // Obtain IDE IO port registers' base addresses\r
+  //\r
+  Status = ReassignIdeResources (IdeDev);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
 \r
   //\r
-  // Enable interrupt for DMA operation\r
+  // Check whether interrupt is pending\r
   //\r
-  DeviceControl = 0;\r
-  IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
-  return EFI_SUCCESS;\r
+  //\r
+  // Reset IDE device to force it de-assert interrupt pin\r
+  // Note: this will reset all devices on this IDE channel\r
+  //\r
+  AtaSoftReset (IdeDev);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Get base address of IDE Bus Master Status Regsiter\r
+  //\r
+  if (IdePrimary == IdeDev->Channel) {\r
+    IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
+  } else {\r
+    if (IdeSecondary == IdeDev->Channel) {\r
+      IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
+    } else {\r
+      return;\r
+    }\r
+  }\r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  IdeDev->PciIo->Io.Read (\r
+                      IdeDev->PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      IoPortForBmis,\r
+                      1,\r
+                      &RegisterValue\r
+                      );\r
+\r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+\r
+  IdeDev->PciIo->Io.Write (\r
+                      IdeDev->PciIo,\r
+                      EfiPciIoWidthUint8,\r
+                      EFI_PCI_IO_PASS_THROUGH_BAR,\r
+                      IoPortForBmis,\r
+                      1,\r
+                      &RegisterValue\r
+                      );\r
+\r
+  //\r
+  // Select the other device on this channel to ensure this device to release the interrupt pin\r
+  //\r
+  if (IdeDev->Device == 0) {\r
+    RegisterValue = (1 << 4) | 0xe0;\r
+  } else {\r
+    RegisterValue = (0 << 4) | 0xe0;\r
+  }\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    RegisterValue\r
+    );\r
+\r
 }\r