ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
*Action = ACTION_NO_ACTION;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));\r
return EFI_SUCCESS;\r
}\r
\r
if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {\r
ScsiDiskDevice->BlkIo.Media->MediaId++;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));\r
return EFI_SUCCESS;\r
}\r
\r
if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {\r
*Action = ACTION_RETRY_COMMAND_LATER;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));\r
return EFI_SUCCESS;\r
}\r
\r
if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
- ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
- ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
- *Action = ACTION_NO_ACTION;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));\r
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
- *Action = ACTION_NO_ACTION;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));\r
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {\r
if (RetryLater) {\r
*Action = ACTION_RETRY_COMMAND_LATER;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));\r
return EFI_SUCCESS;\r
}\r
*Action = ACTION_NO_ACTION;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
+ *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
+ DEBUG ((EFI_D_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));\r
return EFI_SUCCESS;\r
}\r
\r
\r
*NumberOfSenseKeys = 0;\r
*SenseDataArray = ScsiDiskDevice->SenseData;\r
- PtrSenseData = ScsiDiskDevice->SenseData;\r
+ Status = EFI_SUCCESS;\r
+ PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));\r
+ if (PtrSenseData == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
\r
for (SenseReq = TRUE; SenseReq;) {\r
+ ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
Status = ScsiRequestSenseCommand (\r
ScsiDiskDevice->ScsiIo,\r
SCSI_DISK_TIMEOUT,\r
if (EFI_ERROR (FallStatus)) {\r
if (*NumberOfSenseKeys != 0) {\r
*NeedRetry = FALSE;\r
- return EFI_SUCCESS;\r
+ Status = EFI_SUCCESS;\r
+ goto EXIT;\r
} else {\r
- return EFI_DEVICE_ERROR;\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto EXIT;\r
}\r
}\r
\r
+ CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);\r
(*NumberOfSenseKeys) += 1;\r
\r
//\r
(*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {\r
SenseReq = FALSE;\r
}\r
- PtrSenseData += 1;\r
}\r
- return EFI_SUCCESS;\r
+\r
+EXIT:\r
+ FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
+ return Status;\r
}\r
\r
\r
UINT8 Index;\r
UINT8 MaxRetry;\r
BOOLEAN NeedRetry;\r
- EFI_SCSI_SENSE_DATA *SenseData;\r
- UINTN NumberOfSenseKeys;\r
-\r
- SenseData = NULL;\r
- NumberOfSenseKeys = 0;\r
\r
Status = EFI_SUCCESS;\r
\r
Status = ScsiDiskRead10 (\r
ScsiDiskDevice,\r
&NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
Timeout,\r
PtrBuffer,\r
&ByteCount,\r
Status = ScsiDiskRead16 (\r
ScsiDiskDevice,\r
&NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
Timeout,\r
PtrBuffer,\r
&ByteCount,\r
UINT8 Index;\r
UINT8 MaxRetry;\r
BOOLEAN NeedRetry;\r
- EFI_SCSI_SENSE_DATA *SenseData;\r
- UINTN NumberOfSenseKeys;\r
-\r
- SenseData = NULL;\r
- NumberOfSenseKeys = 0;\r
\r
Status = EFI_SUCCESS;\r
\r
Status = ScsiDiskWrite10 (\r
ScsiDiskDevice,\r
&NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
Timeout,\r
PtrBuffer,\r
&ByteCount,\r
Status = ScsiDiskWrite16 (\r
ScsiDiskDevice,\r
&NeedRetry,\r
- &SenseData,\r
- &NumberOfSenseKeys,\r
Timeout,\r
PtrBuffer,\r
&ByteCount,\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
- @param SenseDataArray NOT used yet in this function\r
- @param NumberOfSenseKeys The number of sense key\r
@param Timeout The time to complete the command\r
@param DataBuffer The buffer to fill with the read out data\r
@param DataLength The length of buffer\r
@param StartLba The start logic block address\r
- @param SectorSize The size of sector\r
+ @param SectorCount The number of blocks to read\r
\r
@return EFI_STATUS is returned by calling ScsiRead10Command().\r
**/\r
ScsiDiskRead10 (\r
IN SCSI_DISK_DEV *ScsiDiskDevice,\r
OUT BOOLEAN *NeedRetry,\r
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
- OUT UINTN *NumberOfSenseKeys,\r
IN UINT64 Timeout,\r
OUT UINT8 *DataBuffer,\r
IN OUT UINT32 *DataLength,\r
IN UINT32 StartLba,\r
- IN UINT32 SectorSize\r
+ IN UINT32 SectorCount\r
)\r
{\r
UINT8 SenseDataLength;\r
UINT8 TargetStatus;\r
UINTN Action;\r
\r
+ //\r
+ // Implement a backoff algorithem to resolve some compatibility issues that\r
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
+ // big data in a single operation.\r
+ // This algorithem will at first try to execute original request. If the request fails\r
+ // with media error sense data or else, it will reduce the transfer length to half and\r
+ // try again till the operation succeeds or fails with one sector transfer length.\r
+ //\r
+BackOff:\r
*NeedRetry = FALSE;\r
- *NumberOfSenseKeys = 0;\r
Action = ACTION_NO_ACTION;\r
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ReturnStatus = ScsiRead10Command (\r
DataBuffer,\r
DataLength,\r
StartLba,\r
- SectorSize\r
+ SectorCount\r
);\r
\r
if (ReturnStatus == EFI_NOT_READY) {\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
- DEBUG ((EFI_D_VERBOSE, "ScsiDiskRead10: Check Condition happened!\n"));\r
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
+ DEBUG ((EFI_D_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));\r
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+ if (Action == ACTION_RETRY_COMMAND_LATER) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
+ if (SectorCount <= 1) {\r
+ //\r
+ // Jump out if the operation still fails with one sector transfer length.\r
+ //\r
+ *NeedRetry = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Try again with half length if the sense data shows we need to retry.\r
+ //\r
+ SectorCount >>= 1;\r
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ goto BackOff;\r
} else {\r
*NeedRetry = FALSE;\r
return EFI_DEVICE_ERROR;\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
- @param SenseDataArray NOT used yet in this function\r
- @param NumberOfSenseKeys The number of sense key\r
@param Timeout The time to complete the command\r
@param DataBuffer The buffer to fill with the read out data\r
@param DataLength The length of buffer\r
@param StartLba The start logic block address\r
- @param SectorSize The size of sector\r
+ @param SectorCount The number of blocks to write\r
\r
@return EFI_STATUS is returned by calling ScsiWrite10Command().\r
\r
ScsiDiskWrite10 (\r
IN SCSI_DISK_DEV *ScsiDiskDevice,\r
OUT BOOLEAN *NeedRetry,\r
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
- OUT UINTN *NumberOfSenseKeys,\r
IN UINT64 Timeout,\r
IN UINT8 *DataBuffer,\r
IN OUT UINT32 *DataLength,\r
IN UINT32 StartLba,\r
- IN UINT32 SectorSize\r
+ IN UINT32 SectorCount\r
)\r
{\r
EFI_STATUS Status;\r
UINT8 TargetStatus;\r
UINTN Action;\r
\r
+ //\r
+ // Implement a backoff algorithem to resolve some compatibility issues that\r
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
+ // big data in a single operation.\r
+ // This algorithem will at first try to execute original request. If the request fails\r
+ // with media error sense data or else, it will reduce the transfer length to half and\r
+ // try again till the operation succeeds or fails with one sector transfer length.\r
+ //\r
+BackOff:\r
*NeedRetry = FALSE;\r
- *NumberOfSenseKeys = 0;\r
Action = ACTION_NO_ACTION;\r
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ReturnStatus = ScsiWrite10Command (\r
DataBuffer,\r
DataLength,\r
StartLba,\r
- SectorSize\r
+ SectorCount\r
);\r
if (ReturnStatus == EFI_NOT_READY) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
- DEBUG ((EFI_D_VERBOSE, "ScsiDiskWrite10: Check Condition happened!\n"));\r
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
+ DEBUG ((EFI_D_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));\r
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+ if (Action == ACTION_RETRY_COMMAND_LATER) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
+ if (SectorCount <= 1) {\r
+ //\r
+ // Jump out if the operation still fails with one sector transfer length.\r
+ //\r
+ *NeedRetry = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Try again with half length if the sense data shows we need to retry.\r
+ //\r
+ SectorCount >>= 1;\r
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ goto BackOff;\r
} else {\r
*NeedRetry = FALSE;\r
return EFI_DEVICE_ERROR;\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
- @param SenseDataArray NOT used yet in this function\r
- @param NumberOfSenseKeys The number of sense key\r
@param Timeout The time to complete the command\r
@param DataBuffer The buffer to fill with the read out data\r
@param DataLength The length of buffer\r
@param StartLba The start logic block address\r
- @param SectorSize The size of sector\r
+ @param SectorCount The number of blocks to read\r
\r
- @return EFI_STATUS is returned by calling ScsiRead10Command().\r
+ @return EFI_STATUS is returned by calling ScsiRead16Command().\r
**/\r
EFI_STATUS\r
ScsiDiskRead16 (\r
IN SCSI_DISK_DEV *ScsiDiskDevice,\r
OUT BOOLEAN *NeedRetry,\r
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
- OUT UINTN *NumberOfSenseKeys,\r
IN UINT64 Timeout,\r
OUT UINT8 *DataBuffer,\r
IN OUT UINT32 *DataLength,\r
IN UINT64 StartLba,\r
- IN UINT32 SectorSize\r
+ IN UINT32 SectorCount\r
)\r
{\r
UINT8 SenseDataLength;\r
UINT8 TargetStatus;\r
UINTN Action;\r
\r
+ //\r
+ // Implement a backoff algorithem to resolve some compatibility issues that\r
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
+ // big data in a single operation.\r
+ // This algorithem will at first try to execute original request. If the request fails\r
+ // with media error sense data or else, it will reduce the transfer length to half and\r
+ // try again till the operation succeeds or fails with one sector transfer length.\r
+ //\r
+BackOff:\r
*NeedRetry = FALSE;\r
- *NumberOfSenseKeys = 0;\r
Action = ACTION_NO_ACTION;\r
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ReturnStatus = ScsiRead16Command (\r
DataBuffer,\r
DataLength,\r
StartLba,\r
- SectorSize\r
+ SectorCount\r
);\r
if (ReturnStatus == EFI_NOT_READY) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
- DEBUG ((EFI_D_VERBOSE, "ScsiDiskRead16: Check Condition happened!\n"));\r
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
+ DEBUG ((EFI_D_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));\r
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+ if (Action == ACTION_RETRY_COMMAND_LATER) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
+ if (SectorCount <= 1) {\r
+ //\r
+ // Jump out if the operation still fails with one sector transfer length.\r
+ //\r
+ *NeedRetry = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Try again with half length if the sense data shows we need to retry.\r
+ //\r
+ SectorCount >>= 1;\r
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ goto BackOff;\r
} else {\r
*NeedRetry = FALSE;\r
return EFI_DEVICE_ERROR;\r
\r
@param ScsiDiskDevice The pointer of ScsiDiskDevice\r
@param NeedRetry The pointer of flag indicates if needs retry if error happens\r
- @param SenseDataArray NOT used yet in this function\r
- @param NumberOfSenseKeys The number of sense key\r
@param Timeout The time to complete the command\r
@param DataBuffer The buffer to fill with the read out data\r
@param DataLength The length of buffer\r
@param StartLba The start logic block address\r
- @param SectorSize The size of sector\r
+ @param SectorCount The number of blocks to write\r
\r
- @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
+ @return EFI_STATUS is returned by calling ScsiWrite16Command().\r
\r
**/\r
EFI_STATUS\r
ScsiDiskWrite16 (\r
IN SCSI_DISK_DEV *ScsiDiskDevice,\r
OUT BOOLEAN *NeedRetry,\r
- OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
- OUT UINTN *NumberOfSenseKeys,\r
IN UINT64 Timeout,\r
IN UINT8 *DataBuffer,\r
IN OUT UINT32 *DataLength,\r
IN UINT64 StartLba,\r
- IN UINT32 SectorSize\r
+ IN UINT32 SectorCount\r
)\r
{\r
EFI_STATUS Status;\r
UINT8 TargetStatus;\r
UINTN Action;\r
\r
+ //\r
+ // Implement a backoff algorithem to resolve some compatibility issues that\r
+ // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
+ // big data in a single operation.\r
+ // This algorithem will at first try to execute original request. If the request fails\r
+ // with media error sense data or else, it will reduce the transfer length to half and\r
+ // try again till the operation succeeds or fails with one sector transfer length.\r
+ //\r
+BackOff:\r
*NeedRetry = FALSE;\r
- *NumberOfSenseKeys = 0;\r
Action = ACTION_NO_ACTION;\r
SenseDataLength = (UINT8) (ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ReturnStatus = ScsiWrite16Command (\r
DataBuffer,\r
DataLength,\r
StartLba,\r
- SectorSize\r
+ SectorCount\r
);\r
if (ReturnStatus == EFI_NOT_READY) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
}\r
\r
- if (TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
- DEBUG ((EFI_D_VERBOSE, "ScsiDiskWrite16: Check Condition happened!\n"));\r
+ if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
+ DEBUG ((EFI_D_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));\r
Status = DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+ if (Action == ACTION_RETRY_COMMAND_LATER) {\r
*NeedRetry = TRUE;\r
return EFI_DEVICE_ERROR;\r
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
+ if (SectorCount <= 1) {\r
+ //\r
+ // Jump out if the operation still fails with one sector transfer length.\r
+ //\r
+ *NeedRetry = FALSE;\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Try again with half length if the sense data shows we need to retry.\r
+ //\r
+ SectorCount >>= 1;\r
+ *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ goto BackOff;\r
} else {\r
*NeedRetry = FALSE;\r
return EFI_DEVICE_ERROR;\r