\r
#include "idebus.h"\r
\r
-\r
-EFI_STATUS\r
-AtaReadSectorsExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN OUT VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- );\r
-\r
-EFI_STATUS\r
-AtaWriteSectorsExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- );\r
-\r
-EFI_STATUS\r
-AtaPioDataInExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN OUT VOID *Buffer,\r
- IN UINT32 ByteCount,\r
- IN UINT8 AtaCommand,\r
- IN EFI_LBA StartLba,\r
- IN UINT16 SectorCount\r
- );\r
-\r
-EFI_STATUS\r
-AtaPioDataOutExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *Buffer,\r
- IN UINT32 ByteCount,\r
- IN UINT8 AtaCommand,\r
- IN EFI_LBA StartLba,\r
- IN UINT16 SectorCount\r
- );\r
-\r
/**\r
Sends out an ATA Identify Command to the specified device.\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ Status = EFI_SUCCESS;\r
if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
//\r
// For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism\r
//\r
- Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- if (EFI_ERROR (Status)) {\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
} else {\r
//\r
// For ATA-3 compatible device, use ATA-3 read block mechanism\r
//\r
- Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- if (EFI_ERROR (Status)) {\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
}\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ Status = EFI_SUCCESS;\r
if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
//\r
// For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism\r
//\r
- Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- if (EFI_ERROR (Status)) {\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
} else {\r
//\r
// For ATA-3 compatible device, use ATA-3 write block mechanism\r
//\r
- Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- if (EFI_ERROR (Status)) {\r
+ if (IdeBlkIoDevice->UdmaMode.Valid) {\r
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ } else {\r
Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
}\r
IN UINTN NumberOfBlocks\r
)\r
{\r
- IDE_DMA_PRD *PrdAddr;\r
- IDE_DMA_PRD *UsedPrdAddr;\r
- IDE_DMA_PRD *TempPrdAddr;\r
- UINT8 RegisterValue;\r
- UINT8 Device;\r
- UINT64 IoPortForBmic;\r
- UINT64 IoPortForBmis;\r
- UINT64 IoPortForBmid;\r
- EFI_STATUS Status;\r
- UINTN PrdTableNum;\r
- UINTN ByteCount;\r
- UINTN ByteAvailable;\r
- UINT8 *PrdBuffer;\r
- UINTN RemainBlockNum;\r
- UINT8 DeviceControl;\r
- UINT32 Count;\r
- UINTN PageCount;\r
- VOID *Map;\r
- VOID *MemPage;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
-\r
- //\r
- // Channel and device differential. Select device.\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoReadBlocks() to perform\r
+ reading from media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
+ @param[in] StartLba The starting logical block address to read from\r
+ on the device media.\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaRead (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWriteExt (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);\r
+}\r
+\r
+/**\r
+ This function is called by the AtaBlkIoWriteBlocks() to perform\r
+ writing to media in block unit. The function has been enhanced to\r
+ support >120GB access and transfer at most 65536 blocks per command\r
+\r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba\r
+ The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+ TODO: EFI_UNSUPPORTED - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+ TODO: EFI_DEVICE_ERROR - add return value to function comment\r
+**/\r
+EFI_STATUS\r
+AtaUdmaWrite (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks\r
+ )\r
+{\r
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);\r
+}\r
+\r
+/**\r
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).\r
+ \r
+ @param[in] *IdeDev\r
+ pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+ to record all the information of the IDE device.\r
+\r
+ @param[in] *DataBuffer\r
+ A pointer to the source buffer for the data.\r
+\r
+ @param[in] StartLba\r
+ The starting logical block address to write to\r
+ on the device media.\r
+\r
+ @param[in] NumberOfBlocks\r
+ The number of transfer data blocks.\r
+ \r
+ @param[in] UdmaOp\r
+ The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,\r
+ AtaUdmaWriteOp, AtaUdmaWriteExOp\r
+\r
+ @return The device status of UDMA operation. If the operation is\r
+ successful, return EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+DoAtaUdma (\r
+ IN IDE_BLK_IO_DEV *IdeDev,\r
+ IN VOID *DataBuffer,\r
+ IN EFI_LBA StartLba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN ATA_UDMA_OPERATION UdmaOp\r
+ )\r
+{\r
+ IDE_DMA_PRD *PrdAddr;\r
+ IDE_DMA_PRD *UsedPrdAddr;\r
+ IDE_DMA_PRD *TempPrdAddr;\r
+ UINT8 RegisterValue;\r
+ UINT8 Device;\r
+ UINT64 IoPortForBmic;\r
+ UINT64 IoPortForBmis;\r
+ UINT64 IoPortForBmid;\r
+ EFI_STATUS Status;\r
+ UINTN PrdTableNum;\r
+ UINTN ByteCount;\r
+ UINTN ByteAvailable;\r
+ UINT8 *PrdBuffer;\r
+ UINTN RemainBlockNum;\r
+ UINT8 DeviceControl;\r
+ UINT32 Count;\r
+ UINTN PageCount;\r
+ VOID *Map;\r
+ VOID *MemPage;\r
+ EFI_PHYSICAL_ADDRESS DeviceAddress;\r
+ UINTN MaxDmaCommandSectors;\r
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;\r
+ UINT8 AtaCommand;\r
+\r
+ switch (UdmaOp) {\r
+ case AtaUdmaReadOp:\r
+ MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = READ_DMA_CMD;\r
+ break;\r
+ case AtaUdmaReadExtOp:\r
+ MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;\r
+ AtaCommand = READ_DMA_EXT_CMD;\r
+ break;\r
+ case AtaUdmaWriteOp:\r
+ MaxDmaCommandSectors = MAX_DMA_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = WRITE_DMA_CMD;\r
+ break;\r
+ case AtaUdmaWriteExtOp:\r
+ MaxDmaCommandSectors = MAX_DMA_EXT_COMMAND_SECTORS;\r
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;\r
+ AtaCommand = WRITE_DMA_EXT_CMD;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Channel and device differential\r
//\r
Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
\r
RemainBlockNum = NumberOfBlocks;\r
while (RemainBlockNum > 0) {\r
\r
- if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {\r
+ if (RemainBlockNum >= MaxDmaCommandSectors) {\r
//\r
// SectorCount is used to record the number of sectors to be read\r
// Max 65536 sectors can be transfered at a time.\r
//\r
- NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;\r
- RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;\r
+ NumberOfBlocks = MaxDmaCommandSectors;\r
+ RemainBlockNum -= MaxDmaCommandSectors;\r
} else {\r
NumberOfBlocks = (UINT16) RemainBlockNum;\r
RemainBlockNum = 0;\r
//\r
PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
Status = IdeDev->PciIo->AllocateBuffer (\r
- IdeDev->PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- PageCount,\r
- &MemPage,\r
- 0\r
- );\r
+ IdeDev->PciIo,\r
+ AllocateAnyPages,\r
+ EfiBootServicesData,\r
+ PageCount,\r
+ &MemPage,\r
+ 0\r
+ );\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
+ \r
PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
-\r
//\r
// To make sure PRD is allocated in one 64K page\r
//\r
// Build the PRD table\r
//\r
Status = IdeDev->PciIo->Map (\r
- IdeDev->PciIo,\r
- EfiPciIoOperationBusMasterWrite,\r
- DataBuffer,\r
- &ByteCount,\r
+ IdeDev->PciIo, \r
+ PciIoProtocolOp, \r
+ DataBuffer, \r
+ &ByteCount, \r
&DeviceAddress,\r
&Map\r
);\r
if (EFI_ERROR (Status)) {\r
IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
return EFI_OUT_OF_RESOURCES;\r
- }\r
+ } \r
PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r
TempPrdAddr = UsedPrdAddr;\r
while (TRUE) {\r
&RegisterValue\r
);\r
\r
- RegisterValue |= BMIC_nREAD;\r
+ if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
+ RegisterValue |= BMIC_nREAD;\r
+ } else {\r
+ RegisterValue &= ~((UINT8) BMIC_nREAD);\r
+ }\r
\r
IdeDev->PciIo->Io.Write (\r
IdeDev->PciIo,\r
&RegisterValue\r
);\r
\r
- RegisterValue |= BMIS_INTERRUPT | BMIS_ERROR;\r
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
\r
IdeDev->PciIo->Io.Write (\r
IdeDev->PciIo,\r
&RegisterValue\r
);\r
\r
- //\r
- // Issue READ DMA EXT command\r
- //\r
- Status = AtaCommandIssueExt (\r
- IdeDev,\r
- READ_DMA_EXT_CMD,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
+ if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {\r
+ Status = AtaCommandIssueExt (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ } else {\r
+ Status = AtaCommandIssue (\r
+ IdeDev,\r
+ AtaCommand,\r
+ Device,\r
+ 0,\r
+ (UINT16) NumberOfBlocks,\r
+ StartLba\r
+ );\r
+ }\r
+\r
if (EFI_ERROR (Status)) {\r
IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
\r
return EFI_SUCCESS;\r
}\r
-\r
-/**\r
- This function is called by the AtaBlkIoReadBlocks() to perform\r
- reading from media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer A pointer to the destination buffer for the data.\r
- @param[in] StartLba The starting logical block address to read from\r
- on the device media.\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
-\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaRead (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- )\r
-{\r
- IDE_DMA_PRD *PrdAddr;\r
- IDE_DMA_PRD *UsedPrdAddr;\r
- IDE_DMA_PRD *TempPrdAddr;\r
- UINT8 RegisterValue;\r
- UINT8 Device;\r
- UINT64 IoPortForBmic;\r
- UINT64 IoPortForBmis;\r
- UINT64 IoPortForBmid;\r
- EFI_STATUS Status;\r
- UINTN PrdTableNum;\r
- UINTN ByteCount;\r
- UINTN ByteAvailable;\r
- UINT8 *PrdBuffer;\r
- UINTN RemainBlockNum;\r
- UINT8 DeviceControl;\r
- UINT32 Count;\r
- UINTN PageCount;\r
- VOID *Map;\r
- VOID *MemPage;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
-\r
- //\r
- // Channel and device differential\r
- //\r
- Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-\r
- //\r
- // Enable interrupt to support UDMA and Select device\r
- //\r
- DeviceControl = 0;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
- if (IdePrimary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
- } else {\r
- if (IdeSecondary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- RemainBlockNum = NumberOfBlocks;\r
- while (RemainBlockNum > 0) {\r
-\r
- if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {\r
- //\r
- // SectorCount is used to record the number of sectors to be read\r
- // Max 256 sectors can be transfered at a time.\r
- //\r
- NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;\r
- RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;\r
- } else {\r
- NumberOfBlocks = (UINT16) RemainBlockNum;\r
- RemainBlockNum = 0;\r
- }\r
-\r
- //\r
- // Calculate the number of PRD table to make sure the memory region\r
- // not cross 64K boundary\r
- //\r
- ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
-\r
- //\r
- // Build PRD table\r
- //\r
- PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
- Status = IdeDev->PciIo->AllocateBuffer (\r
- IdeDev->PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- PageCount,\r
- &MemPage,\r
- 0\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
- PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
- //\r
- // To make sure PRD is allocated in one 64K page\r
- //\r
- if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
- } else {\r
- if ((UINTN) PrdAddr & 0x03) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
- } else {\r
- UsedPrdAddr = PrdAddr;\r
- }\r
- }\r
-\r
- //\r
- // Build the PRD table\r
- //\r
- Status = IdeDev->PciIo->Map (\r
- IdeDev->PciIo,\r
- EfiPciIoOperationBusMasterWrite,\r
- DataBuffer,\r
- &ByteCount,\r
- &DeviceAddress,\r
- &Map\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);\r
- TempPrdAddr = UsedPrdAddr;\r
- while (TRUE) {\r
-\r
- ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
-\r
- if (ByteCount <= ByteAvailable) {\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
- TempPrdAddr->EndOfTable = 0x8000;\r
- break;\r
- }\r
-\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
-\r
- ByteCount -= ByteAvailable;\r
- PrdBuffer += ByteAvailable;\r
- TempPrdAddr++;\r
- }\r
-\r
- //\r
- // Set the base address to BMID register\r
- //\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint32,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmid,\r
- 1,\r
- &UsedPrdAddr\r
- );\r
-\r
- //\r
- // Set BMIC register to identify the operation direction\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= BMIC_nREAD;\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Read BMIS register and clear ERROR and INTR bit\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Issue READ DMA command\r
- //\r
- Status = AtaCommandIssue (\r
- IdeDev,\r
- READ_DMA_CMD,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Set START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= BMIC_START;\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Check the INTERRUPT and ERROR bit of BMIS\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second timeout time.\r
- //\r
- Count = 2000;\r
- while (TRUE) {\r
-\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
- if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
- //\r
- // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8)BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
- break;\r
- }\r
-\r
- gBS->Stall (1000);\r
- Count --;\r
- }\r
-\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- //\r
- // Read Status Register of IDE device to clear interrupt\r
- //\r
- RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
- //\r
- // Clear START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8) BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- if (RegisterValue & BMIS_ERROR) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- StartLba += NumberOfBlocks;\r
- }\r
-\r
- //\r
- // Disable interrupt of Select device\r
- //\r
- IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
- DeviceControl |= IEN_L;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing to media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
-\r
- @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer A pointer to the source buffer for the data.\r
-\r
- @param[in] StartLba The starting logical block address to write to\r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks The number of transfer data blocks.\r
-\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaWriteExt (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- )\r
-{\r
- IDE_DMA_PRD *PrdAddr;\r
- IDE_DMA_PRD *UsedPrdAddr;\r
- IDE_DMA_PRD *TempPrdAddr;\r
- UINT8 RegisterValue;\r
- UINT8 Device;\r
- UINT64 IoPortForBmic;\r
- UINT64 IoPortForBmis;\r
- UINT64 IoPortForBmid;\r
- EFI_STATUS Status;\r
- UINTN PrdTableNum;\r
- UINTN ByteCount;\r
- UINTN ByteAvailable;\r
- UINT8 *PrdBuffer;\r
- UINTN RemainBlockNum;\r
- UINT8 DeviceControl;\r
- UINT32 Count;\r
- UINTN PageCount;\r
- VOID *Map;\r
- VOID *MemPage;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
-\r
- //\r
- // Channel and device differential\r
- //\r
- Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-\r
- //\r
- // Enable interrupt to support UDMA and Select device\r
- //\r
- DeviceControl = 0;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
- if (IdePrimary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
- } else {\r
- if (IdeSecondary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- RemainBlockNum = NumberOfBlocks;\r
- while (RemainBlockNum > 0) {\r
-\r
- if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {\r
- //\r
- // SectorCount is used to record the number of sectors to be read\r
- // Max 65536 sectors can be transfered at a time.\r
- //\r
- NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;\r
- RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;\r
- } else {\r
- NumberOfBlocks = (UINT16) RemainBlockNum;\r
- RemainBlockNum = 0;\r
- }\r
-\r
- //\r
- // Calculate the number of PRD table to make sure the memory region\r
- // not cross 64K boundary\r
- //\r
- ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
-\r
- //\r
- // Build PRD table\r
- //\r
- PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
- Status = IdeDev->PciIo->AllocateBuffer (\r
- IdeDev->PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- PageCount,\r
- &MemPage,\r
- 0\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
- PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
- //\r
- // To make sure PRD is allocated in one 64K page\r
- //\r
- if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
- } else {\r
- if ((UINTN) PrdAddr & 0x03) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
- } else {\r
- UsedPrdAddr = PrdAddr;\r
- }\r
- }\r
-\r
- //\r
- // Build the PRD table\r
- //\r
- Status = IdeDev->PciIo->Map (\r
- IdeDev->PciIo,\r
- EfiPciIoOperationBusMasterRead,\r
- DataBuffer,\r
- &ByteCount,\r
- &DeviceAddress,\r
- &Map\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);\r
- TempPrdAddr = UsedPrdAddr;\r
- while (TRUE) {\r
-\r
- ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
-\r
- if (ByteCount <= ByteAvailable) {\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
- TempPrdAddr->EndOfTable = 0x8000;\r
- break;\r
- }\r
-\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
-\r
- ByteCount -= ByteAvailable;\r
- PrdBuffer += ByteAvailable;\r
- TempPrdAddr++;\r
- }\r
-\r
- //\r
- // Set the base address to BMID register\r
- //\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint32,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmid,\r
- 1,\r
- &UsedPrdAddr\r
- );\r
-\r
- //\r
- // Set BMIC register to identify the operation direction\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
- //\r
- // 0000 1000\r
- //\r
- RegisterValue &= ~((UINT8) BMIC_nREAD);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Read BMIS register and clear ERROR and INTR bit\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Issue WRITE DMA EXT command\r
- //\r
- Status = AtaCommandIssueExt (\r
- IdeDev,\r
- WRITE_DMA_EXT_CMD,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Set START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= BMIC_START;\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Check the INTERRUPT and ERROR bit of BMIS\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second timeout time.\r
- //\r
- Count = 2000;\r
- while (TRUE) {\r
-\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
- if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
- //\r
- // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8)BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
- break;\r
- }\r
-\r
- gBS->Stall (1000);\r
- Count --;\r
- }\r
-\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- //\r
- // Read Status Register of IDE device to clear interrupt\r
- //\r
- RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
- //\r
- // Clear START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8) BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- StartLba += NumberOfBlocks;\r
- }\r
-\r
- //\r
- // Disable interrupt of Select device\r
- //\r
- IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
- DeviceControl |= IEN_L;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- This function is called by the AtaBlkIoWriteBlocks() to perform\r
- writing to media in block unit. The function has been enhanced to\r
- support >120GB access and transfer at most 65536 blocks per command\r
-\r
- @param[in] *IdeDev\r
- pointer pointing to IDE_BLK_IO_DEV data structure, used\r
- to record all the information of the IDE device.\r
-\r
- @param[in] *DataBuffer\r
- A pointer to the source buffer for the data.\r
-\r
- @param[in] StartLba\r
- The starting logical block address to write to\r
- on the device media.\r
-\r
- @param[in] NumberOfBlocks\r
- The number of transfer data blocks.\r
-\r
- @return The device status of UDMA operation. If the operation is\r
- successful, return EFI_SUCCESS.\r
-\r
- TODO: EFI_UNSUPPORTED - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
- TODO: EFI_DEVICE_ERROR - add return value to function comment\r
-**/\r
-EFI_STATUS\r
-AtaUdmaWrite (\r
- IN IDE_BLK_IO_DEV *IdeDev,\r
- IN VOID *DataBuffer,\r
- IN EFI_LBA StartLba,\r
- IN UINTN NumberOfBlocks\r
- )\r
-{\r
- IDE_DMA_PRD *PrdAddr;\r
- IDE_DMA_PRD *UsedPrdAddr;\r
- IDE_DMA_PRD *TempPrdAddr;\r
- UINT8 RegisterValue;\r
- UINT8 Device;\r
- UINT64 IoPortForBmic;\r
- UINT64 IoPortForBmis;\r
- UINT64 IoPortForBmid;\r
- EFI_STATUS Status;\r
- UINTN PrdTableNum;\r
- UINTN ByteCount;\r
- UINTN ByteAvailable;\r
- UINT8 *PrdBuffer;\r
- UINTN RemainBlockNum;\r
- UINT8 DeviceControl;\r
- UINT32 Count;\r
- UINTN PageCount;\r
- VOID *Map;\r
- VOID *MemPage;\r
- EFI_PHYSICAL_ADDRESS DeviceAddress;\r
-\r
- //\r
- // Channel and device differential\r
- //\r
- Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
-\r
- //\r
- // Enable interrupt to support UDMA\r
- //\r
- DeviceControl = 0;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
-\r
- if (IdePrimary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;\r
- } else {\r
- if (IdeSecondary == IdeDev->Channel) {\r
- IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;\r
- IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
- IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- RemainBlockNum = NumberOfBlocks;\r
- while (RemainBlockNum > 0) {\r
-\r
- if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {\r
- //\r
- // SectorCount is used to record the number of sectors to be read\r
- // Max 256 sectors can be transfered at a time.\r
- //\r
- NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;\r
- RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;\r
- } else {\r
- NumberOfBlocks = (UINT16) RemainBlockNum;\r
- RemainBlockNum = 0;\r
- }\r
-\r
- //\r
- // Calculate the number of PRD table to make sure the memory region\r
- // not cross 64K boundary\r
- //\r
- ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- PrdTableNum = ((ByteCount >> 16) + 1) + 1;\r
-\r
- //\r
- // Build PRD table\r
- //\r
- PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
- Status = IdeDev->PciIo->AllocateBuffer (\r
- IdeDev->PciIo,\r
- AllocateAnyPages,\r
- EfiBootServicesData,\r
- PageCount,\r
- &MemPage,\r
- 0\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));\r
-\r
- PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);\r
-\r
- //\r
- // To make sure PRD is allocated in one 64K page\r
- //\r
- if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);\r
- } else {\r
- if ((UINTN) PrdAddr & 0x03) {\r
- UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);\r
- } else {\r
- UsedPrdAddr = PrdAddr;\r
- }\r
- }\r
-\r
- //\r
- // Build the PRD table\r
- //\r
- Status = IdeDev->PciIo->Map (\r
- IdeDev->PciIo,\r
- EfiPciIoOperationBusMasterRead,\r
- DataBuffer,\r
- &ByteCount,\r
- &DeviceAddress,\r
- &Map\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- PrdBuffer = (UINT8 *) ((UINTN) DeviceAddress);\r
- TempPrdAddr = UsedPrdAddr;\r
- while (TRUE) {\r
-\r
- ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);\r
-\r
- if (ByteCount <= ByteAvailable) {\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteCount;\r
- TempPrdAddr->EndOfTable = 0x8000;\r
- break;\r
- }\r
-\r
- TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);\r
- TempPrdAddr->ByteCount = (UINT16) ByteAvailable;\r
-\r
- ByteCount -= ByteAvailable;\r
- PrdBuffer += ByteAvailable;\r
- TempPrdAddr++;\r
- }\r
-\r
- //\r
- // Set the base address to BMID register\r
- //\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint32,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmid,\r
- 1,\r
- &UsedPrdAddr\r
- );\r
-\r
- //\r
- // Set BMIC register to identify the operation direction\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
- //\r
- // 0000 1000\r
- //\r
- RegisterValue &= ~((UINT8) BMIC_nREAD);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Read BMIS register and clear ERROR and INTR bit\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Issue WRITE DMA command\r
- //\r
- Status = AtaCommandIssue (\r
- IdeDev,\r
- WRITE_DMA_CMD,\r
- Device,\r
- 0,\r
- (UINT16) NumberOfBlocks,\r
- StartLba\r
- );\r
- if (EFI_ERROR (Status)) {\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- //\r
- // Set START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue |= BMIC_START;\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- //\r
- // Check the INTERRUPT and ERROR bit of BMIS\r
- // Max transfer number of sectors for one command is 65536(32Mbyte),\r
- // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).\r
- // So set the variable Count to 2000, for about 2 second timeout time.\r
- //\r
- Count = 2000;\r
- while (TRUE) {\r
-\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmis,\r
- 1,\r
- &RegisterValue\r
- );\r
- if ((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) || (Count == 0)) {\r
- if ((RegisterValue & BMIS_ERROR) || (Count == 0)) {\r
- //\r
- // Clear START bit of BMIC register before return EFI_DEVICE_ERROR\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8)BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
- return EFI_DEVICE_ERROR;\r
- }\r
- break;\r
- }\r
-\r
- gBS->Stall (1000);\r
- Count --;\r
- }\r
-\r
- IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);\r
- IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
-\r
- //\r
- // Read Status Register of IDE device to clear interrupt\r
- //\r
- RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);\r
- //\r
- // Clear START bit of BMIC register\r
- //\r
- IdeDev->PciIo->Io.Read (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- RegisterValue &= ~((UINT8) BMIC_START);\r
-\r
- IdeDev->PciIo->Io.Write (\r
- IdeDev->PciIo,\r
- EfiPciIoWidthUint8,\r
- EFI_PCI_IO_PASS_THROUGH_BAR,\r
- IoPortForBmic,\r
- 1,\r
- &RegisterValue\r
- );\r
-\r
- DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;\r
- StartLba += NumberOfBlocks;\r
- }\r
-\r
- //\r
- // Disable interrupt of Select device\r
- //\r
- IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);\r
- DeviceControl |= IEN_L;\r
- IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
-\r
- return EFI_SUCCESS;\r
-}\r