--- orig/drivers/scsi/scsi_error.c Wed Sep 25 23:11:26 2002 +++ linux-rpc/drivers/scsi/scsi_error.c Wed Sep 25 23:15:41 2002 @@ -1413,6 +1413,57 @@ return rtn; } + +/* + * Function: scsi_eh_set_device_offline + * + * Purpose: set a device off line + * + * Arguments: SDpnt - SCSI device to take off line + * done - list of commands that have been successfully + * completed. + * reason - text string describing why the device is off-line + * + * Returns: Nothing + * + * Notes: In addition, we complete each failed or timed out command + * attached to this device. + */ +STATIC void scsi_eh_set_device_offline(Scsi_Device *SDpnt, Scsi_Cmnd **done, + const char *reason) +{ + Scsi_Cmnd *SCpnt, *SCnext; + + printk(KERN_ERR "scsi: device set offline - %s: " + "host %d channel %d id %d lun %d\n", + reason, SDpnt->host->host_no, SDpnt->channel, + SDpnt->id, SDpnt->lun); + + SDpnt->online = FALSE; + + for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) { + SCnext = SCpnt->next; + + switch (SCpnt->state) { + case SCSI_STATE_TIMEOUT: + SCpnt->result |= DRIVER_TIMEOUT; + /*FALLTHROUGH*/ + + case SCSI_STATE_FAILED: + SCSI_LOG_ERROR_RECOVERY(3, + printk("Finishing command for device %d %x\n", + SDpnt->id, SCpnt->result)); + + SDpnt->host->host_failed--; + scsi_eh_finish_command(done, SCpnt); + break; + + default: + break; + } + } +} + static void scsi_unjam_request_sense(struct Scsi_Host *host, Scsi_Cmnd **done) { int rtn; @@ -1673,14 +1724,11 @@ * talk to the device, take it offline. * FIXME(eric) - is this really the correct thing to do? */ - if (rtn != SUCCESS) { - printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); - - SDloop->online = FALSE; - SDloop->host->host_failed--; - scsi_eh_finish_command(done, SCloop); - } + if (rtn != SUCCESS) + break; } + if (rtn != SUCCESS) + scsi_eh_set_device_offline(SDloop, done, "not ready or command retry failed after bus reset"); } } } @@ -1761,13 +1809,11 @@ } rtn = scsi_eh_test_and_retry(SCloop, done); - if (rtn != SUCCESS) { - printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); - SDloop->online = FALSE; - SDloop->host->host_failed--; - scsi_eh_finish_command(done, SCloop); - } + if (rtn != SUCCESS) + break; } + if (rtn != SUCCESS) + scsi_eh_set_device_offline(SDloop, done, "not ready or command retry failed after host reset"); } } } @@ -1776,8 +1822,7 @@ static void scsi_unjam_failure(struct Scsi_Host *host, Scsi_Cmnd **done) { - Scsi_Device *SDpnt, *SDloop; - Scsi_Cmnd *SCloop; + Scsi_Device *SDpnt; /* * If the HOST RESET failed, then for now we assume that the entire host @@ -1787,31 +1832,8 @@ */ SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n")); - for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) { - for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) { - if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) { - SDloop = SCloop->device; - if (SDloop->online == TRUE) { - printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun); - SDloop->online = FALSE; - } - - /* - * This should pass the failure up to the top level driver, and - * it will have to try and do something intelligent with it. - */ - SCloop->host->host_failed--; - - if (SCloop->state == SCSI_STATE_TIMEOUT) { - SCloop->result |= (DRIVER_TIMEOUT << 24); - } - SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n", - SDloop->id, SCloop->result)); - - scsi_eh_finish_command(done, SCloop); - } - } - } + for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) + scsi_eh_set_device_offline(SDpnt, done, "command error recover failed"); if (host->host_failed != 0) { panic("scsi_unjam_host: Miscount of number of failed commands.\n");