diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index c3ab093dd8a7..f28ea070d3df 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -319,11 +319,11 @@ static void scsi_host_dev_release(struct device *dev) kfree(shost); } -static unsigned int shost_eh_deadline; +static int shost_eh_deadline = -1; -module_param_named(eh_deadline, shost_eh_deadline, uint, S_IRUGO|S_IWUSR); +module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(eh_deadline, - "SCSI EH timeout in seconds (should be between 1 and 2^32-1)"); + "SCSI EH timeout in seconds (should be between 0 and 2^31-1)"); static struct device_type scsi_host_type = { .name = "scsi_host", @@ -396,9 +396,18 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; - shost->eh_deadline = shost_eh_deadline * HZ; shost->no_write_same = sht->no_write_same; + if (shost_eh_deadline == -1) + shost->eh_deadline = -1; + else if ((ulong) shost_eh_deadline * HZ > INT_MAX) { + shost_printk(KERN_WARNING, shost, + "eh_deadline %u too large, setting to %u\n", + shost_eh_deadline, INT_MAX / HZ); + shost->eh_deadline = INT_MAX; + } else + shost->eh_deadline = shost_eh_deadline * HZ; + if (sht->supported_mode == MODE_UNKNOWN) /* means we didn't set it ... default to INITIATOR */ shost->active_mode = MODE_INITIATOR; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 4e4824beefe4..78b004da2885 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -91,18 +91,18 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh); static int scsi_host_eh_past_deadline(struct Scsi_Host *shost) { - if (!shost->last_reset || !shost->eh_deadline) + if (!shost->last_reset || shost->eh_deadline == -1) return 0; /* * 32bit accesses are guaranteed to be atomic * (on all supported architectures), so instead * of using a spinlock we can as well double check - * if eh_deadline has been unset during the + * if eh_deadline has been set to 'off' during the * time_before call. */ if (time_before(jiffies, shost->last_reset + shost->eh_deadline) && - shost->eh_deadline != 0) + shost->eh_deadline > -1) return 0; return 1; @@ -132,26 +132,34 @@ scmd_eh_abort_handler(struct work_struct *work) rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd); if (rtn == SUCCESS) { scmd->result |= DID_TIME_OUT << 16; - if (!scsi_noretry_cmd(scmd) && + if (scsi_host_eh_past_deadline(sdev->host)) { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_INFO, scmd, + "scmd %p eh timeout, " + "not retrying aborted " + "command\n", scmd)); + } else if (!scsi_noretry_cmd(scmd) && (++scmd->retries <= scmd->allowed)) { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, "scmd %p retry " "aborted command\n", scmd)); scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); + return; } else { SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_WARNING, scmd, "scmd %p finish " "aborted command\n", scmd)); scsi_finish_command(scmd); + return; } - return; + } else { + SCSI_LOG_ERROR_RECOVERY(3, + scmd_printk(KERN_INFO, scmd, + "scmd %p abort failed, rtn %d\n", + scmd, rtn)); } - SCSI_LOG_ERROR_RECOVERY(3, - scmd_printk(KERN_INFO, scmd, - "scmd %p abort failed, rtn %d\n", - scmd, rtn)); } if (!scsi_eh_scmd_add(scmd, 0)) { @@ -202,7 +210,7 @@ scsi_abort_command(struct scsi_cmnd *scmd) return FAILED; } - if (shost->eh_deadline && !shost->last_reset) + if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; spin_unlock_irqrestore(shost->host_lock, flags); @@ -236,7 +244,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) goto out_unlock; - if (shost->eh_deadline && !shost->last_reset) + if (shost->eh_deadline != -1 && !shost->last_reset) shost->last_reset = jiffies; ret = 1; @@ -270,7 +278,7 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) trace_scsi_dispatch_cmd_timeout(scmd); scsi_log_completion(scmd, TIMEOUT_ERROR); - if (host->eh_deadline && !host->last_reset) + if (host->eh_deadline != -1 && !host->last_reset) host->last_reset = jiffies; if (host->transportt->eh_timed_out) @@ -2106,7 +2114,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost) scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); spin_lock_irqsave(shost->host_lock, flags); - if (shost->eh_deadline) + if (shost->eh_deadline != -1) shost->last_reset = 0; spin_unlock_irqrestore(shost->host_lock, flags); scsi_eh_flush_done_q(&eh_done_q); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8ff62c26a41c..9117d0bf408e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -287,7 +287,9 @@ show_shost_eh_deadline(struct device *dev, { struct Scsi_Host *shost = class_to_shost(dev); - return sprintf(buf, "%d\n", shost->eh_deadline / HZ); + if (shost->eh_deadline == -1) + return snprintf(buf, strlen("off") + 2, "off\n"); + return sprintf(buf, "%u\n", shost->eh_deadline / HZ); } static ssize_t @@ -296,22 +298,34 @@ store_shost_eh_deadline(struct device *dev, struct device_attribute *attr, { struct Scsi_Host *shost = class_to_shost(dev); int ret = -EINVAL; - int deadline; - unsigned long flags; + unsigned long deadline, flags; if (shost->transportt && shost->transportt->eh_strategy_handler) return ret; - if (sscanf(buf, "%d\n", &deadline) == 1) { - spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_in_recovery(shost)) - ret = -EBUSY; - else { - shost->eh_deadline = deadline * HZ; - ret = count; - } - spin_unlock_irqrestore(shost->host_lock, flags); + if (!strncmp(buf, "off", strlen("off"))) + deadline = -1; + else { + ret = kstrtoul(buf, 10, &deadline); + if (ret) + return ret; + if (deadline * HZ > UINT_MAX) + return -EINVAL; } + + spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_in_recovery(shost)) + ret = -EBUSY; + else { + if (deadline == -1) + shost->eh_deadline = -1; + else + shost->eh_deadline = deadline * HZ; + + ret = count; + } + spin_unlock_irqrestore(shost->host_lock, flags); + return ret; }