Media detection logic is enhanced to be more robust.

Signed-off-by: erictian
Reviewed-by: hhuan13
Reviewed-by: mdkinney

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12289 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index e9a7788..e8c8ee7 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -697,27 +697,50 @@
   )

 {

   EFI_STATUS          Status;

-  EFI_STATUS          ReadCapacityStatus;

   EFI_SCSI_SENSE_DATA *SenseData;

   UINTN               NumberOfSenseKeys;

   BOOLEAN             NeedRetry;

   BOOLEAN             NeedReadCapacity;

-  UINT8               Index;

+  UINT8               Retry;

   UINT8               MaxRetry;

   EFI_BLOCK_IO_MEDIA  OldMedia;

   UINTN               Action;

+  EFI_EVENT           TimeoutEvt;

 

   Status              = EFI_SUCCESS;

-  ReadCapacityStatus  = EFI_SUCCESS;

   SenseData           = NULL;

   NumberOfSenseKeys   = 0;

-  NeedReadCapacity    = FALSE;

-  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));

-  *MediaChange        = FALSE;

+  Retry               = 0;

   MaxRetry            = 3;

   Action              = ACTION_NO_ACTION;

+  NeedReadCapacity    = FALSE;

+  *MediaChange        = FALSE;

+  TimeoutEvt          = NULL;

 

-  for (Index = 0; Index < MaxRetry; Index++) {

+  CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));

+

+  Status = gBS->CreateEvent (

+                  EVT_TIMER,

+                  TPL_CALLBACK,

+                  NULL,

+                  NULL,

+                  &TimeoutEvt

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS(120));

+  if (EFI_ERROR (Status)) {

+    goto EXIT;

+  }

+

+  //

+  // Sending Test_Unit cmd to poll device status.

+  // If the sense data shows the drive is not ready or reset before, we need poll the device status again.

+  // We limit the upper boundary to 120 seconds.

+  //

+  while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {

     Status = ScsiDiskTestUnitReady (

               ScsiDiskDevice,

               &NeedRetry,

@@ -732,21 +755,22 @@
                  &Action

                  );

       if (EFI_ERROR (Status)) {

-        return Status;

+        goto EXIT;

       } else if (Action == ACTION_RETRY_COMMAND_LATER) {

         continue;

       } else {

         break;

       }

-    }

-

-    if (!NeedRetry) {

-      return Status;

+    } else {

+      Retry++;

+      if (!NeedRetry || (Retry >= MaxRetry)) {

+        goto EXIT;

+      }

     }

   }

 

-  if ((Index == MaxRetry) && EFI_ERROR (Status)) {

-    return EFI_DEVICE_ERROR;

+  if (EFI_ERROR (Status)) {

+    goto EXIT;

   }

 

   //

@@ -765,63 +789,45 @@
     //

     // retrieve media information

     //

-    MaxRetry = 3;

-    for (Index = 0; Index < MaxRetry; Index++) {

-

-      ReadCapacityStatus = ScsiDiskReadCapacity (

-                            ScsiDiskDevice,

-                            &NeedRetry,

-                            &SenseData,

-                            &NumberOfSenseKeys

-                            );

-      if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {

-        return EFI_DEVICE_ERROR;

-      }

-      //

-      // analyze sense key to action

-      //

-      Status = DetectMediaParsingSenseKeys (

-                ScsiDiskDevice,

-                SenseData,

-                NumberOfSenseKeys,

-                &Action

-                );

-      //

-      // if Status is error, it may indicate crisis error,

-      // so return without retry.

-      //

-      if (EFI_ERROR (Status)) {

-        return Status;

-      }

-

-      switch (Action) {

-      case ACTION_NO_ACTION:

+    for (Retry = 0; Retry < MaxRetry; Retry++) {

+      Status = ScsiDiskReadCapacity (

+                 ScsiDiskDevice,

+                 &NeedRetry,

+                 &SenseData,

+                 &NumberOfSenseKeys

+                 );

+      if (!EFI_ERROR (Status)) {

         //

-        // no retry

+        // analyze sense key to action

         //

-        Index = MaxRetry;

-        break;

-

-      case ACTION_RETRY_COMMAND_LATER:

-        //

-        // retry the ReadCapacity later and continuously, until the condition

-        // no longer emerges.

-        // stall time is 100000us, or say 0.1 second.

-        //

-        gBS->Stall (100000);

-        Index = 0;

-        break;

-

-      default:

-        //

-        // other cases, just retry the command

-        //

-        break;

+        Status = DetectMediaParsingSenseKeys (

+                   ScsiDiskDevice,

+                   SenseData,

+                   NumberOfSenseKeys,

+                   &Action

+                   );

+        if (EFI_ERROR (Status)) {

+          //

+          // if Status is error, it may indicate crisis error,

+          // so return without retry.

+          //

+          goto EXIT;

+        } else if (Action == ACTION_RETRY_COMMAND_LATER) {

+          Retry = 0;

+          continue;

+        } else {

+          break;

+        }

+      } else {   

+        Retry++;

+        if (!NeedRetry || (Retry >= MaxRetry)) {

+          goto EXIT;

+        }

       }

     }

 

-    if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {

-      return EFI_DEVICE_ERROR;

+    if (EFI_ERROR (Status)) {

+      goto EXIT;

     }

   }

 

@@ -863,7 +869,11 @@
     *MediaChange = TRUE;

   }

 

-  return EFI_SUCCESS;

+EXIT:

+  if (TimeoutEvt != NULL) {

+    gBS->CloseEvent (TimeoutEvt);

+  }

+  return Status;

 }

 

 

@@ -1188,7 +1198,9 @@
   *Action = ACTION_READ_CAPACITY;

 

   if (NumberOfSenseKeys == 0) {

-    *Action = ACTION_NO_ACTION;

+    if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {

+      *Action = ACTION_NO_ACTION;

+    }

     return EFI_SUCCESS;

   }

 

@@ -1196,7 +1208,9 @@
     //

     // No Sense Key returned from last submitted command

     //

-    *Action = ACTION_NO_ACTION;

+    if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {

+      *Action = ACTION_NO_ACTION;

+    }

     return EFI_SUCCESS;

   }

 

@@ -1220,10 +1234,12 @@
   if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {

     ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;

     ScsiDiskDevice->BlkIo.Media->LastBlock    = 0;

+    *Action = ACTION_NO_ACTION;

     return EFI_DEVICE_ERROR;

   }

 

   if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {

+    *Action = ACTION_NO_ACTION;

     return EFI_DEVICE_ERROR;

   }

 

@@ -1232,7 +1248,7 @@
       *Action = ACTION_RETRY_COMMAND_LATER;

       return EFI_SUCCESS;

     }

-

+    *Action = ACTION_NO_ACTION;

     return EFI_DEVICE_ERROR;

   }