}\r
if (EFI_ERROR (Status)) {\r
//\r
- // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
- // command fails. Otherwise, it will be freed in the callback function\r
- // ScsiDiskNotify().\r
+ // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
+ // length of a SCSI I/O command is too large.\r
+ // In this case, we retry sending the SCSI command with a data length\r
+ // half of its previous value.\r
//\r
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
+ if ((MaxBlock > 1) && (SectorCount > 1)) {\r
+ MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
+ continue;\r
+ }\r
+ }\r
+\r
if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+ //\r
+ // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
+ // SCSI sub-task running. Otherwise, it will be freed in the callback\r
+ // function ScsiDiskNotify().\r
+ //\r
RemoveEntryList (&BlkIo2Req->Link);\r
FreePool (BlkIo2Req);\r
+\r
+ //\r
+ // It is safe to return error status to the caller, since there is no\r
+ // previous SCSI sub-task executing.\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // There are previous SCSI commands still running, EFI_SUCCESS should\r
+ // be returned to make sure that the caller does not free resources\r
+ // still using by these SCSI commands.\r
+ //\r
+ return EFI_SUCCESS;\r
}\r
- return EFI_DEVICE_ERROR;\r
}\r
\r
//\r
}\r
if (EFI_ERROR (Status)) {\r
//\r
- // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
- // command fails. Otherwise, it will be freed in the callback function\r
- // ScsiDiskNotify().\r
+ // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
+ // length of a SCSI I/O command is too large.\r
+ // In this case, we retry sending the SCSI command with a data length\r
+ // half of its previous value.\r
//\r
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
+ if ((MaxBlock > 1) && (SectorCount > 1)) {\r
+ MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
+ continue;\r
+ }\r
+ }\r
+\r
if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+ //\r
+ // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
+ // SCSI sub-task running. Otherwise, it will be freed in the callback\r
+ // function ScsiDiskNotify().\r
+ //\r
RemoveEntryList (&BlkIo2Req->Link);\r
FreePool (BlkIo2Req);\r
+\r
+ //\r
+ // It is safe to return error status to the caller, since there is no\r
+ // previous SCSI sub-task executing.\r
+ //\r
+ return EFI_DEVICE_ERROR;\r
+ } else {\r
+ //\r
+ // There are previous SCSI commands still running, EFI_SUCCESS should\r
+ // be returned to make sure that the caller does not free resources\r
+ // still using by these SCSI commands.\r
+ //\r
+ return EFI_SUCCESS;\r
}\r
- return EFI_DEVICE_ERROR;\r
}\r
\r
//\r