]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
1. Changed device detect method to use ATA/ATAPI device signature;
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / IdeBus / Dxe / atapi.c
index 70433066420bba4c74dafc4e683ae8033fc7b286..a54acf6994f3a1130f772de78a4181414d19dc99 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