1. Changed device detect method to use ATA/ATAPI device signature;
authorjtang12 <jtang12@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 13 Oct 2006 05:51:59 +0000 (05:51 +0000)
committerjtang12 <jtang12@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 13 Oct 2006 05:51:59 +0000 (05:51 +0000)
2. Enhancements to better support SATA CDROM;
3. Fixed UDMA operation for buffer above 4G memory issue;
4. Fixed maximal block setting for ATAPI read sector operation to comply with spec;
5. Some minor fixes.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1739 6f19259b-4bc3-4df7-8a09-765794883524

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

index cb184a4..a08c79c 100644 (file)
@@ -1,12 +1,12 @@
 /** @file\r
-  Copyright (c) 2006, Intel Corporation                                                         \r
-  All rights reserved. This program and the accompanying materials                          \r
-  are licensed and made available under the terms and conditions of the BSD License         \r
-  which accompanies this distribution.  The full text of the license may be found at        \r
-  http://opensource.org/licenses/bsd-license.php                                            \r
+  Copyright (c) 2006, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
   @par Revision Reference:\r
   2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
@@ -64,11 +64,11 @@ AtaPioDataOutExt (
   Sends out an ATA Identify Command to the specified device.\r
 \r
   This function is called by DiscoverIdeDevice() during its device\r
-  identification. It sends out the ATA Identify Command to the \r
-  specified device. Only ATA device responses to this command. If \r
-  the command succeeds, it returns the Identify data structure which \r
-  contains information about the device. This function extracts the \r
-  information it needs to fill the IDE_BLK_IO_DEV data structure, \r
+  identification. It sends out the ATA Identify Command to the\r
+  specified device. Only ATA device responses to this command. If\r
+  the command succeeds, it returns the Identify data structure which\r
+  contains information about the device. This function extracts the\r
+  information it needs to fill the IDE_BLK_IO_DEV data structure,\r
   including device type, media block size, media capacity, and etc.\r
 \r
   @param[in] *IdeDev\r
@@ -76,7 +76,7 @@ AtaPioDataOutExt (
   to record all the information of the IDE device.\r
 \r
   @retval EFI_SUCCESS Identify ATA device successfully.\r
-  \r
+\r
   @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or\r
   device is not ATA device.\r
 \r
@@ -203,13 +203,13 @@ ATAIdentify (
 \r
   @retval  EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one\r
   and 48-bit addressing must be used\r
-  \r
+\r
   @retval  EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but\r
   the capacity is below 120G, 48bit addressing is not\r
   needed\r
 \r
   @note\r
-  This function must be called after DEVICE_IDENTITY command has been \r
+  This function must be called after DEVICE_IDENTITY command has been\r
   successfully returned\r
 \r
 **/\r
