diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 19:42:25 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 19:42:25 -0800 |
commit | 382f51fe2f2276344d8a21447656778cdf6583b6 (patch) | |
tree | c2836a2cca4126c9c026ce5aa2fdf9f1c8ccded6 /drivers/scsi/scsi_error.c | |
parent | 701791cc3c8fc6dd83f6ec8af7e2541b4a316606 (diff) | |
parent | 54987386ee3790f3900de4df2ed4deb0e18dfc9f (diff) | |
download | linux-382f51fe2f2276344d8a21447656778cdf6583b6.tar.gz linux-382f51fe2f2276344d8a21447656778cdf6583b6.tar.bz2 linux-382f51fe2f2276344d8a21447656778cdf6583b6.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (222 commits)
[SCSI] zfcp: Remove flag ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP
[SCSI] zfcp: Activate fc4s attributes for zfcp in FC transport class
[SCSI] zfcp: Block scsi_eh thread for rport state BLOCKED
[SCSI] zfcp: Update FSF error reporting
[SCSI] zfcp: Improve ELS ADISC handling
[SCSI] zfcp: Simplify handling of ct and els requests
[SCSI] zfcp: Remove ZFCP_DID_MASK
[SCSI] zfcp: Move WKA port to zfcp FC code
[SCSI] zfcp: Use common code definitions for FC CT structs
[SCSI] zfcp: Use common code definitions for FC ELS structs
[SCSI] zfcp: Update FCP protocol related code
[SCSI] zfcp: Dont fail SCSI commands when transitioning to blocked fc_rport
[SCSI] zfcp: Assign scheduled work to driver queue
[SCSI] zfcp: Remove STATUS_COMMON_REMOVE flag as it is not required anymore
[SCSI] zfcp: Implement module unloading
[SCSI] zfcp: Merge trace code for fsf requests in one function
[SCSI] zfcp: Access ports and units with container_of in sysfs code
[SCSI] zfcp: Remove suspend callback
[SCSI] zfcp: Remove global config_mutex
[SCSI] zfcp: Replace local reference counting with common kref
...
Diffstat (limited to 'drivers/scsi/scsi_error.c')
-rw-r--r-- | drivers/scsi/scsi_error.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1b0060b791e8..08ed506e6059 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -331,6 +331,64 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) } } +static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) +{ + struct scsi_host_template *sht = sdev->host->hostt; + struct scsi_device *tmp_sdev; + + if (!sht->change_queue_depth || + sdev->queue_depth >= sdev->max_queue_depth) + return; + + if (time_before(jiffies, + sdev->last_queue_ramp_up + sdev->queue_ramp_up_period)) + return; + + if (time_before(jiffies, + sdev->last_queue_full_time + sdev->queue_ramp_up_period)) + return; + + /* + * Walk all devices of a target and do + * ramp up on them. + */ + shost_for_each_device(tmp_sdev, sdev->host) { + if (tmp_sdev->channel != sdev->channel || + tmp_sdev->id != sdev->id || + tmp_sdev->queue_depth == sdev->max_queue_depth) + continue; + /* + * call back into LLD to increase queue_depth by one + * with ramp up reason code. + */ + sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1, + SCSI_QDEPTH_RAMP_UP); + sdev->last_queue_ramp_up = jiffies; + } +} + +static void scsi_handle_queue_full(struct scsi_device *sdev) +{ + struct scsi_host_template *sht = sdev->host->hostt; + struct scsi_device *tmp_sdev; + + if (!sht->change_queue_depth) + return; + + shost_for_each_device(tmp_sdev, sdev->host) { + if (tmp_sdev->channel != sdev->channel || + tmp_sdev->id != sdev->id) + continue; + /* + * We do not know the number of commands that were at + * the device when we got the queue full so we start + * from the highest possible value and work our way down. + */ + sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1, + SCSI_QDEPTH_QFULL); + } +} + /** * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD. * @scmd: SCSI cmd to examine. @@ -371,6 +429,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) */ switch (status_byte(scmd->result)) { case GOOD: + scsi_handle_queue_ramp_up(scmd->device); case COMMAND_TERMINATED: return SUCCESS; case CHECK_CONDITION: @@ -387,8 +446,10 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) * let issuer deal with this, it could be just fine */ return SUCCESS; - case BUSY: case QUEUE_FULL: + scsi_handle_queue_full(scmd->device); + /* fall through */ + case BUSY: default: return FAILED; } @@ -1387,6 +1448,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) */ switch (status_byte(scmd->result)) { case QUEUE_FULL: + scsi_handle_queue_full(scmd->device); /* * the case of trying to send too many commands to a * tagged queueing device. @@ -1400,6 +1462,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) */ return ADD_TO_MLQUEUE; case GOOD: + scsi_handle_queue_ramp_up(scmd->device); case COMMAND_TERMINATED: return SUCCESS; case TASK_ABORTED: |