summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus/Scsi
diff options
context:
space:
mode:
authorHao Wu <hao.a.wu@intel.com>2015-12-22 13:57:14 +0000
committerhwu1225 <hwu1225@Edk2>2015-12-22 13:57:14 +0000
commitd7617bad96979cb1a5ecfbb56a05b97838bbbbb7 (patch)
treec647e2410bf527cc259d0bfbbb1a440fb00e643c /MdeModulePkg/Bus/Scsi
parent032800eccab02bd4fa7dd2afe529ad8b9a712c41 (diff)
downloadedk2-d7617bad96979cb1a5ecfbb56a05b97838bbbbb7.zip
edk2-d7617bad96979cb1a5ecfbb56a05b97838bbbbb7.tar.gz
edk2-d7617bad96979cb1a5ecfbb56a05b97838bbbbb7.tar.bz2
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. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19451 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Bus/Scsi')
-rw-r--r--MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c66
1 files changed, 58 insertions, 8 deletions
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index 4725cf4..2d6d7e3 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -2715,15 +2715,40 @@ ScsiDiskAsyncReadSectors (
}
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;
}
//
@@ -2878,15 +2903,40 @@ ScsiDiskAsyncWriteSectors (
}
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;
}
//