Commit 79ed2429 authored by James Bottomley's avatar James Bottomley

[SCSI] scsi_lib: fix DID_RESET status problems

Andrew Vaszquez said:
> There's a problem that is causing commands returned by the LLD with
> a DID_RESET status to be reissued with cleared cmd->sdb data which
> in our tests are manifesting in firmware detected overruns.  Here's
> a snippet of a READ_10 scsi_cmnd upon completion by the storage

The problem is caused by:

commit b60af5b0
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Mon Nov 3 15:56:47 2008 -0500

    [SCSI] simplify scsi_io_completion()

Because scsi_release_buffers() is called before commands that go
through the ACTION_RETRY and ACTION_DELAYED_RETRY legs are requeued.
However, they're not re-prepared, so nothing ever reallocates the
buffer resources to them.  Fix this by releasing the buffers only if
we're not going to go down these legs (but scsi_release_buffers() on
all legs including two in scsi_end_request(); this latter needs a
special version __scsi_release_buffers() because the final one can be
called after the request has been freed, so the bidi test in
scsi_release_buffers(), which touches the request has to be skipped).
Reported-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 4be98c0c
...@@ -701,6 +701,8 @@ void scsi_run_host_queues(struct Scsi_Host *shost) ...@@ -701,6 +701,8 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
scsi_run_queue(sdev->request_queue); scsi_run_queue(sdev->request_queue);
} }
static void __scsi_release_buffers(struct scsi_cmnd *, int);
/* /*
* Function: scsi_end_request() * Function: scsi_end_request()
* *
...@@ -749,6 +751,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, ...@@ -749,6 +751,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
* leftovers in the front of the * leftovers in the front of the
* queue, and goose the queue again. * queue, and goose the queue again.
*/ */
scsi_release_buffers(cmd);
scsi_requeue_command(q, cmd); scsi_requeue_command(q, cmd);
cmd = NULL; cmd = NULL;
} }
...@@ -760,6 +763,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, ...@@ -760,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 * This will goose the queue request function at the end, so we don't
* need to worry about launching another command. * need to worry about launching another command.
*/ */
__scsi_release_buffers(cmd, 0);
scsi_next_command(cmd); scsi_next_command(cmd);
return NULL; return NULL;
} }
...@@ -815,6 +819,26 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb) ...@@ -815,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); __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() * Function: scsi_release_buffers()
* *
...@@ -834,21 +858,7 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb) ...@@ -834,21 +858,7 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
*/ */
void scsi_release_buffers(struct scsi_cmnd *cmd) void scsi_release_buffers(struct scsi_cmnd *cmd)
{ {
if (cmd->sdb.table.nents) __scsi_release_buffers(cmd, 1);
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);
} }
EXPORT_SYMBOL(scsi_release_buffers); EXPORT_SYMBOL(scsi_release_buffers);
...@@ -962,7 +972,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -962,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 */ 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 * Next deal with any sectors which we were able to correctly
...@@ -1080,6 +1089,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -1080,6 +1089,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
switch (action) { switch (action) {
case ACTION_FAIL: case ACTION_FAIL:
/* Give up and fail the remainder of the request */ /* Give up and fail the remainder of the request */
scsi_release_buffers(cmd);
if (!(req->cmd_flags & REQ_QUIET)) { if (!(req->cmd_flags & REQ_QUIET)) {
if (description) if (description)
scmd_printk(KERN_INFO, cmd, "%s\n", scmd_printk(KERN_INFO, cmd, "%s\n",
...@@ -1095,6 +1105,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) ...@@ -1095,6 +1105,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
/* Unprep the request and put it back at the head of the queue. /* Unprep the request and put it back at the head of the queue.
* A new command will be prepared and issued. * A new command will be prepared and issued.
*/ */
scsi_release_buffers(cmd);
scsi_requeue_command(q, cmd); scsi_requeue_command(q, cmd);
break; break;
case ACTION_RETRY: case ACTION_RETRY:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment