Fix the issue of Linux cannot boot and reset on IPF.
authorxli24 <xli24@de2fecce-e211-0410-80a6-f3fac2684e05>
Wed, 7 Mar 2007 09:34:54 +0000 (09:34 +0000)
committerxli24 <xli24@de2fecce-e211-0410-80a6-f3fac2684e05>
Wed, 7 Mar 2007 09:34:54 +0000 (09:34 +0000)
git-svn-id: https://edk2.tianocore.org/svn/edk2/trunk@2423 de2fecce-e211-0410-80a6-f3fac2684e05

edk2/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c
edk2/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h
edk2/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c
edk2/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h
edk2/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h

index 44e7347..aea126b 100644 (file)
@@ -1075,23 +1075,20 @@ AtaBlkIoReadBlocks (
     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
@@ -1199,23 +1196,20 @@ AtaBlkIoWriteBlocks (
     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
@@ -2113,198 +2107,29 @@ AtaUdmaReadExt (
   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
@@ -2333,13 +2158,13 @@ DoAtaUdma (
   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
@@ -2357,19 +2182,20 @@ DoAtaUdma (
     //\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
@@ -2387,17 +2213,17 @@ DoAtaUdma (
     // 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
@@ -2443,11 +2269,7 @@ DoAtaUdma (
                         &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
@@ -2470,7 +2292,7 @@ DoAtaUdma (
                         &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
@@ -2481,26 +2303,17 @@ DoAtaUdma (
                         &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
@@ -2628,3 +2441,1097 @@ DoAtaUdma (
 \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
index f382279..b83a82a 100644 (file)
@@ -1097,42 +1097,6 @@ AtaUdmaWriteExt (
   )\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
-\r
-\r
 /**\r
   TODO: Add function description\r
 \r
index 73b302c..0e7d43e 100644 (file)
@@ -629,11 +629,7 @@ IDEBusDriverBindingStart (
           IdeBlkIoDevicePtr = NULL;\r
           continue;\r
         }\r
-        //\r
-        // Record Udma Mode\r
-        //\r
-        IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE;\r
-        IdeBlkIoDevicePtr->UdmaMode.Mode  = SupportedModes->UdmaMode.Mode;\r
+\r
         EnableInterrupt (IdeBlkIoDevicePtr);\r
       } else if (SupportedModes->MultiWordDmaMode.Valid) {\r
 \r
index 78c79d7..52c1f26 100644 (file)
@@ -65,7 +65,7 @@ typedef struct {
   INQUIRY_DATA                *pInquiryData;\r
   EFI_IDENTIFY_DATA           *pIdData;\r
   ATA_PIO_MODE                PioMode;\r
-  EFI_ATA_MODE                UdmaMode;\r
+  ATA_UDMA_MODE               UDma_Mode;\r
   CHAR8                       ModelName[41];\r
   REQUEST_SENSE_DATA          *SenseData;\r
   UINT8                       SenseDataNumber;\r
index 0c38311..ec088dc 100644 (file)
@@ -86,13 +86,6 @@ typedef enum {
   SenseOtherSense\r
 } SENSE_RESULT;\r
 \r
-typedef enum {\r
-  AtaUdmaReadOp,\r
-  AtaUdmaReadExtOp,\r
-  AtaUdmaWriteOp,\r
-  AtaUdmaWriteExtOp\r
-} ATA_UDMA_OPERATION;\r
-\r
 //\r
 // IDE Registers\r
 //\r