--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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