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
This commit is contained in:
Hao Wu 2015-12-22 13:57:14 +00:00 committed by hwu1225
parent 032800ecca
commit d7617bad96
1 changed files with 58 additions and 8 deletions

View File

@ -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;
}
//