aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/scsi_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r--drivers/scsi/scsi_lib.c283
1 files changed, 172 insertions, 111 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f5d3b96890d..940dc32ff0d 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req)
scsi_put_command(cmd);
}
-/*
- * Function: scsi_queue_insert()
- *
- * Purpose: Insert a command in the midlevel queue.
- *
- * Arguments: cmd - command that we are adding to queue.
- * reason - why we are inserting command to queue.
- *
- * Lock status: Assumed that lock is not held upon entry.
- *
- * Returns: Nothing.
- *
- * Notes: We do this for one of two cases. Either the host is busy
- * and it cannot accept any more commands for the time being,
- * or the device returned QUEUE_FULL and can accept no more
- * commands.
- * Notes: This could be called either from an interrupt context or a
- * normal process context.
+/**
+ * __scsi_queue_insert - private queue insertion
+ * @cmd: The SCSI command being requeued
+ * @reason: The reason for the requeue
+ * @unbusy: Whether the queue should be unbusied
+ *
+ * This is a private queue insertion. The public interface
+ * scsi_queue_insert() always assumes the queue should be unbusied
+ * because it's always called before the completion. This function is
+ * for a requeue after completion, which should only occur in this
+ * file.
*/
-int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
{
struct Scsi_Host *host = cmd->device->host;
struct scsi_device *device = cmd->device;
@@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* Decrement the counters, since these commands are no longer
* active on the host/device.
*/
- scsi_device_unbusy(device);
+ if (unbusy)
+ scsi_device_unbusy(device);
/*
* Requeue this command. It will go before all other commands
@@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
return 0;
}
+/*
+ * Function: scsi_queue_insert()
+ *
+ * Purpose: Insert a command in the midlevel queue.
+ *
+ * Arguments: cmd - command that we are adding to queue.
+ * reason - why we are inserting command to queue.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: We do this for one of two cases. Either the host is busy
+ * and it cannot accept any more commands for the time being,
+ * or the device returned QUEUE_FULL and can accept no more
+ * commands.
+ * Notes: This could be called either from an interrupt context or a
+ * normal process context.
+ */
+int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+{
+ return __scsi_queue_insert(cmd, reason, 1);
+}
/**
* scsi_execute - insert request and wait for the result
* @sdev: scsi device
@@ -183,13 +200,15 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* @timeout: request timeout in seconds
* @retries: number of times to retry request
* @flags: or into request flags;
+ * @resid: optional residual length
*
* returns the req->errors value which is the scsi_cmnd result
* field.
*/
int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
- unsigned char *sense, int timeout, int retries, int flags)
+ unsigned char *sense, int timeout, int retries, int flags,
+ int *resid)
{
struct request *req;
int write = (data_direction == DMA_TO_DEVICE);
@@ -224,6 +243,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
if (unlikely(req->data_len > 0 && req->data_len <= bufflen))
memset(buffer + (bufflen - req->data_len), 0, req->data_len);
+ if (resid)
+ *resid = req->data_len;
ret = req->errors;
out:
blk_put_request(req);
@@ -235,7 +256,8 @@ EXPORT_SYMBOL(scsi_execute);
int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
- struct scsi_sense_hdr *sshdr, int timeout, int retries)
+ struct scsi_sense_hdr *sshdr, int timeout, int retries,
+ int *resid)
{
char *sense = NULL;
int result;
@@ -246,7 +268,7 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd,
return DRIVER_ERROR << 24;
}
result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen,
- sense, timeout, retries, 0);
+ sense, timeout, retries, 0, resid);
if (sshdr)
scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr);
@@ -567,15 +589,18 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost)
*/
static void scsi_run_queue(struct request_queue *q)
{
- struct scsi_device *starved_head = NULL, *sdev = q->queuedata;
+ struct scsi_device *sdev = q->queuedata;
struct Scsi_Host *shost = sdev->host;
+ LIST_HEAD(starved_list);
unsigned long flags;
if (scsi_target(sdev)->single_lun)
scsi_single_lun_run(sdev);
spin_lock_irqsave(shost->host_lock, flags);
- while (!list_empty(&shost->starved_list) && !scsi_host_is_busy(shost)) {
+ list_splice_init(&shost->starved_list, &starved_list);
+
+ while (!list_empty(&starved_list)) {
int flagset;
/*
@@ -588,24 +613,18 @@ static void scsi_run_queue(struct request_queue *q)
* scsi_request_fn must get the host_lock before checking
* or modifying starved_list or starved_entry.
*/
- sdev = list_entry(shost->starved_list.next,
- struct scsi_device, starved_entry);
- /*
- * The *queue_ready functions can add a device back onto the
- * starved list's tail, so we must check for a infinite loop.
- */
- if (sdev == starved_head)
+ if (scsi_host_is_busy(shost))
break;
- if (!starved_head)
- starved_head = sdev;
+ sdev = list_entry(starved_list.next,
+ struct scsi_device, starved_entry);
+ list_del_init(&sdev->starved_entry);
if (scsi_target_is_busy(scsi_target(sdev))) {
list_move_tail(&sdev->starved_entry,
&shost->starved_list);
continue;
}
- list_del_init(&sdev->starved_entry);
spin_unlock(shost->host_lock);
spin_lock(sdev->request_queue->queue_lock);
@@ -621,6 +640,8 @@ static void scsi_run_queue(struct request_queue *q)
spin_lock(shost->host_lock);
}
+ /* put any unprocessed entries back */
+ list_splice(&starved_list, &shost->starved_list);
spin_unlock_irqrestore(shost->host_lock, flags);
blk_run_queue(q);
@@ -649,8 +670,8 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
struct request *req = cmd->request;
unsigned long flags;
- scsi_unprep_request(req);
spin_lock_irqsave(q->queue_lock, flags);
+ scsi_unprep_request(req);
blk_requeue_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -680,6 +701,8 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
scsi_run_queue(sdev->request_queue);
}
+static void __scsi_release_buffers(struct scsi_cmnd *, int);
+
/*
* Function: scsi_end_request()
*
@@ -728,6 +751,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
* leftovers in the front of the
* queue, and goose the queue again.
*/
+ scsi_release_buffers(cmd);
scsi_requeue_command(q, cmd);
cmd = NULL;
}
@@ -739,6 +763,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
* This will goose the queue request function at the end, so we don't
* need to worry about launching another command.
*/
+ __scsi_release_buffers(cmd, 0);
scsi_next_command(cmd);
return NULL;
}
@@ -794,6 +819,26 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
__sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free);
}
+static void __scsi_release_buffers(struct scsi_cmnd *cmd, int do_bidi_check)
+{
+
+ if (cmd->sdb.table.nents)
+ scsi_free_sgtable(&cmd->sdb);
+
+ memset(&cmd->sdb, 0, sizeof(cmd->sdb));
+
+ if (do_bidi_check && scsi_bidi_cmnd(cmd)) {
+ struct scsi_data_buffer *bidi_sdb =
+ cmd->request->next_rq->special;
+ scsi_free_sgtable(bidi_sdb);
+ kmem_cache_free(scsi_sdb_cache, bidi_sdb);
+ cmd->request->next_rq->special = NULL;
+ }
+
+ if (scsi_prot_sg_count(cmd))
+ scsi_free_sgtable(cmd->prot_sdb);
+}
+
/*
* Function: scsi_release_buffers()
*
@@ -813,21 +858,7 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
*/
void scsi_release_buffers(struct scsi_cmnd *cmd)
{
- if (cmd->sdb.table.nents)
- scsi_free_sgtable(&cmd->sdb);
-
- memset(&cmd->sdb, 0, sizeof(cmd->sdb));
-
- if (scsi_bidi_cmnd(cmd)) {
- struct scsi_data_buffer *bidi_sdb =
- cmd->request->next_rq->special;
- scsi_free_sgtable(bidi_sdb);
- kmem_cache_free(scsi_sdb_cache, bidi_sdb);
- cmd->request->next_rq->special = NULL;
- }
-
- if (scsi_prot_sg_count(cmd))
- scsi_free_sgtable(cmd->prot_sdb);
+ __scsi_release_buffers(cmd, 1);
}
EXPORT_SYMBOL(scsi_release_buffers);
@@ -876,16 +907,24 @@ static void scsi_end_bidi_request(struct scsi_cmnd *cmd)
* (the normal case for most drivers), we don't need
* the logic to deal with cleaning up afterwards.
*
- * We must do one of several things here:
+ * We must call scsi_end_request(). This will finish off
+ * the specified number of sectors. If we are done, the
+ * command block will be released and the queue function
+ * will be goosed. If we are not done then we have to
+ * figure out what to do next:
*
- * a) Call scsi_end_request. This will finish off the
- * specified number of sectors. If we are done, the
- * command block will be released, and the queue
- * function will be goosed. If we are not done, then
- * scsi_end_request will directly goose the queue.
+ * a) We can call scsi_requeue_command(). The request
+ * will be unprepared and put back on the queue. Then
+ * a new command will be created for it. This should
+ * be used if we made forward progress, or if we want
+ * to switch from READ(10) to READ(6) for example.
*
- * b) We can just use scsi_requeue_command() here. This would
- * be used if we just wanted to retry, for example.
+ * b) We can call scsi_queue_insert(). The request will
+ * be put back on the queue and retried using the same
+ * command as before, possibly after a delay.
+ *
+ * c) We can call blk_end_request() with -EIO to fail
+ * the remainder of the request.
*/
void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
@@ -897,6 +936,9 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
+ enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
+ ACTION_DELAYED_RETRY} action;
+ char *description = NULL;
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
@@ -930,7 +972,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */
- scsi_release_buffers(cmd);
/*
* Next deal with any sectors which we were able to correctly
@@ -948,10 +989,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
return;
this_count = blk_rq_bytes(req);
- /* good_bytes = 0, or (inclusive) there were leftovers and
- * result = 0, so scsi_end_request couldn't retry.
- */
- if (sense_valid && !sense_deferred) {
+ error = -EIO;
+
+ if (host_byte(result) == DID_RESET) {
+ /* Third party bus reset or reset for error recovery
+ * reasons. Just retry the command and see what
+ * happens.
+ */
+ action = ACTION_RETRY;
+ } else if (sense_valid && !sense_deferred) {
switch (sshdr.sense_key) {
case UNIT_ATTENTION:
if (cmd->device->removable) {
@@ -959,16 +1005,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
* and quietly refuse further access.
*/
cmd->device->changed = 1;
- scsi_end_request(cmd, -EIO, this_count, 1);
- return;
+ description = "Media Changed";
+ action = ACTION_FAIL;
} else {
/* Must have been a power glitch, or a
* bus reset. Could not have been a
* media change, so we just retry the
- * request and see what happens.
+ * command and see what happens.
*/
- scsi_requeue_command(q, cmd);
- return;
+ action = ACTION_RETRY;
}
break;
case ILLEGAL_REQUEST:
@@ -984,21 +1029,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
(cmd->cmnd[0] == READ_10 ||
cmd->cmnd[0] == WRITE_10)) {
+ /* This will issue a new 6-byte command. */
cmd->device->use_10_for_rw = 0;
- /* This will cause a retry with a
- * 6-byte command.
- */
- scsi_requeue_command(q, cmd);
- } else if (sshdr.asc == 0x10) /* DIX */
- scsi_end_request(cmd, -EIO, this_count, 0);
- else
- scsi_end_request(cmd, -EIO, this_count, 1);
- return;
+ action = ACTION_REPREP;
+ } else if (sshdr.asc == 0x10) /* DIX */ {
+ description = "Host Data Integrity Failure";
+ action = ACTION_FAIL;
+ error = -EILSEQ;
+ } else
+ action = ACTION_FAIL;
+ break;
case ABORTED_COMMAND:
if (sshdr.asc == 0x10) { /* DIF */
- scsi_end_request(cmd, -EIO, this_count, 0);
- return;
- }
+ description = "Target Data Integrity Failure";
+ action = ACTION_FAIL;
+ error = -EILSEQ;
+ } else
+ action = ACTION_RETRY;
break;
case NOT_READY:
/* If the device is in the process of becoming
@@ -1013,49 +1060,63 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
case 0x07: /* operation in progress */
case 0x08: /* Long write in progress */
case 0x09: /* self test in progress */
- scsi_requeue_command(q, cmd);
- return;
+ action = ACTION_DELAYED_RETRY;
+ break;
default:
+ description = "Device not ready";
+ action = ACTION_FAIL;
break;
}
+ } else {
+ description = "Device not ready";
+ action = ACTION_FAIL;
}
- if (!(req->cmd_flags & REQ_QUIET))
- scsi_cmd_print_sense_hdr(cmd,
- "Device not ready",
- &sshdr);
-
- scsi_end_request(cmd, -EIO, this_count, 1);
- return;
+ break;
case VOLUME_OVERFLOW:
- if (!(req->cmd_flags & REQ_QUIET)) {
- scmd_printk(KERN_INFO, cmd,
- "Volume overflow, CDB: ");
- __scsi_print_command(cmd->cmnd);
- scsi_print_sense("", cmd);
- }
/* See SSC3rXX or current. */
- scsi_end_request(cmd, -EIO, this_count, 1);
- return;
+ action = ACTION_FAIL;
+ break;
default:
+ description = "Unhandled sense code";
+ action = ACTION_FAIL;
break;
}
+ } else {
+ description = "Unhandled error code";
+ action = ACTION_FAIL;
}
- if (host_byte(result) == DID_RESET) {
- /* Third party bus reset or reset for error recovery
- * reasons. Just retry the request and see what
- * happens.
- */
- scsi_requeue_command(q, cmd);
- return;
- }
- if (result) {
+
+ switch (action) {
+ case ACTION_FAIL:
+ /* Give up and fail the remainder of the request */
+ scsi_release_buffers(cmd);
if (!(req->cmd_flags & REQ_QUIET)) {
+ if (description)
+ scmd_printk(KERN_INFO, cmd, "%s\n",
+ description);
scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
}
+ blk_end_request(req, -EIO, blk_rq_bytes(req));
+ scsi_next_command(cmd);
+ break;
+ case ACTION_REPREP:
+ /* Unprep the request and put it back at the head of the queue.
+ * A new command will be prepared and issued.
+ */
+ scsi_release_buffers(cmd);
+ scsi_requeue_command(q, cmd);
+ break;
+ case ACTION_RETRY:
+ /* Retry the same command immediately */
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
+ break;
+ case ACTION_DELAYED_RETRY:
+ /* Retry the same command after a delay */
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0);
+ break;
}
- scsi_end_request(cmd, -EIO, this_count, !result);
}
static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
@@ -1999,7 +2060,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage,
}
ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len,
- sshdr, timeout, retries);
+ sshdr, timeout, retries, NULL);
kfree(real_buffer);
return ret;
}
@@ -2064,7 +2125,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
memset(buffer, 0, len);
result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- sshdr, timeout, retries);
+ sshdr, timeout, retries, NULL);
/* This code looks awful: what it's doing is making sure an
* ILLEGAL REQUEST sense return identifies the actual command
@@ -2146,7 +2207,7 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries,
/* try to eat the UNIT_ATTENTION if there are enough retries */
do {
result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr,
- timeout, retries);
+ timeout, retries, NULL);
if (sdev->removable && scsi_sense_valid(sshdr) &&
sshdr->sense_key == UNIT_ATTENTION)
sdev->changed = 1;