@@ -274,7 +274,7 @@ AtaAtapi6Identify (
 \r
 /**\r
   This function is called by ATAIdentify() or ATAPIIdentify()\r
-  to print device's module name. \r
+  to print device's module name.\r
 \r
   @param[in] *IdeDev\r
   pointer pointing to IDE_BLK_IO_DEV data structure, used\r
@@ -295,7 +295,7 @@ PrintAtaModuleName (
 }\r
 \r
 /**\r
-  This function is used to send out ATA commands conforms to the \r
+  This function is used to send out ATA commands conforms to the\r
   PIO Data In Protocol.\r
 \r
   @param[in] *IdeDev\r
@@ -328,7 +328,7 @@ PrintAtaModuleName (
 \r
   @retval EFI_SUCCESS send out the ATA command and device send required\r
   data successfully.\r
-  \r
+\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -462,7 +462,7 @@ AtaPioDataIn (
 }\r
 \r
 /**\r
-  This function is used to send out ATA commands conforms to the \r
+  This function is used to send out ATA commands conforms to the\r
   PIO Data Out Protocol.\r
 \r
   @param *IdeDev\r
@@ -480,7 +480,7 @@ AtaPioDataIn (
 \r
   @retval EFI_SUCCESS send out the ATA command and device received required\r
   data successfully.\r
-  \r
+\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -571,7 +571,7 @@ AtaPioDataOut (
   WordCount = 0;\r
 \r
   while (WordCount < ByteCount / 2) {\r
-    \r
+\r
     //\r
     // DRQReady2-- read Alternate Status Register to determine the DRQ bit\r
     // data transfer can be performed only when DRQ is ready.\r
@@ -595,7 +595,7 @@ AtaPioDataOut (
     //\r
     // perform a series of write without check DRQ ready\r
     //\r
-    \r
+\r
     IDEWritePortWMultiple (\r
       IdeDev->PciIo,\r
       IdeDev->IoPort->Data,\r
@@ -613,7 +613,7 @@ AtaPioDataOut (
 }\r
 \r
 /**\r
-  This function is used to analyze the Status Register and print out \r
+  This function is used to analyze the Status Register and print out\r
   some debug information and if there is ERR bit set in the Status\r
   Register, the Error Register's value is also be parsed and print out.\r
 \r
@@ -729,10 +729,10 @@ CheckErrorStatus (
   to record all the information of the IDE device.\r
 \r
   @param[in] *DataBuffer\r
-  A pointer to the destination buffer for the data. \r
+  A pointer to the destination buffer for the data.\r
 \r
   @param[in] Lba\r
-  The starting logical block address to read from \r
+  The starting logical block address to read from\r
   on the device media.\r
 \r
   @param[in] NumberOfBlocks\r
@@ -770,7 +770,7 @@ AtaReadSectors (
   //\r
   AtaCommand      = READ_SECTORS_CMD;\r
 \r
-  \r
+\r
   BlocksRemaining = NumberOfBlocks;\r
 \r
   Lba32           = (UINT32) Lba;\r
@@ -778,7 +778,7 @@ AtaReadSectors (
   Status          = EFI_SUCCESS;\r
 \r
   while (BlocksRemaining > 0) {\r
-    \r
+\r
     //\r
     // in ATA-3 spec, LBA is in 28 bit width\r
     //\r
@@ -791,7 +791,7 @@ AtaReadSectors (
     Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);\r
 \r
     if (BlocksRemaining >= 0x100) {\r
-      \r
+\r
       //\r
       //  SectorCount8 is sent to Sector Count register, 0x00 means 256\r
       //  sectors to be read\r
@@ -847,10 +847,10 @@ AtaReadSectors (
   to record all the information of the IDE device.\r
 \r
   @param[in] *BufferData\r
-  A pointer to the source buffer for the data. \r
+  A pointer to the source buffer for the data.\r
 \r
   @param[in] Lba\r
-  The starting logical block address to write onto \r
+  The starting logical block address to write onto\r
   the device media.\r
 \r
   @param[in] NumberOfBlocks\r
@@ -902,7 +902,7 @@ AtaWriteSectors (
     Lba3  = (UINT8) ((Lba32 >> 24) & 0x0f);\r
 \r
     if (BlocksRemaining >= 0x100) {\r
-      \r
+\r
       //\r
       //  SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors\r
       //  to be written\r
@@ -945,8 +945,8 @@ AtaWriteSectors (
 \r
 /**\r
   This function is used to implement the Soft Reset on the specified\r
-  device. But, the ATA Soft Reset mechanism is so strong a reset method \r
-  that it will force resetting on both devices connected to the \r
+  device. But, the ATA Soft Reset mechanism is so strong a reset method\r
+  that it will force resetting on both devices connected to the\r
   same cable.\r
 \r
   It is called by IdeBlkIoReset(), a interface function of Block\r
@@ -988,6 +988,10 @@ AtaSoftReset (
 \r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
+  //\r
+  // SRST should assert for at least 5 us, we use 10 us for\r
+  // better compatibility\r
+  //\r
   gBS->Stall (10);\r
 \r
   //\r
@@ -996,6 +1000,11 @@ AtaSoftReset (
   DeviceControl = 0;\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
 \r
+  //\r
+  // Wait for at least 2 ms to check BSY status, we use 10 ms\r
+  // for better compatibility\r
+  //\r
+  gBS->Stall(10000);\r
   //\r
   // slave device needs at most 31s to clear BSY\r
   //\r
@@ -1017,7 +1026,7 @@ AtaSoftReset (
   The media id that the read request is for.\r
 \r
   @param[in] LBA\r
-  The starting logical block address to read from \r
+  The starting logical block address to read from\r
   on the device.\r
 \r
   @param[in] BufferSize\r
@@ -1025,7 +1034,7 @@ AtaSoftReset (
   multiple of the intrinsic block size of the device.\r
 \r
   @param[out] *Buffer\r
-  A pointer to the destination buffer for the data. \r
+  A pointer to the destination buffer for the data.\r
   The caller is responsible for either having implicit\r
   or explicit ownership of the memory that data is read into.\r
 \r
@@ -1033,11 +1042,11 @@ AtaSoftReset (
   @retval EFI_DEVICE_ERROR  Read Blocks failed.\r
   @retval EFI_NO_MEDIA      There is no media in the device.\r
   @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
-  \r
+\r
   @retval EFI_BAD_BUFFER_SIZE\r
   The BufferSize parameter is not a multiple of the\r
   intrinsic block size of the device.\r
-  \r
+\r
   @retval EFI_INVALID_PARAMETER\r
   The read request contains LBAs that are not valid,\r
   or the data buffer is not valid.\r
@@ -1114,13 +1123,9 @@ AtaBlkIoReadBlocks (
   } else {\r
     //\r
     // For ATA-3 compatible device, use ATA-3 read block mechanism\r
-    // Notice DMA operation can only handle 32bit address\r
     //\r
-    if ((UINTN) Buffer <= 0xFFFFFFFF) {\r
-      Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    }\r
-\r
-    if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {\r
+    Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
+    if (EFI_ERROR (Status)) {\r
       Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
   }\r
@@ -1145,7 +1150,7 @@ AtaBlkIoReadBlocks (
   The media id that the write request is for.\r
 \r
   @param[in] LBA\r
-  The starting logical block address to write onto \r
+  The starting logical block address to write onto\r
   the device.\r
 \r
   @param[in] BufferSize\r
@@ -1153,20 +1158,20 @@ AtaBlkIoReadBlocks (
   multiple of the intrinsic block size of the device.\r
 \r
   @param[out] *Buffer\r
-  A pointer to the source buffer for the data. \r
+  A pointer to the source buffer for the data.\r
   The caller is responsible for either having implicit\r
-  or explicit ownership of the memory that data is \r
+  or explicit ownership of the memory that data is\r
   written from.\r
 \r
   @retval EFI_SUCCESS       Write Blocks successfully.\r
   @retval EFI_DEVICE_ERROR  Write Blocks failed.\r
   @retval EFI_NO_MEDIA      There is no media in the device.\r
   @retval EFI_MEDIA_CHANGE  The MediaId is not for the current media.\r
-  \r
+\r
   @retval EFI_BAD_BUFFER_SIZE\r
   The BufferSize parameter is not a multiple of the\r
   intrinsic block size of the device.\r
-  \r
+\r
   @retval EFI_INVALID_PARAMETER\r
   The write request contains LBAs that are not valid,\r
   or the data buffer is not valid.\r
@@ -1241,7 +1246,7 @@ AtaBlkIoWriteBlocks (
     // For ATA-3 compatible device, use ATA-3 write block mechanism\r
     //\r
     Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
-    if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {\r
+    if (EFI_ERROR (Status)) {\r
       Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);\r
     }\r
   }\r
@@ -1256,15 +1261,15 @@ AtaBlkIoWriteBlocks (
 \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
+  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
+  @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
@@ -1339,7 +1344,7 @@ AtaReadSectorsExt (
 \r
 /**\r
   This function is called by the AtaBlkIoWriteBlocks() to perform\r
-  writing onto media in block unit. The function has been enhanced to \r
+  writing onto 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
@@ -1347,10 +1352,10 @@ AtaReadSectorsExt (
   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
+  A pointer to the source buffer for the data.\r
 \r
   @param[in] Lba\r
-  The starting logical block address to write onto \r
+  The starting logical block address to write onto\r
   the device media.\r
 \r
   @param[in] NumberOfBlocks\r
@@ -1427,14 +1432,14 @@ AtaWriteSectorsExt (
 }\r
 \r
 /**\r
-  This function is used to send out ATA commands conforms to the \r
+  This function is used to send out ATA commands conforms to the\r
   PIO Data In Protocol, supporting ATA/ATAPI-6 standard\r
 \r
   Comparing with ATA-3 data in protocol, we have two differents here:<BR>\r
   1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
   wait will frequently fail... cause writing function return error)\r
 \r
-  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly \r
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
   slow down writing performance by 100 times!)\r
 \r
   @param[in] *IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
@@ -1448,7 +1453,7 @@ AtaWriteSectorsExt (
 \r
   @retval EFI_SUCCESS send out the ATA command and device send required\r
   data successfully.\r
-  \r
+\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -1544,7 +1549,7 @@ AtaPioDataInExt (
   // According to PIO data in protocol, host can perform a series of reads to\r
   // the data register after each time device set DRQ ready;\r
   //\r
-  \r
+\r
   //\r
   // 256 words\r
   //\r
@@ -1592,14 +1597,14 @@ AtaPioDataInExt (
 }\r
 \r
 /**\r
-  This function is used to send out ATA commands conforms to the \r
+  This function is used to send out ATA commands conforms to the\r
   PIO Data Out Protocol, supporting ATA/ATAPI-6 standard\r
 \r
   Comparing with ATA-3 data out protocol, we have two differents here:<BR>\r
   1. Do NOT wait for DRQ clear before sending command into IDE device.(the\r
   wait will frequently fail... cause writing function return error)\r
 \r
-  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly \r
+  2. Do NOT wait for DRQ clear after all data readed.(the wait greatly\r
   slow down writing performance by 100 times!)\r
 \r
   @param[in] *IdeDev\r
@@ -1614,7 +1619,7 @@ AtaPioDataInExt (
 \r
   @retval EFI_SUCCESS send out the ATA command and device receive required\r
   data successfully.\r
-  \r
+\r
   @retval EFI_DEVICE_ERROR command sent failed.\r
 \r
 **/\r
@@ -1661,7 +1666,7 @@ AtaPioDataOutExt (
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
-     \r
+\r
   //\r
   // Fill feature register if needed\r
   //\r
@@ -2090,7 +2095,7 @@ AtaCommandIssue (
   //\r
   // Fill the start LBA registers, which are also two-byte FIFO\r
   //\r
-  \r
+\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);\r
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);\r
@@ -2110,15 +2115,15 @@ AtaCommandIssue (
 \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
+  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 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] *DataBuffer A pointer to the destination buffer for the data.\r
 \r
-  @param[in] StartLba The starting logical block address to read from \r
+  @param[in] StartLba The starting logical block address to read from\r
   on the device media.\r
 \r
   @param[in] NumberOfBlocks The number of transfer data blocks.\r
@@ -2139,21 +2144,26 @@ AtaUdmaReadExt (
   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
+  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
+  EFI_PHYSICAL_ADDRESS       MemPage;\r
+  EFI_PHYSICAL_ADDRESS       DeviceAddress;\r
 \r
   //\r
   // Channel and device differential. Select device.\r
@@ -2207,7 +2217,20 @@ AtaUdmaReadExt (
     //\r
     // Build PRD table\r
     //\r
-    PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
+    MemPage = 0xFFFFFFFF;\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage\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
@@ -2225,7 +2248,19 @@ AtaUdmaReadExt (
     //\r
     // Build the PRD table\r
     //\r
-    PrdBuffer   = DataBuffer;\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
+      gBS->FreePages (MemPage, PageCount);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (VOID *) ((UINTN) DeviceAddress);\r
     TempPrdAddr = UsedPrdAddr;\r
     while (TRUE) {\r
 \r
@@ -2245,7 +2280,7 @@ AtaUdmaReadExt (
       PrdBuffer += ByteAvailable;\r
       TempPrdAddr++;\r
     }\r
-  \r
+\r
     //\r
     // Set the base address to BMID register\r
     //\r
@@ -2308,15 +2343,16 @@ AtaUdmaReadExt (
     // 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
+               IdeDev,\r
+               READ_DMA_EXT_CMD,\r
+               Device,\r
+               0,\r
+               (UINT16) NumberOfBlocks,\r
+               StartLba\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      gBS->FreePool (PrdAddr);\r
+      gBS->FreePages (MemPage, PageCount);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
@@ -2345,7 +2381,11 @@ AtaUdmaReadExt (
 \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
@@ -2356,21 +2396,49 @@ AtaUdmaReadExt (
                           1,\r
                           &RegisterValue\r
                           );\r
-      if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
-        if (RegisterValue & BMIS_ERROR) {\r
-          gBS->FreePool (PrdAddr);\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
+          gBS->FreePages (MemPage, PageCount);\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
-    gBS->FreePool (PrdAddr);\r
-\r
+    gBS->FreePages (MemPage, PageCount);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
     //\r
-    // Set START bit of BMIC register\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
@@ -2400,20 +2468,27 @@ AtaUdmaReadExt (
     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 AtaBlkIoReadBlocks() to perform\r
-  reading from media in block unit. The function has been enhanced to \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
+  @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
@@ -2433,21 +2508,26 @@ AtaUdmaRead (
   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
+  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
+  EFI_PHYSICAL_ADDRESS       MemPage;\r
+  EFI_PHYSICAL_ADDRESS       DeviceAddress;\r
 \r
   //\r
   // Channel and device differential\r
@@ -2501,7 +2581,20 @@ AtaUdmaRead (
     //\r
     // Build PRD table\r
     //\r
-    PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
+    MemPage = 0xFFFFFFFF;\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage\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
@@ -2518,7 +2611,19 @@ AtaUdmaRead (
     //\r
     // Build the PRD table\r
     //\r
-    PrdBuffer   = DataBuffer;\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
+      gBS->FreePages (MemPage, PageCount);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (UINT8 *) ((UINTN) DeviceAddress);\r
     TempPrdAddr = UsedPrdAddr;\r
     while (TRUE) {\r
 \r
@@ -2601,15 +2706,16 @@ AtaUdmaRead (
     // 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
+               IdeDev,\r
+               READ_DMA_CMD,\r
+               Device,\r
+               0,\r
+               (UINT16) NumberOfBlocks,\r
+               StartLba\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      gBS->FreePool (PrdAddr);\r
+      gBS->FreePages (MemPage, PageCount);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
@@ -2638,7 +2744,11 @@ AtaUdmaRead (
 \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
@@ -2649,21 +2759,49 @@ AtaUdmaRead (
                           1,\r
                           &RegisterValue\r
                           );\r
-      if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
-        if (RegisterValue & BMIS_ERROR) {\r
-          gBS->FreePool (PrdAddr);\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
+          gBS->FreePages (MemPage, PageCount);\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
-    gBS->FreePool (PrdAddr);\r
-\r
+    gBS->FreePages (MemPage, PageCount);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
     //\r
-    // Set START bit of BMIC register\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
@@ -2693,20 +2831,27 @@ AtaUdmaRead (
     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
+  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
+  @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
+  @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
@@ -2726,21 +2871,26 @@ AtaUdmaWriteExt (
   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
+  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
+  EFI_PHYSICAL_ADDRESS       MemPage;\r
+  EFI_PHYSICAL_ADDRESS       DeviceAddress;\r
 \r
   //\r
   // Channel and device differential\r
@@ -2794,7 +2944,20 @@ AtaUdmaWriteExt (
     //\r
     // Build PRD table\r
     //\r
-    PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
+    MemPage = 0xFFFFFFFF;\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage\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
@@ -2811,7 +2974,19 @@ AtaUdmaWriteExt (
     //\r
     // Build the PRD table\r
     //\r
-    PrdBuffer   = DataBuffer;\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
+      gBS->FreePages (MemPage, PageCount);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (UINT8 *) ((UINTN) DeviceAddress);\r
     TempPrdAddr = UsedPrdAddr;\r
     while (TRUE) {\r
 \r
@@ -2831,7 +3006,7 @@ AtaUdmaWriteExt (
       PrdBuffer += ByteAvailable;\r
       TempPrdAddr++;\r
     }\r
-  \r
+\r
     //\r
     // Set the base address to BMID register\r
     //\r
@@ -2896,15 +3071,16 @@ AtaUdmaWriteExt (
     // 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
+               IdeDev,\r
+               WRITE_DMA_EXT_CMD,\r
+               Device,\r
+               0,\r
+               (UINT16) NumberOfBlocks,\r
+               StartLba\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      gBS->FreePool (PrdAddr);\r
+      gBS->FreePages (MemPage, PageCount);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
@@ -2933,7 +3109,11 @@ AtaUdmaWriteExt (
 \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
@@ -2944,21 +3124,49 @@ AtaUdmaWriteExt (
                           1,\r
                           &RegisterValue\r
                           );\r
-      if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
-        if (RegisterValue & BMIS_ERROR) {\r
-          gBS->FreePool (PrdAddr);\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
+          gBS->FreePages (MemPage, PageCount);\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
-    gBS->FreePool (PrdAddr);\r
-\r
+    gBS->FreePages (MemPage, PageCount);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
     //\r
-    // Set START bit of BMIC register\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
@@ -2984,12 +3192,19 @@ AtaUdmaWriteExt (
     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
+  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
@@ -2997,10 +3212,10 @@ AtaUdmaWriteExt (
   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
+  A pointer to the source buffer for the data.\r
 \r
   @param[in] StartLba\r
-  The starting logical block address to write to \r
+  The starting logical block address to write to\r
   on the device media.\r
 \r
   @param[in] NumberOfBlocks\r
@@ -3021,21 +3236,26 @@ AtaUdmaWrite (
   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
+  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
+  EFI_PHYSICAL_ADDRESS       MemPage;\r
+  EFI_PHYSICAL_ADDRESS       DeviceAddress;\r
 \r
   //\r
   // Channel and device differential\r
@@ -3089,7 +3309,20 @@ AtaUdmaWrite (
     //\r
     // Build PRD table\r
     //\r
-    PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));\r
+    MemPage = 0xFFFFFFFF;\r
+    PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));\r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiBootServicesData,\r
+                    PageCount,\r
+                    &MemPage\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
@@ -3107,7 +3340,19 @@ AtaUdmaWrite (
     //\r
     // Build the PRD table\r
     //\r
-    PrdBuffer   = DataBuffer;\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
+      gBS->FreePages (MemPage, PageCount);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    PrdBuffer   = (UINT8 *) ((UINTN) DeviceAddress);\r
     TempPrdAddr = UsedPrdAddr;\r
     while (TRUE) {\r
 \r
@@ -3127,7 +3372,7 @@ AtaUdmaWrite (
       PrdBuffer += ByteAvailable;\r
       TempPrdAddr++;\r
     }\r
-  \r
+\r
     //\r
     // Set the base address to BMID register\r
     //\r
@@ -3192,15 +3437,16 @@ AtaUdmaWrite (
     // 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
+               IdeDev,\r
+               WRITE_DMA_CMD,\r
+               Device,\r
+               0,\r
+               (UINT16) NumberOfBlocks,\r
+               StartLba\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      gBS->FreePool (PrdAddr);\r
+      gBS->FreePages (MemPage, PageCount);\r
+      IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
       return EFI_DEVICE_ERROR;\r
     }\r
 \r
@@ -3229,7 +3475,11 @@ AtaUdmaWrite (
 \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
@@ -3240,21 +3490,50 @@ AtaUdmaWrite (
                           1,\r
                           &RegisterValue\r
                           );\r
-      if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {\r
-        if (RegisterValue & BMIS_ERROR) {\r
-          gBS->FreePool (PrdAddr);\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
+          gBS->FreePages (MemPage, PageCount);\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
-    gBS->FreePool (PrdAddr);\r
+    gBS->FreePages (MemPage, PageCount);\r
+    IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);\r
 \r
     //\r
-    // Set START bit of BMIC register\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
@@ -3280,5 +3559,12 @@ AtaUdmaWrite (
     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 7043306..a54acf6 100644 (file)
@@ -783,6 +783,15 @@ PioReadWriteData (
     PtrBuffer += WordCount;\r
     ActualWordCount += WordCount;\r
   }\r
+  \r
+  if (Read) {\r
+    //\r
+    // In the case where the drive wants to send more data than we need to read,\r
+    // the DRQ bit will be set and cause delays from DRQClear2().\r
+    // We need to read data from the drive until it clears DRQ so we can move on.\r
+    //\r
+    AtapiReadPendingData (IdeDev);\r
+  }\r
 \r
   //\r
   // After data transfer is completed, normally, DRQ bit should clear.\r
@@ -802,25 +811,25 @@ PioReadWriteData (
   Sends out ATAPI Test Unit Ready Packet Command to the specified device\r
   to find out whether device is accessible.\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
+  @param[in] *IdeDev     Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                         to record all the information of the IDE device.\r
+  @param[in] *SenseCount Sense count for this packet command\r
 \r
-  @retval EFI_SUCCESS\r
-  device is accessible.\r
-  \r
-  @retval EFI_DEVICE_ERROR\r
-  device is not accessible.\r
+  @retval EFI_SUCCESS      Device is accessible.\r
+  @retval EFI_DEVICE_ERROR Device is not accessible.\r
 \r
 **/\r
 EFI_STATUS\r
 AtapiTestUnitReady (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
   )\r
 {\r
   ATAPI_PACKET_COMMAND  Packet;\r
   EFI_STATUS            Status;\r
 \r
+  *SenseCount = 0;\r
+\r
   //\r
   // fill command packet\r
   //\r
@@ -831,7 +840,17 @@ AtapiTestUnitReady (
   // send command packet\r
   //\r
   Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);\r
-  return Status;\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = AtapiRequestSense (IdeDev, SenseCount);\r
+  if (EFI_ERROR (Status)) {\r
+    *SenseCount = 0;\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -927,7 +946,7 @@ AtapiRequestSense (
       //\r
       // Ptr is word-based pointer\r
       //\r
-      Ptr += sizeof (REQUEST_SENSE_DATA) / 2;\r
+      Ptr += (sizeof (REQUEST_SENSE_DATA) + 1) >> 1;\r
 \r
     } else {\r
       //\r
@@ -951,30 +970,28 @@ AtapiRequestSense (
   if the Read Capacity Command failed, the Sense data must be requested\r
   and be analyzed to determine if the Read Capacity Command should retry.\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
+  @param[in] *IdeDev    Pointer pointing to IDE_BLK_IO_DEV data structure, used\r
+                        to record all the information of the IDE device.\r
+  @param[in] SenseCount Sense count for this packet command\r
 \r
-  @retval EFI_SUCCESS\r
-  Read Capacity Command finally completes successfully.\r
-  \r
-  @retval EFI_DEVICE_ERROR\r
-  Read Capacity Command failed because of device error.\r
+  @retval EFI_SUCCESS      Read Capacity Command finally completes successfully.\r
+  @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.\r
 \r
-  @note\r
-  parameter "IdeDev" will be updated in this function.\r
+  @note Parameter "IdeDev" will be updated in this function.\r
 \r
   TODO:    EFI_NOT_READY - add return value to function comment\r
 **/\r
 EFI_STATUS\r
 AtapiReadCapacity (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN               *SenseCount\r
   )\r
 {\r
   //\r
   // status returned by Read Capacity Packet Command\r
   //\r
   EFI_STATUS                Status;\r
+  EFI_STATUS                SenseStatus;\r
   ATAPI_PACKET_COMMAND      Packet;\r
 \r
   //\r
@@ -983,6 +1000,8 @@ AtapiReadCapacity (
   READ_CAPACITY_DATA        Data;\r
   READ_FORMAT_CAPACITY_DATA FormatData;\r
 \r
+  *SenseCount = 0;\r
+\r
   ZeroMem (&Data, sizeof (Data));\r
   ZeroMem (&FormatData, sizeof (FormatData));\r
 \r
@@ -991,12 +1010,12 @@ AtapiReadCapacity (
     ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));\r
     Packet.Inquiry.opcode = READ_CAPACITY;\r
     Status = AtapiPacketCommandIn (\r
-              IdeDev,\r
-              &Packet,\r
-              (UINT16 *) &Data,\r
-              sizeof (READ_CAPACITY_DATA),\r
-              ATAPITIMEOUT\r
-              );\r
+               IdeDev,\r
+               &Packet,\r
+               (UINT16 *) &Data,\r
+               sizeof (READ_CAPACITY_DATA),\r
+               ATAPITIMEOUT\r
+               );\r
 \r
   } else {\r
     //\r
@@ -1006,81 +1025,91 @@ AtapiReadCapacity (
     Packet.ReadFormatCapacity.opcode                = READ_FORMAT_CAPACITY;\r
     Packet.ReadFormatCapacity.allocation_length_lo  = 12;\r
     Status = AtapiPacketCommandIn (\r
-              IdeDev,\r
-              &Packet,\r
-              (UINT16 *) &FormatData,\r
-              sizeof (READ_FORMAT_CAPACITY_DATA),\r
-              ATAPITIMEOUT\r
-              );\r
+               IdeDev,\r
+               &Packet,\r
+               (UINT16 *) &FormatData,\r
+               sizeof (READ_FORMAT_CAPACITY_DATA),\r
+               ATAPITIMEOUT\r
+               );\r
   }\r
 \r
-  if (!EFI_ERROR (Status)) {\r
-\r
-    if (IdeDev->Type == IdeCdRom) {\r
-\r
-      IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
-        (Data.LastLba2 << 16) |\r
-        (Data.LastLba1 << 8) |\r
-        Data.LastLba0;\r
-\r
-      if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
-\r
-        IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
-          (Data.BlockSize2 << 16) |\r
-          (Data.BlockSize1 << 8) |\r
-          Data.BlockSize0;\r
+  if (Status == EFI_TIMEOUT) {\r
+    *SenseCount = 0;\r
+    return Status;\r
+  }\r
 \r
-        IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
-      } else {\r
-        IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
-        return EFI_DEVICE_ERROR;\r
-      }\r
+  SenseStatus = AtapiRequestSense (IdeDev, SenseCount);\r
 \r
-      IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+  if (!EFI_ERROR (SenseStatus)) {\r
 \r
-      //\r
-      // Because the user data portion in the sector of the Data CD supported\r
-      // is always 0x800\r
-      //\r
-      IdeDev->BlkIo.Media->BlockSize = 0x800;\r
-    }\r
+    if (!EFI_ERROR (Status)) {\r
 \r
-    if (IdeDev->Type == IdeMagnetic) {\r
+      if (IdeDev->Type == IdeCdRom) {\r
 \r
-      if (FormatData.DesCode == 3) {\r
-        IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
-        IdeDev->BlkIo.Media->LastBlock    = 0;\r
-      } else {\r
+        IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |\r
+          (Data.LastLba2 << 16) |\r
+          (Data.LastLba1 << 8) |\r
+          Data.LastLba0;\r
 \r
-        IdeDev->BlkIo.Media->LastBlock =  (FormatData.LastLba3 << 24) |\r
-                                          (FormatData.LastLba2 << 16) | \r
-                                          (FormatData.LastLba1 << 8)  |\r
-                                           FormatData.LastLba0;\r
         if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
-          IdeDev->BlkIo.Media->LastBlock--;\r
 \r
-          IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
-            (FormatData.BlockSize1 << 8) |\r
-            FormatData.BlockSize0;\r
+          IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |\r
+            (Data.BlockSize2 << 16) |\r
+            (Data.BlockSize1 << 8) |\r
+            Data.BlockSize0;\r
 \r
           IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
         } else {\r
           IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
-          //\r
-          // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
-          //\r
-          return EFI_NOT_READY;\r
+          return EFI_DEVICE_ERROR;\r
         }\r
 \r
-        IdeDev->BlkIo.Media->BlockSize = 0x200;\r
+        IdeDev->BlkIo.Media->ReadOnly = TRUE;\r
+\r
+        //\r
+        // Because the user data portion in the sector of the Data CD supported\r
+        // is always 0x800\r
+        //\r
+        IdeDev->BlkIo.Media->BlockSize = 0x800;\r
+      }\r
+\r
+      if (IdeDev->Type == IdeMagnetic) {\r
+\r
+        if (FormatData.DesCode == 3) {\r
+          IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+          IdeDev->BlkIo.Media->LastBlock    = 0;\r
+        } else {\r
+\r
+          IdeDev->BlkIo.Media->LastBlock =  (FormatData.LastLba3 << 24) |\r
+            (FormatData.LastLba2 << 16) | \r
+            (FormatData.LastLba1 << 8)  |\r
+            FormatData.LastLba0;\r
+          if (IdeDev->BlkIo.Media->LastBlock != 0) {\r
+            IdeDev->BlkIo.Media->LastBlock--;\r
+\r
+            IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |\r
+              (FormatData.BlockSize1 << 8) |\r
+              FormatData.BlockSize0;\r
+\r
+            IdeDev->BlkIo.Media->MediaPresent = TRUE;\r
+          } else {\r
+            IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+            //\r
+            // Return EFI_NOT_READY operation succeeds but returned capacity is 0\r
+            //\r
+            return EFI_NOT_READY;\r
+          }\r
+\r
+          IdeDev->BlkIo.Media->BlockSize = 0x200;\r
 \r
+        }\r
       }\r
     }\r
 \r
     return EFI_SUCCESS;\r
 \r
   } else {\r
-\r
+    *SenseCount = 0;\r
     return EFI_DEVICE_ERROR;\r
   }\r
 }\r
@@ -1119,240 +1148,158 @@ AtapiDetectMedia (
   OUT BOOLEAN         *MediaChange\r
   )\r
 {\r
-  EFI_STATUS          Status;\r
-  EFI_STATUS          ReadCapacityStatus;\r
-  EFI_BLOCK_IO_MEDIA  OldMediaInfo;\r
-  UINTN               SenseCounts;\r
-  UINTN               RetryIndex;\r
-  UINTN               RetryTimes;\r
-  UINTN               MaximumRetryTimes;\r
-  UINTN               ReadyWaitFactor;\r
-  BOOLEAN             NeedRetry;\r
-  //\r
-  // a flag used to determine whether need to perform Read Capacity command.\r
-  //\r
-  BOOLEAN             NeedReadCapacity;\r
-  BOOLEAN             WriteProtected;\r
+  EFI_STATUS                    Status;\r
+  EFI_STATUS                    CleanStateStatus;\r
+  EFI_BLOCK_IO_MEDIA            OldMediaInfo;\r
+  UINTN                         RetryTimes;\r
+  UINTN                         RetryNotReady;\r
+  UINTN                         SenseCount;\r
+  SENSE_RESULT                  SResult;\r
+  BOOLEAN                       WriteProtected;\r
 \r
+  CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));\r
+  *MediaChange  = FALSE;\r
   //\r
-  // init\r
+  // Retry for SenseDeviceNotReadyNeedRetry.\r
+  // Each retry takes 1s and we limit the upper boundary to\r
+  // 120 times about 2 min.\r
   //\r
-  CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo));\r
-  // OldMediaInfo        = *(IdeDev->BlkIo.Media);\r
-  *MediaChange        = FALSE;\r
-  ReadCapacityStatus  = EFI_DEVICE_ERROR;\r
+  RetryNotReady = 120;\r
 \r
   //\r
-  // if there is no media, or media is not changed,\r
-  // the request sense command will detect faster than read capacity command.\r
-  // read capacity command can be bypassed, thus improve performance.\r
+  // Do Test Unit Ready\r
   //\r
-\r
+ DoTUR:\r
   //\r
-  // Test Unit Ready command is used to detect whether device is accessible,\r
-  // the device will produce corresponding Sense data.\r
+  // Retry 5 times\r
   //\r
-  for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) {\r
-\r
-    Status = AtapiTestUnitReady (IdeDev);\r
-    if (!EFI_ERROR (Status)) {\r
-      //\r
-      // skip the loop if test unit command succeeds.\r
-      //\r
-      break;\r
-    }\r
+  RetryTimes = 5;\r
+  while (RetryTimes != 0) {\r
 \r
-    Status = AtapiSoftReset (IdeDev);\r
+    Status = AtapiTestUnitReady (IdeDev, &SenseCount);\r
 \r
     if (EFI_ERROR (Status)) {\r
-      AtaSoftReset (IdeDev);\r
-    }\r
-  }\r
-\r
-  SenseCounts       = 0;\r
-  NeedReadCapacity  = TRUE;\r
-\r
-  //\r
-  // at most retry 5 times\r
-  //\r
-  MaximumRetryTimes = 5;\r
-  RetryTimes        = 1;\r
-\r
-  for (RetryIndex = 0; \r
-       (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);\r
-       RetryIndex++) {\r
-\r
-    Status = AtapiRequestSense (IdeDev, &SenseCounts);\r
-\r
-    if (!EFI_ERROR (Status)) {\r
       //\r
-      // if first time there is no Sense Key, no need to read capacity any more\r
+      // Test Unit Ready error without sense data.\r
+      // For some devices, this means there's extra data\r
+      // that has not been read, so we read these extra\r
+      // data out before going on.\r
       //\r
-      if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) &&\r
-          (IdeDev->BlkIo.Media->MediaPresent)) {\r
-\r
-        if (RetryIndex == 0) {\r
-          NeedReadCapacity = FALSE;\r
-        }\r
-\r
-      } else {\r
+      CleanStateStatus = AtapiReadPendingData (IdeDev);\r
+      if (EFI_ERROR (CleanStateStatus)) {\r
         //\r
-        // No Media\r
+        // Busy wait failed, try again\r
         //\r
-        if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {\r
-          NeedReadCapacity                  = FALSE;\r
-          IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
-          IdeDev->BlkIo.Media->LastBlock    = 0;\r
+        RetryTimes--;\r
+      }\r
+      //\r
+      // Try again without counting down RetryTimes\r
+      //\r
+      continue;\r
+    } else {\r
+\r
+      ParseSenseData (IdeDev, SenseCount, &SResult);\r
+\r
+      switch (SResult) {\r
+      case SenseNoSenseKey:\r
+        if (IdeDev->BlkIo.Media->MediaPresent) {\r
+          goto Done;\r
         } else {\r
           //\r
-          // Media Changed\r
-          //\r
-          if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {\r
-            NeedReadCapacity = TRUE;\r
-            IdeDev->BlkIo.Media->MediaId++;\r
-          }\r
-          //\r
-          // Media Error\r
+          // Media present but the internal structure need refreshed.\r
+          // Try Read Capacity\r
           //\r
-          if (IsMediaError (IdeDev->SenseData, SenseCounts)) {\r
-            return EFI_DEVICE_ERROR;\r
-          }\r
+          goto DoRC;\r
+        }\r
+        break;\r
+\r
+      case SenseDeviceNotReadyNeedRetry:\r
+        if (--RetryNotReady == 0) {\r
+          return EFI_DEVICE_ERROR;\r
         }\r
+        gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
+        continue;\r
+        break;\r
+\r
+      case SenseNoMedia:\r
+        IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
+        IdeDev->BlkIo.Media->LastBlock    = 0;\r
+        goto Done;\r
+        break;\r
+\r
+      case SenseDeviceNotReadyNoRetry:\r
+      case SenseMediaError:\r
+        return EFI_DEVICE_ERROR;\r
+\r
+      case SenseMediaChange:\r
+        IdeDev->BlkIo.Media->MediaId++;\r
+        goto DoRC;\r
+        break;\r
+\r
+      default:\r
+        RetryTimes--;\r
+        break;\r
       }\r
-    } else {\r
-      //\r
-      // retry once more, if request sense command met errors.\r
-      //\r
-      RetryTimes++;\r
     }\r
   }\r
 \r
-  if (NeedReadCapacity) {\r
-    //\r
-    // at most retry 5 times\r
-    //\r
-    MaximumRetryTimes = 5;\r
-    //\r
-    // initial retry twice\r
-    //\r
-    RetryTimes        = 2;\r
-    ReadyWaitFactor = 2;\r
-\r
-    for (RetryIndex = 0;\r
-         (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);\r
-         RetryIndex++) {\r
+  return EFI_DEVICE_ERROR;\r
 \r
-      ReadCapacityStatus  = AtapiReadCapacity (IdeDev);\r
+  //\r
+  // Do Read Capacity\r
+  //\r
+ DoRC:\r
+    RetryTimes = 5;\r
 \r
-      SenseCounts         = 0;\r
+    while (RetryTimes != 0) {\r
 \r
-      if (!EFI_ERROR (ReadCapacityStatus)) {\r
-        //\r
-        // Read Capacity succeeded\r
-        //\r
-        break;\r
+      Status = AtapiReadCapacity (IdeDev, &SenseCount);\r
 \r
+      if (EFI_ERROR (Status)) {\r
+        RetryTimes--;\r
+        continue;\r
       } else {\r
 \r
-        if (ReadCapacityStatus == EFI_NOT_READY) {\r
-          //\r
-          // If device not ready, wait here... waiting time increases by retry\r
-          // times.\r
-          //\r
-          gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND);\r
-          ReadyWaitFactor++;\r
-          //\r
-          // retry once more\r
-          //\r
-          RetryTimes++;\r
-          continue;\r
-        }\r
-        \r
-        //\r
-        // Other errors returned, requery sense data\r
-        //\r
-        Status = AtapiRequestSense (IdeDev, &SenseCounts);\r
-\r
-        //\r
-        // If Request Sense data failed, reset the device and retry.\r
-        //\r
-        if (EFI_ERROR (Status)) {\r
+        ParseSenseData (IdeDev, SenseCount, &SResult);\r
 \r
-          Status = AtapiSoftReset (IdeDev);\r
+        switch (SResult) {\r
+        case SenseNoSenseKey:\r
+          goto Done;\r
+          break;\r
 \r
+        case SenseDeviceNotReadyNeedRetry:\r
           //\r
-          // if ATAPI soft reset fail,\r
-          // use stronger reset mechanism -- ATA soft reset.\r
-          //\r
-          if (EFI_ERROR (Status)) {\r
-            AtaSoftReset (IdeDev);\r
-          }\r
-          //\r
-          // retry once more\r
+          // We use Test Unit Ready to retry which\r
+          // is faster.\r
           //\r
-          RetryTimes++;\r
-          continue;\r
-        }\r
-        \r
-        //\r
-        // No Media\r
-        //\r
-        if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {\r
+          goto DoTUR;\r
+          break;\r
 \r
+        case SenseNoMedia:\r
           IdeDev->BlkIo.Media->MediaPresent = FALSE;\r
           IdeDev->BlkIo.Media->LastBlock    = 0;\r
-          return EFI_NO_MEDIA;\r
-        }\r
+          goto Done;\r
+          break;\r
 \r
-        if (IsMediaError (IdeDev->SenseData, SenseCounts)) {\r
+        case SenseDeviceNotReadyNoRetry:\r
+        case SenseMediaError:\r
           return EFI_DEVICE_ERROR;\r
-        }\r
-        \r
-        //\r
-        // Media Changed\r
-        //\r
-        if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {\r
+\r
+        case SenseMediaChange:\r
           IdeDev->BlkIo.Media->MediaId++;\r
-        }\r
+          continue;\r
+          break;\r
 \r
-        if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) {\r
-          \r
-          //\r
-          // Drive not ready: if NeedRetry, then retry once more;\r
-          // else return error\r
-          //\r
-          if (NeedRetry) {\r
-            //\r
-            // Stall 1 second to wait for drive becoming ready\r
-            //\r
-            gBS->Stall (1000 * STALL_1_MILLI_SECOND);\r
-            //\r
-            // reset retry variable to zero,\r
-            // to make it retry for "drive in progress of becoming ready".\r
-            //\r
-            RetryIndex = 0;\r
-            continue;\r
-          } else {\r
-            AtapiSoftReset (IdeDev);\r
-            return EFI_DEVICE_ERROR;\r
-          }\r
+        default:\r
+          RetryTimes--;\r
+          break;\r
         }\r
-        //\r
-        // if read capacity fail not for above reasons, retry once more\r
-        //\r
-        RetryTimes++;\r
       }\r
-\r
-    }\r
-  \r
-    //\r
-    // tell whether the readcapacity process is successful or not in the end\r
-    //\r
-    if (EFI_ERROR (ReadCapacityStatus)) {\r
-      return EFI_DEVICE_ERROR;\r
     }\r
-  }\r
 \r
+  return EFI_DEVICE_ERROR;\r
+\r
+ Done:\r
   //\r
   // the following code is to check the write-protected for LS120 media\r
   //\r
@@ -1423,8 +1370,11 @@ AtapiDetectMedia (
           );\r
   }\r
 \r
-  return EFI_SUCCESS;\r
-\r
+  if (IdeDev->BlkIo.Media->MediaPresent) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NO_MEDIA;\r
+  }\r
 }\r
 \r
 /**\r
@@ -1490,7 +1440,7 @@ AtapiReadSectors (
   //\r
   // limit the data bytes that can be transferred by one Read(10) Command\r
   //\r
-  MaxBlock        = (UINT16) (65536 / BlockSize);\r
+  MaxBlock        = 65535;\r
 \r
   BlocksRemaining = NumberOfBlocks;\r
 \r
@@ -2037,259 +1987,114 @@ AtapiBlkIoWriteBlocks (
 \r
 }\r
 \r
-//\r
-// The following functions are a set of helper functions,\r
-// which are used to parse sense key returned by the device.\r
-//\r
-\r
 /**\r
-  TODO: Add function description\r
+  This function is used to parse sense data. Only the first\r
+  sense data is honoured.\r
 \r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
+  @param[in] IdeDev     Indicates the calling context.\r
+  @param[in] SenseCount Count of sense data.\r
+  @param[out] Result    The parsed result.\r
 \r
-  TODO: add return values\r
+  @retval EFI_SUCCESS           Successfully parsed.\r
+  @retval EFI_INVALID_PARAMETER Count of sense data is zero.\r
 \r
 **/\r
-BOOLEAN\r
-IsNoMedia (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
+EFI_STATUS\r
+ParseSenseData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev,\r
+  IN UINTN              SenseCount,\r
+  OUT SENSE_RESULT      *Result\r
   )\r
 {\r
-  REQUEST_SENSE_DATA  *SensePointer;\r
-  UINTN               Index;\r
-  BOOLEAN             NoMedia;\r
-\r
-  NoMedia       = FALSE;\r
-  SensePointer  = SenseData;\r
-\r
-  for (Index = 0; Index < SenseCounts; Index++) {\r
-    //\r
-    // Sense Key is SK_NOT_READY (0x2),\r
-    // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
-    //\r
-    if ((SensePointer->sense_key == SK_NOT_READY) &&\r
-        (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) {\r
-\r
-      NoMedia = TRUE;\r
-    }\r
+  REQUEST_SENSE_DATA      *SenseData;\r
 \r
-    SensePointer++;\r
+  if (SenseCount == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  return NoMedia;\r
-}\r
-\r
-/**\r
-  Test if the device meets a media error after media changed\r
-\r
-  @param[in] *SenseData\r
-  pointer pointing to ATAPI device sense data list.\r
-  @param[in] SenseCounts\r
-  sense data number of the list          \r
-\r
-  @retval TRUE Device meets a media error\r
-  @retval FALSE No media error\r
-\r
-**/\r
-BOOLEAN\r
-IsMediaError (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-{\r
-  REQUEST_SENSE_DATA  *SensePointer;\r
-  UINTN               Index;\r
-  BOOLEAN             IsError;\r
-\r
-  IsError       = FALSE;\r
-  SensePointer  = SenseData;\r
-\r
-  for (Index = 0; Index < SenseCounts; Index++) {\r
-\r
-    switch (SensePointer->sense_key) {\r
-\r
-    case SK_MEDIUM_ERROR:\r
-      //\r
-      // Sense Key is SK_MEDIUM_ERROR (0x3)\r
-      //\r
-      switch (SensePointer->addnl_sense_code) {\r
-      case ASC_MEDIA_ERR1:\r
-      case ASC_MEDIA_ERR2:\r
-      case ASC_MEDIA_ERR3:\r
-      case ASC_MEDIA_ERR4:\r
-        IsError = TRUE;\r
-        break;\r
-\r
-      default:\r
-        break;\r
-      }\r
+  //\r
+  // Only use the first sense data\r
+  //\r
+  SenseData = IdeDev->SenseData;\r
+  *Result   = SenseOtherSense;\r
 \r
+  switch (SenseData->sense_key) {\r
+  case SK_NO_SENSE:\r
+    *Result = SenseNoSenseKey;\r
+    break;\r
+  case SK_NOT_READY:\r
+    switch (SenseData->addnl_sense_code) {\r
+    case ASC_NO_MEDIA:\r
+      *Result = SenseNoMedia;\r
       break;\r
-\r
-    case SK_NOT_READY:\r
-      //\r
-      // Sense Key is SK_NOT_READY (0x2)\r
-      //\r
-      switch (SensePointer->addnl_sense_code) {\r
-      //\r
-      // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
-      //\r
-      case ASC_MEDIA_UPSIDE_DOWN:\r
-        IsError = TRUE;\r
-        break;\r
-\r
-      default:\r
-        break;\r
-      }\r
+    case ASC_MEDIA_UPSIDE_DOWN:\r
+      *Result = SenseMediaError;\r
       break;\r
-\r
-    default:\r
+    case ASC_NOT_READY:\r
+      if (SenseData->addnl_sense_code_qualifier == ASCQ_IN_PROGRESS) {\r
+        *Result = SenseDeviceNotReadyNeedRetry;\r
+      } else {\r
+        *Result = SenseDeviceNotReadyNoRetry;\r
+      }\r
       break;\r
     }\r
-\r
-    SensePointer++;\r
-  }\r
-\r
-  return IsError;\r
-}\r
-\r
-/**\r
-  TODO: Add function description\r
-\r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-\r
-  TODO: add return values\r
-\r
-**/\r
-BOOLEAN\r
-IsMediaChange (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-{\r
-  REQUEST_SENSE_DATA  *SensePointer;\r
-  UINTN               Index;\r
-  BOOLEAN             IsMediaChange;\r
-\r
-  IsMediaChange = FALSE;\r
-  SensePointer  = SenseData;\r
-\r
-  for (Index = 0; Index < SenseCounts; Index++) {\r
-    //\r
-    // Sense Key is SK_UNIT_ATTENTION (0x6)\r
-    //\r
-    if ((SensePointer->sense_key == SK_UNIT_ATTENTION) &&\r
-        (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) {\r
-\r
-      IsMediaChange = TRUE;\r
+    break;\r
+  case SK_UNIT_ATTENTION:\r
+    if (SenseData->addnl_sense_code == ASC_MEDIA_CHANGE) {\r
+      *Result = SenseMediaChange;\r
     }\r
-\r
-    SensePointer++;\r
-  }\r
-\r
-  return IsMediaChange;\r
-}\r
-\r
-/**\r
-  TODO: Add function description\r
-\r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-  @param  NeedRetry TODO: add argument description\r
-\r
-  TODO: add return values\r
-\r
-**/\r
-BOOLEAN\r
-IsDriveReady (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts,\r
-  OUT BOOLEAN               *NeedRetry\r
-  )\r
-{\r
-  REQUEST_SENSE_DATA  *SensePointer;\r
-  UINTN               Index;\r
-  BOOLEAN             IsReady;\r
-\r
-  IsReady       = TRUE;\r
-  *NeedRetry    = FALSE;\r
-  SensePointer  = SenseData;\r
-\r
-  for (Index = 0; Index < SenseCounts; Index++) {\r
-\r
-    switch (SensePointer->sense_key) {\r
-\r
-    case SK_NOT_READY:\r
-      //\r
-      // Sense Key is SK_NOT_READY (0x2)\r
-      //\r
-      switch (SensePointer->addnl_sense_code) {\r
-      case ASC_NOT_READY:\r
-        //\r
-        // Additional Sense Code is ASC_NOT_READY (0x4)\r
-        //\r
-        switch (SensePointer->addnl_sense_code_qualifier) {\r
-        case ASCQ_IN_PROGRESS:\r
-          //\r
-          // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1)\r
-          //\r
-          IsReady     = FALSE;\r
-          *NeedRetry  = TRUE;\r
-          break;\r
-\r
-        default:\r
-          IsReady     = FALSE;\r
-          *NeedRetry  = FALSE;\r
-          break;\r
-        }\r
-        break;\r
-\r
-      default:\r
-        break;\r
-      }\r
-      break;\r
-\r
-    default:\r
+    break;\r
+  case SK_MEDIUM_ERROR:\r
+    switch (SenseData->addnl_sense_code) {\r
+    case ASC_MEDIA_ERR1:\r
+    case ASC_MEDIA_ERR2:\r
+    case ASC_MEDIA_ERR3:\r
+    case ASC_MEDIA_ERR4:\r
+      *Result = SenseMediaError;\r
       break;\r
     }\r
-\r
-    SensePointer++;\r
+    break;\r
+  default:\r
+    break;\r
   }\r
 \r
-  return IsReady;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
-  TODO: Add function description\r
+  This function reads the pending data in the device.\r
 \r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
+  @param[in] IdeDev   Indicates the calling context.\r
 \r
-  TODO: add return values\r
+  @retval EFI_SUCCESS   Successfully read.\r
+  @retval EFI_NOT_READY The BSY is set avoiding reading.\r
 \r
 **/\r
-BOOLEAN\r
-HaveSenseKey (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev\r
   )\r
 {\r
-  BOOLEAN Have;\r
+  UINT8     AltRegister;\r
+  UINT16    TempWordBuffer;\r
 \r
-  Have = TRUE;\r
-\r
-  //\r
-  // if first sense key in the Sense Data Array is SK_NO_SENSE,\r
-  // it indicates there is no more sense key in the Sense Data Array.\r
-  //\r
-  if (SenseData->sense_key == SK_NO_SENSE) {\r
-    Have = FALSE;\r
+  AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
+  if ((AltRegister & BSY) == BSY) {\r
+    return EFI_NOT_READY;\r
   }\r
-\r
-  return Have;\r
+  if ((AltRegister & (BSY | DRQ)) == DRQ) {\r
+    TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+    while ((TempWordBuffer & (BSY | DRQ)) == DRQ) {\r
+      IDEReadPortWMultiple (\r
+        IdeDev->PciIo,\r
+        IdeDev->IoPort->Data, \r
+        1, \r
+        &TempWordBuffer\r
+        );\r
+      TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
index d9562c9..0b28c57 100644 (file)
 \r
 #include "idebus.h"\r
 \r
-BOOLEAN SlaveDeviceExist  = FALSE;\r
-BOOLEAN MasterDeviceExist = FALSE;\r
+BOOLEAN ChannelDeviceDetected = FALSE;\r
+BOOLEAN SlaveDeviceExist      = FALSE;\r
+UINT8   SlaveDeviceType       = INVALID_DEVICE_TYPE;\r
+BOOLEAN MasterDeviceExist     = FALSE;\r
+UINT8   MasterDeviceType      = INVALID_DEVICE_TYPE;\r
 \r
 /**\r
   TODO: Add function description\r
@@ -464,57 +467,6 @@ ReassignIdeResources (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Read SATA registers to detect SATA disks\r
-\r
-  @param  IdeDev The BLK_IO private data which specifies the IDE device\r
-\r
-**/\r
-EFI_STATUS\r
-CheckPowerMode (\r
-  IDE_BLK_IO_DEV    *IdeDev\r
-  )\r
-// TODO:    EFI_NOT_FOUND - add return value to function comment\r
-// TODO:    EFI_SUCCESS - add return value to function comment\r
-// TODO:    EFI_NOT_FOUND - add return value to function comment\r
-{\r
-  UINT8       ErrorRegister;\r
-  EFI_STATUS  Status;\r
-\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
-    );\r
-\r
-  //\r
-  // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists\r
-  // a device (initial state). Normally, BSY is also in clear state if there is\r
-  // no device\r
-  //\r
-  Status = WaitForBSYClear (IdeDev, 31000);\r
-  if (EFI_ERROR (Status)) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  //\r
-  // select device, read error register\r
-  //\r
-  IDEWritePortB (\r
-    IdeDev->PciIo,\r
-    IdeDev->IoPort->Head,\r
-    (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
-    );\r
-  Status        = DRDYReady (IdeDev, 200);\r
-\r
-  ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
-  if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) {\r
-    return EFI_SUCCESS;\r
-  } else {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-}\r
-\r
 //\r
 // DiscoverIdeDevice\r
 //\r
@@ -533,44 +485,67 @@ DiscoverIdeDevice (
 // TODO:    EFI_SUCCESS - add return value to function comment\r
 {\r
   EFI_STATUS  Status;\r
-  BOOLEAN     SataFlag;\r
-\r
-  SataFlag = FALSE;\r
-  //\r
-  // This extra detection is for SATA disks\r
-  //\r
-  Status = CheckPowerMode (IdeDev);\r
-  if (Status == EFI_SUCCESS) {\r
-    SataFlag = TRUE;\r
-  }\r
 \r
   //\r
   // If a channel has not been checked, check it now. Then set it to "checked" state\r
   // After this step, all devices in this channel have been checked.\r
   //\r
-  Status = DetectIDEController (IdeDev);\r
-\r
-  if ((EFI_ERROR (Status)) && !SataFlag) {\r
-    return EFI_NOT_FOUND;\r
+  if (ChannelDeviceDetected == FALSE) {\r
+    Status = DetectIDEController (IdeDev);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
   }\r
 \r
+  Status = EFI_NOT_FOUND;\r
+\r
   //\r
-  // Device exists. test if it is an ATA device\r
+  // Device exists. test if it is an ATA device.\r
+  // Prefer the result from DetectIDEController,\r
+  // if failed, try another device type to handle\r
+  // devices that not follow the spec.\r
   //\r
-  Status = ATAIdentify (IdeDev);\r
-  if (EFI_ERROR (Status)) {\r
-    //\r
-    // if not ATA device, test if it is an ATAPI device\r
-    //\r
-    Status = ATAPIIdentify (IdeDev);\r
-    if (EFI_ERROR (Status)) {\r
-      //\r
-      // if not ATAPI device either, return error.\r
-      //\r
-      return EFI_NOT_FOUND;\r
+  if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
+    if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          MasterDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
     }\r
   }\r
-\r
+  if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
+    if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
+      Status = ATAIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAPIIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
+        }\r
+      }\r
+    } else {\r
+      Status = ATAPIIdentify (IdeDev);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = ATAIdentify (IdeDev);\r
+        if (!EFI_ERROR (Status)) {\r
+          SlaveDeviceType = ATA_DEVICE_TYPE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
   //\r
   // Init Block I/O interface\r
   //\r
@@ -595,6 +570,26 @@ DiscoverIdeDevice (
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  This interface is used to initialize all state data related to the detection of one\r
+  channel.\r
+\r
+  @retval EFI_SUCCESS Completed Successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+  VOID\r
+  )\r
+{\r
+  ChannelDeviceDetected = FALSE;\r
+  MasterDeviceExist = FALSE;\r
+  MasterDeviceType  = 0xff;\r
+  SlaveDeviceExist  = FALSE;\r
+  SlaveDeviceType   = 0xff;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   This function is called by DiscoverIdeDevice(). It is used for detect\r
   whether the IDE device exists in the specified Channel as the specified\r
@@ -633,31 +628,12 @@ DetectIDEController (
   )\r
 {\r
   EFI_STATUS  Status;\r
-  UINT8       ErrorReg;\r
-  UINT8       StatusReg;\r
+  UINT8       SectorCountReg;\r
+  UINT8       LBALowReg;\r
+  UINT8       LBAMidReg;\r
+  UINT8       LBAHighReg;\r
   UINT8       InitStatusReg;\r
-  EFI_STATUS  DeviceStatus;\r
-\r
-  //\r
-  // Slave device has been detected with master device.\r
-  //\r
-  if ((IdeDev->Device) == 1) {\r
-    if (SlaveDeviceExist) {\r
-      //\r
-      // If master not exists but slave exists, slave have to wait a while\r
-      //\r
-      if (!MasterDeviceExist) {\r
-        //\r
-        // if single slave can't be detected, add delay 4s here.\r
-        //\r
-        gBS->Stall (4000000);\r
-      }\r
-\r
-      return EFI_SUCCESS;\r
-    } else {\r
-      return EFI_NOT_FOUND;\r
-    }\r
-  }\r
+  UINT8       StatusReg;\r
 \r
   //\r
   // Select slave device\r
@@ -675,7 +651,7 @@ DetectIDEController (
   InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
 \r
   //\r
-  // Select master back\r
+  // Select Master back\r
   //\r
   IDEWritePortB (\r
     IdeDev->PciIo,\r
@@ -683,6 +659,7 @@ DetectIDEController (
     (UINT8) ((0 << 4) | 0xe0)\r
     );\r
   gBS->Stall (100);\r
+\r
   //\r
   // Send ATA Device Execut Diagnostic command.\r
   // This command should work no matter DRDY is ready or not\r
@@ -690,88 +667,124 @@ DetectIDEController (
   IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
 \r
   Status    = WaitForBSYClear (IdeDev, 3500);\r
-\r
-  ErrorReg  = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
-\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
+    return Status;\r
+  }\r
   //\r
-  // Master Error register is 0x01. D0 passed, D1 passed or not present.\r
-  // Master Error register is 0x81. D0 passed, D1 failed. Return.\r
-  // Master Error register is other value. D0 failed, D1 passed or not present..\r
+  // Read device signature\r
   //\r
-  if (ErrorReg == 0x01) {\r
-    MasterDeviceExist = TRUE;\r
-    DeviceStatus      = EFI_SUCCESS;\r
-  } else if (ErrorReg == 0x81) {\r
-\r
+  //\r
+  // Select Master\r
+  //\r
+  IDEWritePortB (\r
+    IdeDev->PciIo,\r
+    IdeDev->IoPort->Head,\r
+    (UINT8) ((0 << 4) | 0xe0)\r
+    );\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorNumber\r
+                     );\r
+  LBAMidReg      = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderLsb\r
+                     );\r
+  LBAHighReg     = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->CylinderMsb\r
+                     );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
     MasterDeviceExist = TRUE;\r
-    DeviceStatus      = EFI_SUCCESS;\r
-    SlaveDeviceExist  = FALSE;\r
-\r
-    return DeviceStatus;\r
+    MasterDeviceType  = ATA_DEVICE_TYPE;\r
   } else {\r
-    MasterDeviceExist = FALSE;\r
-    DeviceStatus      = EFI_NOT_FOUND;\r
+    if ((LBAMidReg      == 0x14) &&\r
+        (LBAHighReg     == 0xeb)) {\r
+      MasterDeviceExist = TRUE;\r
+      MasterDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
   }\r
 \r
   //\r
-  // Master Error register is not 0x81, Go on check Slave\r
-  //\r
-\r
-  //\r
-  // Stall 20ms to wait for slave device ready if master device not exists\r
+  // For some Hard Drive, it takes some time to get\r
+  // the right signature when operating in single slave mode.\r
+  // We stall 20ms to work around this.\r
   //\r
   if (!MasterDeviceExist) {\r
     gBS->Stall (20000);\r
   }\r
 \r
   //\r
-  // select slave\r
+  // Select Slave\r
   //\r
   IDEWritePortB (\r
     IdeDev->PciIo,\r
     IdeDev->IoPort->Head,\r
     (UINT8) ((1 << 4) | 0xe0)\r
     );\r
-\r
-  gBS->Stall (300);\r
-  ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
-\r
-  //\r
-  // Slave Error register is not 0x01, D1 failed. Return.\r
-  //\r
-  if (ErrorReg != 0x01) {\r
-    SlaveDeviceExist = FALSE;\r
-    return DeviceStatus;\r
+  gBS->Stall (100);\r
+  SectorCountReg = IDEReadPortB (\r
+                     IdeDev->PciIo,\r
+                     IdeDev->IoPort->SectorCount\r
+                     );\r
+  LBALowReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->SectorNumber\r
+                 );\r
+  LBAMidReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderLsb\r
+                 );\r
+  LBAHighReg = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->CylinderMsb\r
+                 );\r
+  StatusReg  = IDEReadPortB (\r
+                 IdeDev->PciIo,\r
+                 IdeDev->IoPort->Reg.Status\r
+                 );\r
+  if ((SectorCountReg == 0x1) &&\r
+      (LBALowReg      == 0x1) &&\r
+      (LBAMidReg      == 0x0) &&\r
+      (LBAHighReg     == 0x0)) {\r
+    SlaveDeviceExist = TRUE;\r
+    SlaveDeviceType  = ATA_DEVICE_TYPE;\r
+  } else {\r
+    if ((LBAMidReg     == 0x14) &&\r
+        (LBAHighReg    == 0xeb)) {\r
+      SlaveDeviceExist = TRUE;\r
+      SlaveDeviceType  = ATAPI_DEVICE_TYPE;\r
+    }\r
   }\r
 \r
-  StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
-\r
   //\r
-  // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate\r
-  //   "ATAPI TEST UNIT READY" command\r
+  // When single master is plugged, slave device\r
+  // will be wrongly detected. Here's the workaround\r
+  // for ATA devices by detecting DRY bit in status\r
+  // register.\r
+  // NOTE: This workaround doesn't apply to ATAPI.\r
   //\r
-  if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) {\r
-    Status = AtapiTestUnitReady (IdeDev);\r
-\r
-    //\r
-    // Still fail, Slave doesn't exist.\r
-    //\r
-    if (EFI_ERROR (Status)) {\r
-      SlaveDeviceExist = FALSE;\r
-      return DeviceStatus;\r
-    }\r
+  if (MasterDeviceExist && SlaveDeviceExist &&\r
+      (StatusReg & DRDY) == 0               &&\r
+      (InitStatusReg & DRDY) == 0           &&\r
+      MasterDeviceType == SlaveDeviceType   &&\r
+      SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
+    SlaveDeviceExist = FALSE;\r
   }\r
 \r
   //\r
-  // Error reg is 0x01 and DRDY is ready,\r
-  //  or ATAPI test unit ready success,\r
-  //  or  init Slave status DRDY is ready\r
-  // Slave exists.\r
+  // Indicate this channel has been detected\r
   //\r
-  SlaveDeviceExist = TRUE;\r
-\r
-  return DeviceStatus;\r
-\r
+  ChannelDeviceDetected = TRUE;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -1251,7 +1264,7 @@ DRDYReady (
       }\r
     }\r
 \r
-    gBS->Stall (15);\r
+    gBS->Stall (30);\r
 \r
     Delay--;\r
   } while (Delay);\r
@@ -1432,6 +1445,11 @@ ReleaseIdeResources (
     gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
   }\r
 \r
+  if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
+    gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
+    IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
+  }\r
+\r
   gBS->FreePool (IdeBlkIoDevice);\r
   IdeBlkIoDevice = NULL;\r
 \r
@@ -1553,8 +1571,14 @@ AtaNonDataCommandIn (
 \r
   //\r
   // Wait for command completion\r
+  // For ATA_SMART_CMD, we may need more timeout to let device\r
+  // adjust internal states.\r
   //\r
-  Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  if (AtaCommand == ATA_SMART_CMD) {\r
+    Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
+  } else {\r
+    Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
+  }\r
   if (EFI_ERROR (Status)) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -1716,12 +1740,11 @@ SetDriveParameters (
   //\r
   // Send Init drive parameters\r
   //\r
-  Status = AtaPioDataIn (\r
+  Status = AtaNonDataCommandIn (\r
             IdeDev,\r
-            NULL,\r
-            0,\r
             INIT_DRIVE_PARAM_CMD,\r
             (UINT8) (DeviceSelect + DriveParameters->Heads),\r
+            0,\r
             DriveParameters->Sector,\r
             0,\r
             0,\r
@@ -1731,18 +1754,16 @@ SetDriveParameters (
   //\r
   // Send Set Multiple parameters\r
   //\r
-  Status = AtaPioDataIn (\r
+  Status = AtaNonDataCommandIn (\r
             IdeDev,\r
-            NULL,\r
-            0,\r
             SET_MULTIPLE_MODE_CMD,\r
             DeviceSelect,\r
+            0,\r
             DriveParameters->MultipleSector,\r
             0,\r
             0,\r
             0\r
             );\r
-\r
   return Status;\r
 }\r
 \r
@@ -1769,13 +1790,13 @@ EnableInterrupt (
 \r
   return EFI_SUCCESS;\r
 }\r
+\r
 /**\r
   Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
 \r
   @param[in]  Event   Pointer to this event\r
   @param[in]  Context Event hanlder private data\r
 \r
-\r
 **/\r
 VOID\r
 EFIAPI\r
index bb9c460..b83a82a 100644 (file)
@@ -1,15 +1,15 @@
 /** @file\r
-  Header file for IDE Bus Driver, containing the helper functions' \r
+  Header file for IDE Bus Driver, containing the helper functions'\r
   entire prototype.\r
 \r
-  Copyright (c) 2006, Intel Corporation                                                         \r
-  All rights reserved. This program and the accompanying materials                          \r
-  are licensed and made available under the terms and conditions of the BSD License         \r
-  which accompanies this distribution.  The full text of the license may be found at        \r
-  http://opensource.org/licenses/bsd-license.php                                            \r
+  Copyright (c) 2006, Intel Corporation\r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
 \r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
   @par Revision Reference:\r
   2002-6: Add Atapi6 enhancement, support >120GB hard disk, including\r
@@ -198,6 +198,19 @@ DiscoverIdeDevice (
   )\r
 ;\r
 \r
+/**\r
+  This interface is used to initialize all state data related to the\r
+  detection of one channel.\r
+\r
+  @retval EFI_SUCCESS Completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InitializeIDEChannelData (\r
+  VOID\r
+  )\r
+;\r
+\r
 /**\r
   TODO: Add function description\r
 \r
@@ -661,6 +674,7 @@ PioReadWriteData (
 /**\r
   TODO: Add function description\r
 \r
+  @param  IdeDev TODO: add argument description\r
   @param  IdeDev TODO: add argument description\r
 \r
   TODO: add return values\r
@@ -668,7 +682,8 @@ PioReadWriteData (
 **/\r
 EFI_STATUS\r
 AtapiTestUnitReady (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
   )\r
 ;\r
 \r
@@ -691,6 +706,7 @@ AtapiRequestSense (
 /**\r
   TODO: Add function description\r
 \r
+  @param  IdeDev TODO: add argument description\r
   @param  IdeDev TODO: add argument description\r
 \r
   TODO: add return values\r
@@ -698,7 +714,8 @@ AtapiRequestSense (
 **/\r
 EFI_STATUS\r
 AtapiReadCapacity (\r
-  IN  IDE_BLK_IO_DEV  *IdeDev\r
+  IN  IDE_BLK_IO_DEV  *IdeDev,\r
+  OUT UINTN           *SenseCount\r
   )\r
 ;\r
 \r
@@ -819,82 +836,32 @@ AtapiBlkIoWriteBlocks (
 /**\r
   TODO: Add function description\r
 \r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-\r
-  TODO: add return values\r
-\r
-**/\r
-BOOLEAN\r
-IsNoMedia (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-;\r
-\r
-/**\r
-  TODO: Add function description\r
-\r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-\r
-  TODO: add return values\r
-\r
-**/\r
-BOOLEAN\r
-IsMediaError (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-;\r
-\r
-/**\r
-  TODO: Add function description\r
-\r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-\r
-  TODO: add return values\r
-\r
-**/\r
-BOOLEAN\r
-IsMediaChange (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
-  )\r
-;\r
-\r
-/**\r
-  TODO: Add function description\r
-\r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
-  @param  NeedRetry TODO: add argument description\r
+  @param  IdeDev TODO: add argument description\r
+  @param  SenseCount TODO: add argument description\r
+  @param  Result TODO: add argument description\r
 \r
   TODO: add return values\r
 \r
 **/\r
-BOOLEAN\r
-IsDriveReady (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts,\r
-  OUT BOOLEAN               *NeedRetry\r
+EFI_STATUS\r
+ParseSenseData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev,\r
+  IN UINTN              SenseCount,\r
+  OUT SENSE_RESULT      *Result\r
   )\r
 ;\r
 \r
 /**\r
   TODO: Add function description\r
 \r
-  @param  SenseData TODO: add argument description\r
-  @param  SenseCounts TODO: add argument description\r
+  @param  IdeDev TODO: add argument description\r
 \r
   TODO: add return values\r
 \r
 **/\r
-BOOLEAN\r
-HaveSenseKey (\r
-  IN  REQUEST_SENSE_DATA    *SenseData,\r
-  IN  UINTN                 SenseCounts\r
+EFI_STATUS\r
+AtapiReadPendingData (\r
+  IN IDE_BLK_IO_DEV     *IdeDev\r
   )\r
 ;\r
 \r
@@ -1304,6 +1271,7 @@ EnableInterrupt (
   IN IDE_BLK_IO_DEV       *IdeDev\r
   )\r
 ;\r
+\r
 /**\r
   Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
 \r
index 45baa9e..83dd551 100644 (file)
@@ -183,7 +183,6 @@ IDEBusDriverBindingStart (
   UINTN                             DataSize;\r
   UINT32                            Attributes;\r
   IDE_BUS_DRIVER_PRIVATE_DATA       *IdeBusDriverPrivateData;\r
-  EFI_EVENT                         Event;\r
 \r
   //\r
   // Local variables declaration for IdeControllerInit support\r
@@ -417,6 +416,12 @@ IDEBusDriverBindingStart (
               EfiIdeBusBeforeDevicePresenceDetection,\r
               IdeChannel\r
               );\r
+\r
+    //\r
+    // Prepare to detect IDE device of this channel\r
+    //\r
+    InitializeIDEChannelData ();\r
+\r
     //\r
     // -- 1st inner loop --- Master/Slave ------------  Step14\r
     //\r
@@ -488,6 +493,15 @@ IDEBusDriverBindingStart (
       IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData;\r
       IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr;\r
 \r
+      //\r
+      // Report Status code: is about to detect IDE drive\r
+      //\r
+      REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
+        EFI_PROGRESS_CODE,\r
+        (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),\r
+        IdeBlkIoDevicePtr->DevicePath\r
+        );\r
+\r
       //\r
       // Discover device, now!\r
       //\r
@@ -523,7 +537,6 @@ IDEBusDriverBindingStart (
         // Submit identify data to IDE controller init driver\r
         //\r
         CopyMem (&IdentifyData, IdeBlkIoDevicePtr->pIdData, sizeof (IdentifyData));\r
-        // IdentifyData  = *IdeBlkIoDevicePtr->pIdData;\r
         IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE;\r
         IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData);\r
       } else {\r
@@ -706,10 +719,9 @@ IDEBusDriverBindingStart (
                       EFI_TPL_NOTIFY,\r
                       ClearInterrupt,\r
                       IdeBlkIoDevicePtr,\r
-                      &Event\r
+                      &IdeBlkIoDevicePtr->ExitBootServiceEvent\r
                       );\r
 \r
-  \r
       //\r
       // end of 2nd inner loop ----\r
       //\r
@@ -1028,7 +1040,8 @@ IDEBlkIoReset (
   //\r
   // for ATA device, using ATA reset method\r
   //\r
-  if (IdeBlkIoDevice->Type == IdeHardDisk) {\r
+  if (IdeBlkIoDevice->Type == IdeHardDisk ||\r
+      IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {\r
     return AtaSoftReset (IdeBlkIoDevice);\r
   }\r
 \r
index d1721b9..e49e762 100644 (file)
 #define MAX_IDE_CHANNELS  2\r
 #define MAX_IDE_DRIVES    2\r
 \r
+#define INVALID_DEVICE_TYPE 0xff\r
+#define ATA_DEVICE_TYPE     0x00\r
+#define ATAPI_DEVICE_TYPE   0x01\r
+\r
 typedef struct {\r
   BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE];\r
   BOOLEAN DeviceFound[MAX_IDE_DEVICE];\r
@@ -67,6 +71,11 @@ typedef struct {
   UINT8                       SenseDataNumber;\r
   UINT8                       *Cache;\r
 \r
+  //\r
+  // ExitBootService Event, it is used to clear pending IDE interrupt\r
+  //\r
+  EFI_EVENT                   ExitBootServiceEvent;\r
+\r
   EFI_UNICODE_STRING_TABLE    *ControllerNameTable;\r
 } IDE_BLK_IO_DEV;\r
 \r
index 55ae217..ec088dc 100644 (file)
@@ -76,6 +76,16 @@ typedef enum {
   IdeUnknown\r
 } IDE_DEVICE_TYPE;\r
 \r
+typedef enum {\r
+  SenseNoSenseKey,\r
+  SenseDeviceNotReadyNoRetry,\r
+  SenseDeviceNotReadyNeedRetry,\r
+  SenseNoMedia,\r
+  SenseMediaChange,\r
+  SenseMediaError,\r
+  SenseOtherSense\r
+} SENSE_RESULT;\r
+\r
 //\r
 // IDE Registers\r
 //\r
@@ -234,6 +244,11 @@ typedef struct {
 //\r
 #define ATAPILONGTIMEOUT  5000  \r
 \r
+//\r
+// 10 seconds\r
+//\r
+#define ATASMARTTIMEOUT   10000\r
+\r
 //\r
 // ATA Commands Code\r
 //\r