Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+27 −16
Original line number Diff line number Diff line
@@ -701,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()
 *
@@ -749,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;
			}
@@ -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
	 * need to worry about launching another command.
	 */
	__scsi_release_buffers(cmd, 0);
	scsi_next_command(cmd);
	return NULL;
}
@@ -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);
}

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()
 *
@@ -834,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);

@@ -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 */
	scsi_release_buffers(cmd);

	/*
	 * 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)
	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",
@@ -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.
		 * A new command will be prepared and issued.
		 */
		scsi_release_buffers(cmd);
		scsi_requeue_command(q, cmd);
		break;
	case ACTION_RETRY: