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
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\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
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\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
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
} else {\r
//\r
// For ATA-3 compatible device, use ATA-3 write block mechanism\r
//\r
- if (IdeBlkIoDevice->UdmaMode.Valid) {\r
- Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
- } else {\r
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+ if (EFI_ERROR (Status)) {\r
Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
}\r
}\r
IN UINTN NumberOfBlocks\r
)\r
{\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
+ 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
//\r
Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);\r
\r
RemainBlockNum = NumberOfBlocks;\r
while (RemainBlockNum > 0) {\r
\r
- if (RemainBlockNum >= MaxDmaCommandSectors) {\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 = MaxDmaCommandSectors;\r
- RemainBlockNum -= MaxDmaCommandSectors;\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
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
- PciIoProtocolOp, \r
- DataBuffer, \r
- &ByteCount, \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
+ }\r
PrdBuffer = (VOID *) ((UINTN) DeviceAddress);\r
TempPrdAddr = UsedPrdAddr;\r
while (TRUE) {\r
&RegisterValue\r
);\r
\r
- if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {\r
- RegisterValue |= BMIC_nREAD;\r
- } else {\r
- RegisterValue &= ~((UINT8) BMIC_nREAD);\r
- }\r
+ RegisterValue |= BMIC_nREAD;\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
- 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
+ //\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 (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