]> git.proxmox.com Git - mirror_edk2.git/commitdiff
add native ide/ahci driver
authorerictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 29 Sep 2010 05:50:45 +0000 (05:50 +0000)
committererictian <erictian@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 29 Sep 2010 05:50:45 +0000 (05:50 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10901 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c [new file with mode: 0644]
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h [new file with mode: 0644]

diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.c
new file mode 100644 (file)
index 0000000..71d58f6
--- /dev/null
@@ -0,0 +1,2010 @@
+/** @file\r
+  The file for AHCI mode of ATA host controller.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+\r
+#include "AtaAtapiPassThru.h"\r
+\r
+/**\r
+  Read AHCI Operation register.\r
+\r
+  @param  PciIo        The PCI IO protocol instance.\r
+  @param  Offset       The operation register offset.\r
+\r
+  @return The register content read.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+AhciReadReg (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  UINT32              Offset\r
+  )\r
+{\r
+  UINT32                  Data;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  \r
+  Data = 0;\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               EFI_AHCI_BAR_INDEX,\r
+               (UINT64) Offset,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  return Data;\r
+}\r
+\r
+/**\r
+  Write AHCI Operation register.\r
+\r
+  @param  PciIo        The PCI IO protocol instance.\r
+  @param  Offset       The operation register offset.\r
+  @param  Data         The data used to write down.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciWriteReg (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN UINT32               Offset,\r
+  IN UINT32               Data\r
+  )\r
+{\r
+  ASSERT (PciIo != NULL);\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               EFI_AHCI_BAR_INDEX,\r
+               (UINT64) Offset,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+  Do AND operation with the value of AHCI Operation register.\r
+\r
+  @param  PciIo        The PCI IO protocol instance.\r
+  @param  Offset       The operation register offset.\r
+  @param  AndData      The data used to do AND operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciAndReg (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN UINT32               Offset,\r
+  IN UINT32               AndData\r
+  )\r
+{\r
+  UINT32 Data;\r
+  \r
+  ASSERT (PciIo != NULL);\r
+\r
+  Data  = AhciReadReg (PciIo, Offset);\r
+\r
+  Data &= AndData;\r
+\r
+  AhciWriteReg (PciIo, Offset, Data);\r
+}\r
+\r
+/**\r
+  Do OR operation with the value of AHCI Operation register.\r
+\r
+  @param  PciIo        The PCI IO protocol instance.\r
+  @param  Offset       The operation register offset.\r
+  @param  OrData       The data used to do OR operation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciOrReg (\r
+  IN EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN UINT32               Offset,\r
+  IN UINT32               OrData\r
+  )\r
+{\r
+  UINT32 Data;\r
+\r
+  ASSERT (PciIo != NULL);\r
+\r
+  Data  = AhciReadReg (PciIo, Offset);\r
+\r
+  Data |= OrData;\r
+\r
+  AhciWriteReg (PciIo, Offset, Data);\r
+}\r
+\r
+/**\r
+  Wait for memory set to the test value.\r
+    \r
+  @param  PciIo      The PCI IO protocol instance.\r
+  @param  Offset         The memory address to test.\r
+  @param  MaskValue      The mask value of memory.\r
+  @param  TestValue      The test value of memory.\r
+  @param  Timeout        The time out value for wait memory set.\r
+\r
+  @retval EFI_DEVICE_ERROR  The memory is not set.\r
+  @retval EFI_TIMEOUT       The memory setting is time out.\r
+  @retval EFI_SUCCESS       The memory is correct set.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciWaitMemSet (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT32                    MaskValue,\r
+  IN  UINT32                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     Value;  \r
+  UINT32     Delay;\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+  do {\r
+    Value = AhciReadReg (PciIo, Offset) & MaskValue;\r
+\r
+    if (Value == TestValue) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
+/**\r
+  Check if the device is still on port. It also checks if the AHCI controller \r
+  supports the address and data count will be transfered.\r
+\r
+  @param  PciIo      The PCI IO protocol instance.\r
+  @param  Port           The number of port.\r
+\r
+  @retval EFI_SUCCESS      The device is attached to port and the transfer data is \r
+                           supported by AHCI controller.\r
+  @retval EFI_UNSUPPORTED  The transfer address and count is not supported by AHCI\r
+                           controller.\r
+  @retval EFI_NOT_READY    The physical communication between AHCI controller and device\r
+                           is not ready.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCheckDeviceStatus (\r
+  IN  EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN  UINT8                  Port\r
+  )\r
+{\r
+  UINT32      Data; \r
+  UINT32      Offset;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
+\r
+  Data   = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+\r
+  if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
+    return EFI_SUCCESS;      \r
+  }\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+\r
+  Clear the port interrupt and error status. It will also clear\r
+  HBA interrupt status.\r
+    \r
+  @param      PciIo          The PCI IO protocol instance.\r
+  @param      Port           The number of port.\r
+     \r
+**/ \r
+VOID\r
+EFIAPI\r
+AhciClearPortStatus (\r
+  IN  EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN  UINT8                  Port\r
+  )  \r
+{\r
+  UINT32 Offset;\r
+\r
+  //\r
+  // Clear any error status\r
+  //  \r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+  AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
+\r
+  //\r
+  // Clear any port interrupt status\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+  AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
+\r
+  //\r
+  // Clear any HBA interrupt status\r
+  //\r
+  AhciWriteReg (PciIo, EFI_AHCI_IS_OFFSET, AhciReadReg (PciIo, EFI_AHCI_IS_OFFSET));\r
+}\r
+\r
+/**\r
+  Enable the FIS running for giving port.\r
+    \r
+  @param      PciIo          The PCI IO protocol instance.\r
+  @param      Port           The number of port.\r
+  @param      Timeout        The timeout value of enabling FIS.\r
+\r
+  @retval EFI_DEVICE_ERROR   The FIS enable setting fails.\r
+  @retval EFI_TIMEOUT        The FIS enable setting is time out.\r
+  @retval EFI_SUCCESS        The FIS enable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciEnableFisReceive (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )     \r
+{ \r
+  UINT32 Offset;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_FRE);\r
+\r
+  return AhciWaitMemSet (\r
+           PciIo, \r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           Timeout\r
+           );\r
+}\r
+\r
+/**\r
+  Disable the FIS running for giving port.\r
+\r
+  @param      PciIo          The PCI IO protocol instance.\r
+  @param      Port           The number of port.\r
+  @param      Timeout        The timeout value of disabling FIS.\r
+\r
+  @retval EFI_DEVICE_ERROR   The FIS disable setting fails.\r
+  @retval EFI_TIMEOUT        The FIS disable setting is time out.\r
+  @retval EFI_UNSUPPORTED    The port is in running state.\r
+  @retval EFI_SUCCESS        The FIS disable successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDisableFisReceive (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )  \r
+{\r
+  UINT32 Offset;\r
+  UINT32 Data;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  Data   = AhciReadReg (PciIo, Offset);\r
+\r
+  //\r
+  // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.\r
+  //\r
+  if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  \r
+  //\r
+  // Check if the Fis receive DMA engine for the port is running.\r
+  //\r
+  if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));\r
+\r
+  return AhciWaitMemSet (\r
+           PciIo, \r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_FR,\r
+           0,\r
+           Timeout\r
+           ); \r
+}\r
+\r
+\r
+\r
+/**\r
+  Build the command list, command table and prepare the fis receiver.\r
+    \r
+  @param    PciIo         The PCI IO protocol instance.\r
+  @param    AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param    Port          The number of port.\r
+  @param    PortMultiplier    The timeout value of stop.\r
+  @param    CommandFis      The control fis will be used for the transfer.\r
+  @param    CommandList     The command list will be used for the transfer.\r
+  @param    AtapiCommand      The atapi command will be used for the transfer.\r
+  @param    AtapiCommandLength  The length of the atapi command.\r
+  @param    CommandSlotNumber   The command slot will be used for the transfer.\r
+  @param    DataPhysicalAddr      The pointer to the data buffer pci bus master address.\r
+  @param    DataLength            The data count to be transferred.\r
+\r
+**/  \r
+VOID\r
+EFIAPI\r
+AhciBuildCommand (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_COMMAND_FIS       *CommandFis,\r
+  IN     EFI_AHCI_COMMAND_LIST      *CommandList,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     UINT8                      CommandSlotNumber,\r
+  IN OUT VOID                       *DataPhysicalAddr,\r
+  IN     UINT64                     DataLength\r
+  )   \r
+{\r
+  UINT64     BaseAddr; \r
+  UINT64     PrdtNumber;\r
+  UINT64     PrdtIndex;\r
+  UINTN      RemainedData;\r
+  UINTN      MemAddr;\r
+  DATA_64    Data64;\r
+  UINT32     Offset;\r
+\r
+  //\r
+  // Filling the PRDT\r
+  //  \r
+  PrdtNumber = (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1) / EFI_AHCI_MAX_DATA_PER_PRDT;\r
+\r
+  //\r
+  // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB data block.\r
+  // It also limits that the maximum amount of the PRDT entry in the command table\r
+  // is 65535.\r
+  //\r
+  ASSERT (PrdtNumber <= 65535);\r
+\r
+  Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
+\r
+  BaseAddr = Data64.Uint64;\r
+  \r
+  ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));  \r
+    \r
+  ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));\r
+\r
+  CommandFis->AhciCFisPmNum = PortMultiplier;\r
+  \r
+  CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  if (AtapiCommand != NULL) {\r
+    CopyMem (\r
+      &AhciRegisters->AhciCommandTable->AtapiCmd,\r
+      AtapiCommand,\r
+      AtapiCommandLength\r
+      );\r
+\r
+    CommandList->AhciCmdA = 1;\r
+    CommandList->AhciCmdP = 1;\r
+    CommandList->AhciCmdC = (DataLength == 0) ? 1 : 0;\r
+\r
+    AhciOrReg (PciIo, Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+  } else {\r
+    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));\r
+  }\r
+  \r
+  RemainedData = DataLength;\r
+  MemAddr      = (UINTN) DataPhysicalAddr;\r
+  CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;\r
+  \r
+  for (PrdtIndex = 0; PrdtIndex < PrdtNumber; PrdtIndex++) {\r
+    if (RemainedData < EFI_AHCI_MAX_DATA_PER_PRDT) {     \r
+      AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = (UINT32)RemainedData - 1;\r
+    } else {\r
+      AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbc = EFI_AHCI_MAX_DATA_PER_PRDT - 1;\r
+    }\r
+\r
+    Data64.Uint64 = (UINT64)MemAddr;\r
+    AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDba  = Data64.Uint32.Lower32;\r
+    AhciRegisters->AhciCommandTable->PrdtTable[PrdtIndex].AhciPrdtDbau = Data64.Uint32.Upper32;\r
+    RemainedData -= EFI_AHCI_MAX_DATA_PER_PRDT;    \r
+    MemAddr      += EFI_AHCI_MAX_DATA_PER_PRDT;\r
+  }\r
+\r
+  //\r
+  // Set the last PRDT to Interrupt On Complete\r
+  //\r
+  if (PrdtNumber > 0) {\r
+    AhciRegisters->AhciCommandTable->PrdtTable[PrdtNumber - 1].AhciPrdtIoc = 1;\r
+  }\r
+\r
+  CopyMem (\r
+    (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),\r
+    CommandList,\r
+    sizeof (EFI_AHCI_COMMAND_LIST)\r
+    );  \r
+\r
+  Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTablePciAddr;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba  = Data64.Uint32.Lower32;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;\r
+  AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp   = PortMultiplier;\r
+\r
+}\r
+\r
+/**\r
+  Buid a command FIS.\r
+    \r
+  @param  CmdFis          A pointer to the EFI_AHCI_COMMAND_FIS data structure.\r
+  @param  AtaCommandBlock   A pointer to the AhciBuildCommandFis data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AhciBuildCommandFis (\r
+  IN OUT EFI_AHCI_COMMAND_FIS    *CmdFis,\r
+  IN     EFI_ATA_COMMAND_BLOCK   *AtaCommandBlock\r
+  )\r
+{\r
+  ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));\r
+\r
+  CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;\r
+  //\r
+  // Indicator it's a command\r
+  //\r
+  CmdFis->AhciCFisCmdInd      = 0x1; \r
+  CmdFis->AhciCFisCmd         = AtaCommandBlock->AtaCommand;\r
+\r
+  CmdFis->AhciCFisFeature     = AtaCommandBlock->AtaFeatures;\r
+  CmdFis->AhciCFisFeatureExp  = AtaCommandBlock->AtaFeaturesExp;\r
+\r
+  CmdFis->AhciCFisSecNum      = AtaCommandBlock->AtaSectorNumber;\r
+  CmdFis->AhciCFisSecNumExp   = AtaCommandBlock->AtaSectorNumberExp;\r
+\r
+  CmdFis->AhciCFisClyLow      = AtaCommandBlock->AtaCylinderLow;\r
+  CmdFis->AhciCFisClyLowExp   = AtaCommandBlock->AtaCylinderLowExp;\r
+\r
+  CmdFis->AhciCFisClyHigh     = AtaCommandBlock->AtaCylinderHigh;\r
+  CmdFis->AhciCFisClyHighExp  = AtaCommandBlock->AtaCylinderHighExp;\r
+\r
+  CmdFis->AhciCFisSecCount    = AtaCommandBlock->AtaSectorCount;\r
+  CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;\r
+\r
+  CmdFis->AhciCFisDevHead     = AtaCommandBlock->AtaDeviceHead | 0xE0;\r
+}\r
+\r
+/**\r
+  Start a PIO data transfer on specific port.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier    The timeout value of stop.\r
+  @param  AtapiCommand      The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength  The length of the atapi command.\r
+  @param  Read                The transfer direction.\r
+  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
+  @param  MemoryAddr          The pointer to the data buffer.\r
+  @param  DataCount           The data count to be transferred.\r
+  @param  Timeout             The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The PIO data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The PIO data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+AhciPioTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,  \r
+  IN     BOOLEAN                    Read,  \r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINT32                     DataCount,\r
+  IN     UINT64                     Timeout \r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         FisBaseAddr;\r
+  UINT32                        Offset;\r
+  UINT32                        Value;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  VOID                          *Map;\r
+  UINTN                         MapLength;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
+  UINT32                        Delay;\r
+  EFI_AHCI_COMMAND_FIS          CFis;\r
+  EFI_AHCI_COMMAND_LIST         CmdList;\r
+\r
+  if (Read) {\r
+    Flag = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    Flag = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  //\r
+  // construct command list and command table with pci bus address\r
+  //\r
+  MapLength = DataCount;\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    Flag,\r
+                    MemoryAddr,\r
+                    &MapLength,\r
+                    &PhyAddr,\r
+                    &Map\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  //\r
+  // Package read needed\r
+  //\r
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+  CmdList.AhciCmdW   = Read ? 0 : 1;\r
+\r
+  AhciBuildCommand (\r
+    PciIo,\r
+    AhciRegisters,\r
+    Port,\r
+    PortMultiplier,\r
+    &CFis,\r
+    &CmdList,\r
+    AtapiCommand,\r
+    AtapiCommandLength,\r
+    0,\r
+    (VOID *)(UINTN)PhyAddr,\r
+    DataCount\r
+    );    \r
+  \r
+  Status = AhciStartCommand (\r
+             PciIo, \r
+             Port, \r
+             0,\r
+             Timeout\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+  \r
+  //\r
+  // Checking the status and wait the driver sending data\r
+  //\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+  //\r
+  // Wait device sends the PIO setup fis before data transfer\r
+  //\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET);\r
+\r
+    if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_PIO_SETUP) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay(100);\r
+\r
+    Delay--;    \r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    Status = EFI_TIMEOUT;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Wait for command compelte\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             0xFFFFFFFF,\r
+             0,\r
+             Timeout\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;   \r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,            \r
+             EFI_AHCI_PORT_IS_PSS,\r
+             EFI_AHCI_PORT_IS_PSS,\r
+             Timeout\r
+             );  \r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;  \r
+  }\r
+\r
+Exit: \r
+  AhciStopCommand (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+  \r
+  AhciDisableFisReceive (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  PciIo->Unmap (\r
+    PciIo,\r
+    Map\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start a DMA data transfer on specific port\r
+\r
+  @param  PciIo         The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port          The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtapiCommand        The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength    The length of the atapi command.\r
+  @param  Read                  The transfer direction.\r
+  @param  AtaCommandBlock       The EFI_ATA_COMMAND_BLOCK data.\r
+  @param  AtaStatusBlock        The EFI_ATA_STATUS_BLOCK data.\r
+  @param  MemoryAddr            The pointer to the data buffer.\r
+  @param  DataCount             The data count to be transferred.\r
+  @param  Timeout               The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR  The DMA data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT     The operation is time out.\r
+  @retval EFI_UNSUPPORTED   The device is not ready for transfer.\r
+  @retval EFI_SUCCESS     The DMA data transfer executes successfully.\r
+   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDmaTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     BOOLEAN                    Read,  \r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINTN                      DataCount,\r
+  IN     UINT64                     Timeout\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINT32                        Offset;\r
+  EFI_PHYSICAL_ADDRESS          PhyAddr;\r
+  VOID                          *Map;\r
+  UINTN                         MapLength;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
+  EFI_AHCI_COMMAND_FIS          CFis;\r
+  EFI_AHCI_COMMAND_LIST         CmdList;\r
+\r
+  if (Read) {\r
+    Flag = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    Flag = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  //\r
+  // construct command list and command table with pci bus address\r
+  //\r
+  MapLength = DataCount;\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    Flag,\r
+                    MemoryAddr,\r
+                    &MapLength,\r
+                    &PhyAddr,\r
+                    &Map\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (DataCount != MapLength)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Package read needed\r
+  //\r
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+  CmdList.AhciCmdW   = Read ? 0 : 1;\r
+\r
+  AhciBuildCommand (\r
+    PciIo,\r
+    AhciRegisters,\r
+    Port,\r
+    PortMultiplier,\r
+    &CFis,\r
+    &CmdList,\r
+    AtapiCommand,\r
+    AtapiCommandLength,\r
+    0,\r
+    (VOID *)(UINTN)PhyAddr,\r
+    DataCount\r
+    ); \r
+  \r
+  Status = AhciStartCommand (\r
+             PciIo, \r
+             Port, \r
+             0,\r
+             Timeout\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+  \r
+  //\r
+  // Wait device PRD processed\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             EFI_AHCI_PORT_IS_DPS,\r
+             EFI_AHCI_PORT_IS_DPS,\r
+             Timeout\r
+             ); \r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Wait for command compelte\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             0xFFFFFFFF,\r
+             0,\r
+             Timeout\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             EFI_AHCI_PORT_IS_DHRS,\r
+             EFI_AHCI_PORT_IS_DHRS,\r
+             Timeout\r
+             );  \r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+Exit: \r
+  AhciStopCommand (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  AhciDisableFisReceive (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  PciIo->Unmap (\r
+           PciIo,\r
+           Map\r
+           );  \r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start a non data transfer on specific port.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtapiCommand      The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength    The length of the atapi command.\r
+  @param    AtaCommandBlock       The EFI_ATA_COMMAND_BLOCK data.\r
+  @param    AtaStatusBlock        The EFI_ATA_STATUS_BLOCK data.\r
+  @param  Timeout               The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The non data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The non data transfer executes successfully.\r
+\r
+**/ \r
+EFI_STATUS\r
+EFIAPI\r
+AhciNonDataTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN     EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN     UINT8                         Port,\r
+  IN     UINT8                         PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND        *AtapiCommand OPTIONAL,\r
+  IN     UINT8                         AtapiCommandLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
+  IN     UINT64                        Timeout\r
+  ) \r
+{\r
+  EFI_STATUS                   Status;  \r
+  UINTN                        FisBaseAddr;\r
+  UINT32                       Offset;\r
+  UINT32                       Value;\r
+  UINT32                       Delay;\r
+  \r
+  EFI_AHCI_COMMAND_FIS         CFis;\r
+  EFI_AHCI_COMMAND_LIST        CmdList;\r
+\r
+  //\r
+  // Package read needed\r
+  //\r
+  AhciBuildCommandFis (&CFis, AtaCommandBlock);\r
+\r
+  ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));\r
+\r
+  CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;\r
+\r
+  AhciBuildCommand (\r
+    PciIo,\r
+    AhciRegisters,\r
+    Port,\r
+    PortMultiplier,\r
+    &CFis,\r
+    &CmdList,\r
+    AtapiCommand,\r
+    AtapiCommandLength,\r
+    0,\r
+    NULL,\r
+    0\r
+    ); \r
+  \r
+  Status = AhciStartCommand (\r
+             PciIo, \r
+             Port, \r
+             0,\r
+             Timeout\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+  \r
+  //\r
+  // Wait device sends the Response Fis\r
+  //\r
+  FisBaseAddr = (UINTN)AhciRegisters->AhciRFis + Port * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+  //\r
+  // Wait device sends the PIO setup fis before data transfer\r
+  //\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    Value = *(UINT32 *) (FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET);\r
+\r
+    if ((Value & EFI_AHCI_FIS_TYPE_MASK) == EFI_AHCI_FIS_REGISTER_D2H) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay(100);\r
+\r
+    Delay --;    \r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    Status = EFI_TIMEOUT;\r
+    goto Exit;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             0xFFFFFFFF,\r
+             0,\r
+             Timeout\r
+             );  \r
+  \r
+Exit:  \r
+  AhciStopCommand (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  AhciDisableFisReceive (\r
+    PciIo, \r
+    Port,\r
+    Timeout\r
+    );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stop command running for giving port\r
+    \r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Port               The number of port.\r
+  @param  Timeout            The timeout value of stop.\r
+   \r
+  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32 Offset;\r
+  UINT32 Data;\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  Data   = AhciReadReg (PciIo, Offset);\r
+\r
+  if ((Data & (EFI_AHCI_PORT_CMD_ST |  EFI_AHCI_PORT_CMD_CR)) == 0) {\r
+    return EFI_SUCCESS;    \r
+  }\r
+\r
+  if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {\r
+    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));\r
+  }\r
+\r
+  return AhciWaitMemSet (\r
+           PciIo, \r
+           Offset,\r
+           EFI_AHCI_PORT_CMD_CR,\r
+           0,\r
+           Timeout\r
+           ); \r
+}\r
+\r
+/**\r
+  Start command for give slot on specific port.\r
+    \r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Port               The number of port.\r
+  @param  CommandSlot        The number of CommandSlot.\r
+  @param  Timeout            The timeout value of start.\r
+   \r
+  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT8                     CommandSlot,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32     CmdSlotBit;\r
+  EFI_STATUS Status;\r
+  UINT32     PortStatus;\r
+  UINT32     StartCmd;\r
+  UINT32     PortTfd;\r
+  UINT32     Offset;\r
+  UINT32     Capability;\r
+\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+  CmdSlotBit = (UINT32) (1 << CommandSlot);\r
+\r
+  AhciClearPortStatus (\r
+    PciIo,\r
+    Port\r
+    );\r
+\r
+  Status = AhciEnableFisReceive (\r
+             PciIo, \r
+             Port,\r
+             Timeout\r
+             );\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Setting the command\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;\r
+  AhciAndReg (PciIo, Offset, 0);\r
+  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;\r
+  AhciAndReg (PciIo, Offset, 0);\r
+  AhciOrReg (PciIo, Offset, CmdSlotBit);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  PortStatus = AhciReadReg (PciIo, Offset);\r
+  \r
+  StartCmd = 0;\r
+  if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {\r
+    StartCmd = AhciReadReg (PciIo, Offset);\r
+    StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;\r
+    StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;\r
+  PortTfd = AhciReadReg (PciIo, Offset);\r
+\r
+  if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {\r
+    if ((Capability & BIT24) != 0) {\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+      AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_COL);\r
+\r
+      AhciWaitMemSet (\r
+        PciIo, \r
+        Offset,\r
+        EFI_AHCI_PORT_CMD_COL,\r
+        0,\r
+        Timeout\r
+        ); \r
+    }\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Do AHCI port reset.\r
+\r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Port               The number of port.\r
+  @param  Timeout            The timeout value of reset.\r
+   \r
+  @retval EFI_DEVICE_ERROR   The port reset unsuccessfully\r
+  @retval EFI_TIMEOUT        The reset operation is time out.\r
+  @retval EFI_SUCCESS        The port reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPortReset (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINT32          Offset;  \r
+  \r
+  AhciClearPortStatus (PciIo, Port);\r
+\r
+  AhciStopCommand (PciIo, Port, Timeout);\r
+\r
+  AhciDisableFisReceive (PciIo, Port, Timeout);\r
+\r
+  AhciEnableFisReceive (PciIo, Port, Timeout);\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+\r
+  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_DET_INIT);\r
+\r
+  //\r
+  // wait 5 milliseceond before de-assert DET  \r
+  //\r
+  MicroSecondDelay (5000);\r
+\r
+  AhciAndReg (PciIo, Offset, (UINT32)EFI_AHCI_PORT_SCTL_MASK);\r
+\r
+  //\r
+  // wait 5 milliseceond before de-assert DET  \r
+  //\r
+  MicroSecondDelay (5000);\r
+\r
+  //\r
+  // Wait for communication to be re-established\r
+  //\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
+  Status = AhciWaitMemSet (\r
+             PciIo,\r
+             Offset,\r
+             EFI_AHCI_PORT_SSTS_DET_MASK,\r
+             EFI_AHCI_PORT_SSTS_DET_PCE,\r
+             Timeout\r
+             ); \r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+  AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_ERR_CLEAR);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Do AHCI HBA reset.\r
+    \r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Timeout            The timeout value of reset.\r
\r
+   \r
+  @retval EFI_DEVICE_ERROR   AHCI controller is failed to complete hardware reset.\r
+  @retval EFI_TIMEOUT        The reset operation is time out.\r
+  @retval EFI_SUCCESS        AHCI controller is reset successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciReset (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT64                    Timeout\r
+  )    \r
+{\r
+  EFI_STATUS             Status;\r
+  UINT32                 Delay;\r
+  UINT32                 Value;\r
+\r
+  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+\r
+  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);\r
+\r
+  Status  = EFI_TIMEOUT;\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+  do {\r
+    Value = AhciReadReg(PciIo, EFI_AHCI_GHC_OFFSET);\r
+\r
+    if ((Value & EFI_AHCI_GHC_RESET) == 0) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay(100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send Buffer cmd to specific device.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param    Buffer                The data buffer to store IDENTIFY PACKET data.\r
+\r
+  @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for executing.\r
+  @retval EFI_SUCCESS         The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentify (\r
+  IN EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN EFI_AHCI_REGISTERS       *AhciRegisters,\r
+  IN UINT8                    Port,\r
+  IN UINT8                    PortMultiplier,\r
+  IN OUT EFI_IDENTIFY_DATA    *Buffer  \r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
+\r
+  if (PciIo == NULL || AhciRegisters == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  \r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DRIVE;\r
+  AtaCommandBlock.AtaSectorCount = 1;\r
+\r
+  Status = AhciPioTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             Port,\r
+             PortMultiplier,\r
+             NULL,\r
+             0,\r
+             TRUE,\r
+             &AtaCommandBlock,\r
+             &AtaStatusBlock,\r
+             Buffer,\r
+             sizeof (EFI_IDENTIFY_DATA),\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send Buffer cmd to specific device.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param    Buffer                The data buffer to store IDENTIFY PACKET data.\r
+\r
+  @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for executing.\r
+  @retval EFI_SUCCESS         The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciIdentifyPacket (\r
+  IN EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN EFI_AHCI_REGISTERS       *AhciRegisters,\r
+  IN UINT8                    Port,\r
+  IN UINT8                    PortMultiplier,\r
+  IN OUT EFI_IDENTIFY_DATA    *Buffer  \r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
+\r
+  if (PciIo == NULL || AhciRegisters == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_IDENTIFY_DEVICE;\r
+  AtaCommandBlock.AtaSectorCount = 1;\r
+\r
+  Status = AhciPioTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             Port,\r
+             PortMultiplier,\r
+             NULL,\r
+             0,\r
+             TRUE,\r
+             &AtaCommandBlock,\r
+             &AtaStatusBlock,\r
+             Buffer,\r
+             sizeof (EFI_IDENTIFY_DATA),\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send SET FEATURE cmd on specific device.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param    Feature               The data to send Feature register.\r
+  @param  FeatureSpecificData   The specific data for SET FEATURE cmd.\r
+\r
+  @retval EFI_DEVICE_ERROR    The cmd abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for executing.\r
+  @retval EFI_SUCCESS         The cmd executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDeviceSetFeature (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN EFI_AHCI_REGISTERS     *AhciRegisters,\r
+  IN UINT8                  Port,\r
+  IN UINT8                  PortMultiplier,\r
+  IN UINT16                 Feature,\r
+  IN UINT32                 FeatureSpecificData\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_ATA_COMMAND_BLOCK    AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK     AtaStatusBlock;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  \r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_SET_FEATURES;\r
+  AtaCommandBlock.AtaFeatures     = (UINT8) Feature;\r
+  AtaCommandBlock.AtaFeaturesExp  = (UINT8) (Feature >> 8);\r
+  AtaCommandBlock.AtaSectorCount  = (UINT8) FeatureSpecificData;\r
+  AtaCommandBlock.AtaSectorNumber = (UINT8) (FeatureSpecificData >> 8);\r
+  AtaCommandBlock.AtaCylinderLow  = (UINT8) (FeatureSpecificData >> 16);\r
+  AtaCommandBlock.AtaCylinderHigh = (UINT8) (FeatureSpecificData >> 24);\r
+\r
+  Status = AhciNonDataTransfer (\r
+             PciIo,\r
+             AhciRegisters,\r
+             (UINT8)Port,\r
+             (UINT8)PortMultiplier,\r
+             NULL,\r
+             0,\r
+             &AtaCommandBlock,\r
+             &AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the Packet Command \r
+  with PIO Protocol.\r
+\r
+  @param PciIo              The PCI IO protocol instance.\r
+  @param AhciRegisters      The pointer to the EFI_AHCI_REGISTERS.\r
+  @param Port               The number of port.     \r
+  @param PortMultiplier     The number of port multiplier.\r
+  @param Packet             A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
+\r
+  @retval EFI_SUCCESS       send out the ATAPI packet command successfully\r
+                            and device sends data successfully.\r
+  @retval EFI_DEVICE_ERROR  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPacketCommandExecute (\r
+  IN  EFI_PCI_IO_PROTOCOL                           *PciIo,\r
+  IN  EFI_AHCI_REGISTERS                            *AhciRegisters,\r
+  IN  UINT8                                         Port,\r
+  IN  UINT8                                         PortMultiplier,\r
+  IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  VOID                         *Buffer;\r
+  UINT32                       Length;\r
+  EFI_ATA_COMMAND_BLOCK        AtaCommandBlock;\r
+  EFI_ATA_STATUS_BLOCK         AtaStatusBlock;\r
+  BOOLEAN                      Read;\r
+  UINT8                        Retry;\r
+\r
+  if (Packet == NULL || Packet->Cdb == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  ZeroMem (&AtaStatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_PACKET;\r
+  //\r
+  // No OVL; No DMA\r
+  //\r
+  AtaCommandBlock.AtaFeatures     = 0x00;\r
+  //\r
+  // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
+  // determine how many data should be transferred.\r
+  //\r
+  AtaCommandBlock.AtaCylinderLow  = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
+  AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
+\r
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+    Buffer = Packet->InDataBuffer;\r
+    Length = Packet->InTransferLength;\r
+    Read = TRUE;\r
+  } else {\r
+    Buffer = Packet->OutDataBuffer;\r
+    Length = Packet->OutTransferLength;\r
+    Read = FALSE;\r
+  }\r
+\r
+  if (Length == 0) {    \r
+    Status = AhciNonDataTransfer (\r
+               PciIo,\r
+               AhciRegisters,\r
+               Port,\r
+               PortMultiplier,\r
+               Packet->Cdb,\r
+               Packet->CdbLength,\r
+               &AtaCommandBlock,\r
+               &AtaStatusBlock,\r
+               Packet->Timeout\r
+               );\r
+  } else {\r
+    //\r
+    // READ_CAPACITY cmd may execute failure. Retry 5 times\r
+    //\r
+    if (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_READ_CAPACITY) {\r
+      Retry = 5;\r
+    } else {\r
+      Retry = 1;\r
+    }\r
+    do {\r
+      Status = AhciPioTransfer (\r
+                 PciIo,\r
+                 AhciRegisters,\r
+                 Port,\r
+                 PortMultiplier,\r
+                 Packet->Cdb,\r
+                 Packet->CdbLength,\r
+                 Read,\r
+                 &AtaCommandBlock,\r
+                 &AtaStatusBlock,\r
+                 Buffer,\r
+                 Length,\r
+                 Packet->Timeout\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      Retry--;\r
+    } while (Retry != 0);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocate transfer-related data struct which is used at AHCI mode.\r
+  \r
+  @param  PciIo                 The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciCreateTransferDescriptor (\r
+  IN     EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN OUT EFI_AHCI_REGISTERS     *AhciRegisters\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 Bytes;\r
+  VOID                  *Buffer;\r
+\r
+  UINT32                Capability;\r
+  UINT8                 MaxPortNumber;\r
+  UINT8                 MaxCommandSlotNumber;\r
+  BOOLEAN               Support64Bit;\r
+  UINT64                MaxReceiveFisSize;\r
+  UINT64                MaxCommandListSize;\r
+  UINT64                MaxCommandTableSize;\r
+\r
+  Buffer = NULL;\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
+  //\r
+  // Get the number of command slots per port supported by this HBA.\r
+  //\r
+  MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
+  Support64Bit         = ((Capability & BIT31) != 0) ? TRUE : FALSE;\r
+\r
+  MaxReceiveFisSize    = MaxPortNumber * sizeof (EFI_AHCI_RECEIVED_FIS);\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+                    &Buffer,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ZeroMem (Buffer, MaxReceiveFisSize);\r
+\r
+  AhciRegisters->AhciRFis          = Buffer;\r
+  AhciRegisters->MaxReceiveFisSize = MaxReceiveFisSize;\r
+  Bytes  = MaxReceiveFisSize;\r
+\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Buffer,\r
+                    &Bytes,\r
+                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciRFisPciAddr,\r
+                    &AhciRegisters->MapRFis\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != MaxReceiveFisSize)) {\r
+    //\r
+    // Map error or unable to map the whole RFis buffer into a contiguous region. \r
+    //\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error6;\r
+  }\r
+\r
+  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciRFisPciAddr > 0x100000000UL)) {\r
+    //\r
+    // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
+    //\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Error5;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for command list\r
+  // Note that the implemenation is a single task model which only use a command list for all ports.\r
+  //\r
+  Buffer = NULL;\r
+  MaxCommandListSize = MaxCommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST);\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+                    &Buffer,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Free mapped resource. \r
+    //\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error5;\r
+  }\r
+\r
+  ZeroMem (Buffer, MaxCommandListSize);\r
+\r
+  AhciRegisters->AhciCmdList        = Buffer;\r
+  AhciRegisters->MaxCommandListSize = MaxCommandListSize;\r
+  Bytes  = MaxCommandListSize;\r
+\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Buffer,\r
+                    &Bytes,\r
+                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCmdListPciAddr,\r
+                    &AhciRegisters->MapCmdList\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != MaxCommandListSize)) {\r
+    //\r
+    // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
+    //\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error4;\r
+  }\r
+\r
+  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCmdListPciAddr > 0x100000000UL)) {\r
+    //\r
+    // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
+    //\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Error3;\r
+  }\r
+\r
+  //\r
+  // Allocate memory for command table\r
+  // According to AHCI 1.3 spec, a PRD table can contain maximum 65535 entries.\r
+  //\r
+  Buffer = NULL;\r
+  MaxCommandTableSize = sizeof (EFI_AHCI_COMMAND_TABLE);\r
+\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+                    &Buffer,\r
+                    0\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Free mapped resource. \r
+    //\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error3;\r
+  }\r
+\r
+  ZeroMem (Buffer, MaxCommandTableSize);\r
+\r
+  AhciRegisters->AhciCommandTable    = Buffer;\r
+  AhciRegisters->MaxCommandTableSize = MaxCommandTableSize;\r
+  Bytes  = MaxCommandTableSize;\r
+\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Buffer,\r
+                    &Bytes,\r
+                    &(EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCommandTablePciAddr,\r
+                    &AhciRegisters->MapCommandTable\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != MaxCommandTableSize)) {\r
+    //\r
+    // Map error or unable to map the whole cmd list buffer into a contiguous region.\r
+    //\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error2;\r
+  }\r
+\r
+  if ((!Support64Bit) && ((EFI_PHYSICAL_ADDRESS)AhciRegisters->AhciCommandTablePciAddr > 0x100000000UL)) {\r
+    //\r
+    // The AHCI HBA doesn't support 64bit addressing, so should not get a >4G pci bus master address.\r
+    //\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Error1;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+  //\r
+  // Map error or unable to map the whole CmdList buffer into a contiguous region. \r
+  //\r
+Error1:\r
+  PciIo->Unmap (\r
+           PciIo,\r
+           AhciRegisters->MapCommandTable\r
+           );\r
+Error2:\r
+  PciIo->FreeBuffer (\r
+           PciIo,\r
+           EFI_SIZE_TO_PAGES (MaxCommandTableSize),\r
+           AhciRegisters->AhciCommandTable\r
+           );\r
+Error3:\r
+  PciIo->Unmap (\r
+           PciIo,\r
+           AhciRegisters->MapCmdList\r
+           );\r
+Error4:\r
+  PciIo->FreeBuffer (\r
+           PciIo,\r
+           EFI_SIZE_TO_PAGES (MaxCommandListSize),\r
+           AhciRegisters->AhciCmdList\r
+           );\r
+Error5:\r
+  PciIo->Unmap (\r
+           PciIo,\r
+           AhciRegisters->MapRFis\r
+           );\r
+Error6:\r
+  PciIo->FreeBuffer (\r
+           PciIo,\r
+           EFI_SIZE_TO_PAGES (MaxReceiveFisSize),\r
+           AhciRegisters->AhciRFis\r
+           );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize ATA host controller at AHCI mode.\r
+\r
+  The function is designed to initialize ATA host controller. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialization (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_PCI_IO_PROTOCOL              *PciIo;\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;\r
+  UINT32                           Capability;\r
+  UINT8                            MaxPortNumber;\r
+  UINT32                           PortImplementBitMap;\r
+  UINT8                            MaxCommandSlotNumber;\r
+  BOOLEAN                          Support64Bit;\r
+\r
+  EFI_AHCI_REGISTERS               *AhciRegisters;\r
+\r
+  UINT8                            Port;\r
+  DATA_64                          Data64;\r
+  UINT32                           Offset;\r
+  UINT32                           Data;\r
+  EFI_IDENTIFY_DATA                Buffer;\r
+  EFI_ATA_DEVICE_TYPE              DeviceType;\r
+  EFI_ATA_COLLECTIVE_MODE          *SupportedModes;\r
+  EFI_ATA_TRANSFER_MODE            TransferMode;\r
+  \r
+  if (Instance == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PciIo   = Instance->PciIo;\r
+  IdeInit = Instance->IdeControllerInit;\r
+\r
+  Status = AhciReset (PciIo, ATA_ATAPI_TIMEOUT); \r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Enable AE before accessing any AHCI registers\r
+  //\r
+  AhciOrReg (PciIo, EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);\r
+\r
+  //\r
+  // Collect AHCI controller information\r
+  //\r
+  Capability           = AhciReadReg(PciIo, EFI_AHCI_CAPABILITY_OFFSET);\r
+\r
+  //\r
+  // Get the number of command slots per port supported by this HBA.\r
+  //\r
+  MaxCommandSlotNumber = (UINT8) (((Capability & 0x1F00) >> 8) + 1);\r
+  Support64Bit         = ((Capability & BIT31) != 0) ? TRUE : FALSE;\r
+\r
+  //\r
+  // Get the bit map of those ports exposed by this HBA.\r
+  // It indicates which ports that the HBA supports are available for software to use. \r
+  //\r
+  PortImplementBitMap  = AhciReadReg(PciIo, EFI_AHCI_PI_OFFSET);\r
+  MaxPortNumber        = (UINT8) ((Capability & 0x1F) + 1);\r
+  \r
+  AhciRegisters = &Instance->AhciRegisters;\r
+  Status = AhciCreateTransferDescriptor (PciIo, AhciRegisters);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
+    Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFisPciAddr) + sizeof (EFI_AHCI_RECEIVED_FIS) * Port;\r
+  \r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;\r
+    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;\r
+    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+  \r
+    //\r
+    // Single task envrionment, we only use one command table for all port\r
+    //\r
+    Data64.Uint64 = (UINTN) (AhciRegisters->AhciCmdListPciAddr);\r
+  \r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;\r
+    AhciWriteReg (PciIo, Offset, Data64.Uint32.Lower32);\r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;\r
+    AhciWriteReg (PciIo, Offset, Data64.Uint32.Upper32);\r
+  \r
+    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;\r
+  \r
+      if ((Capability & EFI_AHCI_PORT_CMD_ASP) != 0) {\r
+        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_SUD);\r
+      }\r
+      Data = AhciReadReg (PciIo, Offset);\r
+      if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {\r
+        AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_CMD_POD);\r
+      }\r
+  \r
+      AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE|EFI_AHCI_PORT_CMD_COL|EFI_AHCI_PORT_CMD_ST));\r
+    }\r
+  \r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;\r
+    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_MASK));\r
\r
+    AhciAndReg (PciIo, Offset,(UINT32) ~(EFI_AHCI_PORT_SCTL_IPM_PSD));\r
+    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_PSD);\r
+  \r
+    AhciAndReg (PciIo, Offset, (UINT32)~(EFI_AHCI_PORT_SCTL_IPM_SSD));\r
+    AhciOrReg (PciIo, Offset, EFI_AHCI_PORT_SCTL_IPM_SSD);\r
+  \r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;\r
+    AhciAndReg (PciIo, Offset, 0);\r
+  \r
+    Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;\r
+    AhciWriteReg (PciIo, Offset, AhciReadReg (PciIo, Offset));\r
+  }\r
+\r
+  //\r
+  // Stall for 100 milliseconds.\r
+  //\r
+  MicroSecondDelay(100000);\r
+  \r
+  IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, Port);\r
+  \r
+  for (Port = 0; Port < MaxPortNumber; Port ++) {  \r
+    if ((PortImplementBitMap & (BIT0 << Port)) != 0) {\r
+    \r
+      Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SSTS;\r
+      Data = AhciReadReg (PciIo, Offset) & EFI_AHCI_PORT_SSTS_DET_MASK;\r
+\r
+      if (Data == 0) {\r
+        continue;\r
+      }\r
+      //\r
+      // Found device in the port\r
+      //\r
+      if (Data == EFI_AHCI_PORT_SSTS_DET_PCE) {\r
+        Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;\r
+\r
+        Status = AhciWaitMemSet (\r
+                   PciIo, \r
+                   Offset,\r
+                   0x0000FFFF,\r
+                   0x00000101,\r
+                   ATA_ATAPI_TIMEOUT\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+\r
+        //\r
+        // Now inform the IDE Controller Init Module.\r
+        //\r
+        IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, Port);\r
+\r
+        Data = AhciReadReg (PciIo, Offset);\r
+\r
+        if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATAPI_DEVICE_SIG) {\r
+          Status = AhciIdentifyPacket (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+\r
+          if (EFI_ERROR (Status)) {\r
+            continue;\r
+          }\r
+\r
+          DeviceType = EfiIdeCdrom;\r
+        } else if ((Data & EFI_AHCI_ATAPI_SIG_MASK) == EFI_AHCI_ATA_DEVICE_SIG) {\r
+          Status = AhciIdentify (PciIo, AhciRegisters, Port, 0, &Buffer);\r
+\r
+          if (EFI_ERROR (Status)) {\r
+            continue;\r
+          }\r
+\r
+          DeviceType = EfiIdeHarddisk;\r
+        } else {\r
+          continue;\r
+        }\r
+    \r
+        DEBUG ((EFI_D_INFO, "port [%d] port mulitplier [%d] has a [%a]\n", \r
+            Port, 0, DeviceType == EfiIdeCdrom ? "cdrom" : "harddisk"));\r
+\r
+        //\r
+        // Submit identify data to IDE controller init driver\r
+        //\r
+        IdeInit->SubmitData (IdeInit, Port, 0, &Buffer);\r
+\r
+        //\r
+        // Now start to config ide device parameter and transfer mode.\r
+        //\r
+        Status = IdeInit->CalculateMode (\r
+                            IdeInit,\r
+                            Port,\r
+                            0,\r
+                            &SupportedModes\r
+                            );\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+          continue;\r
+        }\r
+\r
+        //\r
+        // Set best supported PIO mode on this IDE device\r
+        //\r
+        if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
+          TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
+        } else {\r
+          TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
+        }\r
+\r
+        TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
+    \r
+        //\r
+        // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
+        // be set together. Only one DMA mode can be set to a device. If setting\r
+        // DMA mode operation fails, we can continue moving on because we only use\r
+        // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
+        //\r
+        if (SupportedModes->UdmaMode.Valid) {\r
+          TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
+          TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);\r
+        } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
+          TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
+          TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;  \r
+        }\r
+\r
+        Status = AhciDeviceSetFeature (PciIo, AhciRegisters, Port, 0, 0x03, (UINT32)(*(UINT8 *)&TransferMode));\r
+    \r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+          continue;\r
+        }\r
+        //\r
+        // Found a ATA or ATAPI device, add it into the device list.\r
+        //\r
+        CreateNewDeviceInfo (Instance, Port, 0, DeviceType, &Buffer);\r
+      }\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
new file mode 100644 (file)
index 0000000..668e992
--- /dev/null
@@ -0,0 +1,464 @@
+/** @file\r
+  Header file for AHCI mode of ATA host controller.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+#ifndef __ATA_HC_AHCI_MODE_H__\r
+#define __ATA_HC_AHCI_MODE_H__\r
+\r
+#define EFI_AHCI_BAR_INDEX                     0x05\r
+\r
+#define EFI_AHCI_CAPABILITY_OFFSET             0x0000\r
+#define EFI_AHCI_GHC_OFFSET                    0x0004\r
+#define   EFI_AHCI_GHC_RESET                   BIT0\r
+#define   EFI_AHCI_GHC_IE                      BIT1\r
+#define   EFI_AHCI_GHC_ENABLE                  BIT31\r
+#define EFI_AHCI_IS_OFFSET                     0x0008\r
+#define EFI_AHCI_PI_OFFSET                     0x000C\r
+\r
+typedef struct {\r
+  UINT32  Lower32;\r
+  UINT32  Upper32;\r
+} DATA_32;\r
+\r
+typedef union {\r
+  DATA_32   Uint32;\r
+  UINT64    Uint64;\r
+} DATA_64;\r
+\r
+#define  EFI_AHCI_ATAPI_DEVICE_SIG             0xEB140000\r
+#define  EFI_AHCI_ATA_DEVICE_SIG               0x00000000\r
+#define  EFI_AHCI_PORT_MULTIPLIER_SIG          0x96690000\r
+#define  EFI_AHCI_ATAPI_SIG_MASK               0xFFFF0000\r
+\r
+//\r
+// Each PRDT entry can point to a memory block up to 4M byte\r
+//\r
+#define EFI_AHCI_MAX_DATA_PER_PRDT             0x400000\r
+\r
+#define EFI_AHCI_FIS_REGISTER_H2D              0x27      //Register FIS - Host to Device\r
+#define   EFI_AHCI_FIS_REGISTER_H2D_LENGTH     20 \r
+#define EFI_AHCI_FIS_REGISTER_D2H              0x34      //Register FIS - Device to Host\r
+#define   EFI_AHCI_FIS_REGISTER_D2H_LENGTH     20\r
+#define EFI_AHCI_FIS_DMA_ACTIVATE              0x39      //DMA Activate FIS - Device to Host\r
+#define   EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH     4\r
+#define EFI_AHCI_FIS_DMA_SETUP                 0x41      //DMA Setup FIS - Bi-directional\r
+#define   EFI_AHCI_FIS_DMA_SETUP_LENGTH        28\r
+#define EFI_AHCI_FIS_DATA                      0x46      //Data FIS - Bi-directional\r
+#define EFI_AHCI_FIS_BIST                      0x58      //BIST Activate FIS - Bi-directional\r
+#define   EFI_AHCI_FIS_BIST_LENGTH             12\r
+#define EFI_AHCI_FIS_PIO_SETUP                 0x5F      //PIO Setup FIS - Device to Host\r
+#define   EFI_AHCI_FIS_PIO_SETUP_LENGTH        20\r
+#define EFI_AHCI_FIS_SET_DEVICE                0xA1      //Set Device Bits FIS - Device to Host\r
+#define   EFI_AHCI_FIS_SET_DEVICE_LENGTH       8\r
+\r
+#define EFI_AHCI_D2H_FIS_OFFSET                0x40\r
+#define EFI_AHCI_DMA_FIS_OFFSET                0x00\r
+#define EFI_AHCI_PIO_FIS_OFFSET                0x20\r
+#define EFI_AHCI_SDB_FIS_OFFSET                0x58\r
+#define EFI_AHCI_FIS_TYPE_MASK                 0xFF\r
+#define EFI_AHCI_U_FIS_OFFSET                  0x60\r
+\r
+//\r
+// Port register\r
+//\r
+#define EFI_AHCI_PORT_START                    0x0100\r
+#define EFI_AHCI_PORT_REG_WIDTH                0x0080\r
+#define EFI_AHCI_PORT_CLB                      0x0000\r
+#define EFI_AHCI_PORT_CLBU                     0x0004\r
+#define EFI_AHCI_PORT_FB                       0x0008\r
+#define EFI_AHCI_PORT_FBU                      0x000C\r
+#define EFI_AHCI_PORT_IS                       0x0010\r
+#define   EFI_AHCI_PORT_IS_DHRS                BIT0\r
+#define   EFI_AHCI_PORT_IS_PSS                 BIT1\r
+#define   EFI_AHCI_PORT_IS_SSS                 BIT2\r
+#define   EFI_AHCI_PORT_IS_SDBS                BIT3\r
+#define   EFI_AHCI_PORT_IS_UFS                 BIT4\r
+#define   EFI_AHCI_PORT_IS_DPS                 BIT5\r
+#define   EFI_AHCI_PORT_IS_PCS                 BIT6\r
+#define   EFI_AHCI_PORT_IS_DIS                 BIT7\r
+#define   EFI_AHCI_PORT_IS_PRCS                BIT22\r
+#define   EFI_AHCI_PORT_IS_IPMS                BIT23\r
+#define   EFI_AHCI_PORT_IS_OFS                 BIT24\r
+#define   EFI_AHCI_PORT_IS_INFS                BIT26\r
+#define   EFI_AHCI_PORT_IS_IFS                 BIT27\r
+#define   EFI_AHCI_PORT_IS_HBDS                BIT28\r
+#define   EFI_AHCI_PORT_IS_HBFS                BIT29\r
+#define   EFI_AHCI_PORT_IS_TFES                BIT30\r
+#define   EFI_AHCI_PORT_IS_CPDS                BIT31\r
+#define   EFI_AHCI_PORT_IS_CLEAR               0xFFFFFFFF\r
+#define   EFI_AHCI_PORT_IS_FIS_CLEAR           0x0000000F\r
+\r
+#define EFI_AHCI_PORT_IE                       0x0014\r
+#define EFI_AHCI_PORT_CMD                      0x0018\r
+#define   EFI_AHCI_PORT_CMD_ST_MASK            0xFFFFFFFE\r
+#define   EFI_AHCI_PORT_CMD_ST                 BIT0\r
+#define   EFI_AHCI_PORT_CMD_SUD                BIT1\r
+#define   EFI_AHCI_PORT_CMD_POD                BIT2\r
+#define   EFI_AHCI_PORT_CMD_COL                BIT3\r
+#define   EFI_AHCI_PORT_CMD_CR                 BIT15\r
+#define   EFI_AHCI_PORT_CMD_FRE                BIT4\r
+#define   EFI_AHCI_PORT_CMD_FR                 BIT14\r
+#define   EFI_AHCI_PORT_CMD_MASK               ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)\r
+#define   EFI_AHCI_PORT_CMD_PMA                BIT17\r
+#define   EFI_AHCI_PORT_CMD_HPCP               BIT18\r
+#define   EFI_AHCI_PORT_CMD_MPSP               BIT19\r
+#define   EFI_AHCI_PORT_CMD_CPD                BIT20\r
+#define   EFI_AHCI_PORT_CMD_ESP                BIT21\r
+#define   EFI_AHCI_PORT_CMD_ATAPI              BIT24\r
+#define   EFI_AHCI_PORT_CMD_DLAE               BIT25\r
+#define   EFI_AHCI_PORT_CMD_ALPE               BIT26\r
+#define   EFI_AHCI_PORT_CMD_ASP                BIT27\r
+#define   EFI_AHCI_PORT_CMD_ICC_MASK           (BIT28 | BIT29 | BIT30 | BIT31)\r
+#define   EFI_AHCI_PORT_CMD_ACTIVE             (1 << 28 )\r
+#define EFI_AHCI_PORT_TFD                      0x0020\r
+#define   EFI_AHCI_PORT_TFD_MASK               (BIT7 | BIT3 | BIT0)\r
+#define   EFI_AHCI_PORT_TFD_BSY                BIT7\r
+#define   EFI_AHCI_PORT_TFD_DRQ                BIT3\r
+#define   EFI_AHCI_PORT_TFD_ERR                BIT0\r
+#define   EFI_AHCI_PORT_TFD_ERR_MASK           0x00FF00\r
+#define EFI_AHCI_PORT_SIG                      0x0024\r
+#define EFI_AHCI_PORT_SSTS                     0x0028\r
+#define   EFI_AHCI_PORT_SSTS_DET_MASK          0x000F\r
+#define   EFI_AHCI_PORT_SSTS_DET               0x0001\r
+#define   EFI_AHCI_PORT_SSTS_DET_PCE           0x0003\r
+#define   EFI_AHCI_PORT_SSTS_SPD_MASK          0x00F0\r
+#define EFI_AHCI_PORT_SCTL                     0x002C\r
+#define   EFI_AHCI_PORT_SCTL_DET_MASK          0x000F\r
+#define   EFI_AHCI_PORT_SCTL_MASK              (~EFI_AHCI_PORT_SCTL_DET_MASK)\r
+#define   EFI_AHCI_PORT_SCTL_DET_INIT          0x0001\r
+#define   EFI_AHCI_PORT_SCTL_DET_PHYCOMM       0x0003\r
+#define   EFI_AHCI_PORT_SCTL_SPD_MASK          0x00F0\r
+#define   EFI_AHCI_PORT_SCTL_IPM_MASK          0x0F00\r
+#define   EFI_AHCI_PORT_SCTL_IPM_INIT          0x0300\r
+#define   EFI_AHCI_PORT_SCTL_IPM_PSD           0x0100\r
+#define   EFI_AHCI_PORT_SCTL_IPM_SSD           0x0200\r
+#define EFI_AHCI_PORT_SERR                     0x0030\r
+#define   EFI_AHCI_PORT_SERR_RDIE              BIT0\r
+#define   EFI_AHCI_PORT_SERR_RCE               BIT1\r
+#define   EFI_AHCI_PORT_SERR_TDIE              BIT8\r
+#define   EFI_AHCI_PORT_SERR_PCDIE             BIT9\r
+#define   EFI_AHCI_PORT_SERR_PE                BIT10\r
+#define   EFI_AHCI_PORT_SERR_IE                BIT11\r
+#define   EFI_AHCI_PORT_SERR_PRC               BIT16\r
+#define   EFI_AHCI_PORT_SERR_PIE               BIT17\r
+#define   EFI_AHCI_PORT_SERR_CW                BIT18\r
+#define   EFI_AHCI_PORT_SERR_BDE               BIT19\r
+#define   EFI_AHCI_PORT_SERR_DE                BIT20\r
+#define   EFI_AHCI_PORT_SERR_CRCE              BIT21\r
+#define   EFI_AHCI_PORT_SERR_HE                BIT22          \r
+#define   EFI_AHCI_PORT_SERR_LSE               BIT23\r
+#define   EFI_AHCI_PORT_SERR_TSTE              BIT24\r
+#define   EFI_AHCI_PORT_SERR_UFT               BIT25\r
+#define   EFI_AHCI_PORT_SERR_EX                BIT26\r
+#define   EFI_AHCI_PORT_ERR_CLEAR              0xFFFFFFFF\r
+#define EFI_AHCI_PORT_SACT                     0x0034\r
+#define EFI_AHCI_PORT_CI                       0x0038\r
+#define EFI_AHCI_PORT_SNTF                     0x003C\r
+\r
+\r
+#pragma pack(1)\r
+//\r
+// Command List structure includes total 32 entries.\r
+// The entry data structure is listed at the following.\r
+//\r
+typedef struct {\r
+  UINT32   AhciCmdCfl:5;      //Command FIS Length\r
+  UINT32   AhciCmdA:1;        //ATAPI\r
+  UINT32   AhciCmdW:1;        //Write\r
+  UINT32   AhciCmdP:1;        //Prefetchable\r
+  UINT32   AhciCmdR:1;        //Reset\r
+  UINT32   AhciCmdB:1;        //BIST\r
+  UINT32   AhciCmdC:1;        //Clear Busy upon R_OK\r
+  UINT32   AhciCmdRsvd:1;\r
+  UINT32   AhciCmdPmp:4;      //Port Multiplier Port\r
+  UINT32   AhciCmdPrdtl:16;   //Physical Region Descriptor Table Length\r
+  UINT32   AhciCmdPrdbc;      //Physical Region Descriptor Byte Count\r
+  UINT32   AhciCmdCtba;       //Command Table Descriptor Base Address\r
+  UINT32   AhciCmdCtbau;      //Command Table Descriptor Base Address Upper 32-BITs\r
+  UINT32   AhciCmdRsvd1[4]; \r
+} EFI_AHCI_COMMAND_LIST;\r
+\r
+//\r
+// This is a software constructed FIS.\r
+// For data transfer operations, this is the H2D Register FIS format as \r
+// specified in the Serial ATA Revision 2.6 specification.\r
+//\r
+typedef struct {\r
+  UINT8    AhciCFisType;\r
+  UINT8    AhciCFisPmNum:4;\r
+  UINT8    AhciCFisRsvd:1;\r
+  UINT8    AhciCFisRsvd1:1;\r
+  UINT8    AhciCFisRsvd2:1;\r
+  UINT8    AhciCFisCmdInd:1;\r
+  UINT8    AhciCFisCmd;\r
+  UINT8    AhciCFisFeature;\r
+  UINT8    AhciCFisSecNum;\r
+  UINT8    AhciCFisClyLow;\r
+  UINT8    AhciCFisClyHigh;\r
+  UINT8    AhciCFisDevHead;\r
+  UINT8    AhciCFisSecNumExp;\r
+  UINT8    AhciCFisClyLowExp;\r
+  UINT8    AhciCFisClyHighExp;\r
+  UINT8    AhciCFisFeatureExp;\r
+  UINT8    AhciCFisSecCount;\r
+  UINT8    AhciCFisSecCountExp;\r
+  UINT8    AhciCFisRsvd3;\r
+  UINT8    AhciCFisControl;\r
+  UINT8    AhciCFisRsvd4[4];\r
+  UINT8    AhciCFisRsvd5[44];\r
+} EFI_AHCI_COMMAND_FIS;\r
+\r
+//\r
+// ACMD: ATAPI command (12 or 16 bytes)\r
+//\r
+typedef struct {\r
+  UINT8    AtapiCmd[0x10];\r
+} EFI_AHCI_ATAPI_COMMAND;\r
+\r
+//\r
+// Physical Region Descriptor Table includes up to 65535 entries\r
+// The entry data structure is listed at the following.\r
+// the actual entry number comes from the PRDTL field in the command\r
+// list entry for this command slot. \r
+//\r
+typedef struct {\r
+  UINT32   AhciPrdtDba;       //Data Base Address\r
+  UINT32   AhciPrdtDbau;      //Data Base Address Upper 32-BITs\r
+  UINT32   AhciPrdtRsvd;\r
+  UINT32   AhciPrdtDbc:22;    //Data Byte Count\r
+  UINT32   AhciPrdtRsvd1:9;\r
+  UINT32   AhciPrdtIoc:1;     //Interrupt on Completion\r
+} EFI_AHCI_COMMAND_PRDT;\r
+\r
+//\r
+// Command table data strucute which is pointed to by the entry in the command list\r
+//\r
+typedef struct {\r
+  EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.\r
+  EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.\r
+  UINT8                     Reserved[0x30];\r
+  EFI_AHCI_COMMAND_PRDT     PrdtTable[65535];     // The scatter/gather list for data transfer\r
+} EFI_AHCI_COMMAND_TABLE;\r
+\r
+//\r
+// Received FIS structure\r
+//\r
+typedef struct {\r
+  UINT8    AhciDmaSetupFis[0x1C];         // Dma Setup Fis: offset 0x00\r
+  UINT8    AhciDmaSetupFisRsvd[0x04];\r
+  UINT8    AhciPioSetupFis[0x14];         // Pio Setup Fis: offset 0x20\r
+  UINT8    AhciPioSetupFisRsvd[0x0C];     \r
+  UINT8    AhciD2HRegisterFis[0x14];      // D2H Register Fis: offset 0x40\r
+  UINT8    AhciD2HRegisterFisRsvd[0x04];\r
+  UINT64   AhciSetDeviceBitsFis;          // Set Device Bits Fix: offset 0x58\r
+  UINT8    AhciUnknownFis[0x40];          // Unkonwn Fis: offset 0x60\r
+  UINT8    AhciUnknownFisRsvd[0x60];      \r
+} EFI_AHCI_RECEIVED_FIS; \r
+\r
+#pragma pack()\r
+\r
+typedef struct {\r
+  EFI_AHCI_RECEIVED_FIS     *AhciRFis;\r
+  EFI_AHCI_COMMAND_LIST     *AhciCmdList;\r
+  EFI_AHCI_COMMAND_TABLE    *AhciCommandTable;\r
+  EFI_AHCI_RECEIVED_FIS     *AhciRFisPciAddr;\r
+  EFI_AHCI_COMMAND_LIST     *AhciCmdListPciAddr;\r
+  EFI_AHCI_COMMAND_TABLE    *AhciCommandTablePciAddr;\r
+  UINT64                    MaxCommandListSize;\r
+  UINT64                    MaxCommandTableSize;\r
+  UINT64                    MaxReceiveFisSize;\r
+  VOID                      *MapRFis;\r
+  VOID                      *MapCmdList;\r
+  VOID                      *MapCommandTable;\r
+} EFI_AHCI_REGISTERS;\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the Packet Command \r
+  with PIO Protocol.\r
+\r
+  @param PciIo              The PCI IO protocol instance.\r
+  @param AhciRegisters      The pointer to the EFI_AHCI_REGISTERS.\r
+  @param Port               The number of port.     \r
+  @param PortMultiplier     The number of port multiplier.\r
+  @param Packet             A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.\r
+\r
+  @retval EFI_SUCCESS       send out the ATAPI packet command successfully\r
+                            and device sends data successfully.\r
+  @retval EFI_DEVICE_ERROR  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPacketCommandExecute (\r
+  IN  EFI_PCI_IO_PROTOCOL                           *PciIo,\r
+  IN  EFI_AHCI_REGISTERS                            *AhciRegisters,\r
+  IN  UINT8                                         Port,\r
+  IN  UINT8                                         PortMultiplier,\r
+  IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  );\r
+\r
+/**\r
+  Start command for give slot on specific port.\r
+    \r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Port               The number of port.\r
+  @param  CommandSlot        The number of CommandSlot.\r
+  @param  Timeout            The timeout value of start.\r
+   \r
+  @retval EFI_DEVICE_ERROR   The command start unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command start successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStartCommand (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT8                     CommandSlot,\r
+  IN  UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Stop command running for giving port\r
+    \r
+  @param  PciIo              The PCI IO protocol instance.\r
+  @param  Port               The number of port.\r
+  @param  Timeout            The timeout value of stop.\r
+   \r
+  @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.\r
+  @retval EFI_TIMEOUT        The operation is time out.\r
+  @retval EFI_SUCCESS        The command stop successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciStopCommand (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     Port,\r
+  IN  UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Start a non data transfer on specific port.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtapiCommand      The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength    The length of the atapi command.\r
+  @param    AtaCommandBlock       The EFI_ATA_COMMAND_BLOCK data.\r
+  @param    AtaStatusBlock        The EFI_ATA_STATUS_BLOCK data.\r
+  @param  Timeout               The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The non data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The non data transfer executes successfully.\r
+\r
+**/ \r
+EFI_STATUS\r
+EFIAPI\r
+AhciNonDataTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL           *PciIo,\r
+  IN     EFI_AHCI_REGISTERS            *AhciRegisters,\r
+  IN     UINT8                         Port,\r
+  IN     UINT8                         PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND        *AtapiCommand OPTIONAL,\r
+  IN     UINT8                         AtapiCommandLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK         *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock,\r
+  IN     UINT64                        Timeout\r
+  );\r
+\r
+/**\r
+  Start a DMA data transfer on specific port\r
+\r
+  @param  PciIo         The PCI IO protocol instance.\r
+  @param  AhciRegisters         The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port          The number of port.\r
+  @param  PortMultiplier      The timeout value of stop.\r
+  @param  AtapiCommand        The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength    The length of the atapi command.\r
+  @param  Read                  The transfer direction.\r
+  @param  AtaCommandBlock       The EFI_ATA_COMMAND_BLOCK data.\r
+  @param  AtaStatusBlock        The EFI_ATA_STATUS_BLOCK data.\r
+  @param  MemoryAddr            The pointer to the data buffer.\r
+  @param  DataCount             The data count to be transferred.\r
+  @param  Timeout               The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR  The DMA data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT     The operation is time out.\r
+  @retval EFI_UNSUPPORTED   The device is not ready for transfer.\r
+  @retval EFI_SUCCESS     The DMA data transfer executes successfully.\r
+   \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciDmaTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,\r
+  IN     BOOLEAN                    Read,  \r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINTN                      DataCount,\r
+  IN     UINT64                     Timeout\r
+  );\r
+\r
+/**\r
+  Start a PIO data transfer on specific port.\r
+    \r
+  @param  PciIo             The PCI IO protocol instance.\r
+  @param  AhciRegisters       The pointer to the EFI_AHCI_REGISTERS.\r
+  @param  Port              The number of port.\r
+  @param  PortMultiplier    The timeout value of stop.\r
+  @param  AtapiCommand      The atapi command will be used for the transfer.\r
+  @param  AtapiCommandLength  The length of the atapi command.\r
+  @param  Read                The transfer direction.\r
+  @param  AtaCommandBlock     The EFI_ATA_COMMAND_BLOCK data.\r
+  @param  AtaStatusBlock      The EFI_ATA_STATUS_BLOCK data.\r
+  @param  MemoryAddr          The pointer to the data buffer.\r
+  @param  DataCount           The data count to be transferred.\r
+  @param  Timeout             The timeout value of non data transfer.\r
+\r
+  @retval EFI_DEVICE_ERROR    The PIO data transfer abort with error occurs.\r
+  @retval EFI_TIMEOUT         The operation is time out.\r
+  @retval EFI_UNSUPPORTED     The device is not ready for transfer.\r
+  @retval EFI_SUCCESS         The PIO data transfer executes successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciPioTransfer (\r
+  IN     EFI_PCI_IO_PROTOCOL        *PciIo,\r
+  IN     EFI_AHCI_REGISTERS         *AhciRegisters,\r
+  IN     UINT8                      Port,\r
+  IN     UINT8                      PortMultiplier,\r
+  IN     EFI_AHCI_ATAPI_COMMAND     *AtapiCommand OPTIONAL,\r
+  IN     UINT8                      AtapiCommandLength,  \r
+  IN     BOOLEAN                    Read,  \r
+  IN     EFI_ATA_COMMAND_BLOCK      *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK       *AtaStatusBlock,\r
+  IN OUT VOID                       *MemoryAddr,\r
+  IN     UINT32                     DataCount,\r
+  IN     UINT64                     Timeout \r
+  );\r
+\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
new file mode 100644 (file)
index 0000000..f90846a
--- /dev/null
@@ -0,0 +1,2195 @@
+/** @file\r
+  This file implements ATA_PASSTHRU_PROCTOCOL and EXT_SCSI_PASSTHRU_PROTOCOL interfaces\r
+  for managed ATA controllers.\r
+    \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  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
+\r
+**/\r
+\r
+#include "AtaAtapiPassThru.h"\r
+\r
+//\r
+//  EFI_DRIVER_BINDING_PROTOCOL instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gAtaAtapiPassThruDriverBinding = {\r
+  AtaAtapiPassThruSupported,\r
+  AtaAtapiPassThruStart,\r
+  AtaAtapiPassThruStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {\r
+  ATA_ATAPI_PASS_THRU_SIGNATURE,\r
+  0,                  // Controller Handle\r
+  NULL,               // PciIo Protocol\r
+  NULL,               // IdeControllerInit Protocol\r
+  {                   // AtaPassThruMode\r
+    //\r
+    // According to UEFI2.3 spec Section 12.10, Drivers for non-RAID ATA controllers should set\r
+    // both EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL and EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL\r
+    // bits.\r
+    // Note that the driver doesn't support AtaPassThru non blocking I/O.\r
+    //\r
+    EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+    //\r
+    // IoAlign\r
+    //\r
+    sizeof (UINTN)\r
+  },\r
+  {                   // AtaPassThru\r
+    NULL,  \r
+    AtaPassThruPassThru,\r
+    AtaPassThruGetNextPort,\r
+    AtaPassThruGetNextDevice,\r
+    AtaPassThruBuildDevicePath,\r
+    AtaPassThruGetDevice,\r
+    AtaPassThruResetPort,\r
+    AtaPassThruResetDevice  \r
+  },\r
+  {                   // ExtScsiPassThruMode\r
+    //\r
+    // AdapterId\r
+    //\r
+    0,\r
+    //\r
+    // According to UEFI2.3 spec Section 14.7, Drivers for non-RAID SCSI controllers should set\r
+    // both EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL and EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL\r
+    // bits.\r
+    // Note that the driver doesn't support ExtScsiPassThru non blocking I/O.\r
+    // \r
+    EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,\r
+    //\r
+    // IoAlign\r
+    //\r
+    sizeof (UINTN)\r
+  },\r
+  {                   // ExtScsiPassThru\r
+    NULL,\r
+    ExtScsiPassThruPassThru,\r
+    ExtScsiPassThruGetNextTargetLun,\r
+    ExtScsiPassThruBuildDevicePath,\r
+    ExtScsiPassThruGetTargetLun,\r
+    ExtScsiPassThruResetChannel,\r
+    ExtScsiPassThruResetTargetLun,\r
+    ExtScsiPassThruGetNextTarget\r
+  },\r
+  EfiAtaUnknownMode,  // Work Mode\r
+  {                   // IdeRegisters\r
+    {0},\r
+    {0}\r
+  },\r
+  {                   // AhciRegisters\r
+    0\r
+  },\r
+  {                   // DeviceList\r
+    NULL,\r
+    NULL\r
+  },\r
+  0,                  // OriginalAttributes\r
+  0,                  // PreviousPort\r
+  0,                  // PreviousPortMultiplier\r
+  0,                  // PreviousTargetId\r
+  0                   // PreviousLun\r
+};\r
+\r
+ATAPI_DEVICE_PATH    mAtapiDevicePathTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_ATAPI_DP,\r
+    (UINT8) (sizeof (ATAPI_DEVICE_PATH)),\r
+    (UINT8) ((sizeof (ATAPI_DEVICE_PATH)) >> 8),\r
+  },\r
+  0,\r
+  0,\r
+  0\r
+};\r
+\r
+SATA_DEVICE_PATH    mSataDevicePathTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_SATA_DP,\r
+    (UINT8) (sizeof (SATA_DEVICE_PATH)),\r
+    (UINT8) ((sizeof (SATA_DEVICE_PATH)) >> 8),\r
+  },\r
+  0,\r
+  0,\r
+  0\r
+};\r
+\r
+UINT8 mScsiId[TARGET_MAX_BYTES] = {\r
+  0xFF, 0xFF, 0xFF, 0xFF,\r
+  0xFF, 0xFF, 0xFF, 0xFF,\r
+  0xFF, 0xFF, 0xFF, 0xFF,\r
+  0xFF, 0xFF, 0xFF, 0xFF\r
+};\r
+\r
+/**\r
+  The Entry Point of module.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeAtaAtapiPassThru (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gAtaAtapiPassThruDriverBinding,\r
+             ImageHandle,\r
+             &gAtaAtapiPassThruComponentName,\r
+             &gAtaAtapiPassThruComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN EFI_HANDLE                        Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  PCI_TYPE00                        PciData;\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeControllerInit;\r
+\r
+  //\r
+  // SATA Controller is a device driver, and should ingore the\r
+  // "RemainingDevicePath" according to UEFI spec\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID *) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the protocol because we don't use it here\r
+  //\r
+  gBS->CloseProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  This->DriverBindingHandle,\r
+                  Controller\r
+                  );\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiIdeControllerInitProtocolGuid,\r
+                  (VOID **) &IdeControllerInit,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error\r
+    //\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiIdeControllerInitProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Now test the EfiPciIoProtocol\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Now further check the PCI header: Base class (offset 0x0B) and\r
+  // Sub Class (offset 0x0A). This controller should be an ATA controller\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_CLASSCODE_OFFSET,\r
+                        sizeof (PciData.Hdr.ClassCode),\r
+                        PciData.Hdr.ClassCode\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiPciIoProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Close PciIo protocol as we have gotten the PciData.\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  if (IS_PCI_IDE (&PciData) || IS_PCI_SATADPA (&PciData)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL        *This,\r
+  IN EFI_HANDLE                         Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeControllerInit;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE      *Instance;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  UINT64                            Supports;\r
+  BOOLEAN                           PciAttributesSaved;\r
+  UINT64                            OriginalPciAttributes;\r
+\r
+  Status                = EFI_SUCCESS;\r
+  IdeControllerInit     = NULL;\r
+  Instance              = NULL;\r
+  PciAttributesSaved    = FALSE;\r
+  OriginalPciAttributes = 0;\r
+\r
+  DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Start== Controller = %x\n", Controller));\r
+\r
+  Status  = gBS->OpenProtocol (\r
+                   Controller,\r
+                   &gEfiIdeControllerInitProtocolGuid,\r
+                   (VOID **) &IdeControllerInit,\r
+                   This->DriverBindingHandle,\r
+                   Controller,\r
+                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                   );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Open Ide_Controller_Init Error, Status=%r", Status));\r
+    goto ErrorExit;\r
+  }\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Get Pci_Io Protocol Error, Status=%r", Status));\r
+    goto ErrorExit;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationGet,\r
+                    0,\r
+                    &OriginalPciAttributes\r
+                    );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+  PciAttributesSaved = TRUE;\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    Status = PciIo->Attributes (\r
+                      PciIo,\r
+                      EfiPciIoAttributeOperationEnable,\r
+                      Supports,\r
+                      NULL\r
+                      );\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  //\r
+  // Allocate a buffer to store the ATA_ATAPI_PASS_THRU_INSTANCE data structure\r
+  //\r
+  Instance = AllocateCopyPool (sizeof (ATA_ATAPI_PASS_THRU_INSTANCE), &gAtaAtapiPassThruInstanceTemplate);\r
+  if (Instance == NULL) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  Instance->ControllerHandle      = Controller;\r
+  Instance->IdeControllerInit     = IdeControllerInit;\r
+  Instance->PciIo                 = PciIo;\r
+  Instance->OriginalPciAttributes = OriginalPciAttributes;\r
+  Instance->AtaPassThru.Mode      = &Instance->AtaPassThruMode;\r
+  Instance->ExtScsiPassThru.Mode  = &Instance->ExtScsiPassThruMode;\r
+  InitializeListHead(&Instance->DeviceList);\r
+\r
+  //\r
+  // Enumerate all inserted ATA devices.\r
+  //\r
+  Status = EnumerateAttachedDevice (Instance);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Controller,\r
+                  &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru),\r
+                  &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru),\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+\r
+ErrorExit:\r
+  if (IdeControllerInit != NULL) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiIdeControllerInitProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+  }\r
+\r
+  //\r
+  // Remove all inserted ATA devices.\r
+  //\r
+  DestroyDeviceInfoList(Instance);\r
+\r
+  if (Instance != NULL) {\r
+    FreePool (Instance);\r
+  }\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN  EFI_HANDLE                        Controller,\r
+  IN  UINTN                             NumberOfChildren,\r
+  IN  EFI_HANDLE                        *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE      *Instance;\r
+  EFI_ATA_PASS_THRU_PROTOCOL        *AtaPassThru;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_AHCI_REGISTERS                *AhciRegisters;\r
+  UINT64                            Supports;\r
+\r
+  DEBUG ((EFI_D_INFO, "==AtaAtapiPassThru Stop== Controller = %x\n", Controller));\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiAtaPassThruProtocolGuid,\r
+                  (VOID **) &AtaPassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(AtaPassThru);\r
+  PciIo    = Instance->PciIo;\r
+\r
+  //\r
+  // Disable this ATA host controller.\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= EFI_PCI_DEVICE_ENABLE;\r
+    PciIo->Attributes (\r
+             PciIo,\r
+             EfiPciIoAttributeOperationDisable,\r
+             Supports,\r
+             NULL\r
+             );\r
+  }\r
+\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSet,\r
+                    Instance->OriginalPciAttributes,\r
+                    NULL\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         Controller,\r
+         &gEfiAtaPassThruProtocolGuid, &(Instance->AtaPassThru),\r
+         &gEfiExtScsiPassThruProtocolGuid, &(Instance->ExtScsiPassThru),\r
+         NULL\r
+         );\r
+\r
+  //\r
+  // Close protocols opened by AtaAtapiPassThru controller driver\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiIdeControllerInitProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  //\r
+  // Free allocated resource\r
+  //\r
+  DestroyDeviceInfoList(Instance);\r
+\r
+  //\r
+  // If the current working mode is AHCI mode, then pre-allocated resource\r
+  // for AHCI initialization should be released.\r
+  //\r
+  if (Instance->Mode == EfiAtaAhciMode) {\r
+    AhciRegisters = &Instance->AhciRegisters;\r
+    PciIo->Unmap (\r
+             PciIo,\r
+             AhciRegisters->MapCommandTable\r
+             );\r
+    PciIo->FreeBuffer (\r
+             PciIo,\r
+             EFI_SIZE_TO_PAGES (AhciRegisters->MaxCommandTableSize),\r
+             AhciRegisters->AhciCommandTable\r
+             );\r
+    PciIo->Unmap (\r
+             PciIo,\r
+             AhciRegisters->MapCmdList\r
+             );\r
+    PciIo->FreeBuffer (\r
+             PciIo,\r
+             EFI_SIZE_TO_PAGES (AhciRegisters->MaxCommandListSize),\r
+             AhciRegisters->AhciCmdList\r
+             );\r
+    PciIo->Unmap (\r
+             PciIo,\r
+             AhciRegisters->MapRFis\r
+             );\r
+    PciIo->FreeBuffer (\r
+             PciIo,\r
+             EFI_SIZE_TO_PAGES (AhciRegisters->MaxReceiveFisSize),\r
+             AhciRegisters->AhciRFis\r
+             );\r
+  }\r
+  FreePool (Instance);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Traverse the attached ATA devices list to find out the device to access.\r
+  \r
+  @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+  @param[in]  Port                The port number of the ATA device to send the command. \r
+  @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
+                                  If there is no port multiplier, then specify 0.\r
+  @param[in]  DeviceType          The device type of the ATA device.\r
+  \r
+  @retval     The pointer to the data structure of the device info to access.\r
+\r
+**/\r
+LIST_ENTRY *\r
+EFIAPI\r
+SearchDeviceInfoList (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN  UINT16                         Port,\r
+  IN  UINT16                         PortMultiplier,\r
+  IN  EFI_ATA_DEVICE_TYPE            DeviceType\r
+  )\r
+{\r
+  EFI_ATA_DEVICE_INFO  *DeviceInfo;\r
+  LIST_ENTRY           *Node;\r
+\r
+  Node = GetFirstNode (&Instance->DeviceList);\r
+  while (!IsNull (&Instance->DeviceList, Node)) {\r
+    DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+    if ((DeviceInfo->Type == DeviceType) &&\r
+        (Port == DeviceInfo->Port) && \r
+        (PortMultiplier == DeviceInfo->PortMultiplier)) {\r
+      return Node;\r
+    }\r
+\r
+    Node = GetNextNode (&Instance->DeviceList, Node);\r
+  }  \r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Allocate device info data structure to contain device info.\r
+  And insert the data structure to the tail of device list for tracing.\r
+    \r
+  @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+  @param[in]  Port                The port number of the ATA device to send the command. \r
+  @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
+                                  If there is no port multiplier, then specify 0.\r
+  @param[in]  DeviceType          The device type of the ATA device.\r
+  @param[in]  IdentifyData        The data buffer to store the output of the IDENTIFY cmd.\r
+\r
+  @retval EFI_SUCCESS             Successfully insert the ata device to the tail of device list.\r
+  @retval EFI_OUT_OF_RESOURCES    Can not allocate enough resource for use.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreateNewDeviceInfo (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE   *Instance,\r
+  IN  UINT16                         Port,\r
+  IN  UINT16                         PortMultiplier,\r
+  IN  EFI_ATA_DEVICE_TYPE            DeviceType,\r
+  IN  EFI_IDENTIFY_DATA              *IdentifyData\r
+  )\r
+{\r
+  EFI_ATA_DEVICE_INFO  *DeviceInfo;\r
+\r
+  DeviceInfo = AllocateZeroPool (sizeof (EFI_ATA_DEVICE_INFO));\r
+\r
+  if (DeviceInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DeviceInfo->Signature      = ATA_ATAPI_DEVICE_SIGNATURE;\r
+  DeviceInfo->Port           = Port;\r
+  DeviceInfo->PortMultiplier = PortMultiplier;\r
+  DeviceInfo->Type           = DeviceType;\r
+\r
+  if (IdentifyData != NULL) {\r
+    DeviceInfo->IdentifyData = AllocateCopyPool (sizeof (EFI_IDENTIFY_DATA), IdentifyData);\r
+    if (DeviceInfo->IdentifyData == NULL) {\r
+      FreePool (DeviceInfo);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  InsertTailList (&Instance->DeviceList, &DeviceInfo->Link);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Destroy all attached ATA devices info.\r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DestroyDeviceInfoList (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance\r
+  )\r
+{\r
+  EFI_ATA_DEVICE_INFO  *DeviceInfo;\r
+  LIST_ENTRY           *Node;\r
+\r
+  Node = GetFirstNode (&Instance->DeviceList);\r
+  while (!IsNull (&Instance->DeviceList, Node)) {\r
+    DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+    Node = GetNextNode (&Instance->DeviceList, Node);\r
+\r
+    RemoveEntryList (&DeviceInfo->Link);\r
+    if (DeviceInfo->IdentifyData != NULL) {\r
+      FreePool (DeviceInfo->IdentifyData);\r
+    }\r
+    FreePool (DeviceInfo);\r
+  }\r
+}\r
+\r
+/**\r
+  Enumerate all attached ATA devices at IDE mode or AHCI mode separately.\r
+  \r
+  The function is designed to enumerate all attached ATA devices. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+  @retval EFI_SUCCESS           Successfully enumerate attached ATA devices.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnumerateAttachedDevice (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE      *Instance\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  PCI_TYPE00                   PciData;\r
+  UINT8                        ClassCode;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  Status = Instance->PciIo->Pci.Read (\r
+                                  Instance->PciIo,\r
+                                  EfiPciIoWidthUint8,\r
+                                  PCI_CLASSCODE_OFFSET,\r
+                                  sizeof (PciData.Hdr.ClassCode),\r
+                                  PciData.Hdr.ClassCode\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ClassCode = PciData.Hdr.ClassCode[1];\r
+\r
+  switch (ClassCode) {\r
+    case PCI_CLASS_MASS_STORAGE_IDE :\r
+      //\r
+      // The ATA controller is working at IDE mode\r
+      //\r
+      Instance->Mode = EfiAtaIdeMode;\r
+\r
+      Status = IdeModeInitialization (Instance);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Done;\r
+      }\r
+      break;\r
+    case PCI_CLASS_MASS_STORAGE_SATADPA :\r
+      //\r
+      // The ATA controller is working at AHCI mode\r
+      //\r
+      Instance->Mode = EfiAtaAhciMode;\r
+\r
+      Status = AhciModeInitialization (Instance);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Done;\r
+      }\r
+\r
+      break;\r
+    default :\r
+      Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends an ATA command to an ATA device that is attached to the ATA controller. This function\r
+  supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,\r
+  and the non-blocking I/O functionality is optional.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. \r
+  @param[in]      Port               The port number of the ATA device to send the command. \r
+  @param[in]      PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+                                     If there is no port multiplier, then specify 0.\r
+  @param[in, out] Packet             A pointer to the ATA command to send to the ATA device specified by Port\r
+                                     and PortMultiplierPort.\r
+  @param[in]      Event               If non-blocking I/O is not supported then Event is ignored, and blocking\r
+                                     I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                                     Event is not NULL and non blocking I/O is supported, then non-blocking\r
+                                     I/O is performed, and Event will be signaled when the ATA command completes.\r
+\r
+  @retval EFI_SUCCESS                The ATA command was sent by the host. For bi-directional commands, \r
+                                     InTransferLength bytes were transferred from InDataBuffer. For write and\r
+                                     bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE        The ATA command was not executed. The number of bytes that could be transferred\r
+                                     is returned in InTransferLength. For write and bi-directional commands, \r
+                                     OutTransferLength bytes were transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY              The ATA command could not be sent because there are too many ATA commands\r
+                                     already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting to send the ATA command.\r
+  @retval EFI_INVALID_PARAMETER      Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA\r
+                                     command was not sent, so no additional status information is available.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruPassThru (\r
+  IN     EFI_ATA_PASS_THRU_PROTOCOL       *This,\r
+  IN     UINT16                           Port,\r
+  IN     UINT16                           PortMultiplierPort,\r
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,\r
+  IN     EFI_EVENT                        Event OPTIONAL\r
+  ) \r
+{\r
+  EFI_STATUS                      Status;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  EFI_ATA_PASS_THRU_CMD_PROTOCOL  Protocol;\r
+  EFI_ATA_HC_WORK_MODE            Mode;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+  EFI_IDENTIFY_DATA               *IdentifyData;\r
+  UINT64                          Capacity;\r
+  UINT32                          MaxSectorCount;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->Asb, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // convert the transfer length from sector count to byte.\r
+  //\r
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) && \r
+       (Packet->InTransferLength != 0)) {\r
+    Packet->InTransferLength = Packet->InTransferLength * 0x200;\r
+  }\r
+\r
+  //\r
+  // convert the transfer length from sector count to byte.\r
+  //\r
+  if (((Packet->Length & EFI_ATA_PASS_THRU_LENGTH_BYTES) == 0) &&\r
+       (Packet->OutTransferLength != 0)) {\r
+    Packet->OutTransferLength = Packet->OutTransferLength * 0x200;\r
+  }\r
+\r
+  Node = SearchDeviceInfoList (Instance, Port, PortMultiplierPort, EfiIdeHarddisk);\r
+\r
+  if (Node == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether this device needs 48-bit addressing (ATAPI-6 ata device).\r
+  // Per ATA-6 spec, word83: bit15 is zero and bit14 is one.\r
+  // If bit10 is one, it means the ata device support 48-bit addressing. \r
+  //\r
+  DeviceInfo     = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+  IdentifyData   = DeviceInfo->IdentifyData;\r
+  MaxSectorCount = 0x100;\r
+  if ((IdentifyData->AtaData.command_set_supported_83 & (BIT10 | BIT15 | BIT14)) == 0x4400) {\r
+    Capacity = *((UINT64 *)IdentifyData->AtaData.maximum_lba_for_48bit_addressing);\r
+    if (Capacity > 0xFFFFFFF) {\r
+      //\r
+      // Capacity exceeds 120GB. 48-bit addressing is really needed\r
+      // In this case, the max sector count is 0x10000\r
+      //\r
+      MaxSectorCount = 0x10000;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If the data buffer described by InDataBuffer/OutDataBuffer and InTransferLength/OutTransferLength\r
+  // is too big to be transferred in a single command, then no data is transferred and EFI_BAD_BUFFER_SIZE\r
+  // is returned. \r
+  //\r
+  if (((Packet->InTransferLength != 0) && (Packet->InTransferLength > MaxSectorCount * 0x200)) || \r
+      ((Packet->OutTransferLength != 0) && (Packet->OutTransferLength > MaxSectorCount * 0x200))) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  Status   = EFI_UNSUPPORTED;\r
+  Protocol = Packet->Protocol;\r
+\r
+  Mode = Instance->Mode;\r
+  switch (Mode) {\r
+    case EfiAtaIdeMode:\r
+      //\r
+      // Reassign IDE mode io port registers' base addresses\r
+      //\r
+      Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);\r
+      \r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      \r
+      switch (Protocol) {\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
+          Status = AtaNonDataCommandIn(\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
+          Status = AtaPioDataInOut(\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
+          Status = AtaPioDataInOut(\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
+          Status = AtaUdmaInOut(\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     TRUE,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
+          Status = AtaUdmaInOut(\r
+                     Instance->PciIo,\r
+                     &Instance->IdeRegisters[Port],\r
+                     FALSE,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        default :\r
+          return EFI_UNSUPPORTED;\r
+      }\r
+      break;\r
+    case EfiAtaAhciMode :\r
+      switch (Protocol) {\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA:\r
+          Status = AhciNonDataTransfer(\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN:\r
+          Status = AhciPioTransfer(\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT:\r
+          Status = AhciPioTransfer(\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN:\r
+          Status = AhciDmaTransfer(\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     TRUE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->InDataBuffer,\r
+                     Packet->InTransferLength,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT:\r
+          Status = AhciDmaTransfer(\r
+                     Instance->PciIo,\r
+                     &Instance->AhciRegisters,\r
+                     (UINT8)Port,\r
+                     (UINT8)PortMultiplierPort,\r
+                     NULL,\r
+                     0,\r
+                     FALSE,\r
+                     Packet->Acb,\r
+                     Packet->Asb,\r
+                     Packet->OutDataBuffer,\r
+                     Packet->OutTransferLength,\r
+                     Packet->Timeout\r
+                     );\r
+          break;\r
+        default :\r
+          return EFI_UNSUPPORTED;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.\r
+  These can either be the list of ports where ATA devices are actually present or the\r
+  list of legal port numbers for the ATA controller. Regardless, the caller of this\r
+  function must probe the port number returned to see if an ATA device is actually\r
+  present at that location on the ATA controller.\r
+\r
+  The GetNextPort() function retrieves the port number on an ATA controller. If on input\r
+  Port is 0xFFFF, then the port number of the first port on the ATA controller is returned\r
+  in Port and EFI_SUCCESS is returned.\r
+\r
+  If Port is a port number that was returned on a previous call to GetNextPort(), then the\r
+  port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS\r
+  is returned. If Port is not 0xFFFF and Port was not returned on a previous call to\r
+  GetNextPort(), then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is\r
+  returned.\r
+\r
+  @param[in]      This          A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. \r
+  @param[in, out] Port          On input, a pointer to the port number on the ATA controller.\r
+                                On output, a pointer to the next port number on the ATA\r
+                                controller. An input value of 0xFFFF retrieves the first port\r
+                                number on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS           The next port number on the ATA controller was returned in Port.\r
+  @retval EFI_NOT_FOUND         There are no more ports on this ATA controller.\r
+  @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call\r
+                                to GetNextPort().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruGetNextPort (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN OUT UINT16                 *Port\r
+  )\r
+{\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (Port == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Port == 0xFFFF) {\r
+    //\r
+    // If the Port is all 0xFF's, start to traverse the device list from the beginning\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if (DeviceInfo->Type == EfiIdeHarddisk) {\r
+        *Port = DeviceInfo->Port;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else if (*Port == Instance->PreviousPort) {\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if ((DeviceInfo->Type == EfiIdeHarddisk) &&\r
+           (DeviceInfo->Port > *Port)){\r
+        *Port = DeviceInfo->Port;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // Port is not equal to 0xFFFF and also not equal to previous return value\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+Exit:\r
+  //\r
+  // Update the PreviousPort and PreviousPortMultiplier.\r
+  //\r
+  Instance->PreviousPort = *Port;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA \r
+  controller. These can either be the list of port multiplier ports where ATA devices are actually \r
+  present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this \r
+  function must probe the port number and port multiplier port number returned to see if an ATA \r
+  device is actually present.\r
+\r
+  The GetNextDevice() function retrieves the port multiplier port number of an ATA device \r
+  present on a port of an ATA controller.\r
+  \r
+  If PortMultiplierPort points to a port multiplier port number value that was returned on a \r
+  previous call to GetNextDevice(), then the port multiplier port number of the next ATA device\r
+  on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is\r
+  returned.\r
+  \r
+  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first \r
+  ATA device on port of the ATA controller is returned in PortMultiplierPort and \r
+  EFI_SUCCESS is returned.\r
+  \r
+  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort\r
+  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER\r
+  is returned.\r
+  \r
+  If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of \r
+  the ATA controller, then EFI_NOT_FOUND is returned.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]      Port               The port number present on the ATA controller.\r
+  @param[in, out] PortMultiplierPort On input, a pointer to the port multiplier port number of an\r
+                                     ATA device present on the ATA controller. \r
+                                     If on input a PortMultiplierPort of 0xFFFF is specified, \r
+                                     then the port multiplier port number of the first ATA device\r
+                                     is returned. On output, a pointer to the port multiplier port\r
+                                     number of the next ATA device present on an ATA controller.\r
+\r
+  @retval EFI_SUCCESS                The port multiplier port number of the next ATA device on the port\r
+                                     of the ATA controller was returned in PortMultiplierPort.\r
+  @retval EFI_NOT_FOUND              There are no more ATA devices on this port of the ATA controller.\r
+  @retval EFI_INVALID_PARAMETER      PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not\r
+                                     returned on a previous call to GetNextDevice().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruGetNextDevice (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port,\r
+  IN OUT UINT16                 *PortMultiplierPort\r
+  )\r
+{\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (PortMultiplierPort == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*PortMultiplierPort == 0xFFFF) {\r
+    //\r
+    // If the PortMultiplierPort is all 0xFF's, start to traverse the device list from the beginning\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if ((DeviceInfo->Type == EfiIdeHarddisk) &&\r
+           (DeviceInfo->Port == Port)){\r
+        *PortMultiplierPort = DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else if (*PortMultiplierPort == Instance->PreviousPortMultiplier) {\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if ((DeviceInfo->Type == EfiIdeHarddisk) &&\r
+           (DeviceInfo->Port == Port) &&\r
+           (DeviceInfo->PortMultiplier > *PortMultiplierPort)){\r
+        *PortMultiplierPort = DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // PortMultiplierPort is not equal to 0xFFFF and also not equal to previous return value\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+Exit:\r
+  //\r
+  // Update the PreviousPort and PreviousPortMultiplier.\r
+  //\r
+  Instance->PreviousPortMultiplier = *PortMultiplierPort;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to allocate and build a device path node for an ATA device on an ATA controller.\r
+\r
+  The BuildDevicePath() function allocates and builds a single device node for the ATA\r
+  device specified by Port and PortMultiplierPort. If the ATA device specified by Port and\r
+  PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.\r
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough\r
+  resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
+\r
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+  DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,\r
+  and EFI_SUCCESS is returned.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]      Port               Port specifies the port number of the ATA device for which a\r
+                                     device path node is to be allocated and built.\r
+  @param[in]      PortMultiplierPort The port multiplier port number of the ATA device for which a\r
+                                     device path node is to be allocated and built. If there is no\r
+                                     port multiplier, then specify 0.\r
+  @param[in, out] DevicePath         A pointer to a single device path node that describes the ATA\r
+                                     device specified by Port and PortMultiplierPort. This function\r
+                                     is responsible for allocating the buffer DevicePath with the\r
+                                     boot service AllocatePool(). It is the caller's responsibility\r
+                                     to free DevicePath when the caller is finished with DevicePath.\r
+  @retval EFI_SUCCESS                The device path node that describes the ATA device specified by\r
+                                     Port and PortMultiplierPort was allocated and returned in DevicePath.\r
+  @retval EFI_NOT_FOUND              The ATA device specified by Port and PortMultiplierPort does not\r
+                                     exist on the ATA controller.\r
+  @retval EFI_INVALID_PARAMETER      DevicePath is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES       There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruBuildDevicePath (\r
+  IN     EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN     UINT16                     Port,\r
+  IN     UINT16                     PortMultiplierPort,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath\r
+  )\r
+{\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Node = SearchDeviceInfoList(Instance, Port, PortMultiplierPort, EfiIdeHarddisk);\r
+  if (Node == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  if (Instance->Mode == EfiAtaIdeMode) {\r
+    DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);\r
+    if (DevicePathNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    DevicePathNode->Atapi.PrimarySecondary = (UINT8) Port;\r
+    DevicePathNode->Atapi.SlaveMaster      = (UINT8) PortMultiplierPort;\r
+    DevicePathNode->Atapi.Lun              = 0;\r
+  } else {\r
+    DevicePathNode = AllocateCopyPool (sizeof (SATA_DEVICE_PATH), &mSataDevicePathTemplate);\r
+    if (DevicePathNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    DevicePathNode->Sata.HBAPortNumber            = Port;\r
+    DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplierPort;\r
+    DevicePathNode->Sata.Lun                      = 0;\r
+  }\r
+\r
+  *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to translate a device path node to a port number and port multiplier port number.\r
+\r
+  The GetDevice() function determines the port and port multiplier port number associated with\r
+  the ATA device described by DevicePath. If DevicePath is a device path node type that the\r
+  ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents \r
+  DevicePath into a port number and port multiplier port number.\r
+\r
+  If this translation is successful, then that port number and port multiplier port number are returned\r
+  in Port and PortMultiplierPort, and EFI_SUCCESS is returned.\r
+\r
+  If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then \r
+  EFI_UNSUPPORTED is returned.\r
+\r
+  If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not \r
+  a valid translation from DevicePath to a port number and port multiplier port number, then \r
+  EFI_NOT_FOUND is returned.\r
+\r
+  @param[in]  This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  DevicePath          A pointer to the device path node that describes an ATA device on the\r
+                                  ATA controller.\r
+  @param[out] Port                On return, points to the port number of an ATA device on the ATA controller.\r
+  @param[out] PortMultiplierPort  On return, points to the port multiplier port number of an ATA device\r
+                                  on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS             DevicePath was successfully translated to a port number and port multiplier\r
+                                  port number, and they were returned in Port and PortMultiplierPort.\r
+  @retval EFI_INVALID_PARAMETER   DevicePath is NULL.\r
+  @retval EFI_INVALID_PARAMETER   Port is NULL.\r
+  @retval EFI_INVALID_PARAMETER   PortMultiplierPort is NULL.\r
+  @retval EFI_UNSUPPORTED         This driver does not support the device path node type in DevicePath.\r
+  @retval EFI_NOT_FOUND           A valid translation from DevicePath to a port number and port multiplier\r
+                                  port number does not exist.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruGetDevice (\r
+  IN  EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *DevicePath,\r
+  OUT UINT16                     *Port,\r
+  OUT UINT16                     *PortMultiplierPort\r
+  )\r
+{\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL || Port == NULL || PortMultiplierPort == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH or ATAPI_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      ((DevicePath->SubType != MSG_SATA_DP) &&\r
+      (DevicePath->SubType != MSG_ATAPI_DP)) ||\r
+      ((DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH)) &&\r
+      (DevicePathNodeLength(DevicePath) != sizeof(SATA_DEVICE_PATH)))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  DevicePathNode = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  if (Instance->Mode == EfiAtaIdeMode) {\r
+    *Port               = DevicePathNode->Atapi.PrimarySecondary;\r
+    *PortMultiplierPort = DevicePathNode->Atapi.SlaveMaster;\r
+  } else {\r
+    *Port               = DevicePathNode->Sata.HBAPortNumber;\r
+    *PortMultiplierPort = DevicePathNode->Sata.PortMultiplierPortNumber;\r
+  }\r
+\r
+  Node = SearchDeviceInfoList(Instance, *Port, *PortMultiplierPort, EfiIdeHarddisk);\r
+\r
+  if (Node == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a specific port on the ATA controller. This operation also resets all the ATA devices\r
+  connected to the port.\r
+\r
+  The ResetChannel() function resets an a specific port on an ATA controller. This operation\r
+  resets all the ATA devices connected to that port. If this ATA controller does not support\r
+  a reset port operation, then EFI_UNSUPPORTED is returned.\r
+\r
+  If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is\r
+  returned.\r
+\r
+  If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.\r
+\r
+  If the port reset operation is completed, then EFI_SUCCESS is returned.\r
+\r
+  @param[in]  This          A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Port          The port number on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS       The ATA controller port was reset.\r
+  @retval EFI_UNSUPPORTED   The ATA controller does not support a port reset operation.\r
+  @retval EFI_DEVICE_ERROR  A device error occurred while attempting to reset the ATA port.\r
+  @retval EFI_TIMEOUT       A timeout occurred while attempting to reset the ATA port.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruResetPort (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Resets an ATA device that is connected to an ATA controller.\r
+\r
+  The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.\r
+  If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is\r
+  returned.\r
+\r
+  If Port or PortMultiplierPort are not in a valid range for this ATA controller, then \r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR\r
+  is returned.\r
+\r
+  If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is\r
+  returned.\r
+\r
+  If the device reset operation is completed, then EFI_SUCCESS is returned.\r
+\r
+  @param[in] This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Port                Port represents the port number of the ATA device to be reset.\r
+  @param[in] PortMultiplierPort  The port multiplier port number of the ATA device to reset.\r
+                                 If there is no port multiplier, then specify 0.\r
+  @retval EFI_SUCCESS            The ATA device specified by Port and PortMultiplierPort was reset.\r
+  @retval EFI_UNSUPPORTED        The ATA controller does not support a device reset operation.\r
+  @retval EFI_INVALID_PARAMETER  Port or PortMultiplierPort are invalid.\r
+  @retval EFI_DEVICE_ERROR       A device error occurred while attempting to reset the ATA device\r
+                                 specified by Port and PortMultiplierPort.\r
+  @retval EFI_TIMEOUT            A timeout occurred while attempting to reset the ATA device\r
+                                 specified by Port and PortMultiplierPort.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPassThruResetDevice (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port,\r
+  IN UINT16                     PortMultiplierPort\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function   \r
+  supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the\r
+  nonblocking I/O functionality is optional.                                                             \r
+\r
+  @param  This    A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target  The Target is an array of size TARGET_MAX_BYTES and it represents\r
+                  the id of the SCSI device to send the SCSI Request Packet. Each\r
+                  transport driver may choose to utilize a subset of this size to suit the needs\r
+                  of transport target representation. For example, a Fibre Channel driver\r
+                  may use only 8 bytes (WWN) to represent an FC target.\r
+  @param  Lun     The LUN of the SCSI device to send the SCSI Request Packet.\r
+  @param  Packet  A pointer to the SCSI Request Packet to send to the SCSI device\r
+                  specified by Target and Lun.\r
+  @param  Event   If nonblocking I/O is not supported then Event is ignored, and blocking\r
+                  I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                  Event is not NULL and non blocking I/O is supported, then\r
+                  nonblocking I/O is performed, and Event will be signaled when the\r
+                  SCSI Request Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE   The SCSI Request Packet was not executed. The number of bytes that\r
+                                could be transferred is returned in InTransferLength. For write\r
+                                and bi-directional commands, OutTransferLength bytes were\r
+                                transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY         The SCSI Request Packet could not be sent because there are too many\r
+                                SCSI Request Packets already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.\r
+  @retval EFI_UNSUPPORTED       The command described by the SCSI Request Packet is not supported\r
+                                by the host adapter. This includes the case of Bi-directional SCSI\r
+                                commands not supported by the implementation. The SCSI Request\r
+                                Packet was not sent, so no additional status information is available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruPassThru (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  UINT8                           Port;\r
+  UINT8                           PortMultiplier;\r
+  EFI_ATA_HC_WORK_MODE            Mode;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+\r
+  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((Packet == NULL) || (Packet->Cdb == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Don't support variable length CDB\r
+  //\r
+  if ((Packet->CdbLength != 6) && (Packet->CdbLength != 10) &&\r
+      (Packet->CdbLength != 12) && (Packet->CdbLength != 16)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->InDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->OutDataBuffer, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((This->Mode->IoAlign > 1) && !IS_ALIGNED(Packet->SenseData, This->Mode->IoAlign)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // For ATAPI device, doesn't support multiple LUN device.\r
+  //\r
+  if (Lun != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // \r
+  // The layout of Target array:\r
+  //  ________________________________________________________________________\r
+  // |       Byte 0        |       Byte 1        | ... | TARGET_MAX_BYTES - 1 |\r
+  // |_____________________|_____________________|_____|______________________|\r
+  // |                     | The port multiplier |     |                      |\r
+  // |   The port number   |    port number      | N/A |         N/A          |\r
+  // |_____________________|_____________________|_____|______________________|\r
+  //\r
+  // For ATAPI device, 2 bytes is enough to represent the location of SCSI device.\r
+  //\r
+  Port           = Target[0];\r
+  PortMultiplier = Target[1];\r
+\r
+  Node = SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom);\r
+  if (Node == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+  //\r
+  // ATA_CMD_IDENTIFY_DEVICE cmd is a ATA cmd but not a SCSI cmd.\r
+  // Normally it should NOT be passed down through ExtScsiPassThru protocol interface.\r
+  // But to response EFI_DISK_INFO.Identify() request from ScsiDisk, we should handle this command.\r
+  //\r
+  if (*((UINT8*)Packet->Cdb) == ATA_CMD_IDENTIFY_DEVICE) {\r
+    CopyMem (Packet->InDataBuffer, DeviceInfo->IdentifyData, sizeof (EFI_IDENTIFY_DATA));\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Mode = Instance->Mode;\r
+  switch (Mode) {\r
+    case EfiAtaIdeMode:\r
+      //\r
+      // Reassign IDE mode io port registers' base addresses\r
+      //\r
+      Status = GetIdeRegisterIoAddr (Instance->PciIo, Instance->IdeRegisters);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Status = AtaPacketCommandExecute (Instance->PciIo, &Instance->IdeRegisters[Port], Port, PortMultiplier, Packet);\r
+      break;\r
+    case EfiAtaAhciMode:\r
+      Status = AhciPacketCommandExecute (Instance->PciIo, &Instance->AhciRegisters, Port, PortMultiplier, Packet);\r
+      break;\r
+    default :\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These       \r
+  can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal\r
+  Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the       \r
+  Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI    \r
+  channel.                                                                                               \r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target On input, a pointer to the Target ID (an array of size\r
+                 TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+  @param  Lun    On input, a pointer to the LUN of a SCSI device present on the SCSI\r
+                 channel. On output, a pointer to the LUN of the next SCSI device present\r
+                 on a SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID and LUN of the next SCSI device on the SCSI\r
+                                channel was returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were\r
+                                not returned on a previous call to GetNextTargetLun().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  )\r
+{\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+  UINT8                           *Target8;\r
+  UINT16                          *Target16;\r
+\r
+  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Target8  = *Target;\r
+  Target16 = (UINT16 *)*Target;\r
+\r
+  if (CompareMem(Target8, mScsiId, TARGET_MAX_BYTES) != 0) {\r
+    //\r
+    // For ATAPI device, we use 2 least significant bytes to represent the location of SCSI device.\r
+    // So the higher bytes in Target array should be 0xFF.\r
+    //\r
+    if (CompareMem (&Target8[2], &mScsiId[2], TARGET_MAX_BYTES - 2) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // When Target is not all 0xFF's, compare 2 least significant bytes with\r
+    // previous target id to see if it is returned by previous call.\r
+    //\r
+    if ((*Target16 != Instance->PreviousTargetId) ||\r
+        (*Lun != Instance->PreviousLun)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Traverse the whole device list to find the next cdrom closed to\r
+    // the device signified by Target[0] and Target[1].\r
+    //\r
+    // Note that we here use a tricky way to find the next cdrom :\r
+    // All ata devices are detected and inserted into the device list\r
+    // sequentially.\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if ((DeviceInfo->Type == EfiIdeCdrom) &&\r
+         ((Target8[0] < DeviceInfo->Port) || \r
+          (Target8[1] < DeviceInfo->PortMultiplier))) {\r
+        Target8[0] = (UINT8)DeviceInfo->Port;\r
+        Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // If the array is all 0xFF's, start to traverse the device list from the beginning\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if (DeviceInfo->Type == EfiIdeCdrom) {\r
+        Target8[0] = (UINT8)DeviceInfo->Port;\r
+        Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+Exit:\r
+  *Lun = 0;\r
+\r
+  //\r
+  // Update the PreviousTargetId.\r
+  //\r
+  Instance->PreviousTargetId = *Target16;\r
+  Instance->PreviousLun      = *Lun;\r
+  \r
+  return EFI_SUCCESS;\r
+}   \r
+\r
+/**\r
+  Used to allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target     The Target is an array of size TARGET_MAX_BYTES and it specifies the\r
+                     Target ID of the SCSI device for which a device path node is to be\r
+                     allocated and built. Transport drivers may chose to utilize a subset of\r
+                     this size to suit the representation of targets. For example, a Fibre\r
+                     Channel driver may use only 8 bytes (WWN) in the array to represent a\r
+                     FC target.\r
+  @param  Lun        The LUN of the SCSI device for which a device path node is to be\r
+                     allocated and built.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     specified by Target and Lun. This function is responsible for\r
+                     allocating the buffer DevicePath with the boot service\r
+                     AllocatePool(). It is the caller's responsibility to free\r
+                     DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SCSI device specified by\r
+                                Target and Lun was allocated and returned in\r
+                                DevicePath.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_NOT_FOUND         The SCSI devices specified by Target and Lun does not exist\r
+                                on the SCSI channel.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  )\r
+{\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  UINT8                           Port;\r
+  UINT8                           PortMultiplier;\r
+\r
+  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  Port           = Target[0];\r
+  PortMultiplier = Target[1];\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // can not build device path for the SCSI Host Controller.\r
+  //\r
+  if (Lun != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (SearchDeviceInfoList(Instance, Port, PortMultiplier, EfiIdeCdrom) == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  if (Instance->Mode == EfiAtaIdeMode) {\r
+    DevicePathNode = AllocateCopyPool (sizeof (ATAPI_DEVICE_PATH), &mAtapiDevicePathTemplate);\r
+    if (DevicePathNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    DevicePathNode->Atapi.PrimarySecondary = Port;\r
+    DevicePathNode->Atapi.SlaveMaster      = PortMultiplier;\r
+    DevicePathNode->Atapi.Lun              = (UINT16) Lun;\r
+  } else {\r
+    DevicePathNode = AllocateCopyPool (sizeof (SATA_DEVICE_PATH), &mSataDevicePathTemplate);\r
+    if (DevicePathNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    DevicePathNode->Sata.HBAPortNumber            = Port;\r
+    DevicePathNode->Sata.PortMultiplierPortNumber = PortMultiplier;\r
+    DevicePathNode->Sata.Lun                      = (UINT16) Lun;\r
+  }\r
+\r
+  *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathNode;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     on the SCSI channel.\r
+  @param  Target     A pointer to the Target Array which represents the ID of a SCSI device\r
+                     on the SCSI channel.\r
+  @param  Lun        A pointer to the LUN of a SCSI device on the SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           DevicePath was successfully translated to a Target ID and\r
+                                LUN, and they were returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.\r
+  @retval EFI_NOT_FOUND         A valid translation from DevicePath to a Target ID and LUN\r
+                                does not exist.\r
+  @retval EFI_UNSUPPORTED       This driver does not support the device path node type in\r
+                                 DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,\r
+  OUT UINT8                              **Target,\r
+  OUT UINT64                             *Lun\r
+  )\r
+{\r
+  EFI_DEV_PATH                    *DevicePathNode;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+\r
+  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Validate parameters passed in.\r
+  //\r
+  if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (*Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      ((DevicePath->SubType != MSG_ATAPI_DP) &&\r
+      (DevicePath->SubType != MSG_SATA_DP)) ||\r
+      ((DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH)) &&\r
+      (DevicePathNodeLength(DevicePath) != sizeof(SATA_DEVICE_PATH)))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SetMem (*Target, TARGET_MAX_BYTES, 0xFF);\r
+\r
+  DevicePathNode = (EFI_DEV_PATH *) DevicePath;\r
+\r
+  if (Instance->Mode == EfiAtaIdeMode) {\r
+    (*Target)[0] = (UINT8) DevicePathNode->Atapi.PrimarySecondary;\r
+    (*Target)[1] = (UINT8) DevicePathNode->Atapi.SlaveMaster;\r
+    *Lun         = (UINT8) DevicePathNode->Atapi.Lun;\r
+  } else {\r
+    (*Target)[0] = (UINT8) DevicePathNode->Sata.HBAPortNumber;\r
+    (*Target)[1] = (UINT8) DevicePathNode->Sata.PortMultiplierPortNumber;\r
+    *Lun         = (UINT8) DevicePathNode->Sata.Lun;\r
+  }\r
+\r
+  Node = SearchDeviceInfoList(Instance, (*Target)[0], (*Target)[1], EfiIdeCdrom);\r
+\r
+  if (Node == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (*Lun != 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.\r
+\r
+  @param  This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS      The SCSI channel was reset.\r
+  @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_TIMEOUT      A timeout occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_UNSUPPORTED  The SCSI channel does not support a channel reset operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}    \r
+  \r
+/**\r
+  Resets a SCSI logical unit that is connected to a SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target The Target is an array of size TARGET_MAX_BYTE and it represents the\r
+                 target port ID of the SCSI device containing the SCSI logical unit to\r
+                 reset. Transport drivers may chose to utilize a subset of this array to suit\r
+                 the representation of their targets.\r
+  @param  Lun    The LUN of the SCSI device to reset.\r
+\r
+  @retval EFI_SUCCESS           The SCSI device specified by Target and Lun was reset.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           A timeout occurred while attempting to reset the SCSI device\r
+                                specified by Target and Lun.\r
+  @retval EFI_UNSUPPORTED       The SCSI channel does not support a target reset operation.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to reset the SCSI device\r
+                                 specified by Target and Lun.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  )\r
+{\r
+  return EFI_UNSUPPORTED;\r
+}         \r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either     \r
+  be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs\r
+  for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to     \r
+  see if a SCSI device is actually present at that location on the SCSI channel.                         \r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID of the next SCSI device on the SCSI\r
+                                channel was returned in Target.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           Target array is not all 0xF, and Target was not\r
+                                returned on a previous call to GetNextTarget().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  )\r
+{\r
+  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance;\r
+  LIST_ENTRY                      *Node;\r
+  EFI_ATA_DEVICE_INFO             *DeviceInfo;\r
+  UINT8                           *Target8;\r
+  UINT16                          *Target16;\r
+\r
+  Instance = EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (Target == NULL || *Target == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Target8  = *Target;\r
+  Target16 = (UINT16 *)*Target;\r
+\r
+  if (CompareMem(Target8, mScsiId, TARGET_MAX_BYTES) != 0) {\r
+    //\r
+    // For ATAPI device, we use 2 least significant bytes to represent the location of SCSI device.\r
+    // So the higher bytes in Target array should be 0xFF.\r
+    //\r
+    if (CompareMem (&Target8[2], &mScsiId[2], TARGET_MAX_BYTES - 2) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // When Target is not all 0xFF's, compare 2 least significant bytes with\r
+    // previous target id to see if it is returned by previous call.\r
+    //\r
+    if (*Target16 != Instance->PreviousTargetId) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Traverse the whole device list to find the next cdrom closed to\r
+    // the device signified by Target[0] and Target[1].\r
+    //\r
+    // Note that we here use a tricky way to find the next cdrom :\r
+    // All ata devices are detected and inserted into the device list\r
+    // sequentially.\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if ((DeviceInfo->Type == EfiIdeCdrom) &&\r
+         ((Target8[0] < DeviceInfo->Port) || \r
+          (Target8[1] < DeviceInfo->PortMultiplier))) {\r
+        Target8[0] = (UINT8)DeviceInfo->Port;\r
+        Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    //\r
+    // If the array is all 0xFF's, start to traverse the device list from the beginning\r
+    //\r
+    Node = GetFirstNode (&Instance->DeviceList);\r
+\r
+    while (!IsNull (&Instance->DeviceList, Node)) {\r
+      DeviceInfo = ATA_ATAPI_DEVICE_INFO_FROM_THIS (Node);\r
+\r
+      if (DeviceInfo->Type == EfiIdeCdrom) {\r
+        Target8[0] = (UINT8)DeviceInfo->Port;\r
+        Target8[1] = (UINT8)DeviceInfo->PortMultiplier;\r
+        goto Exit;\r
+      }\r
+\r
+      Node = GetNextNode (&Instance->DeviceList, Node);\r
+    }\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+Exit:\r
+  //\r
+  // Update the PreviousTargetId.\r
+  //\r
+  Instance->PreviousTargetId = *Target16;\r
+\r
+  return EFI_SUCCESS;\r
+}    \r
+\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
new file mode 100644 (file)
index 0000000..69e6dc0
--- /dev/null
@@ -0,0 +1,1000 @@
+/** @file\r
+  Header file for ATA/ATAPI PASS THRU driver.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+#ifndef __ATA_ATAPI_PASS_THRU_H__\r
+#define __ATA_ATAPI_PASS_THRU_H__\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/Atapi.h>\r
+#include <IndustryStandard/Scsi.h>\r
+\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/IdeControllerInit.h>\r
+#include <Protocol/AtaPassThru.h>\r
+#include <Protocol/ScsiPassThruExt.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+#include "IdeMode.h"\r
+#include "AhciMode.h"\r
+\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gAtaAtapiPassThruDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gAtaAtapiPassThruComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gAtaAtapiPassThruComponentName2;\r
+\r
+#define ATA_ATAPI_PASS_THRU_SIGNATURE  SIGNATURE_32 ('a', 'a', 'p', 't')\r
+#define ATA_ATAPI_DEVICE_SIGNATURE     SIGNATURE_32 ('a', 'd', 'e', 'v')\r
+\r
+typedef enum {\r
+  EfiAtaIdeMode,\r
+  EfiAtaAhciMode,\r
+  EfiAtaRaidMode,\r
+  EfiAtaUnknownMode\r
+} EFI_ATA_HC_WORK_MODE;\r
+\r
+typedef enum {\r
+  EfiIdeCdrom,                  /* ATAPI CDROM */\r
+  EfiIdeHarddisk,               /* Hard Disk */\r
+  EfiPortMultiplier,            /* Port Multiplier */\r
+  EfiIdeUnknown\r
+} EFI_ATA_DEVICE_TYPE;\r
+\r
+//\r
+// Ahci mode device info\r
+//\r
+typedef struct {\r
+  UINT32                            Signature;\r
+  LIST_ENTRY                        Link;\r
+\r
+  UINT16                            Port;\r
+  UINT16                            PortMultiplier;\r
+  EFI_ATA_DEVICE_TYPE               Type;\r
+\r
+  EFI_IDENTIFY_DATA                 *IdentifyData;\r
+} EFI_ATA_DEVICE_INFO;\r
+\r
+typedef struct {\r
+  UINT32                            Signature;\r
+\r
+  EFI_HANDLE                        ControllerHandle;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeControllerInit;\r
+\r
+  EFI_ATA_PASS_THRU_MODE            AtaPassThruMode;\r
+  EFI_ATA_PASS_THRU_PROTOCOL        AtaPassThru;\r
+  EFI_EXT_SCSI_PASS_THRU_MODE       ExtScsiPassThruMode;\r
+  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   ExtScsiPassThru;\r
+\r
+  EFI_ATA_HC_WORK_MODE              Mode;\r
+\r
+  EFI_IDE_REGISTERS                 IdeRegisters[EfiIdeMaxChannel];\r
+  EFI_AHCI_REGISTERS                AhciRegisters;\r
+  \r
+  //\r
+  // The attached device list\r
+  //\r
+  LIST_ENTRY                        DeviceList;\r
+  UINT64                            OriginalPciAttributes;\r
+\r\r
+  //\r
+  // For AtaPassThru protocol, using the following bytes to record the previous call in \r
+  // GetNextPort()/GetNextDevice().\r
+  //\r
+  UINT16                            PreviousPort;\r
+  UINT16                            PreviousPortMultiplier;\r
+  //\r
+  // For ExtScsiPassThru protocol, using the following bytes to record the previous call in \r
+  // GetNextTarget()/GetNextTargetLun().\r
+  //\r
+  UINT16                            PreviousTargetId;\r
+  UINT64                            PreviousLun;\r
+\r
+} ATA_ATAPI_PASS_THRU_INSTANCE;\r
+\r
+//\r
+// Timeout value which uses 100ns as a unit.\r
+// It means 3 second span.\r
+//\r
+#define ATA_ATAPI_TIMEOUT           EFI_TIMER_PERIOD_SECONDS(3)\r
+\r
+#define IS_ALIGNED(addr, size)      (((UINTN) (addr) & (size - 1)) == 0)\r
+\r
+#define ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \\r
+  CR (a, \\r
+      ATA_ATAPI_PASS_THRU_INSTANCE, \\r
+      AtaPassThru, \\r
+      ATA_ATAPI_PASS_THRU_SIGNATURE \\r
+      )\r
+\r
+#define EXT_SCSI_PASS_THRU_PRIVATE_DATA_FROM_THIS(a) \\r
+  CR (a, \\r
+      ATA_ATAPI_PASS_THRU_INSTANCE, \\r
+      ExtScsiPassThru, \\r
+      ATA_ATAPI_PASS_THRU_SIGNATURE \\r
+      )\r
+\r
+#define ATA_ATAPI_DEVICE_INFO_FROM_THIS(a) \\r
+  CR (a, \\r
+      EFI_ATA_DEVICE_INFO, \\r
+      Link, \\r
+      ATA_ATAPI_DEVICE_SIGNATURE \\r
+      );\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided, \r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by \r
+  ControllerHandle. Drivers will typically use the device path attached to \r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to \r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function \r
+  may be called many times during platform initialization. In order to reduce boot times, the tests \r
+  performed by this function must be very small, and take as little time as possible to execute. This \r
+  function must not change the state of any hardware devices, and this function must be aware that the \r
+  device specified by ControllerHandle may already be managed by the same driver or a \r
+  different driver. This function must match its calls to AllocatePages() with FreePages(), \r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().  \r
+  Because ControllerHandle may have been previously started by the same driver, if a protocol is \r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required \r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For bus drivers, if this parameter is not NULL, then \r
+                                   the bus driver must determine if the bus controller specified \r
+                                   by ControllerHandle and the child controller specified \r
+                                   by RemainingDevicePath are both supported by this \r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN EFI_HANDLE                        Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this \r
+  common boot service. It is legal to call Start() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.  \r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle \r
+                                   must support a protocol interface that supplies \r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This \r
+                                   parameter is ignored by device drivers, and is optional for bus \r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles \r
+                                   for all the children of Controller are created by this driver.  \r
+                                   If this parameter is not NULL and the first Device Path Node is \r
+                                   not the End of Device Path Node, then only the handle for the \r
+                                   child device specified by the first Device Path Node of \r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is \r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL        *This,\r
+  IN EFI_HANDLE                         Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+  \r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). \r
+  As a result, much of the error checking on the parameters to Stop() has been moved \r
+  into this common boot service. It is legal to call Stop() from other locations, \r
+  but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+  \r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must \r
+                                support a bus specific I/O protocol for the driver \r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL \r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL       *This,\r
+  IN  EFI_HANDLE                        Controller,\r
+  IN  UINTN                             NumberOfChildren,\r
+  IN  EFI_HANDLE                        *ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Traverse the attached ATA devices list to find out the device to access.\r
+  \r
+  @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+  @param[in]  Port                The port number of the ATA device to send the command. \r
+  @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
+                                  If there is no port multiplier, then specify 0.\r
+  @param[in]  DeviceType          The device type of the ATA device.\r
+  \r
+  @retval     The pointer to the data structure of the device info to access.\r
+\r
+**/\r
+LIST_ENTRY *\r
+EFIAPI\r
+SearchDeviceInfoList (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN  UINT16                         Port,\r
+  IN  UINT16                         PortMultiplier,\r
+  IN  EFI_ATA_DEVICE_TYPE            DeviceType\r
+  );\r
+\r
+/**\r
+  Allocate device info data structure to contain device info.\r
+  And insert the data structure to the tail of device list for tracing.\r
+    \r
+  @param[in]  Instance            A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+  @param[in]  Port                The port number of the ATA device to send the command. \r
+  @param[in]  PortMultiplierPort  The port multiplier port number of the ATA device to send the command.\r
+                                  If there is no port multiplier, then specify 0.\r
+  @param[in]  DeviceType          The device type of the ATA device.\r
+  @param[in]  IdentifyData        The data buffer to store the output of the IDENTIFY cmd.\r
+\r
+  @retval EFI_SUCCESS             Successfully insert the ata device to the tail of device list.\r
+  @retval EFI_OUT_OF_RESOURCES    Can not allocate enough resource for use.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CreateNewDeviceInfo (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN  UINT16                         Port,\r
+  IN  UINT16                         PortMultiplier,\r
+  IN  EFI_ATA_DEVICE_TYPE            DeviceType,\r
+  IN  EFI_IDENTIFY_DATA              *IdentifyData\r
+  );\r
+\r
+/**\r
+  Destroy all attached ATA devices info.\r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DestroyDeviceInfoList (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance\r
+  );\r
+\r
+/**\r
+  Enumerate all attached ATA devices at IDE mode or AHCI mode separately.\r
+  \r
+  The function is designed to enumerate all attached ATA devices. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+  @retval EFI_SUCCESS           Successfully enumerate attached ATA devices.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnumerateAttachedDevice (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE      *Instance\r
+  );\r
+\r
+/**\r
+  Sends an ATA command to an ATA device that is attached to the ATA controller. This function\r
+  supports both blocking I/O and non-blocking I/O. The blocking I/O functionality is required,\r
+  and the non-blocking I/O functionality is optional.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. \r
+  @param[in]      Port               The port number of the ATA device to send the command. \r
+  @param[in]      PortMultiplierPort The port multiplier port number of the ATA device to send the command.\r
+                                     If there is no port multiplier, then specify 0.\r
+  @param[in, out] Packet             A pointer to the ATA command to send to the ATA device specified by Port\r
+                                     and PortMultiplierPort.\r
+  @param[in]      Event              If non-blocking I/O is not supported then Event is ignored, and blocking\r
+                                     I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                                     Event is not NULL and non blocking I/O is supported, then non-blocking\r
+                                     I/O is performed, and Event will be signaled when the ATA command completes.\r
+\r
+  @retval EFI_SUCCESS                The ATA command was sent by the host. For bi-directional commands, \r
+                                     InTransferLength bytes were transferred from InDataBuffer. For write and\r
+                                     bi-directional commands, OutTransferLength bytes were transferred by OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE        The ATA command was not executed. The number of bytes that could be transferred\r
+                                     is returned in InTransferLength. For write and bi-directional commands, \r
+                                     OutTransferLength bytes were transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY              The ATA command could not be sent because there are too many ATA commands\r
+                                     already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR           A device error occurred while attempting to send the ATA command.\r
+  @retval EFI_INVALID_PARAMETER      Port, PortMultiplierPort, or the contents of Acb are invalid. The ATA\r
+                                     command was not sent, so no additional status information is available.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruPassThru (\r
+  IN     EFI_ATA_PASS_THRU_PROTOCOL       *This,\r
+  IN     UINT16                           Port,\r
+  IN     UINT16                           PortMultiplierPort,\r
+  IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet,\r
+  IN     EFI_EVENT                        Event OPTIONAL\r
+  );\r
+\r
+/**\r
+  Used to retrieve the list of legal port numbers for ATA devices on an ATA controller.\r
+  These can either be the list of ports where ATA devices are actually present or the\r
+  list of legal port numbers for the ATA controller. Regardless, the caller of this\r
+  function must probe the port number returned to see if an ATA device is actually\r
+  present at that location on the ATA controller.\r
+\r
+  The GetNextPort() function retrieves the port number on an ATA controller. If on input\r
+  Port is 0xFFFF, then the port number of the first port on the ATA controller is returned\r
+  in Port and EFI_SUCCESS is returned.\r
+\r
+  If Port is a port number that was returned on a previous call to GetNextPort(), then the\r
+  port number of the next port on the ATA controller is returned in Port, and EFI_SUCCESS\r
+  is returned. If Port is not 0xFFFF and Port was not returned on a previous call to\r
+  GetNextPort(), then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If Port is the port number of the last port on the ATA controller, then EFI_NOT_FOUND is\r
+  returned.\r
+\r
+  @param[in]      This          A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance. \r
+  @param[in, out] Port          On input, a pointer to the port number on the ATA controller.\r
+                                On output, a pointer to the next port number on the ATA\r
+                                controller. An input value of 0xFFFF retrieves the first port\r
+                                number on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS           The next port number on the ATA controller was returned in Port.\r
+  @retval EFI_NOT_FOUND         There are no more ports on this ATA controller.\r
+  @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not returned on a previous call\r
+                                to GetNextPort().\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruGetNextPort (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN OUT UINT16                 *Port\r
+  );\r
+\r
+/**\r
+  Used to retrieve the list of legal port multiplier port numbers for ATA devices on a port of an ATA \r
+  controller. These can either be the list of port multiplier ports where ATA devices are actually \r
+  present on port or the list of legal port multiplier ports on that port. Regardless, the caller of this \r
+  function must probe the port number and port multiplier port number returned to see if an ATA \r
+  device is actually present.\r
+\r
+  The GetNextDevice() function retrieves the port multiplier port number of an ATA device \r
+  present on a port of an ATA controller.\r
+  \r
+  If PortMultiplierPort points to a port multiplier port number value that was returned on a \r
+  previous call to GetNextDevice(), then the port multiplier port number of the next ATA device\r
+  on the port of the ATA controller is returned in PortMultiplierPort, and EFI_SUCCESS is\r
+  returned.\r
+  \r
+  If PortMultiplierPort points to 0xFFFF, then the port multiplier port number of the first \r
+  ATA device on port of the ATA controller is returned in PortMultiplierPort and \r
+  EFI_SUCCESS is returned.\r
+  \r
+  If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMultiplierPort\r
+  was not returned on a previous call to GetNextDevice(), then EFI_INVALID_PARAMETER\r
+  is returned.\r
+  \r
+  If PortMultiplierPort is the port multiplier port number of the last ATA device on the port of \r
+  the ATA controller, then EFI_NOT_FOUND is returned.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]      Port               The port number present on the ATA controller.\r
+  @param[in, out] PortMultiplierPort On input, a pointer to the port multiplier port number of an\r
+                                     ATA device present on the ATA controller. \r
+                                     If on input a PortMultiplierPort of 0xFFFF is specified, \r
+                                     then the port multiplier port number of the first ATA device\r
+                                     is returned. On output, a pointer to the port multiplier port\r
+                                     number of the next ATA device present on an ATA controller.\r
+\r
+  @retval EFI_SUCCESS                The port multiplier port number of the next ATA device on the port\r
+                                     of the ATA controller was returned in PortMultiplierPort.\r
+  @retval EFI_NOT_FOUND              There are no more ATA devices on this port of the ATA controller.\r
+  @retval EFI_INVALID_PARAMETER      PortMultiplierPort is not 0xFFFF, and PortMultiplierPort was not\r
+                                     returned on a previous call to GetNextDevice().\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruGetNextDevice (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port,\r
+  IN OUT UINT16                 *PortMultiplierPort\r
+  );\r
+\r
+/**\r
+  Used to allocate and build a device path node for an ATA device on an ATA controller.\r
+\r
+  The BuildDevicePath() function allocates and builds a single device node for the ATA\r
+  device specified by Port and PortMultiplierPort. If the ATA device specified by Port and\r
+  PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FOUND is returned.\r
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there are not enough\r
+  resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is returned.\r
+\r
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+  DevicePath are initialized to describe the ATA device specified by Port and PortMultiplierPort,\r
+  and EFI_SUCCESS is returned.\r
+\r
+  @param[in]      This               A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]      Port               Port specifies the port number of the ATA device for which a\r
+                                     device path node is to be allocated and built.\r
+  @param[in]      PortMultiplierPort The port multiplier port number of the ATA device for which a\r
+                                     device path node is to be allocated and built. If there is no\r
+                                     port multiplier, then specify 0.\r
+  @param[in, out] DevicePath         A pointer to a single device path node that describes the ATA\r
+                                     device specified by Port and PortMultiplierPort. This function\r
+                                     is responsible for allocating the buffer DevicePath with the\r
+                                     boot service AllocatePool(). It is the caller's responsibility\r
+                                     to free DevicePath when the caller is finished with DevicePath.\r
+  @retval EFI_SUCCESS                The device path node that describes the ATA device specified by\r
+                                     Port and PortMultiplierPort was allocated and returned in DevicePath.\r
+  @retval EFI_NOT_FOUND              The ATA device specified by Port and PortMultiplierPort does not\r
+                                     exist on the ATA controller.\r
+  @retval EFI_INVALID_PARAMETER      DevicePath is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES       There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruBuildDevicePath (\r
+  IN     EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN     UINT16                     Port,\r
+  IN     UINT16                     PortMultiplierPort,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL   **DevicePath\r
+  );\r
+\r
+/**\r
+  Used to translate a device path node to a port number and port multiplier port number.\r
+\r
+  The GetDevice() function determines the port and port multiplier port number associated with\r
+  the ATA device described by DevicePath. If DevicePath is a device path node type that the\r
+  ATA Pass Thru driver supports, then the ATA Pass Thru driver will attempt to translate the contents \r
+  DevicePath into a port number and port multiplier port number.\r
+\r
+  If this translation is successful, then that port number and port multiplier port number are returned\r
+  in Port and PortMultiplierPort, and EFI_SUCCESS is returned.\r
+\r
+  If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If DevicePath is not a device path node type that the ATA Pass Thru driver supports, then \r
+  EFI_UNSUPPORTED is returned.\r
+\r
+  If DevicePath is a device path node type that the ATA Pass Thru driver supports, but there is not \r
+  a valid translation from DevicePath to a port number and port multiplier port number, then \r
+  EFI_NOT_FOUND is returned.\r
+\r
+  @param[in]  This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  DevicePath          A pointer to the device path node that describes an ATA device on the\r
+                                  ATA controller.\r
+  @param[out] Port                On return, points to the port number of an ATA device on the ATA controller.\r
+  @param[out] PortMultiplierPort  On return, points to the port multiplier port number of an ATA device\r
+                                  on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS             DevicePath was successfully translated to a port number and port multiplier\r
+                                  port number, and they were returned in Port and PortMultiplierPort.\r
+  @retval EFI_INVALID_PARAMETER   DevicePath is NULL.\r
+  @retval EFI_INVALID_PARAMETER   Port is NULL.\r
+  @retval EFI_INVALID_PARAMETER   PortMultiplierPort is NULL.\r
+  @retval EFI_UNSUPPORTED         This driver does not support the device path node type in DevicePath.\r
+  @retval EFI_NOT_FOUND           A valid translation from DevicePath to a port number and port multiplier\r
+                                  port number does not exist.\r
+**/\r
+EFI_STATUS\r
+AtaPassThruGetDevice (\r
+  IN  EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL   *DevicePath,\r
+  OUT UINT16                     *Port,\r
+  OUT UINT16                     *PortMultiplierPort\r
+  );\r
+\r
+/**\r
+  Resets a specific port on the ATA controller. This operation also resets all the ATA devices\r
+  connected to the port.\r
+\r
+  The ResetChannel() function resets an a specific port on an ATA controller. This operation\r
+  resets all the ATA devices connected to that port. If this ATA controller does not support\r
+  a reset port operation, then EFI_UNSUPPORTED is returned.\r
+\r
+  If a device error occurs while executing that port reset operation, then EFI_DEVICE_ERROR is\r
+  returned.\r
+\r
+  If a timeout occurs during the execution of the port reset operation, then EFI_TIMEOUT is returned.\r
+\r
+  If the port reset operation is completed, then EFI_SUCCESS is returned.\r
+\r
+  @param[in]  This          A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Port          The port number on the ATA controller.\r
+\r
+  @retval EFI_SUCCESS       The ATA controller port was reset.\r
+  @retval EFI_UNSUPPORTED   The ATA controller does not support a port reset operation.\r
+  @retval EFI_DEVICE_ERROR  A device error occurred while attempting to reset the ATA port.\r
+  @retval EFI_TIMEOUT       A timeout occurred while attempting to reset the ATA port.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruResetPort (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port\r
+  );\r
+\r
+/**\r
+  Resets an ATA device that is connected to an ATA controller.\r
+\r
+  The ResetDevice() function resets the ATA device specified by Port and PortMultiplierPort.\r
+  If this ATA controller does not support a device reset operation, then EFI_UNSUPPORTED is\r
+  returned.\r
+\r
+  If Port or PortMultiplierPort are not in a valid range for this ATA controller, then \r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  If a device error occurs while executing that device reset operation, then EFI_DEVICE_ERROR\r
+  is returned.\r
+\r
+  If a timeout occurs during the execution of the device reset operation, then EFI_TIMEOUT is\r
+  returned.\r
+\r
+  If the device reset operation is completed, then EFI_SUCCESS is returned.\r
+\r
+  @param[in] This                A pointer to the EFI_ATA_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Port                Port represents the port number of the ATA device to be reset.\r
+  @param[in] PortMultiplierPort  The port multiplier port number of the ATA device to reset.\r
+                                 If there is no port multiplier, then specify 0.\r
+  @retval EFI_SUCCESS            The ATA device specified by Port and PortMultiplierPort was reset.\r
+  @retval EFI_UNSUPPORTED        The ATA controller does not support a device reset operation.\r
+  @retval EFI_INVALID_PARAMETER  Port or PortMultiplierPort are invalid.\r
+  @retval EFI_DEVICE_ERROR       A device error occurred while attempting to reset the ATA device\r
+                                 specified by Port and PortMultiplierPort.\r
+  @retval EFI_TIMEOUT            A timeout occurred while attempting to reset the ATA device\r
+                                 specified by Port and PortMultiplierPort.\r
+\r
+**/\r
+EFI_STATUS\r
+AtaPassThruResetDevice (\r
+  IN EFI_ATA_PASS_THRU_PROTOCOL *This,\r
+  IN UINT16                     Port,\r
+  IN UINT16                     PortMultiplierPort\r
+  );\r
+\r
+/**\r
+  Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel. This function   \r
+  supports both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the\r
+  nonblocking I/O functionality is optional.                                                             \r
+\r
+  @param  This    A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target  The Target is an array of size TARGET_MAX_BYTES and it represents\r
+                  the id of the SCSI device to send the SCSI Request Packet. Each\r
+                  transport driver may choose to utilize a subset of this size to suit the needs\r
+                  of transport target representation. For example, a Fibre Channel driver\r
+                  may use only 8 bytes (WWN) to represent an FC target.\r
+  @param  Lun     The LUN of the SCSI device to send the SCSI Request Packet.\r
+  @param  Packet  A pointer to the SCSI Request Packet to send to the SCSI device\r
+                  specified by Target and Lun.\r
+  @param  Event   If nonblocking I/O is not supported then Event is ignored, and blocking\r
+                  I/O is performed. If Event is NULL, then blocking I/O is performed. If\r
+                  Event is not NULL and non blocking I/O is supported, then\r
+                  nonblocking I/O is performed, and Event will be signaled when the\r
+                  SCSI Request Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SCSI Request Packet was sent by the host. For bi-directional\r
+                                commands, InTransferLength bytes were transferred from\r
+                                InDataBuffer. For write and bi-directional commands,\r
+                                OutTransferLength bytes were transferred by\r
+                                OutDataBuffer.\r
+  @retval EFI_BAD_BUFFER_SIZE   The SCSI Request Packet was not executed. The number of bytes that\r
+                                could be transferred is returned in InTransferLength. For write\r
+                                and bi-directional commands, OutTransferLength bytes were\r
+                                transferred by OutDataBuffer.\r
+  @retval EFI_NOT_READY         The SCSI Request Packet could not be sent because there are too many\r
+                                SCSI Request Packets already queued. The caller may retry again later.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SCSI Request\r
+                                Packet.\r
+  @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket are invalid.\r
+  @retval EFI_UNSUPPORTED       The command described by the SCSI Request Packet is not supported\r
+                                by the host adapter. This includes the case of Bi-directional SCSI\r
+                                commands not supported by the implementation. The SCSI Request\r
+                                Packet was not sent, so no additional status information is available.\r
+  @retval EFI_TIMEOUT           A timeout occurred while waiting for the SCSI Request Packet to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruPassThru (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL                    *This,\r
+  IN UINT8                                              *Target,\r
+  IN UINT64                                             Lun,\r
+  IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET     *Packet,\r
+  IN EFI_EVENT                                          Event OPTIONAL\r
+  );\r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on a SCSI channel. These       \r
+  can either be the list SCSI devices that are actually present on the SCSI channel, or the list of legal\r
+  Target Ids and LUNs for the SCSI channel. Regardless, the caller of this function must probe the       \r
+  Target ID and LUN returned to see if a SCSI device is actually present at that location on the SCSI    \r
+  channel.                                                                                               \r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target On input, a pointer to the Target ID (an array of size\r
+                 TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+  @param  Lun    On input, a pointer to the LUN of a SCSI device present on the SCSI\r
+                 channel. On output, a pointer to the LUN of the next SCSI device present\r
+                 on a SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID and LUN of the next SCSI device on the SCSI\r
+                                channel was returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER Target array is not all 0xF, and Target and Lun were\r
+                                not returned on a previous call to GetNextTargetLun().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetNextTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target,\r
+  IN OUT UINT64                          *Lun\r
+  );\r
+\r
+/**\r
+  Used to allocate and build a device path node for a SCSI device on a SCSI channel.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target     The Target is an array of size TARGET_MAX_BYTES and it specifies the\r
+                     Target ID of the SCSI device for which a device path node is to be\r
+                     allocated and built. Transport drivers may chose to utilize a subset of\r
+                     this size to suit the representation of targets. For example, a Fibre\r
+                     Channel driver may use only 8 bytes (WWN) in the array to represent a\r
+                     FC target.\r
+  @param  Lun        The LUN of the SCSI device for which a device path node is to be\r
+                     allocated and built.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     specified by Target and Lun. This function is responsible for\r
+                     allocating the buffer DevicePath with the boot service\r
+                     AllocatePool(). It is the caller's responsibility to free\r
+                     DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SCSI device specified by\r
+                                Target and Lun was allocated and returned in\r
+                                DevicePath.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_NOT_FOUND         The SCSI devices specified by Target and Lun does not exist\r
+                                on the SCSI channel.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruBuildDevicePath (\r
+  IN     EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN     UINT8                              *Target,\r
+  IN     UINT64                             Lun,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL           **DevicePath\r
+  );\r
+\r
+/**\r
+  Used to translate a device path node to a Target ID and LUN.\r
+\r
+  @param  This       A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  DevicePath A pointer to a single device path node that describes the SCSI device\r
+                     on the SCSI channel.\r
+  @param  Target     A pointer to the Target Array which represents the ID of a SCSI device\r
+                     on the SCSI channel.\r
+  @param  Lun        A pointer to the LUN of a SCSI device on the SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           DevicePath was successfully translated to a Target ID and\r
+                                LUN, and they were returned in Target and Lun.\r
+  @retval EFI_INVALID_PARAMETER DevicePath or Target or Lun is NULL.\r
+  @retval EFI_NOT_FOUND         A valid translation from DevicePath to a Target ID and LUN\r
+                                does not exist.\r
+  @retval EFI_UNSUPPORTED       This driver does not support the device path node type in\r
+                                 DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetTargetLun (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL           *DevicePath,\r
+  OUT UINT8                              **Target,\r
+  OUT UINT64                             *Lun\r
+  );\r
+\r
+/**\r
+  Resets a SCSI channel. This operation resets all the SCSI devices connected to the SCSI channel.\r
+\r
+  @param  This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS      The SCSI channel was reset.\r
+  @retval EFI_DEVICE_ERROR A device error occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_TIMEOUT      A timeout occurred while attempting to reset the SCSI channel.\r
+  @retval EFI_UNSUPPORTED  The SCSI channel does not support a channel reset operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruResetChannel (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This\r
+  );\r
+  \r
+/**\r
+  Resets a SCSI logical unit that is connected to a SCSI channel.\r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target The Target is an array of size TARGET_MAX_BYTE and it represents the\r
+                 target port ID of the SCSI device containing the SCSI logical unit to\r
+                 reset. Transport drivers may chose to utilize a subset of this array to suit\r
+                 the representation of their targets.\r
+  @param  Lun    The LUN of the SCSI device to reset.\r
+\r
+  @retval EFI_SUCCESS           The SCSI device specified by Target and Lun was reset.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           A timeout occurred while attempting to reset the SCSI device\r
+                                specified by Target and Lun.\r
+  @retval EFI_UNSUPPORTED       The SCSI channel does not support a target reset operation.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to reset the SCSI device\r
+                                 specified by Target and Lun.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruResetTargetLun (\r
+  IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN UINT8                              *Target,\r
+  IN UINT64                             Lun\r
+  );     \r
+\r
+/**\r
+  Used to retrieve the list of legal Target IDs for SCSI devices on a SCSI channel. These can either     \r
+  be the list SCSI devices that are actually present on the SCSI channel, or the list of legal Target IDs\r
+  for the SCSI channel. Regardless, the caller of this function must probe the Target ID returned to     \r
+  see if a SCSI device is actually present at that location on the SCSI channel.                         \r
+\r
+  @param  This   A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.\r
+  @param  Target (TARGET_MAX_BYTES) of a SCSI device present on the SCSI channel.\r
+                 On output, a pointer to the Target ID (an array of\r
+                 TARGET_MAX_BYTES) of the next SCSI device present on a SCSI\r
+                 channel. An input value of 0xF(all bytes in the array are 0xF) in the\r
+                 Target array retrieves the Target ID of the first SCSI device present on a\r
+                 SCSI channel.\r
+\r
+  @retval EFI_SUCCESS           The Target ID of the next SCSI device on the SCSI\r
+                                channel was returned in Target.\r
+  @retval EFI_INVALID_PARAMETER Target or Lun is NULL.\r
+  @retval EFI_TIMEOUT           Target array is not all 0xF, and Target was not\r
+                                returned on a previous call to GetNextTarget().\r
+  @retval EFI_NOT_FOUND         There are no more SCSI devices on this SCSI channel.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExtScsiPassThruGetNextTarget (\r
+  IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,\r
+  IN OUT UINT8                           **Target\r
+  );\r
+\r
+/**\r
+  Initialize ATA host controller at IDE mode.\r
+  \r
+  The function is designed to initialize ATA host controller. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IdeModeInitialization (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance\r
+  );\r
+\r
+/**\r
+  Initialize ATA host controller at AHCI mode.\r
+  \r
+  The function is designed to initialize ATA host controller. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AhciModeInitialization (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf
new file mode 100644 (file)
index 0000000..be73bd9
--- /dev/null
@@ -0,0 +1,68 @@
+## @file\r
+#  AtaAtapiPassThru driver to provide native IDE/AHCI mode support.\r
+#\r
+#  This driver installs AtaPassThru and ExtScsiPassThru protocol in each ide/sata controller\r
+#  to access to all attached Ata/Atapi devices.\r
+#\r
+#  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\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
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = AtaAtapiPassThruDxe\r
+  FILE_GUID                      = 5E523CB4-D397-4986-87BD-A6DD8B22F455\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeAtaAtapiPassThru\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gAtaAtapiPassThruDriverBinding                         \r
+#  COMPONENT_NAME                =  gAtaAtapiPassThruComponentName\r
+#  COMPONENT_NAME2               =  gAtaAtapiPassThruComponentName2                         \r
+#\r
+#\r
+\r
+[Sources]\r
+  AtaAtapiPassThru.c\r
+  AtaAtapiPassThru.h\r
+  AhciMode.c\r
+  AhciMode.h\r
+  IdeMode.c\r
+  IdeMode.h\r
+  ComponentName.c\r
+  \r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+  TimerLib\r
+\r
+[Guids]\r
+\r
+[Protocols]\r
+  gEfiIdeControllerInitProtocolGuid             # BY_START\r
+  gEfiAtaPassThruProtocolGuid                   # BY_START\r
+  gEfiExtScsiPassThruProtocolGuid               # BY_START\r
+  gEfiDevicePathProtocolGuid                    # TO_START\r
+  gEfiPciIoProtocolGuid                         # TO_START\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/ComponentName.c
new file mode 100644 (file)
index 0000000..9419726
--- /dev/null
@@ -0,0 +1,251 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for AtaAtapiPassThru driver.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+\r
+#include "AtaAtapiPassThru.h"\r
+\r
+//\r
+// Driver name table \r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruDriverNameTable[] = {\r
+  { "eng;en", L"AtaAtapiPassThru Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// Controller name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruIdeControllerNameTable[] = {\r
+  { "eng;en", L"IDE Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mAtaAtapiPassThruAhciControllerNameTable[] = {\r
+  { "eng;en", L"AHCI Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gAtaAtapiPassThruComponentName = {\r
+  AtaAtapiPassThruComponentNameGetDriverName,\r
+  AtaAtapiPassThruComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gAtaAtapiPassThruComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) AtaAtapiPassThruComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) AtaAtapiPassThruComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mAtaAtapiPassThruDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gAtaAtapiPassThruComponentName)\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaAtapiPassThruComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_UNICODE_STRING_TABLE      *ControllerNameTable;\r
+  VOID                          *Interface;\r
+  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance;\r
+\r
+  if (Language == NULL || ControllerName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Make sure this driver is currently managing Controller Handle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gAtaAtapiPassThruDriverBinding.DriverBindingHandle,\r
+             &gEfiIdeControllerInitProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // AtaPassThru and ExtScsiPassThru should also be installed at the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiAtaPassThruProtocolGuid,\r
+                  &Interface,\r
+                  gAtaAtapiPassThruDriverBinding.DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Instance = ATA_PASS_THRU_PRIVATE_DATA_FROM_THIS (Interface);\r
+\r
+  if (Instance->Mode == EfiAtaIdeMode) {\r
+    ControllerNameTable = mAtaAtapiPassThruIdeControllerNameTable;\r
+  } else if (Instance->Mode == EfiAtaAhciMode) {\r
+    ControllerNameTable = mAtaAtapiPassThruAhciControllerNameTable;\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           ControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gAtaAtapiPassThruComponentName)\r
+           );\r
+}\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
new file mode 100644 (file)
index 0000000..d3eb940
--- /dev/null
@@ -0,0 +1,2524 @@
+/** @file\r
+  Header file for AHCI mode of ATA host controller.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+\r
+#include "AtaAtapiPassThru.h"\r
+\r
+/**\r
+  read a one-byte data from a IDE port.\r
+\r
+  @param  PciIo  The PCI IO protocol instance\r
+  @param  Port   The IDE Port number \r
+\r
+  @return  the one-byte data read from IDE port\r
+**/\r
+UINT8\r
+EFIAPI\r
+IdeReadPortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port\r
+  )\r
+{\r
+  UINT8 Data;\r
+\r
+  ASSERT (PciIo != NULL);\r
+\r
+  Data = 0;\r
+  //\r
+  // perform 1-byte data read from register\r
+  //\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+  return Data;\r
+}\r
+\r
+/**\r
+  write a 1-byte data to a specific IDE port.\r
+\r
+  @param  PciIo  The PCI IO protocol instance\r
+  @param  Port   The IDE port to be writen\r
+  @param  Data   The data to write to the port\r
+**/\r
+VOID\r
+EFIAPI\r
+IdeWritePortB (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT8                 Data\r
+  )\r
+{\r
+  ASSERT (PciIo != NULL);\r
+\r
+  //\r
+  // perform 1-byte data write to register\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint8,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+}\r
+\r
+/**\r
+  write a 1-word data to a specific IDE port.\r
+\r
+  @param  PciIo  PCI IO protocol instance\r
+  @param  Port   The IDE port to be writen\r
+  @param  Data   The data to write to the port\r
+**/\r
+VOID\r
+EFIAPI\r
+IdeWritePortW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT16                Data\r
+  )\r
+{\r
+  ASSERT (PciIo != NULL);\r
+\r
+  //\r
+  // perform 1-word data write to register\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\r
+}\r
+\r
+/**\r
+  write a 2-word data to a specific IDE port.\r
+\r
+  @param  PciIo  PCI IO protocol instance\r
+  @param  Port   The IDE port to be writen\r
+  @param  Data   The data to write to the port\r
+**/\r
+VOID\r
+EFIAPI\r
+IdeWritePortDW (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINT32                Data\r
+  )\r
+{\r
+  ASSERT (PciIo != NULL);\r
+\r
+  //\r
+  // perform 2-word data write to register\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthUint32,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              1,\r
+              &Data\r
+              );\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
+EFIAPI\r
+IdeWritePortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  IN  VOID                  *Buffer\r
+  )\r
+{\r
+  ASSERT (PciIo  != NULL);\r
+  ASSERT (Buffer != NULL);\r
+\r
+  //\r
+  // perform UINT16 data write to the FIFO\r
+  //\r
+  PciIo->Io.Write (\r
+              PciIo,\r
+              EfiPciIoWidthFifoUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              Count,\r
+              (UINT16 *) Buffer\r
+              );\r
+\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    Number of UINT16's to read\r
+  @param  Buffer   Pointer to the data buffer for read\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IdeReadPortWMultiple (\r
+  IN  EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN  UINT16                Port,\r
+  IN  UINTN                 Count,\r
+  IN  VOID                  *Buffer\r
+  )\r
+{\r
+  ASSERT (PciIo  != NULL);\r
+  ASSERT (Buffer != NULL);\r
+\r
+  //\r
+  // Perform UINT16 data read from FIFO\r
+  //\r
+  PciIo->Io.Read (\r
+              PciIo,\r
+              EfiPciIoWidthFifoUint16,\r
+              EFI_PCI_IO_PASS_THROUGH_BAR,\r
+              (UINT64) Port,\r
+              Count,\r
+              (UINT16 *) Buffer\r
+              );\r
+\r
+}\r
+\r
+/**\r
+  This function is used to analyze the Status Register and print out\r
+  some debug information and if there is ERR bit set in the Status\r
+  Register, the Error Register's value is also be parsed and print out.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DumpAllIdeRegisters (\r
+  IN     EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN     EFI_IDE_REGISTERS        *IdeRegisters,\r
+  IN OUT EFI_ATA_STATUS_BLOCK     *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_ATA_STATUS_BLOCK StatusBlock;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  ZeroMem (&StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+\r
+  StatusBlock.AtaStatus          = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+  StatusBlock.AtaError           = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+  StatusBlock.AtaSectorCount     = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
+  StatusBlock.AtaSectorCountExp  = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
+  StatusBlock.AtaSectorNumber    = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
+  StatusBlock.AtaSectorNumberExp = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
+  StatusBlock.AtaCylinderLow     = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
+  StatusBlock.AtaCylinderLowExp  = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
+  StatusBlock.AtaCylinderHigh    = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
+  StatusBlock.AtaCylinderHighExp = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
+  StatusBlock.AtaDeviceHead      = IdeReadPortB (PciIo, IdeRegisters->Head);\r
+\r
+  if (AtaStatusBlock != NULL) {\r
+    //\r
+    // Dump the content of all ATA registers.\r
+    //\r
+    CopyMem (AtaStatusBlock, &StatusBlock, sizeof (EFI_ATA_STATUS_BLOCK));\r
+  }\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+  if ((StatusBlock.AtaStatus & ATA_STSREG_DWF) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", StatusBlock.AtaStatus));\r
+  }\r
+\r
+  if ((StatusBlock.AtaStatus & ATA_STSREG_CORR) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", StatusBlock.AtaStatus));\r
+  }\r
+\r
+  if ((StatusBlock.AtaStatus & ATA_STSREG_ERR) != 0) {\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_BBK) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", StatusBlock.AtaError));\r
+    }\r
+\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_UNC) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", StatusBlock.AtaError));\r
+    }\r
+\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_MC) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", StatusBlock.AtaError));\r
+    }\r
+\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_ABRT) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", StatusBlock.AtaError));\r
+    }\r
+\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_TK0NF) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", StatusBlock.AtaError));\r
+    }\r
+\r
+    if ((StatusBlock.AtaError & ATA_ERRREG_AMNF) != 0) {\r
+      DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", StatusBlock.AtaError));\r
+    }\r
+  }\r
+  DEBUG_CODE_END ();\r
+}\r
+\r
+/**\r
+  This function is used to analyze the Status Register and print out\r
+  some debug information and if there is ERR bit set in the Status\r
+  Register, the Error Register's value is also be parsed and print out.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+\r
+  @retval EFI_SUCCESS       No err information in the Status Register.\r
+  @retval EFI_DEVICE_ERROR  Any err information in the Status Register.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CheckStatusRegister (\r
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN  EFI_IDE_REGISTERS        *IdeRegisters\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINT8           StatusRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+\r
+  if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\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
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS     DRQ bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT     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
+EFIAPI\r
+DRQClear (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+\r
+    //\r
+    // wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    //  Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\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 PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS     DRQ bit clear within the time out.\r
+\r
+  @retval EFI_TIMEOUT     DRQ bit not clear within the time out.\r
+  @note   Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DRQClear2 (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+\r
+    //\r
+    //  wait for BSY == 0 and DRQ == 0\r
+    //\r
+    if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\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
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS          DRQ bit set within the time out.\r
+  @retval EFI_TIMEOUT          DRQ bit not set within the time out.\r
+  @retval EFI_ABORTED          DRQ bit not set caused by the command abort.\r
+\r
+  @note  Read Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DRQReady (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    //\r
+    //  read Status Register will clear interrupt\r
+    //\r
+    StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+\r
+    //\r
+    //  BSY==0,DRQ==1\r
+    //\r
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
+  DRQ is set when the device is ready to transfer data. So this function is called after \r
+  the command is sent to the device and before required data is transferred.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS           DRQ bit set within the time out.\r
+  @retval EFI_TIMEOUT           DRQ bit not set within the time out.\r
+  @retval EFI_ABORTED           DRQ bit not set caused by the command abort.\r
+  @note  Read Alternate Status Register will not clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DRQReady2 (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+\r
+  do {\r
+    //\r
+    //  Read Alternate Status Register will not clear interrupt status\r
+    //\r
+    AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    //\r
+    // BSY == 0 , DRQ == 1\r
+    //\r
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
+  bit is set when the device is ready to accept command. Most ATA commands must be \r
+  sent after DRDY set except the ATAPI Packet Command.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS         DRDY bit set within the time out.\r
+  @retval EFI_TIMEOUT         DRDY bit not set within the time out.\r
+\r
+  @note  Read Status Register will clear interrupt status.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DRDYReady (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the DRDY bit set in the Alternate Status Register. \r
+  DRDY bit is set when the device is ready to accept command. Most ATA commands must \r
+  be sent after DRDY set except the ATAPI Packet Command.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS      DRDY bit set within the time out.\r
+  @retval EFI_TIMEOUT      DRDY bit not set within the time out.\r
+\r
+  @note  Read Alternate Status Register will clear interrupt status.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DRDYReady2 (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltRegister;\r
+  UINT8   ErrorRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    //\r
+    //  BSY == 0 , DRDY == 1\r
+    //\r
+    if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
+      break;\r
+    }\r
+\r
+    if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
+      ErrorRegister = IdeReadPortB (PciIo, IdeRegisters->ErrOrFeature);\r
+\r
+      if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
+        return EFI_ABORTED;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the BSY bit clear in the Status Register. BSY\r
+  is clear when the device is not busy. Every command must be sent after device is not busy.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS          BSY bit clear within the time out.\r
+  @retval EFI_TIMEOUT          BSY bit not clear within the time out.\r
+\r
+  @note Read Status Register will clear interrupt status.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WaitForBSYClear (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   StatusRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    StatusRegister = IdeReadPortB (PciIo, IdeRegisters->CmdOrStatus);\r
+\r
+    if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to poll for the BSY bit clear in the Status Register. BSY\r
+  is clear when the device is not busy. Every command must be sent after device is not busy.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS          BSY bit clear within the time out.\r
+  @retval EFI_TIMEOUT          BSY bit not clear within the time out.\r
+\r
+  @note Read Status Register will clear interrupt status.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WaitForBSYClear2 (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT32  Delay;\r
+  UINT8   AltStatusRegister;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+\r
+  Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);\r
+  do {\r
+    AltStatusRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+\r
+    if ((AltStatusRegister & ATA_STSREG_BSY) == 0x00) {\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Stall for 100 microseconds.\r
+    //\r
+    MicroSecondDelay (100);\r
+\r
+    Delay--;\r
+\r
+  } while (Delay > 0);\r
+\r
+  if (Delay == 0) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get IDE i/o port registers' base addresses by mode. \r
+\r
+  In 'Compatibility' mode, use fixed addresses.\r
+  In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's\r
+  Configuration Space.\r
+\r
+  The steps to get IDE i/o 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
+  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
+\r
+  @param[in]      PciIo          Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param[in, out] IdeRegisters    Pointer to EFI_IDE_REGISTERS which is used to\r
+                                 store the IDE i/o port registers' base addresses\r
+           \r
+  @retval EFI_UNSUPPORTED        Return this value when the BARs is not IO type\r
+  @retval EFI_SUCCESS            Get the Base address successfully\r
+  @retval Other                  Read the pci configureation data error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetIdeRegisterIoAddr (\r
+  IN     EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN OUT EFI_IDE_REGISTERS           *IdeRegisters\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  PCI_TYPE00        PciData;\r
+  UINT16            CommandBlockBaseAddr;\r
+  UINT16            ControlBlockBaseAddr;\r
+  UINT16            BusMasterBaseAddr;\r
+\r
+  if ((PciIo == NULL) || (IdeRegisters == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        0,\r
+                        sizeof (PciData),\r
+                        &PciData\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BusMasterBaseAddr    = (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
+    CommandBlockBaseAddr = 0x1f0;\r
+    ControlBlockBaseAddr = 0x3f6;\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
+        (PciData.Device.Bar[1] & BIT0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
+    ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
+  }\r
+\r
+  //\r
+  // Calculate IDE primary channel I/O register base address.\r
+  //\r
+  IdeRegisters[EfiIdePrimary].Data              = CommandBlockBaseAddr;\r
+  IdeRegisters[EfiIdePrimary].ErrOrFeature      = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+  IdeRegisters[EfiIdePrimary].SectorCount       = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+  IdeRegisters[EfiIdePrimary].SectorNumber      = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+  IdeRegisters[EfiIdePrimary].CylinderLsb       = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+  IdeRegisters[EfiIdePrimary].CylinderMsb       = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+  IdeRegisters[EfiIdePrimary].Head              = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+  IdeRegisters[EfiIdePrimary].CmdOrStatus       = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+  IdeRegisters[EfiIdePrimary].AltOrDev          = ControlBlockBaseAddr;\r
+  IdeRegisters[EfiIdePrimary].BusMasterBaseAddr = BusMasterBaseAddr;\r
+\r
+  if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
+    CommandBlockBaseAddr = 0x170;\r
+    ControlBlockBaseAddr = 0x376;\r
+  } else {\r
+    //\r
+    // The BARs should be of IO type\r
+    //\r
+    if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
+        (PciData.Device.Bar[3] & BIT0) == 0) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    CommandBlockBaseAddr = (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
+    ControlBlockBaseAddr = (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
+  }\r
+\r
+  //\r
+  // Calculate IDE secondary channel I/O register base address.\r
+  //\r
+  IdeRegisters[EfiIdeSecondary].Data              = CommandBlockBaseAddr;\r
+  IdeRegisters[EfiIdeSecondary].ErrOrFeature      = (UINT16) (CommandBlockBaseAddr + 0x01);\r
+  IdeRegisters[EfiIdeSecondary].SectorCount       = (UINT16) (CommandBlockBaseAddr + 0x02);\r
+  IdeRegisters[EfiIdeSecondary].SectorNumber      = (UINT16) (CommandBlockBaseAddr + 0x03);\r
+  IdeRegisters[EfiIdeSecondary].CylinderLsb       = (UINT16) (CommandBlockBaseAddr + 0x04);\r
+  IdeRegisters[EfiIdeSecondary].CylinderMsb       = (UINT16) (CommandBlockBaseAddr + 0x05);\r
+  IdeRegisters[EfiIdeSecondary].Head              = (UINT16) (CommandBlockBaseAddr + 0x06);\r
+  IdeRegisters[EfiIdeSecondary].CmdOrStatus       = (UINT16) (CommandBlockBaseAddr + 0x07);\r
+  IdeRegisters[EfiIdeSecondary].AltOrDev          = ControlBlockBaseAddr;\r
+  IdeRegisters[EfiIdeSecondary].BusMasterBaseAddr = BusMasterBaseAddr + 0x8;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\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
+\r
+  This function can also be used by the ATAPI device to perform reset when\r
+  ATAPI Reset command is failed.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval EFI_SUCCESS       Soft reset completes successfully.\r
+  @retval EFI_DEVICE_ERROR  Any step during the reset process is failed.\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
+EFIAPI\r
+AtaSoftReset (\r
+  IN  EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN  EFI_IDE_REGISTERS    *IdeRegisters,\r
+  IN  UINT64               Timeout\r
+  )\r
+{\r
+  UINT8 DeviceControl;\r
+\r
+  DeviceControl = 0;\r
+  //\r
+  // disable Interrupt and set SRST bit to initiate soft reset\r
+  //\r
+  DeviceControl = ATA_CTLREG_SRST | ATA_CTLREG_IEN_L;\r
+\r
+  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+\r
+  //\r
+  // SRST should assert for at least 5 us, we use 10 us for\r
+  // better compatibility\r
+  //\r
+  MicroSecondDelay (10);\r
+\r
+  //\r
+  // Enable interrupt to support UDMA, and clear SRST bit\r
+  //\r
+  DeviceControl = 0;\r
+  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+\r
+  //\r
+  // Wait for at least 10 ms to check BSY status, we use 10 ms\r
+  // for better compatibility\r
+  //  \r
+  MicroSecondDelay (10000);\r
+\r
+  //\r
+  // slave device needs at most 31ms to clear BSY\r
+  //\r
+  if (WaitForBSYClear (PciIo, IdeRegisters, Timeout) == EFI_TIMEOUT) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send ATA Ext command into device with NON_DATA protocol.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+\r
+  @retval  EFI_SUCCESS Reading succeed\r
+  @retval  EFI_DEVICE_ERROR Error executing commands on this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaIssueCommand (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN  EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       DeviceHead;\r
+  UINT8       AtaCommand;\r
+\r
+  ASSERT (PciIo != NULL);\r
+  ASSERT (IdeRegisters != NULL);\r
+  ASSERT (AtaCommandBlock != NULL);\r
+\r
+  DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
+  AtaCommand = AtaCommandBlock->AtaCommand;\r
+\r
+  Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\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 (PciIo, IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));\r
+\r
+  //\r
+  // set all the command parameters\r
+  // Before write to all the following registers, BSY and DRQ must be 0.\r
+  //\r
+  Status = DRQClear2 (PciIo, IdeRegisters, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);\r
+  IdeWritePortB (PciIo, IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);\r
+\r
+  //\r
+  // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
+  //\r
+  IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);\r
+  IdeWritePortB (PciIo, IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);\r
+\r
+  //\r
+  // Fill the start LBA registers, which are also two-byte FIFO\r
+  //\r
+  IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);\r
+  IdeWritePortB (PciIo, IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);\r
+\r
+  IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);\r
+  IdeWritePortB (PciIo, IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);\r
+\r
+  IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);\r
+  IdeWritePortB (PciIo, IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);\r
+\r
+  //\r
+  // Send command via Command Register\r
+  //\r
+  IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, AtaCommand);\r
+\r
+  //\r
+  // Stall at least 400 microseconds.\r
+  //\r
+  MicroSecondDelay (400);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Buffer           A pointer to the source buffer for the data.\r
+  @param ByteCount        The length of  the data.\r
+  @param Read             Flag used to determine the data transfer direction.\r
+                          Read equals 1, means data transferred from device to host;\r
+                          Read equals 0, means data transferred from host to device.  \r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+  \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
+EFIAPI\r
+AtaPioDataInOut (  \r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN OUT VOID                      *Buffer,\r
+  IN     UINT64                    ByteCount,\r
+  IN     BOOLEAN                   Read,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  )\r
+{\r
+  UINTN       WordCount;\r
+  UINTN       Increment;\r
+  UINT16      *Buffer16;\r
+  EFI_STATUS  Status;\r
+\r
+  if ((PciIo == NULL) || (IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Issue ATA command\r
+  //\r
+  Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\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
+  // The data size of "a series of read" is command specific.\r
+  // For most ATA command, data size received from device will not exceed\r
+  // 1 sector, hence the data size for "a series of read" can be the whole data\r
+  // size of one command request.\r
+  // For ATA command such as Read Sector command, the data size of one ATA\r
+  // command request is often larger than 1 sector, according to the\r
+  // Read Sector command, the data size of "a series of read" is exactly 1\r
+  // sector.\r
+  // Here for simplification reason, we specify the data size for\r
+  // "a series of read" to 1 sector (256 words) if data size of one ATA command\r
+  // request is larger than 256 words.\r
+  //\r
+  Increment = 256;\r
+\r
+  //\r
+  // used to record bytes of currently transfered data\r
+  //\r
+  WordCount = 0;\r
+\r
+  while (WordCount < RShiftU64(ByteCount, 1)) {\r
+    //\r
+    // Poll DRQ bit set, data transfer can be performed only when DRQ is ready\r
+    //\r
+    Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
+    if (EFI_ERROR (Status)) {      \r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Get the byte count for one series of read\r
+    //\r
+    if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {\r
+      Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);\r
+    }\r
+\r
+    if (Read) {\r
+      IdeReadPortWMultiple (\r
+        PciIo,\r
+        IdeRegisters->Data,\r
+        Increment,\r
+        Buffer16\r
+        );\r
+    } else {\r
+      IdeWritePortWMultiple (\r
+        PciIo,\r
+        IdeRegisters->Data,\r
+        Increment,\r
+        Buffer16\r
+        );\r
+    }\r
+\r
+    Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Exit;\r
+    }\r
+\r
+    WordCount += Increment;\r
+    Buffer16  += Increment;\r
+  }\r
+\r
+  Status = DRQClear (PciIo, IdeRegisters, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+Exit:\r
+  //\r
+  // Dump All Ide registers to ATA_STATUS_BLOCK\r
+  //\r
+  DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send ATA command into device with NON_DATA protocol\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+\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
+EFIAPI\r
+AtaNonDataCommandIn (  \r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((PciIo == NULL) || (IdeRegisters == NULL) || (AtaCommandBlock == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Issue ATA command\r
+  //\r
+  Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Wait for command completion\r
+  //\r
+  Status = WaitForBSYClear (PciIo, IdeRegisters, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+  \r
+  Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+Exit:\r
+  //\r
+  // Dump All Ide registers to ATA_STATUS_BLOCK\r
+  //\r
+  DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Read             Flag used to determine the data transfer direction.\r
+                          Read equals 1, means data transferred from device to host;\r
+                          Read equals 0, means data transferred from host to device.\r
+  @param DataBuffer       A pointer to the source buffer for the data.\r
+  @param DataLength       The length of  the data.\r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+\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
+EFIAPI\r
+AtaUdmaInOut (\r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN     BOOLEAN                   Read,\r
+  IN     VOID                      *DataBuffer,\r
+  IN     UINT64                    DataLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINT16                        IoPortForBmic;\r
+  UINT16                        IoPortForBmis;\r
+  UINT16                        IoPortForBmid;\r
+\r
+  UINT8                         RegisterValue;\r
+\r
+  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
+  UINTN                         PrdTableNum;\r
+  UINTN                         PrdTableSize;\r
+  EFI_PHYSICAL_ADDRESS          PrdTableMapAddr;\r
+  VOID                          *PrdTableMap;\r
+\r
+  UINTN                         PageCount;\r
+  UINTN                         ByteCount;\r
+  UINTN                         ByteRemaining;\r
+\r
+  UINT8                         DeviceControl;\r
+\r
+  VOID                          *BufferMap;\r
+  EFI_PHYSICAL_ADDRESS          BufferMapAddress;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION PciIoOperation;\r
+\r
+  UINT8                         DeviceHead;\r
+  UINT8                         AtaCommand;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  PrdBaseAddr = NULL;\r
+\r
+  if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // The data buffer should be even alignment\r
+  //\r
+  if (((UINTN)DataBuffer & 0x1) != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Calculate the number of PRD entry.\r
+  // Every entry in PRD table can specify a 64K memory region.\r
+  //\r
+  PrdTableNum   = (UINTN)(RShiftU64(DataLength, 16) + 1);\r
+\r
+  //\r
+  // Make sure that the memory region of PRD table is not cross 64K boundary\r
+  //\r
+  PrdTableSize = PrdTableNum * sizeof (EFI_ATA_DMA_PRD);\r
+  if (PrdTableSize > 0x10000) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for PRD table initialization.\r
+  //\r
+  PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+  Status    = PciIo->AllocateBuffer (\r
+                       PciIo,\r
+                       AllocateAnyPages,\r
+                       EfiBootServicesData,\r
+                       PageCount,\r
+                       &PrdBaseAddr,\r
+                       0\r
+                       );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+  Status    = PciIo->Map (\r
+                       PciIo,\r
+                       EfiPciIoOperationBusMasterCommonBuffer,\r
+                       PrdBaseAddr,\r
+                       &ByteCount,\r
+                       &PrdTableMapAddr,\r
+                       &PrdTableMap\r
+                       );\r
+  if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+    //\r
+    // If the data length actually mapped is not equal to the requested amount,\r
+    // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
+    // Can't handle this case.\r
+    //\r
+    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
+\r
+  //\r
+  // Map the host address of DataBuffer to DMA master address.\r
+  //\r
+  if (Read) {\r
+    PciIoOperation = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    PciIoOperation = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  ByteCount = DataLength;\r
+  Status    = PciIo->Map (\r
+                       PciIo,\r
+                       PciIoOperation,\r
+                       DataBuffer,\r
+                       &ByteCount,\r
+                       &BufferMapAddress,\r
+                       &BufferMap\r
+                       );\r
+  if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
+    PciIo->Unmap (PciIo, PrdTableMap);\r
+    PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // According to Ata spec, it requires the buffer address and size to be even.\r
+  //\r
+  ASSERT ((BufferMapAddress & 0x1) == 0);\r
+  ASSERT ((ByteCount & 0x1) == 0);\r
+\r
+  //\r
+  // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
+  //\r
+  ByteRemaining = ByteCount;\r
+  while (ByteRemaining != 0) {\r
+    if (ByteRemaining <= 0x10000) {\r
+      PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
+      PrdBaseAddr->ByteCount      = (UINT16) ByteRemaining;\r
+      PrdBaseAddr->EndOfTable     = 0x8000;\r
+      break;\r
+    }\r
+\r
+    PrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
+    PrdBaseAddr->ByteCount      = (UINT16) 0x0;\r
+\r
+    ByteRemaining    -= 0x10000;\r
+    BufferMapAddress += 0x10000;\r
+    PrdBaseAddr++;\r
+  }\r
+\r
+  //\r
+  // Start to enable the DMA operation\r
+  //\r
+  DeviceHead = AtaCommandBlock->AtaDeviceHead;\r
+  AtaCommand = AtaCommandBlock->AtaCommand;\r
+\r
+  IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | DeviceHead));\r
+\r
+  //\r
+  // Enable interrupt to support UDMA\r
+  //\r
+  DeviceControl = 0;\r
+  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+\r
+  IoPortForBmic = IdeRegisters->BusMasterBaseAddr + BMIC_OFFSET;\r
+  IoPortForBmis = IdeRegisters->BusMasterBaseAddr + BMIS_OFFSET;\r
+  IoPortForBmid = IdeRegisters->BusMasterBaseAddr + BMID_OFFSET;\r
+\r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+\r
+  //\r
+  // Set the base address to BMID register\r
+  //\r
+  IdeWritePortDW(PciIo, IoPortForBmid, (UINT32)PrdTableMapAddr);\r
+\r
+  //\r
+  // Set BMIC register to identify the operation direction\r
+  //\r
+  RegisterValue = IdeReadPortB(PciIo, IoPortForBmic);\r
+  if (Read) {\r
+    RegisterValue |= BMIC_NREAD;\r
+  } else {\r
+    RegisterValue &= ~((UINT8) BMIC_NREAD);\r
+  }\r
+  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+\r
+  //\r
+  // Issue ATA command\r
+  //\r
+  Status = AtaIssueCommand (PciIo, IdeRegisters, AtaCommandBlock, Timeout);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Set START bit of BMIC register\r
+  //\r
+  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+  RegisterValue |= BMIC_START;\r
+  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+\r
+  //\r
+  // Check the INTERRUPT and ERROR bit of BMIS\r
+  // Max transfer number of sectors for one command is 65536(32Mbyte),\r
+  // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
+  // So set the variable Count to 2000, for about 2 second Timeout time.\r
+  //\r
+  Timeout = 2000;\r
+  while (TRUE) {\r
+    RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+\r
+    if (((RegisterValue & BMIS_ERROR) != 0) || (Timeout == 0)) {\r
+      DEBUG ((EFI_D_ERROR, "ATA UDMA operation fails\n"));\r
+      Status = EFI_DEVICE_ERROR;\r
+      break;\r
+    }\r
+\r
+    if ((RegisterValue & BMIS_INTERRUPT) != 0) {\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+    //\r
+    // Stall for 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+    Timeout--;\r
+  }\r
+\r
+  //\r
+  // Read BMIS register and clear ERROR and INTR bit\r
+  //\r
+  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmis);\r
+  RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
+  IdeWritePortB(PciIo, IoPortForBmis, RegisterValue);\r
+\r
+  //\r
+  // Read Status Register of IDE device to clear interrupt\r
+  //\r
+  RegisterValue  = IdeReadPortB(PciIo, IdeRegisters->CmdOrStatus);\r
+\r
+  //\r
+  // Clear START bit of BMIC register\r
+  //\r
+  RegisterValue  = IdeReadPortB(PciIo, IoPortForBmic);\r
+  RegisterValue &= ~((UINT8) BMIC_START);\r
+  IdeWritePortB(PciIo, IoPortForBmic, RegisterValue);\r
+\r
+  //\r
+  // Disable interrupt of Select device\r
+  //\r
+  DeviceControl  = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+  DeviceControl |= ATA_CTLREG_IEN_L;\r
+  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, DeviceControl);\r
+  //\r
+  // Stall for 10 milliseconds.\r
+  //\r
+  MicroSecondDelay (10000);\r
+\r
+Exit:\r
+  //\r
+  // Free all allocated resource\r
+  //\r
+  PciIo->Unmap (PciIo, PrdTableMap);\r
+  PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+  PciIo->Unmap (PciIo, BufferMap);\r
+\r
+  //\r
+  // Dump All Ide registers to ATA_STATUS_BLOCK\r
+  //\r
+  DumpAllIdeRegisters (PciIo, IdeRegisters, AtaStatusBlock);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function reads the pending data in the device.\r
+\r
+  @param PciIo         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters  A pointer to EFI_IDE_REGISTERS data structure.\r
+\r
+  @retval EFI_SUCCESS   Successfully read.\r
+  @retval EFI_NOT_READY The BSY is set avoiding reading.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketReadPendingData (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  EFI_IDE_REGISTERS         *IdeRegisters\r
+  )\r
+{\r
+  UINT8     AltRegister;\r
+  UINT16    TempWordBuffer;\r
+\r
+  AltRegister = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+  if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+    TempWordBuffer = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
+      IdeReadPortWMultiple (\r
+        PciIo,\r
+        IdeRegisters->Data, \r
+        1, \r
+        &TempWordBuffer\r
+        );\r
+      TempWordBuffer = IdeReadPortB (PciIo, IdeRegisters->AltOrDev);\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function is called by AtaPacketCommandExecute(). \r
+  It is used to transfer data between host and device. The data direction is specified\r
+  by the fourth parameter.\r
+\r
+  @param PciIo         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters  A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Buffer        Buffer contained data transferred between host and device.\r
+  @param ByteCount     Data size in byte unit of the buffer.\r
+  @param Read          Flag used to determine the data transfer direction.\r
+                       Read equals 1, means data transferred from device to host;\r
+                       Read equals 0, means data transferred from host to device.\r
+  @param Timeout       Timeout value for wait DRQ ready before each data stream's transfer.\r
+\r
+  @retval EFI_SUCCESS      data is transferred successfully.\r
+  @retval EFI_DEVICE_ERROR the device failed to transfer data.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketReadWrite (\r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN OUT VOID                      *Buffer,\r
+  IN     UINT64                    ByteCount,\r
+  IN     BOOLEAN                   Read,\r
+  IN     UINT64                    Timeout\r
+  )\r
+{\r
+  UINT32      RequiredWordCount;\r
+  UINT32      ActualWordCount;\r
+  UINT32      WordCount;\r
+  EFI_STATUS  Status;\r
+  UINT16      *PtrBuffer;\r
+\r
+  //\r
+  // No data transfer is premitted.\r
+  //\r
+  if (ByteCount == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  PtrBuffer         = Buffer;\r
+  RequiredWordCount = (UINT32)RShiftU64(ByteCount, 1);\r
+  //\r
+  // ActuralWordCount means the word count of data really transferred.\r
+  //\r
+  ActualWordCount = 0;\r
+\r
+  while (ActualWordCount < RequiredWordCount) {\r
+    //\r
+    // before each data transfer stream, the host should poll DRQ bit ready,\r
+    // to see whether indicates device is ready to transfer data.\r
+    //\r
+    Status = DRQReady2 (PciIo, IdeRegisters, Timeout);\r
+    if (EFI_ERROR (Status)) {\r
+      CheckStatusRegister (PciIo, IdeRegisters);\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    //\r
+    // get current data transfer size from Cylinder Registers.\r
+    //\r
+    WordCount  = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb) << 8;\r
+    WordCount  = WordCount | IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
+    WordCount  = WordCount & 0xffff;\r
+    WordCount /= 2;\r
+\r
+    WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));\r
+\r
+    if (Read) {\r
+      IdeReadPortWMultiple (\r
+        PciIo,\r
+        IdeRegisters->Data,\r
+        WordCount,\r
+        PtrBuffer\r
+        );\r
+    } else {\r
+      IdeWritePortWMultiple (\r
+        PciIo,\r
+        IdeRegisters->Data,\r
+        WordCount,\r
+        PtrBuffer\r
+        );\r
+    }\r
+\r
+    //\r
+    // read status register to check whether error happens.\r
+    //\r
+    Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    PtrBuffer       += WordCount;\r
+    ActualWordCount += WordCount;\r
+  }\r
+  \r
+  if (Read) {\r
+    //\r
+    // In the case where the drive wants to send more data than we need to read,\r
+    // the DRQ bit will be set and cause delays from DRQClear2().\r
+    // We need to read data from the drive until it clears DRQ so we can move on.\r
+    //\r
+    AtaPacketReadPendingData (PciIo, IdeRegisters);\r
+  }\r
+\r
+  //\r
+  // read status register to check whether error happens.\r
+  //\r
+  Status = CheckStatusRegister (PciIo, IdeRegisters);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // After data transfer is completed, normally, DRQ bit should clear.\r
+  //\r
+  Status = DRQClear2 (PciIo, IdeRegisters, Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sumbit ATAPI request sense command.\r
+\r
+  @param[in] PciIo           Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param[in] IdeRegisters    Pointer to EFI_IDE_REGISTERS which is used to\r
+                             store the IDE i/o port registers' base addresses\r
+  @param[in] Channel         The channel number of device.\r
+  @param[in] Device          The device number of device.\r
+  @param[in] SenseData       A pointer to store sense data.\r
+  @param[in] SenseDataLength The sense data length.\r
+  @param[in] Timeout         The timeout value to execute this cmd.\r
+\r
+  @retval EFI_SUCCESS        Send out the ATAPI packet command successfully.\r
+  @retval EFI_DEVICE_ERROR   The device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketRequestSense (\r
+  IN  EFI_PCI_IO_PROTOCOL               *PciIo,\r
+  IN  EFI_IDE_REGISTERS                 *IdeRegisters,\r
+  IN  UINT8                             Channel,\r
+  IN  UINT8                             Device,\r
+  IN  VOID                              *SenseData,\r
+  IN  UINT8                             SenseDataLength,\r
+  IN  UINT64                            Timeout\r
+  )\r
+{\r
+  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  Packet;\r
+  UINT8                                       Cdb[12];\r
+  EFI_STATUS                                  Status;\r
+\r
+  ZeroMem (&Packet, sizeof (EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
+  ZeroMem (Cdb, 12);\r
+\r
+  Cdb[0] = ATA_CMD_REQUEST_SENSE;\r
+  Cdb[4] = SenseDataLength;\r
+\r
+  Packet.Timeout          = Timeout;\r
+  Packet.Cdb              = Cdb;\r
+  Packet.CdbLength        = 12;\r
+  Packet.DataDirection    = EFI_EXT_SCSI_DATA_DIRECTION_READ;\r
+  Packet.InDataBuffer     = SenseData;\r
+  Packet.InTransferLength = SenseDataLength;\r
+\r
+  Status = AtaPacketCommandExecute (PciIo, IdeRegisters, Channel, Device, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the Packet Command \r
+  with PIO Data In Protocol.\r
+\r
+  @param[in] PciIo          Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param[in] IdeRegisters   Pointer to EFI_IDE_REGISTERS which is used to\r
+                            store the IDE i/o port registers' base addresses\r
+  @param[in] Channel        The channel number of device.\r
+  @param[in] Device         The device number of device.\r
+  @param[in] Packet         A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
+\r
+  @retval EFI_SUCCESS       send out the ATAPI packet command successfully\r
+                            and device sends data successfully.\r
+  @retval EFI_DEVICE_ERROR  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketCommandExecute (\r
+  IN  EFI_PCI_IO_PROTOCOL                           *PciIo,\r
+  IN  EFI_IDE_REGISTERS                             *IdeRegisters,\r
+  IN  UINT8                                         Channel,\r
+  IN  UINT8                                         Device,\r
+  IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  )\r
+{\r
+  EFI_STATUS                  PacketCommandStatus;\r
+  EFI_ATA_COMMAND_BLOCK       AtaCommandBlock;\r
+  EFI_STATUS                  Status;\r
+  UINT8                       Count;\r
+  UINT8                       PacketCommand[12];\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  //\r
+  // Fill ATAPI Command Packet according to CDB.\r
+  // For Atapi cmd, its length should be less than or equal to 12 bytes.\r
+  //\r
+  if (Packet->CdbLength > 12) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ZeroMem (PacketCommand, 12);\r
+  CopyMem (PacketCommand, Packet->Cdb, Packet->CdbLength);\r
+\r
+  //\r
+  // No OVL; No DMA\r
+  //\r
+  AtaCommandBlock.AtaFeatures = 0x00;\r
+  //\r
+  // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device\r
+  // determine how many data should be transferred.\r
+  //\r
+  AtaCommandBlock.AtaCylinderLow  = (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff);\r
+  AtaCommandBlock.AtaCylinderHigh = (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8);\r
+  AtaCommandBlock.AtaDeviceHead   = Device << 0x4;\r
+  AtaCommandBlock.AtaCommand      = ATA_CMD_PACKET;\r
+\r
+  IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)(0xe0 | (Device << 0x4)));\r
+  //\r
+  //  Disable interrupt\r
+  //\r
+  IdeWritePortB (PciIo, IdeRegisters->AltOrDev, ATA_DEFAULT_CTL);\r
+\r
+  //\r
+  // Issue ATA PACKET command firstly\r
+  //\r
+  Status = AtaIssueCommand (PciIo, IdeRegisters, &AtaCommandBlock, Packet->Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = DRQReady (PciIo, IdeRegisters, Packet->Timeout);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Send out ATAPI command packet\r
+  //\r
+  for (Count = 0; Count < 6; Count++) {\r
+    IdeWritePortW (PciIo, IdeRegisters->Data, *((UINT16*)PacketCommand + Count)); \r
+    //\r
+    // Stall for 10 microseconds.\r
+    //\r
+    MicroSecondDelay (10);\r
+  }\r
+\r
+  //\r
+  // Read/Write the data of ATAPI Command\r
+  //\r
+  if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {\r
+    PacketCommandStatus = AtaPacketReadWrite (\r
+                            PciIo,\r
+                            IdeRegisters,\r
+                            Packet->InDataBuffer,\r
+                            Packet->InTransferLength,\r
+                            TRUE,\r
+                            Packet->Timeout\r
+                            );\r
+  } else {\r
+    PacketCommandStatus = AtaPacketReadWrite (\r
+                            PciIo,\r
+                            IdeRegisters,\r
+                            Packet->OutDataBuffer,\r
+                            Packet->OutTransferLength,\r
+                            FALSE,\r
+                            Packet->Timeout\r
+                            );\r
+  }\r
+\r
+  if (!EFI_ERROR (PacketCommandStatus)) {\r
+    return PacketCommandStatus;\r
+  }\r
+\r
+  //\r
+  // Return SenseData if PacketCommandStatus matches\r
+  // the following return codes.\r
+  //\r
+  if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||\r
+      (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
+      (PacketCommandStatus == EFI_TIMEOUT)) {\r
+\r
+    //\r
+    // avoid submit request sense command continuously.\r
+    //\r
+    if ((Packet->SenseData == NULL) || (((UINT8 *)Packet->Cdb)[0] == ATA_CMD_REQUEST_SENSE)) {\r
+      return PacketCommandStatus;\r
+    }\r
+\r
+    AtaPacketRequestSense (\r
+      PciIo,\r
+      IdeRegisters,\r
+      Channel,\r
+      Device,\r
+      Packet->SenseData,\r
+      Packet->SenseDataLength,\r
+      Packet->Timeout\r
+      );\r
+  }\r
+\r
+  return PacketCommandStatus;\r
+}\r
+\r
+\r
+/**\r
+  Set the calculated Best transfer mode to a detected device.\r
+\r
+  @param Instance               A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel                The channel number of device.\r
+  @param Device                 The device number of device.\r
+  @param TransferMode           A pointer to EFI_ATA_TRANSFER_MODE data structure.\r
+  @param AtaStatusBlock         A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS          Set transfer mode successfully.\r
+  @retval EFI_DEVICE_ERROR     Set transfer mode failed.\r
+  @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetDeviceTransferMode (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\r
+  IN     EFI_ATA_TRANSFER_MODE         *TransferMode,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+\r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_SET_FEATURES;\r
+  AtaCommandBlock.AtaDeviceHead  = (UINT8)(Device << 0x4);\r
+  AtaCommandBlock.AtaFeatures    = 0x03;\r
+  AtaCommandBlock.AtaSectorCount = *((UINT8 *)TransferMode);\r
+\r
+  //\r
+  // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set drive parameters for devices not support PACKETS command.\r
+\r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\r
+  @param DriveParameters  A pointer to EFI_ATA_DRIVE_PARMS data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS          Set drive parameter successfully.\r
+  @retval EFI_DEVICE_ERROR     Set drive parameter failed.\r
+  @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetDriveParameters (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\r
+  IN     EFI_ATA_DRIVE_PARMS           *DriveParameters,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock\r
+  \r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_ATA_COMMAND_BLOCK   AtaCommandBlock;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
\r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_INIT_DRIVE_PARAM;\r
+  AtaCommandBlock.AtaSectorCount = DriveParameters->Sector;\r
+  AtaCommandBlock.AtaDeviceHead  = (UINT8) ((Device << 0x4) + DriveParameters->Heads);\r
+\r
+  //\r
+  // Send Init drive parameters\r
+  //\r
+  Status = AtaNonDataCommandIn (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  //\r
+  // Send Set Multiple parameters\r
+  //\r
+  AtaCommandBlock.AtaCommand     = ATA_CMD_SET_MULTIPLE_MODE;\r
+  AtaCommandBlock.AtaSectorCount = DriveParameters->MultipleSector;\r
+  AtaCommandBlock.AtaDeviceHead  = (UINT8)(Device << 0x4);\r
+\r
+  Status = AtaNonDataCommandIn (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends out an ATA Identify Command to the specified device.\r
+\r
+  This function is called by DiscoverIdeDevice() during its device\r
+  identification. It sends out the ATA Identify Command to the\r
+  specified device. Only ATA device responses to this command. If\r
+  the command succeeds, it returns the Identify data structure which\r
+  contains information about the device. This function extracts the\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 Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\r
+  @param Buffer           A pointer to data buffer which is used to contain IDENTIFY data.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS          Identify ATA device successfully.\r
+  @retval EFI_DEVICE_ERROR     ATA Identify Device Command failed or device is not ATA device.\r
+  @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaIdentify (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\r
+  IN OUT EFI_IDENTIFY_DATA             *Buffer,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;  \r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  \r
+  AtaCommandBlock.AtaCommand    = ATA_CMD_IDENTIFY_DRIVE;\r
+  AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
+\r
+  Status = AtaPioDataInOut (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             Buffer,\r
+             sizeof (EFI_IDENTIFY_DATA),\r
+             TRUE,\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function is called by DiscoverIdeDevice() during its device\r
+  identification.\r
+  Its main purpose is to get enough information for the device media\r
+  to fill in the Media data structure of the Block I/O Protocol interface.\r
+\r
+  There are 5 steps to reach such objective:\r
+  1. Sends out the ATAPI Identify Command to the specified device. \r
+  Only ATAPI device responses to this command. If the command succeeds,\r
+  it returns the Identify data structure which filled with information \r
+  about the device. Since the ATAPI device contains removable media, \r
+  the only meaningful information is the device module name.\r
+  2. Sends out ATAPI Inquiry Packet Command to the specified device.\r
+  This command will return inquiry data of the device, which contains\r
+  the device type information.\r
+  3. Allocate sense data space for future use. We don't detect the media\r
+  presence here to improvement boot performance, especially when CD \r
+  media is present. The media detection will be performed just before\r
+  each BLK_IO read/write\r
+  \r
+  @param Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param Channel          The channel number of device.\r
+  @param Device           The device number of device.\r
+  @param Buffer           A pointer to data buffer which is used to contain IDENTIFY data.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+\r
+  @retval EFI_SUCCESS          Identify ATAPI device successfully.\r
+  @retval EFI_DEVICE_ERROR     ATA Identify Packet Device Command failed or device type\r
+                               is not supported by this IDE driver.\r
+  @retval EFI_OUT_OF_RESOURCES Allocate memory failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaIdentifyPacket (\r
+  IN     ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN     UINT8                         Channel,\r
+  IN     UINT8                         Device,\r
+  IN OUT EFI_IDENTIFY_DATA             *Buffer,\r
+  IN OUT EFI_ATA_STATUS_BLOCK          *AtaStatusBlock\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EFI_ATA_COMMAND_BLOCK  AtaCommandBlock;\r
+\r
+  ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));\r
+  \r
+  AtaCommandBlock.AtaCommand    = ATA_CMD_IDENTIFY_DEVICE;\r
+  AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);\r
+\r
+  //\r
+  // Send ATAPI Identify Command to get IDENTIFY data.\r
+  //\r
+  Status = AtaPioDataInOut (\r
+             Instance->PciIo,\r
+             &Instance->IdeRegisters[Channel],\r
+             (VOID *) Buffer,\r
+             sizeof (EFI_IDENTIFY_DATA),\r
+             TRUE,\r
+             &AtaCommandBlock,\r
+             AtaStatusBlock,\r
+             ATA_ATAPI_TIMEOUT\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function is used for detect whether the IDE device exists in the\r
+  specified Channel as the specified 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
+\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 Instance         A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeChannel       The channel number of device.\r
+\r
+  @retval EFI_SUCCESS successfully detects device.\r
+  @retval other       any failure during detection process will return this value.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectAndConfigIdeDevice (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE  *Instance,\r
+  IN  UINT8                         IdeChannel\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT8                             SectorCountReg;\r
+  UINT8                             LBALowReg;\r
+  UINT8                             LBAMidReg;\r
+  UINT8                             LBAHighReg;\r
+  EFI_ATA_DEVICE_TYPE               DeviceType;\r
+  EFI_IDE_DEVICE                    IdeDevice;\r
+  EFI_IDE_REGISTERS                 *IdeRegisters;\r
+  EFI_IDENTIFY_DATA                 Buffer;\r
+\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeInit;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+\r
+  EFI_ATA_COLLECTIVE_MODE           *SupportedModes;\r
+  EFI_ATA_TRANSFER_MODE             TransferMode;\r
+  EFI_ATA_DRIVE_PARMS               DriveParameters;\r
+\r
+  IdeRegisters = &Instance->IdeRegisters[IdeChannel];\r
+  IdeInit      = Instance->IdeControllerInit;\r
+  PciIo        = Instance->PciIo;\r
+\r
+  for (IdeDevice = 0; IdeDevice < EfiIdeMaxDevice; IdeDevice++) {    \r
+    //\r
+    // Send ATA Device Execut Diagnostic command.\r
+    // This command should work no matter DRDY is ready or not\r
+    //\r
+    IdeWritePortB (PciIo, IdeRegisters->CmdOrStatus, ATA_CMD_EXEC_DRIVE_DIAG);\r
+  \r
+    Status = WaitForBSYClear (PciIo, IdeRegisters, 350000000);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Select Master or Slave device to get the return signature for ATA DEVICE DIAGNOSTIC cmd.\r
+    //\r
+    IdeWritePortB (PciIo, IdeRegisters->Head, (UINT8)((IdeDevice << 4) | 0xe0));\r
+    //\r
+    // Stall for 1 milliseconds.\r
+    //\r
+    MicroSecondDelay (1000);\r
+\r
+    SectorCountReg = IdeReadPortB (PciIo, IdeRegisters->SectorCount);\r
+    LBALowReg      = IdeReadPortB (PciIo, IdeRegisters->SectorNumber);\r
+    LBAMidReg      = IdeReadPortB (PciIo, IdeRegisters->CylinderLsb);\r
+    LBAHighReg     = IdeReadPortB (PciIo, IdeRegisters->CylinderMsb);\r
+\r
+    //\r
+    // Refer to ATA/ATAPI 4 Spec, section 9.1\r
+    //\r
+    if ((SectorCountReg == 0x1) && (LBALowReg == 0x1) && (LBAMidReg == 0x0) && (LBAHighReg == 0x0)) {\r
+      DeviceType = EfiIdeHarddisk;\r
+    } else if ((LBAMidReg == 0x14) && (LBAHighReg == 0xeb)) {\r
+      DeviceType = EfiIdeCdrom;\r
+    } else {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Send IDENTIFY cmd to the device to test if it is really attached.\r
+    //\r
+    if (DeviceType == EfiIdeHarddisk) {\r
+      Status = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
+      //\r
+      // if identifying ata device is failure, then try to send identify packet cmd.\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        DeviceType = EfiIdeCdrom;\r
+        Status     = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
+      }\r
+    } else {\r
+      Status = AtaIdentifyPacket (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
+      //\r
+      // if identifying atapi device is failure, then try to send identify cmd.\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        DeviceType = EfiIdeHarddisk;\r
+        Status     = AtaIdentify (Instance, IdeChannel, IdeDevice, &Buffer, NULL);\r
+      } \r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // No device is found at this port\r
+      //\r
+      continue;\r
+    } \r
+  \r
+    DEBUG ((EFI_D_INFO, "[%a] channel [%a] [%a] device\n", \r
+            (IdeChannel == 1) ? "secondary" : "primary  ", (IdeDevice == 1) ? "slave " : "master",\r
+            DeviceType == EfiIdeCdrom ? "cdrom   " : "harddisk"));\r
+\r
+    //\r
+    // Submit identify data to IDE controller init driver\r
+    //\r
+    IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &Buffer);\r
+\r
+    //\r
+    // Now start to config ide device parameter and transfer mode.\r
+    //\r
+    Status = IdeInit->CalculateMode (\r
+                        IdeInit,\r
+                        IdeChannel,\r
+                        IdeDevice,\r
+                        &SupportedModes\r
+                        );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Calculate Mode Fail, Status = %r\n", Status));\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Set best supported PIO mode on this IDE device\r
+    //\r
+    if (SupportedModes->PioMode.Mode <= EfiAtaPioMode2) {\r
+      TransferMode.ModeCategory = EFI_ATA_MODE_DEFAULT_PIO;\r
+    } else {\r
+      TransferMode.ModeCategory = EFI_ATA_MODE_FLOW_PIO;\r
+    }\r
+\r
+    TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);\r
+\r
+    if (SupportedModes->ExtModeCount == 0){\r
+      Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+    }\r
+    \r
+    //\r
+    // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't\r
+    // be set together. Only one DMA mode can be set to a device. If setting\r
+    // DMA mode operation fails, we can continue moving on because we only use\r
+    // PIO mode at boot time. DMA modes are used by certain kind of OS booting\r
+    //\r
+    if (SupportedModes->UdmaMode.Valid) {\r
+      TransferMode.ModeCategory = EFI_ATA_MODE_UDMA;\r
+      TransferMode.ModeNumber   = (UINT8) (SupportedModes->UdmaMode.Mode);\r
+      Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
+    \r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+    } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
+      TransferMode.ModeCategory = EFI_ATA_MODE_MDMA;\r
+      TransferMode.ModeNumber   = (UINT8) SupportedModes->MultiWordDmaMode.Mode;\r
+      Status = SetDeviceTransferMode (Instance, IdeChannel, IdeDevice, &TransferMode, NULL);\r
+    \r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Set transfer Mode Fail, Status = %r\n", Status));\r
+        continue;\r
+      }\r
+    }\r
+    \r
+    //\r
+    // Set Parameters for the device:\r
+    // 1) Init\r
+    // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command\r
+    //\r
+    if (DeviceType == EfiIdeHarddisk) {\r
+      //\r
+      // Init driver parameters\r
+      //\r
+      DriveParameters.Sector         = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->sectors_per_track;\r
+      DriveParameters.Heads          = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->heads - 1;\r
+      DriveParameters.MultipleSector = (UINT8) ((ATA5_IDENTIFY_DATA *)(&Buffer.AtaData))->multi_sector_cmd_max_sct_cnt;\r
+    \r
+      Status = SetDriveParameters (Instance, IdeChannel, IdeDevice, &DriveParameters, NULL);\r
+    }\r
+    \r
+    //\r
+    // Set IDE controller Timing Blocks in the PCI Configuration Space\r
+    //\r
+    IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);\r
+\r
+    //\r
+    // IDE controller and IDE device timing is configured successfully.\r
+    // Now insert the device into device list.\r
+    //\r
+    Status = CreateNewDeviceInfo (Instance, IdeChannel, IdeDevice, DeviceType, &Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Initialize ATA host controller at IDE mode.\r
+  \r
+  The function is designed to initialize ATA host controller. \r
+  \r
+  @param[in]  Instance          A pointer to the ATA_ATAPI_PASS_THRU_INSTANCE instance.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+IdeModeInitialization (\r
+  IN  ATA_ATAPI_PASS_THRU_INSTANCE    *Instance\r
+  )\r
+{\r
+  BOOLEAN                           EnumAll;\r
+  EFI_STATUS                        Status;\r
+  EFI_IDE_CONTROLLER_INIT_PROTOCOL  *IdeInit;\r
+  EFI_PCI_IO_PROTOCOL               *PciIo;\r
+  UINT8                             Channel;\r
+  UINT8                             IdeChannel;\r
+  BOOLEAN                           ChannelEnabled;\r
+  UINT8                             MaxDevices;\r
+\r
+  IdeInit = Instance->IdeControllerInit;\r
+  PciIo   = Instance->PciIo;\r
+  EnumAll = IdeInit->EnumAll;\r
+  Channel = IdeInit->ChannelCount;\r
+\r
+  //\r
+  // Obtain IDE IO port registers' base addresses\r
+  //\r
+  Status = GetIdeRegisterIoAddr (PciIo, Instance->IdeRegisters);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  for (IdeChannel = 0; IdeChannel < Channel; IdeChannel++) {\r
+    IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);\r
+\r
+    //\r
+    // now obtain channel information fron IdeControllerInit protocol.\r
+    //\r
+    Status = IdeInit->GetChannelInfo (\r
+                        IdeInit,\r
+                        IdeChannel,\r
+                        &ChannelEnabled,\r
+                        &MaxDevices\r
+                        );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));\r
+      continue;\r
+    }\r
+\r
+    if (!ChannelEnabled) {\r
+      continue;\r
+    }\r
+\r
+    ASSERT (MaxDevices <= 2);\r
+    //\r
+    // Now inform the IDE Controller Init Module.\r
+    //\r
+    IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);\r
+\r
+    //\r
+    // No reset channel function implemented.\r
+    //\r
+    IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);\r
+\r
+    //\r
+    // Now inform the IDE Controller Init Module.\r
+    //\r
+    IdeInit->NotifyPhase (IdeInit, EfiIdeBusBeforeDevicePresenceDetection, IdeChannel);\r
+\r
+    //\r
+    // Detect all attached ATA devices and set the transfer mode for each device.\r
+    //\r
+    DetectAndConfigIdeDevice (Instance, IdeChannel);\r
+  }\r
+\r
+  //\r
+  // All configurations done! Notify IdeController to do post initialization\r
+  // work such as saving IDE controller PCI settings for S3 resume\r
+  //\r
+  IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);\r
+\r
+ErrorExit:\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.h
new file mode 100644 (file)
index 0000000..b9c58c6
--- /dev/null
@@ -0,0 +1,293 @@
+/** @file\r
+  Header file for IDE mode of ATA host controller.\r
+  \r
+  Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  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
+\r
+**/\r
+#ifndef __ATA_HC_IDE_MODE_H__\r
+#define __ATA_HC_IDE_MODE_H__\r
+\r
+typedef enum {\r
+  EfiIdePrimary    = 0,\r
+  EfiIdeSecondary  = 1,\r
+  EfiIdeMaxChannel = 2\r
+} EFI_IDE_CHANNEL;\r
+\r
+typedef enum {\r
+  EfiIdeMaster    = 0,\r
+  EfiIdeSlave     = 1,\r
+  EfiIdeMaxDevice = 2\r
+} EFI_IDE_DEVICE;\r
+\r
+///\r
+/// PIO mode definition\r
+///\r
+typedef enum {\r
+  EfiAtaPioModeBelow2,\r
+  EfiAtaPioMode2,\r
+  EfiAtaPioMode3,\r
+  EfiAtaPioMode4\r
+} EFI_ATA_PIO_MODE;\r
+\r
+//\r
+// Multi word DMA definition\r
+//\r
+typedef enum {\r
+  EfiAtaMdmaMode0,\r
+  EfiAtaMdmaMode1,\r
+  EfiAtaMdmaMode2\r
+} EFI_ATA_MDMA_MODE;\r
+\r
+//\r
+// UDMA mode definition\r
+//\r
+typedef enum {\r
+  EfiAtaUdmaMode0,\r
+  EfiAtaUdmaMode1,\r
+  EfiAtaUdmaMode2,\r
+  EfiAtaUdmaMode3,\r
+  EfiAtaUdmaMode4,\r
+  EfiAtaUdmaMode5\r
+} EFI_ATA_UDMA_MODE;\r
+\r
+//\r
+// Bus Master Reg\r
+//\r
+#define BMIC_NREAD      BIT3\r
+#define BMIC_START      BIT0\r
+#define BMIS_INTERRUPT  BIT2\r
+#define BMIS_ERROR      BIT1\r
+\r
+#define BMIC_OFFSET    0x00\r
+#define BMIS_OFFSET    0x02\r
+#define BMID_OFFSET    0x04\r
+\r
+//\r
+// IDE transfer mode\r
+//\r
+#define EFI_ATA_MODE_DEFAULT_PIO 0x00\r
+#define EFI_ATA_MODE_FLOW_PIO    0x01\r
+#define EFI_ATA_MODE_MDMA        0x04\r
+#define EFI_ATA_MODE_UDMA        0x08\r
+\r
+typedef struct {\r
+  UINT32  RegionBaseAddr;\r
+  UINT16  ByteCount;\r
+  UINT16  EndOfTable;\r
+} EFI_ATA_DMA_PRD;\r
+\r
+typedef struct {\r
+  UINT8 ModeNumber   : 3;\r
+  UINT8 ModeCategory : 5;\r
+} EFI_ATA_TRANSFER_MODE;\r
+\r
+typedef struct {\r
+  UINT8 Sector;\r
+  UINT8 Heads;\r
+  UINT8 MultipleSector;\r
+} EFI_ATA_DRIVE_PARMS;\r
+\r
+//\r
+// IDE registers set\r
+//\r
+typedef struct {\r
+  UINT16                          Data;\r
+  UINT16                          ErrOrFeature;\r
+  UINT16                          SectorCount;\r
+  UINT16                          SectorNumber;\r
+  UINT16                          CylinderLsb;\r
+  UINT16                          CylinderMsb;\r
+  UINT16                          Head;\r
+  UINT16                          CmdOrStatus;\r
+  UINT16                          AltOrDev;\r
+\r
+  UINT16                          BusMasterBaseAddr;\r
+} EFI_IDE_REGISTERS;\r
+\r
+//\r
+// Bit definitions in Programming Interface byte of the Class Code field\r
+// in PCI IDE controller's Configuration Space\r
+//\r
+#define IDE_PRIMARY_OPERATING_MODE            BIT0\r
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR    BIT1\r
+#define IDE_SECONDARY_OPERATING_MODE          BIT2\r
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR  BIT3\r
+\r
+/**\r
+  Get IDE i/o port registers' base addresses by mode. \r
+\r
+  In 'Compatibility' mode, use fixed addresses.\r
+  In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's\r
+  Configuration Space.\r
+\r
+  The steps to get IDE i/o 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
+  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
+\r
+  @param[in]      PciIo          Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param[in, out] IdeRegisters   Pointer to EFI_IDE_REGISTERS which is used to\r
+                                 store the IDE i/o port registers' base addresses\r
+           \r
+  @retval EFI_UNSUPPORTED        Return this value when the BARs is not IO type\r
+  @retval EFI_SUCCESS            Get the Base address successfully\r
+  @retval Other                  Read the pci configureation data error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetIdeRegisterIoAddr (\r
+  IN     EFI_PCI_IO_PROTOCOL         *PciIo,\r
+  IN OUT EFI_IDE_REGISTERS           *IdeRegisters\r
+  );\r
+\r
+/**\r
+  This function is used to send out ATAPI commands conforms to the Packet Command \r
+  with PIO Data In Protocol.\r
+\r
+  @param[in] PciIo          Pointer to the EFI_PCI_IO_PROTOCOL instance\r
+  @param[in] IdeRegisters   Pointer to EFI_IDE_REGISTERS which is used to\r
+                            store the IDE i/o port registers' base addresses\r
+  @param[in] Channel        The channel number of device.\r
+  @param[in] Device         The device number of device.\r
+  @param[in] Packet         A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET data structure.\r
+\r
+  @retval EFI_SUCCESS       send out the ATAPI packet command successfully\r
+                            and device sends data successfully.\r
+  @retval EFI_DEVICE_ERROR  the device failed to send data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AtaPacketCommandExecute (\r
+  IN  EFI_PCI_IO_PROTOCOL                           *PciIo,\r
+  IN  EFI_IDE_REGISTERS                             *IdeRegisters,\r
+  IN  UINT8                                         Channel,\r
+  IN  UINT8                                         Device,\r
+  IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet\r
+  );\r
+\r
+/**\r
+  Send ATA command into device with NON_DATA protocol\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+\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
+EFIAPI\r
+AtaNonDataCommandIn (  \r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Read             Flag used to determine the data transfer direction.\r
+                          Read equals 1, means data transferred from device to host;\r
+                          Read equals 0, means data transferred from host to device.\r
+  @param DataBuffer       A pointer to the source buffer for the data.\r
+  @param DataLength       The length of  the data.\r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+\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
+EFIAPI\r
+AtaUdmaInOut (\r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN     BOOLEAN                   Read,\r
+  IN     VOID                      *DataBuffer,\r
+  IN     UINT64                    DataLength,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  This function is used to send out ATA commands conforms to the PIO Data In Protocol.\r
+\r
+  @param PciIo            A pointer to ATA_ATAPI_PASS_THRU_INSTANCE data structure.\r
+  @param IdeRegisters     A pointer to EFI_IDE_REGISTERS data structure.\r
+  @param Buffer           A pointer to the source buffer for the data.\r
+  @param ByteCount        The length of  the data.\r
+  @param Read             Flag used to determine the data transfer direction.\r
+                          Read equals 1, means data transferred from device to host;\r
+                          Read equals 0, means data transferred from host to device.  \r
+  @param AtaCommandBlock  A pointer to EFI_ATA_COMMAND_BLOCK data structure.\r
+  @param AtaStatusBlock   A pointer to EFI_ATA_STATUS_BLOCK data structure.\r
+  @param Timeout          The time to complete the command.\r
+  \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
+EFIAPI\r
+AtaPioDataInOut (  \r
+  IN     EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN     EFI_IDE_REGISTERS         *IdeRegisters,\r
+  IN OUT VOID                      *Buffer,\r
+  IN     UINT64                    ByteCount,\r
+  IN     BOOLEAN                   Read,\r
+  IN     EFI_ATA_COMMAND_BLOCK     *AtaCommandBlock,\r
+  IN OUT EFI_ATA_STATUS_BLOCK      *AtaStatusBlock,\r
+  IN     UINT64                    Timeout\r
+  );\r
+\r
+\r
+#endif\r
+\r