summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
index 6da1751a57..282e9c2832 100644
--- a/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
+++ b/MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
@@ -1789,6 +1789,7 @@ ScsiDiskReadSectors (
UINT32 ByteCount;
UINT32 MaxBlock;
UINT32 SectorCount;
+ UINT32 NextSectorCount;
UINT64 Timeout;
EFI_STATUS Status;
UINT8 Index;
@@ -1889,6 +1890,25 @@ ScsiDiskReadSectors (
return EFI_DEVICE_ERROR;
}
+ //
+ // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has
+ // lowered ByteCount on output, we must make sure that we lower
+ // SectorCount accordingly. SectorCount will be encoded in the CDB, and
+ // it is invalid to request more sectors in the CDB than the entire
+ // transfer (ie. ByteCount) can carry.
+ //
+ // In addition, ByteCount is only expected to go down, or stay unchaged.
+ // Therefore we don't need to update Timeout: the original timeout should
+ // accommodate shorter transfers too.
+ //
+ NextSectorCount = ByteCount / BlockSize;
+ if (NextSectorCount < SectorCount) {
+ SectorCount = NextSectorCount;
+ //
+ // Account for any rounding down.
+ //
+ ByteCount = SectorCount * BlockSize;
+ }
}
if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {
@@ -1934,6 +1954,7 @@ ScsiDiskWriteSectors (
UINT32 ByteCount;
UINT32 MaxBlock;
UINT32 SectorCount;
+ UINT32 NextSectorCount;
UINT64 Timeout;
EFI_STATUS Status;
UINT8 Index;
@@ -2032,6 +2053,26 @@ ScsiDiskWriteSectors (
if (!NeedRetry) {
return EFI_DEVICE_ERROR;
}
+
+ //
+ // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()
+ // has lowered ByteCount on output, we must make sure that we lower
+ // SectorCount accordingly. SectorCount will be encoded in the CDB, and
+ // it is invalid to request more sectors in the CDB than the entire
+ // transfer (ie. ByteCount) can carry.
+ //
+ // In addition, ByteCount is only expected to go down, or stay unchaged.
+ // Therefore we don't need to update Timeout: the original timeout should
+ // accommodate shorter transfers too.
+ //
+ NextSectorCount = ByteCount / BlockSize;
+ if (NextSectorCount < SectorCount) {
+ SectorCount = NextSectorCount;
+ //
+ // Account for any rounding down.
+ //
+ ByteCount = SectorCount * BlockSize;
+ }
}
if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {