X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fscsi%2Fscsi_error.c;h=ad019ece21391c8dc1c653fdc92703a94e7149dc;hb=0f1f53a7efd60d7cdd8e82925f0c62dcf64ba092;hp=39ce3aba1dac5f459d668ee7ce4d15832918ec66;hpb=99c3563e64cf887cca0b181149c0f85c39569276;p=linux-2.6-omap-h63xx.git diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 39ce3aba1da..ad019ece213 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -111,70 +111,9 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) return ret; } -/** - * scsi_add_timer - Start timeout timer for a single scsi command. - * @scmd: scsi command that is about to start running. - * @timeout: amount of time to allow this command to run. - * @complete: timeout function to call if timer isn't canceled. - * - * Notes: - * This should be turned into an inline function. Each scsi command - * has its own timer, and as it is added to the queue, we set up the - * timer. When the command completes, we cancel the timer. - */ -void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, - void (*complete)(struct scsi_cmnd *)) -{ - - /* - * If the clock was already running for this command, then - * first delete the timer. The timer handling code gets rather - * confused if we don't do this. - */ - if (scmd->eh_timeout.function) - del_timer(&scmd->eh_timeout); - - scmd->eh_timeout.data = (unsigned long)scmd; - scmd->eh_timeout.expires = jiffies + timeout; - scmd->eh_timeout.function = (void (*)(unsigned long)) complete; - - SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:" - " %d, (%p)\n", __func__, - scmd, timeout, complete)); - - add_timer(&scmd->eh_timeout); -} - -/** - * scsi_delete_timer - Delete/cancel timer for a given function. - * @scmd: Cmd that we are canceling timer for - * - * Notes: - * This should be turned into an inline function. - * - * Return value: - * 1 if we were able to detach the timer. 0 if we blew it, and the - * timer function has already started to run. - */ -int scsi_delete_timer(struct scsi_cmnd *scmd) -{ - int rtn; - - rtn = del_timer(&scmd->eh_timeout); - - SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p," - " rtn: %d\n", __func__, - scmd, rtn)); - - scmd->eh_timeout.data = (unsigned long)NULL; - scmd->eh_timeout.function = NULL; - - return rtn; -} - /** * scsi_times_out - Timeout function for normal scsi commands. - * @scmd: Cmd that is timing out. + * @req: request that is timing out. * * Notes: * We do not need to lock this. There is the potential for a race @@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) * normal completion function determines that the timer has already * fired, then it mustn't do anything. */ -void scsi_times_out(struct scsi_cmnd *scmd) +enum blk_eh_timer_return scsi_times_out(struct request *req) { - enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); + struct scsi_cmnd *scmd = req->special; + enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); + enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; scsi_log_completion(scmd, TIMEOUT_ERROR); @@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd) eh_timed_out = NULL; if (eh_timed_out) - switch (eh_timed_out(scmd)) { - case EH_HANDLED: - __scsi_done(scmd); - return; - case EH_RESET_TIMER: - scsi_add_timer(scmd, scmd->timeout_per_command, - scsi_times_out); - return; - case EH_NOT_HANDLED: + rtn = eh_timed_out(scmd); + switch (rtn) { + case BLK_EH_NOT_HANDLED: break; + default: + return rtn; } if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { scmd->result |= DID_TIME_OUT << 16; - __scsi_done(scmd); + return BLK_EH_HANDLED; } + + return BLK_EH_NOT_HANDLED; } /** @@ -1279,6 +1218,40 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, return; } +/** + * scsi_noretry_cmd - determinte if command should be failed fast + * @scmd: SCSI cmd to examine. + */ +int scsi_noretry_cmd(struct scsi_cmnd *scmd) +{ + switch (host_byte(scmd->result)) { + case DID_OK: + break; + case DID_BUS_BUSY: + return blk_failfast_transport(scmd->request); + case DID_PARITY: + return blk_failfast_dev(scmd->request); + case DID_ERROR: + if (msg_byte(scmd->result) == COMMAND_COMPLETE && + status_byte(scmd->result) == RESERVATION_CONFLICT) + return 0; + /* fall through */ + case DID_SOFT_ERROR: + return blk_failfast_driver(scmd->request); + } + + switch (status_byte(scmd->result)) { + case CHECK_CONDITION: + /* + * assume caller has checked sense and determinted + * the check condition was retryable. + */ + return blk_failfast_dev(scmd->request); + } + + return 0; +} + /** * scsi_decide_disposition - Disposition a cmd on return from LLD. * @scmd: SCSI cmd to examine. @@ -1351,7 +1324,20 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) case DID_REQUEUE: return ADD_TO_MLQUEUE; - + case DID_TRANSPORT_DISRUPTED: + /* + * LLD/transport was disrupted during processing of the IO. + * The transport class is now blocked/blocking, + * and the transport will decide what to do with the IO + * based on its timers and recovery capablilities. + */ + return ADD_TO_MLQUEUE; + case DID_TRANSPORT_FAILFAST: + /* + * The transport decided to failfast the IO (most likely + * the fast io fail tmo fired), so send IO directly upwards. + */ + return SUCCESS; case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && status_byte(scmd->result) == RESERVATION_CONFLICT) @@ -1444,7 +1430,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) * even if the request is marked fast fail, we still requeue * for queue congestion conditions (QUEUE_FULL or BUSY) */ if ((++scmd->retries) <= scmd->allowed - && !blk_noretry_request(scmd->request)) { + && !scsi_noretry_cmd(scmd)) { return NEEDS_RETRY; } else { /* @@ -1569,7 +1555,7 @@ void scsi_eh_flush_done_q(struct list_head *done_q) list_for_each_entry_safe(scmd, next, done_q, eh_entry) { list_del_init(&scmd->eh_entry); if (scsi_device_online(scmd->device) && - !blk_noretry_request(scmd->request) && + !scsi_noretry_cmd(scmd) && (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush" " retry cmd: %p\n", @@ -1793,7 +1779,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) blk_rq_init(NULL, &req); scmd->request = &req; - memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); scmd->cmnd = req.cmd; @@ -1804,8 +1789,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scmd->sc_data_direction = DMA_BIDIRECTIONAL; - init_timer(&scmd->eh_timeout); - spin_lock_irqsave(shost->host_lock, flags); shost->tmf_in_progress = 1; spin_unlock_irqrestore(shost->host_lock, flags);