Commit 9b4a996f authored by James Bottomley's avatar James Bottomley Committed by James Bottomley

[PATCH] sd.c spinup code can go into a wild loop

This problem was reported against 2.4 by Eddie.Williams@SteelEye.com

There's a problem in the sd spinup code in that if the unit returns NOT
READY, we begin to spin it up, but thereafter if it returns anything
other than NOT READY or success, the while loop in the spinup code will
be executed *without* the 1s delay that's in the NOT READY case.

The problem was seen with a real device: Compaq multi-path storage
arrays return NOT READY to probes down inactive paths, but when the
start unit is sent to activate the path, they can then respond back with
error conditions.

The fix is to terminate the while loop for any unexpected return.
parent 3e17fda6
...@@ -811,7 +811,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -811,7 +811,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer) { struct scsi_request *SRpnt, unsigned char *buffer) {
unsigned char cmd[10]; unsigned char cmd[10];
unsigned long spintime_value = 0; unsigned long spintime_value = 0;
int the_result, retries, spintime; int retries, spintime;
unsigned int the_result;
spintime = 0; spintime = 0;
...@@ -820,7 +821,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -820,7 +821,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
do { do {
retries = 0; retries = 0;
while (retries < 3) { do {
cmd[0] = TEST_UNIT_READY; cmd[0] = TEST_UNIT_READY;
memset((void *) &cmd[1], 0, 9); memset((void *) &cmd[1], 0, 9);
...@@ -834,10 +835,9 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -834,10 +835,9 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
the_result = SRpnt->sr_result; the_result = SRpnt->sr_result;
retries++; retries++;
if (the_result == 0 } while (retries < 3 && !scsi_status_is_good(the_result)
|| SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION) && ((driver_byte(the_result) & DRIVER_SENSE)
break; && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION));
}
/* /*
* If the drive has indicated to us that it doesn't have * If the drive has indicated to us that it doesn't have
...@@ -847,8 +847,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -847,8 +847,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
if (media_not_present(sdkp, SRpnt)) if (media_not_present(sdkp, SRpnt))
return; return;
if (the_result == 0) if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
break; /* all is well now */ /* no sense, TUR either succeeded or failed
* with a status error */
if(!spintime && !scsi_status_is_good(the_result))
printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result);
break;
}
/* /*
* If manual intervention is required, or this is an * If manual intervention is required, or this is an
...@@ -856,13 +863,13 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -856,13 +863,13 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
*/ */
if (SRpnt->sr_sense_buffer[2] == NOT_READY && if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
SRpnt->sr_sense_buffer[12] == 4 /* not ready */ && SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
SRpnt->sr_sense_buffer[13] == 3) SRpnt->sr_sense_buffer[13] == 3) {
break; /* manual intervention required */ break; /* manual intervention required */
/* /*
* Issue command to spin up drive when not ready * Issue command to spin up drive when not ready
*/ */
if (SRpnt->sr_sense_buffer[2] == NOT_READY) { } else if (SRpnt->sr_sense_buffer[2] == NOT_READY) {
unsigned long time1; unsigned long time1;
if (!spintime) { if (!spintime) {
printk(KERN_NOTICE "%s: Spinning up disk...", printk(KERN_NOTICE "%s: Spinning up disk...",
...@@ -889,15 +896,24 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, ...@@ -889,15 +896,24 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
time1 = schedule_timeout(time1); time1 = schedule_timeout(time1);
} while(time1); } while(time1);
printk("."); printk(".");
} else {
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname);
print_req_sense("", SRpnt);
}
break;
} }
} while (spintime && } while (spintime &&
time_after(spintime_value + 100 * HZ, jiffies)); time_after(spintime_value + 100 * HZ, jiffies));
if (spintime) { if (spintime) {
if (the_result) if (scsi_status_is_good(the_result))
printk("not responding...\n");
else
printk("ready\n"); printk("ready\n");
else
printk("not responding...\n");
} }
} }
......
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