Commit 3233ac19 authored by James Bottomley's avatar James Bottomley

[SCSI] sd: retry read_capacity on UNIT_ATTENTION

Hazard testing uncovered yet another bug in sd. Under heavy reset
activity the retry counter might be exhausted and the command will be
returned with sense UNIT_ATTENTION/0x29/00 (POWER ON, RESET, OR BUS
DEVICE RESET OCCURRED). In those cases we should just increase the
retry counter again, retrying one more to clear up this Unit Attention
state.

[jejb: update to work with RC16 devices and not to loop endlessly]
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 14695853
......@@ -1433,6 +1433,8 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
#error RC16_LEN must not be more than SD_BUF_SIZE
#endif
#define READ_CAPACITY_RETRIES_ON_RESET 10
static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
unsigned char *buffer)
{
......@@ -1440,7 +1442,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int the_result;
int retries = 3;
int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
unsigned int alignment;
unsigned long long lba;
unsigned sector_size;
......@@ -1469,6 +1471,13 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
* Invalid Field in CDB, just retry
* silently with RC10 */
return -EINVAL;
if (sense_valid &&
sshdr.sense_key == UNIT_ATTENTION &&
sshdr.asc == 0x29 && sshdr.ascq == 0x00)
/* Device reset might occur several times,
* give it one more chance */
if (--reset_retries > 0)
continue;
}
retries--;
......@@ -1527,7 +1536,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int the_result;
int retries = 3;
int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET;
sector_t lba;
unsigned sector_size;
......@@ -1543,8 +1552,16 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
if (media_not_present(sdkp, &sshdr))
return -ENODEV;
if (the_result)
if (the_result) {
sense_valid = scsi_sense_valid(&sshdr);
if (sense_valid &&
sshdr.sense_key == UNIT_ATTENTION &&
sshdr.asc == 0x29 && sshdr.ascq == 0x00)
/* Device reset might occur several times,
* give it one more chance */
if (--reset_retries > 0)
continue;
}
retries--;
} while (the_result && retries);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment