Revision: 19472
          http://sourceforge.net/p/edk2/code/19472
Author:   hwu1225
Date:     2015-12-23 01:37:22 +0000 (Wed, 23 Dec 2015)
Log Message:
-----------
MdeModulePkg ScsiDiskDxe: Add retry scheme for async SCSI I/O command

Some SCSI devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the
data length of a SCSI I/O command is too large.

This commit will repeatedly retry sending the SCSI command with a data
length half of its previous value.

(Sync patch r19451 from main trunk.)

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Hao Wu <[email protected]>
Reviewed-by: Feng Tian <[email protected]>

Revision Links:
--------------
    http://sourceforge.net/p/edk2/code/19451

Modified Paths:
--------------
    branches/UDK2015/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c

Modified: branches/UDK2015/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
===================================================================
--- branches/UDK2015/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c       
2015-12-23 01:37:00 UTC (rev 19471)
+++ branches/UDK2015/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c       
2015-12-23 01:37:22 UTC (rev 19472)
@@ -2674,15 +2674,40 @@
     }
     if (EFI_ERROR (Status)) {
       //
-      // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
-      // command fails. Otherwise, it will be freed in the callback function
-      // ScsiDiskNotify().
+      // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
+      // length of a SCSI I/O command is too large.
+      // In this case, we retry sending the SCSI command with a data length
+      // half of its previous value.
       //
+      if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+        if ((MaxBlock > 1) && (SectorCount > 1)) {
+          MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
+          continue;
+        }
+      }
+
       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+        //
+        // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
+        // SCSI sub-task running. Otherwise, it will be freed in the callback
+        // function ScsiDiskNotify().
+        //
         RemoveEntryList (&BlkIo2Req->Link);
         FreePool (BlkIo2Req);
+
+        //
+        // It is safe to return error status to the caller, since there is no
+        // previous SCSI sub-task executing.
+        //
+        return EFI_DEVICE_ERROR;
+      } else {
+        //
+        // There are previous SCSI commands still running, EFI_SUCCESS should
+        // be returned to make sure that the caller does not free resources
+        // still using by these SCSI commands.
+        //
+        return EFI_SUCCESS;
       }
-      return EFI_DEVICE_ERROR;
     }
 
     //
@@ -2837,15 +2862,40 @@
     }
     if (EFI_ERROR (Status)) {
       //
-      // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI
-      // command fails. Otherwise, it will be freed in the callback function
-      // ScsiDiskNotify().
+      // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data
+      // length of a SCSI I/O command is too large.
+      // In this case, we retry sending the SCSI command with a data length
+      // half of its previous value.
       //
+      if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+        if ((MaxBlock > 1) && (SectorCount > 1)) {
+          MaxBlock = MIN (MaxBlock, SectorCount) >> 1;
+          continue;
+        }
+      }
+
       if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {
+        //
+        // Free the SCSI_BLKIO2_REQUEST structure only when there is no other
+        // SCSI sub-task running. Otherwise, it will be freed in the callback
+        // function ScsiDiskNotify().
+        //
         RemoveEntryList (&BlkIo2Req->Link);
         FreePool (BlkIo2Req);
+
+        //
+        // It is safe to return error status to the caller, since there is no
+        // previous SCSI sub-task executing.
+        //
+        return EFI_DEVICE_ERROR;
+      } else {
+        //
+        // There are previous SCSI commands still running, EFI_SUCCESS should
+        // be returned to make sure that the caller does not free resources
+        // still using by these SCSI commands.
+        //
+        return EFI_SUCCESS;
       }
-      return EFI_DEVICE_ERROR;
     }
 
     //


------------------------------------------------------------------------------
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits

Reply via email to