linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation
@ 2005-05-14 13:57 Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn() Tejun Heo
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 13:57 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

 Hello, James.

 This is repost of reqfn-reimplmentation patchset posted about a month
ago.  As REQ_SPECIAL semantics patchset, which this patchset depends
on, has been accepted with slight modification (REQ_SOFTBARRIER
handled by blk layer), this patchset is adjusted accordingly.  Also,
it's updated to use original scsi_add_timer function as timer API
change patch isn't accepted yet.

 scsi_reqfn_reimplementation patch depends on the timer update
patchset I've posted yesterday.  The only dependency is the removal of
scsi_dispatch_cmd() because the timer patchset modifies
scsi_queue_insert() call in that function.  If you decide to not
accept the timer updates, just removing scsi_cmd_get_serial() and
scsi_dispatch_cmd() by hand should suffice.

 Original description follows.

 This patchset reimplements scsi_request_fn().  All prep's are moved
into prep_fn and all state checking/issueing are moved into
scsi_reqfn.  prep_fn() only terminates/defers unpreparable requests
and all requests are terminated through scsi midlayer.

[ Start of patch descriptions ]

01_scsi_reqfn_consolidate_error_handling.patch
	: consolidate error handling out of scsi_init_io() into scsi_prep_fn()

	This patch fixes a queue stall bug which occurred when sgtable
	allocation failed and device_busy == 0.  When scsi_init_io()
	returns BLKPREP_DEFER or BLKPREP_KILL, it's supposed to free
	resources itself.  This patch consolidates defer and kill
	handling into scsi_prep_fn().

	Note that this patch doesn't consolidate state defer/kill
	handlings in scsi_prep_fn() as all state checks will be moved
	into scsi_reques_fn() by the following reqfn_reimpl patch.

	ret value checking was changed to switch() as in James's
	patch.  Also, kill: comment is copied from James's patch.

02_scsi_reqfn_move_preps_to_prep_fn.patch
	: move request preps in other places into prep_fn()

	Move request preparations scattered in scsi_request_fn() and
	scsi_dispatch_cmd() into scsi_prep_fn()

	* CDB_SIZE check in scsi_dispatch_cmd()
	* SCSI-2 LUN preparation in scsi_dispatch_cmd()

	No invalid request reaches scsi_request_fn() anymore.

	Note that scsi_init_cmd_errh() is still left in
	scsi_request_fn().  As all requeued requests need its sense
	buffer and result value cleared, we can't move this to
	prep_fn() yet.  This is moved into prep_fn in the following
	requeue path consoildation patchset.

03_scsi_reqfn_reimplementation.patch
	: reimplement scsi_request_fn()

	New scsi_request_fn() is formatted mostly as Chistoph Hellwig
	suggested.

	This patch rewrites scsi_request_fn().	scsi_dispatch_cmd() is
	merged into scsi_request_fn().	Goals are

	* Remove unnecessary operations (host_lock unlocking/locking,
	  recursing into scsi_run_queue(), ...)
	* Consolidate defer/kill paths.
	* Be concise.

	The following bugs are fixed.

	* All killed requests now get fully prep'ed and pass through
	  __scsi_done().  This is the only kill path.
		- scsi_cmnd leak in offline-kill path removed
		- unfinished request bug in
		  scsi_dispatch_cmd():SDEV_DEL-kill path removed.
		- commands are never terminated directly from blk
		  layer unless they are invalid, so no need to supply
		  req->end_io callback for special requests.
	* Timer is added while holding host_lock, after all conditions
	  are checked and serial number is assigned.  This guarantees
	  that until host_lock is released, the scsi_cmnd pointed to
	  by cmd isn't released.  That didn't hold in the original
	  code and, theoretically, the original code could access
	  already released cmd.
	* For the same reason, if shost->hostt->queuecommand() fails,
	  we try to delete the timer before releasing host_lock.

	Other changes/notes

	* host_lock is acquired and released only once.
	  enter (qlocked) -> enter loop -> dev-prep -> switch to hlock -\
			  ^---- switch to qlock <- issue <- host-prep <-/
	* unnecessary if () on get_device() removed.
	* loop on elv_next_request() instead of blk_queue_plugged().
	  We now explicitly break out of loop when we plug and check if
	  the queue has been plugged underneath us at the end of loop.
	* All device/host state checks are done in this function and
	  done only once while holding qlock/host_lock respectively.
	* Requests which get deferred during dev-prep are never
	  removed from request queue, so deferring is achieved by
	  simply breaking out of the loop and returning.
	* Failure of blk_queue_start_tag() on tagged queue is a BUG
	  now.	This condition should have been catched by
	  scsi_dev_queue_ready().
	* req->special == NULL test removed.  This just can't happen,
	  and even if it ever happens, scsi_request_fn() will
	  deterministically oops.
	* Requests which gets deferred during host-prep are requeued
	  using blk_requeue_request().	This is the only requeue path.

04_scsi_reqfn_remove_wait_req_end_io.patch
	: remove unnecessary scsi_wait_req_end_io()

	As all requests are now terminated via scsi midlayer, we don't
	need to set end_io for special reqs, remove it.

[ End of patch descriptions ]

 Thanks a lot.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn()
  2005-05-14 13:57 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
@ 2005-05-14 13:57 ` Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn() Tejun Heo
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 13:57 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

01_scsi_reqfn_consolidate_error_handling.patch

	This patch fixes a queue stall bug which occurred when sgtable
	allocation failed and device_busy == 0.  When scsi_init_io()
	returns BLKPREP_DEFER or BLKPREP_KILL, it's supposed to free
	resources itself.  This patch consolidates defer and kill
	handling into scsi_prep_fn().

	Note that this patch doesn't consolidate state defer/kill
	handlings in scsi_prep_fn() as all state checks will be moved
	into scsi_reques_fn() by the following reqfn_reimpl patch.

	ret value checking was changed to switch() as in James's
	patch.  Also, kill: comment is copied from James's patch.

Signed-off-by: Tejun Heo <htejun@gmail.com>

 scsi_lib.c |   40 ++++++++++++++++++++++++++++------------
 1 files changed, 28 insertions(+), 12 deletions(-)

Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-14 22:35:18.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-14 22:35:18.000000000 +0900
@@ -977,9 +977,6 @@ static int scsi_init_io(struct scsi_cmnd
 	printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
 			req->current_nr_sectors);
 
-	/* release the command and kill it */
-	scsi_release_buffers(cmd);
-	scsi_put_command(cmd);
 	return BLKPREP_KILL;
 }
 
@@ -1147,18 +1144,24 @@ static int scsi_prep_fn(struct request_q
 		 * required).
 		 */
 		ret = scsi_init_io(cmd);
-		if (ret)	/* BLKPREP_KILL return also releases the command */
-			return ret;
+		switch (ret) {
+		case 0:
+			/* Successful initialization. */
+			break;
+		case BLKPREP_DEFER:
+			goto defer;
+		default:
+			/* Unknown return value, fall through. */
+		case BLKPREP_KILL:
+			goto kill;
+		}
 		
 		/*
 		 * Initialize the actual SCSI command for this request.
 		 */
 		drv = *(struct scsi_driver **)req->rq_disk->private_data;
-		if (unlikely(!drv->init_command(cmd))) {
-			scsi_release_buffers(cmd);
-			scsi_put_command(cmd);
-			return BLKPREP_KILL;
-		}
+		if (unlikely(!drv->init_command(cmd)))
+			goto kill;
 	}
 
 	/*
@@ -1168,12 +1171,25 @@ static int scsi_prep_fn(struct request_q
 	return BLKPREP_OK;
 
  defer:
-	/* If we defer, the elv_next_request() returns NULL, but the
+	/*
+	 * If we defer, the elv_next_request() returns NULL, but the
 	 * queue must be restarted, so we plug here if no returning
-	 * command will automatically do that. */
+	 * command will automatically do that.
+	 */
 	if (sdev->device_busy == 0)
 		blk_plug_device(q);
 	return BLKPREP_DEFER;
+
+ kill:
+	/*
+	 * Here we have to release every resource associated with the
+	 * request because this will complete at the request level
+	 * (req->end_io), not the scsi command level, so no scsi
+	 * routine will get to free the associated resources.
+	 */
+	scsi_release_buffers(cmd);
+	scsi_put_command(cmd);
+	return BLKPREP_KILL;
 }
 
 /*


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn()
  2005-05-14 13:57 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn() Tejun Heo
@ 2005-05-14 13:57 ` Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn() Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io() Tejun Heo
  3 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 13:57 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

02_scsi_reqfn_move_preps_to_prep_fn.patch

	Move request preparations scattered in scsi_request_fn() and
	scsi_dispatch_cmd() into scsi_prep_fn()

	* CDB_SIZE check in scsi_dispatch_cmd()
	* SCSI-2 LUN preparation in scsi_dispatch_cmd()

	No invalid request reaches scsi_request_fn() anymore.

	Note that scsi_init_cmd_errh() is still left in
	scsi_request_fn().  As all requeued requests need its sense
	buffer and result value cleared, we can't move this to
	prep_fn() yet.  This is moved into prep_fn in the following
	requeue path consoildation patchset.

Signed-off-by: Tejun Heo <htejun@gmail.com>

 scsi.c     |   30 ------------------------------
 scsi_lib.c |   17 +++++++++++++++++
 2 files changed, 17 insertions(+), 30 deletions(-)

Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c	2005-05-14 22:35:18.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c	2005-05-14 22:35:18.000000000 +0900
@@ -79,15 +79,6 @@
 #define MIN_RESET_PERIOD (15*HZ)
 
 /*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd)	(((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
-				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -566,14 +557,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		goto out;
 	}
 
-	/* 
-	 * If SCSI-2 or lower, store the LUN value in cmnd.
-	 */
-	if (cmd->device->scsi_level <= SCSI_2) {
-		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
-			       (cmd->device->lun << 5 & 0xe0);
-	}
-
 	/*
 	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so
 	 * we can avoid the drive not being ready.
@@ -614,19 +597,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 
 	atomic_inc(&cmd->device->iorequest_cnt);
 
-	/*
-	 * Before we queue this command, check if the command
-	 * length exceeds what the host adapter can handle.
-	 */
-	if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
-		SCSI_LOG_MLQUEUE(3,
-				printk("queuecommand : command too long.\n"));
-		cmd->result = (DID_ABORT << 16);
-
-		scsi_done(cmd);
-		goto out;
-	}
-
 	spin_lock_irqsave(host->host_lock, flags);
 	scsi_cmd_get_serial(host, cmd); 
 
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-14 22:35:18.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-14 22:35:18.000000000 +0900
@@ -28,6 +28,14 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+/*
+ * Macro to determine the size of SCSI command. This macro takes vendor
+ * unique commands into account. SCSI commands in groups 6 and 7 are
+ * vendor unique and we will depend upon the command length being
+ * supplied correctly in cmd_len.
+ */
+#define CDB_SIZE(cmd)	(((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
+				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
 
 #define SG_MEMPOOL_NR		(sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool))
 #define SG_MEMPOOL_SIZE		32
@@ -1164,6 +1172,15 @@ static int scsi_prep_fn(struct request_q
 			goto kill;
 	}
 
+	/* Check command length. */
+	if (CDB_SIZE(cmd) > sdev->host->max_cmd_len)
+		goto kill;
+
+	/* If SCSI-2 or lower, store the LUN value in cmnd. */
+	if (cmd->device->scsi_level <= SCSI_2)
+		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
+			(cmd->device->lun << 5 & 0xe0);
+
 	/*
 	 * The request is now prepped, no need to come back here
 	 */


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn()
  2005-05-14 13:57 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn() Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn() Tejun Heo
@ 2005-05-14 13:57 ` Tejun Heo
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io() Tejun Heo
  3 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 13:57 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

03_scsi_reqfn_reimplementation.patch

	New scsi_request_fn() is formatted mostly as Chistoph Hellwig
	suggested.

	This patch rewrites scsi_request_fn().	scsi_dispatch_cmd() is
	merged into scsi_request_fn().	Goals are

	* Remove unnecessary operations (host_lock unlocking/locking,
	  recursing into scsi_run_queue(), ...)
	* Consolidate defer/kill paths.
	* Be concise.

	The following bugs are fixed.

	* All killed requests now get fully prep'ed and pass through
	  __scsi_done().  This is the only kill path.
		- scsi_cmnd leak in offline-kill path removed
		- unfinished request bug in
		  scsi_dispatch_cmd():SDEV_DEL-kill path removed.
		- commands are never terminated directly from blk
		  layer unless they are invalid, so no need to supply
		  req->end_io callback for special requests.
	* Timer is added while holding host_lock, after all conditions
	  are checked and serial number is assigned.  This guarantees
	  that until host_lock is released, the scsi_cmnd pointed to
	  by cmd isn't released.  That didn't hold in the original
	  code and, theoretically, the original code could access
	  already released cmd.
	* For the same reason, if shost->hostt->queuecommand() fails,
	  we try to delete the timer before releasing host_lock.

	Other changes/notes

	* host_lock is acquired and released only once.
	  enter (qlocked) -> enter loop -> dev-prep -> switch to hlock -\
			  ^---- switch to qlock <- issue <- host-prep <-/
	* unnecessary if () on get_device() removed.
	* loop on elv_next_request() instead of blk_queue_plugged().
	  We now explicitly break out of loop when we plug and check if
	  the queue has been plugged underneath us at the end of loop.
	* All device/host state checks are done in this function and
	  done only once while holding qlock/host_lock respectively.
	* Requests which get deferred during dev-prep are never
	  removed from request queue, so deferring is achieved by
	  simply breaking out of the loop and returning.
	* Failure of blk_queue_start_tag() on tagged queue is a BUG
	  now.	This condition should have been catched by
	  scsi_dev_queue_ready().
	* req->special == NULL test removed.  This just can't happen,
	  and even if it ever happens, scsi_request_fn() will
	  deterministically oops.
	* Requests which gets deferred during host-prep are requeued
	  using blk_requeue_request().	This is the only requeue path.

Signed-off-by: Tejun Heo <htejun@gmail.com>

 scsi.c      |  137 ----------------------------
 scsi_lib.c  |  286 +++++++++++++++++++++++++++++++++---------------------------
 scsi_priv.h |    1 
 3 files changed, 159 insertions(+), 265 deletions(-)

Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c	2005-05-14 22:35:18.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c	2005-05-14 22:35:19.000000000 +0900
@@ -70,15 +70,6 @@
 
 
 /*
- * Definitions and constants.
- */
-
-#define MIN_RESET_DELAY (2*HZ)
-
-/* Do not call reset on error if we just did a reset within 15 sec. */
-#define MIN_RESET_PERIOD (15*HZ)
-
-/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -495,134 +486,6 @@ void scsi_log_completion(struct scsi_cmn
 }
 #endif
 
-/* 
- * Assign a serial number and pid to the request for error recovery
- * and debugging purposes.  Protected by the Host_Lock of host.
- */
-static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
-{
-	cmd->serial_number = host->cmd_serial_number++;
-	if (cmd->serial_number == 0) 
-		cmd->serial_number = host->cmd_serial_number++;
-	
-	cmd->pid = host->cmd_pid++;
-	if (cmd->pid == 0)
-		cmd->pid = host->cmd_pid++;
-}
-
-/*
- * Function:    scsi_dispatch_command
- *
- * Purpose:     Dispatch a command to the low-level driver.
- *
- * Arguments:   cmd - command block we are dispatching.
- *
- * Notes:
- */
-int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
-{
-	struct Scsi_Host *host = cmd->device->host;
-	unsigned long flags = 0;
-	unsigned long timeout;
-	int rtn = 0;
-
-	/* check if the device is still usable */
-	if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
-		/* in SDEV_DEL we error all commands. DID_NO_CONNECT
-		 * returns an immediate error upwards, and signals
-		 * that the device is no longer present */
-		cmd->result = DID_NO_CONNECT << 16;
-		atomic_inc(&cmd->device->iorequest_cnt);
-		scsi_done(cmd);
-		/* return 0 (because the command has been processed) */
-		goto out;
-	}
-
-	/* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
-	if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
-		/* 
-		 * in SDEV_BLOCK, the command is just put back on the device
-		 * queue.  The suspend state has already blocked the queue so
-		 * future requests should not occur until the device 
-		 * transitions out of the suspend state.
-		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
-
-		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
-
-		/*
-		 * NOTE: rtn is still zero here because we don't need the
-		 * queue to be plugged on return (it's already stopped)
-		 */
-		goto out;
-	}
-
-	/*
-	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so
-	 * we can avoid the drive not being ready.
-	 */
-	timeout = host->last_reset + MIN_RESET_DELAY;
-
-	if (host->resetting && time_before(jiffies, timeout)) {
-		int ticks_remaining = timeout - jiffies;
-		/*
-		 * NOTE: This may be executed from within an interrupt
-		 * handler!  This is bad, but for now, it'll do.  The irq
-		 * level of the interrupt handler has been masked out by the
-		 * platform dependent interrupt handling code already, so the
-		 * sti() here will not cause another call to the SCSI host's
-		 * interrupt handler (assuming there is one irq-level per
-		 * host).
-		 */
-		while (--ticks_remaining >= 0)
-			mdelay(1 + 999 / HZ);
-		host->resetting = 0;
-	}
-
-	/* 
-	 * AK: unlikely race here: for some reason the timer could
-	 * expire before the serial number is set up below.
-	 */
-	scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
-
-	scsi_log_send(cmd);
-
-	/*
-	 * We will use a queued command if possible, otherwise we will
-	 * emulate the queuing and calling of completion function ourselves.
-	 */
-
-	cmd->state = SCSI_STATE_QUEUED;
-	cmd->owner = SCSI_OWNER_LOWLEVEL;
-
-	atomic_inc(&cmd->device->iorequest_cnt);
-
-	spin_lock_irqsave(host->host_lock, flags);
-	scsi_cmd_get_serial(host, cmd); 
-
-	if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
-		cmd->result = (DID_NO_CONNECT << 16);
-		scsi_done(cmd);
-	} else {
-		rtn = host->hostt->queuecommand(cmd, scsi_done);
-	}
-	spin_unlock_irqrestore(host->host_lock, flags);
-	if (rtn) {
-		if (scsi_delete_timer(cmd)) {
-			atomic_inc(&cmd->device->iodone_cnt);
-			scsi_queue_insert(cmd,
-					  (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
-					  rtn : SCSI_MLQUEUE_HOST_BUSY);
-		}
-		SCSI_LOG_MLQUEUE(3,
-		    printk("queuecommand : request rejected\n"));
-	}
-
- out:
-	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
-	return rtn;
-}
-
 /*
  * Function:    scsi_init_cmd_from_req
  *
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-14 22:35:18.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-14 22:35:19.000000000 +0900
@@ -28,6 +28,8 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+#define MIN_RESET_DELAY (2*HZ)
+
 /*
  * Macro to determine the size of SCSI command. This macro takes vendor
  * unique commands into account. SCSI commands in groups 6 and 7 are
@@ -1040,32 +1042,6 @@ static int scsi_prep_fn(struct request_q
 {
 	struct scsi_device *sdev = q->queuedata;
 	struct scsi_cmnd *cmd;
-	int specials_only = 0;
-
-	/*
-	 * Just check to see if the device is online.  If it isn't, we
-	 * refuse to process any commands.  The device must be brought
-	 * online before trying any recovery commands
-	 */
-	if (unlikely(!scsi_device_online(sdev))) {
-		printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
-		       sdev->host->host_no, sdev->id, sdev->lun);
-		return BLKPREP_KILL;
-	}
-	if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
-		/* OK, we're not in a running state don't prep
-		 * user commands */
-		if (sdev->sdev_state == SDEV_DEL) {
-			/* Device is fully deleted, no commands
-			 * at all allowed down */
-			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
-			       sdev->host->host_no, sdev->id, sdev->lun);
-			return BLKPREP_KILL;
-		}
-		/* OK, we only allow special commands (i.e. not
-		 * user initiated ones */
-		specials_only = sdev->sdev_state;
-	}
 
 	/*
 	 * Find the actual device driver associated with this command.
@@ -1088,30 +1064,12 @@ static int scsi_prep_fn(struct request_q
 		} else
 			cmd = req->special;
 	} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-
-		if(unlikely(specials_only)) {
-			if(specials_only == SDEV_QUIESCE ||
-					specials_only == SDEV_BLOCK)
-				return BLKPREP_DEFER;
-			
-			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
-			       sdev->host->host_no, sdev->id, sdev->lun);
-			return BLKPREP_KILL;
-		}
-			
-			
-		/*
-		 * Now try and find a command block that we can use.
-		 */
 		if (!req->special) {
 			cmd = scsi_get_command(sdev, GFP_ATOMIC);
 			if (unlikely(!cmd))
 				goto defer;
 		} else
 			cmd = req->special;
-		
-		/* pull a tag out of the request if we have one */
-		cmd->tag = req->tag;
 	} else {
 		blk_dump_rq_flags(req, "SCSI bad req");
 		return BLKPREP_KILL;
@@ -1297,6 +1255,54 @@ static void scsi_kill_requests(request_q
 }
 
 /*
+ * scsi_wait_reset: We will wait MIN_RESET_DELAY clock ticks after the
+ * last reset so we can avoid the drive not being ready.
+ *
+ * Called with no lock held and irq disabled.
+ */
+static inline void scsi_wait_reset(struct Scsi_Host *shost)
+{
+	unsigned long timeout = shost->last_reset + MIN_RESET_DELAY;
+
+	if (shost->resetting && time_before(jiffies, timeout)) {
+		int ticks_remaining = timeout - jiffies;
+		/*
+		 * NOTE: This may be executed from within an interrupt
+		 * handler!  This is bad, but for now, it'll do.  The
+		 * irq level of the interrupt handler has been masked
+		 * out by the platform dependent interrupt handling
+		 * code already, so the local_irq_enable() here will
+		 * not cause another call to the SCSI host's interrupt
+		 * handler (assuming there is one irq-level per host).
+		 */
+		local_irq_enable();
+
+		while (--ticks_remaining >= 0)
+			mdelay(1 + 999 / HZ);
+		shost->resetting = 0;
+
+		local_irq_disable();
+	}
+}
+
+/* 
+ * scsi_cmd_get_serial: Assign a serial number and pid to the request
+ * for error recovery and debugging purposes.
+ *
+ * Called with host_lock held.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+	cmd->serial_number = host->cmd_serial_number++;
+	if (cmd->serial_number == 0) 
+		cmd->serial_number = host->cmd_serial_number++;
+
+	cmd->pid = host->cmd_pid++;
+	if (cmd->pid == 0)
+		cmd->pid = host->cmd_pid++;
+}
+
+/*
  * Function:    scsi_request_fn()
  *
  * Purpose:     Main strategy routine for SCSI.
@@ -1311,8 +1317,9 @@ static void scsi_request_fn(struct reque
 {
 	struct scsi_device *sdev = q->queuedata;
 	struct Scsi_Host *shost;
-	struct scsi_cmnd *cmd;
 	struct request *req;
+	struct scsi_cmnd *cmd;
+	int ret = 0;
 
 	if (!sdev) {
 		printk("scsi: killing requests for dead queue\n");
@@ -1320,117 +1327,142 @@ static void scsi_request_fn(struct reque
 		return;
 	}
 
-	if(!get_device(&sdev->sdev_gendev))
-		/* We must be tearing the block queue down already */
-		return;
+	/* FIXME: Once fire & forgetters are fixed, this and the
+	 * unlock_irq/put_device/lock_irq dance at the end of this
+	 * function can go away. */
+	get_device(&sdev->sdev_gendev);
 
-	/*
-	 * To start with, we keep looping until the queue is empty, or until
-	 * the host is no longer able to accept any more requests.
-	 */
 	shost = sdev->host;
-	while (!blk_queue_plugged(q)) {
-		int rtn;
-		/*
-		 * get next queueable request.  We do this early to make sure
-		 * that the request is fully prepared even if we cannot 
-		 * accept it.
-		 */
-		req = elv_next_request(q);
-		if (!req || !scsi_dev_queue_ready(q, sdev))
-			break;
-
-		if (unlikely(!scsi_device_online(sdev))) {
-			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
-			       sdev->host->host_no, sdev->id, sdev->lun);
-			blkdev_dequeue_request(req);
-			req->flags |= REQ_QUIET;
-			while (end_that_request_first(req, 0, req->nr_sectors))
-				;
-			end_that_request_last(req);
-			continue;
-		}
+	while ((req = elv_next_request(q))) {
+		enum scsi_device_state state;
+		int kill = 0, is_special = req->flags & REQ_SPECIAL;
 
+		cmd = req->special;
+		state = cmd->device->sdev_state;
 
-		/*
-		 * Remove the request from the request list.
-		 */
-		if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
+		if (state == SDEV_OFFLINE || state == SDEV_DEL ||
+		    (state == SDEV_CANCEL && !is_special)) {
+			printk(KERN_ERR
+			       "scsi%d (%d:%d): rejecting I/O to %s\n",
+			       shost->host_no, sdev->id, sdev->lun,
+			       (state == SDEV_OFFLINE ?
+					"offline device" :
+				(state == SDEV_DEL ?
+					"dead device" :
+					"device being removed")));
+			kill = 1;
+		} else if (state == SDEV_BLOCK ||
+			   (state == SDEV_QUIESCE && !is_special) ||
+			   !scsi_dev_queue_ready(q, sdev))
+			goto out;
+
+		/* Start tag / remove from the request queue. */
+		if (blk_queue_tagged(q)) {
+			if (blk_queue_start_tag(q, req))
+				BUG();
+			cmd->tag = req->tag;
+		} else
 			blkdev_dequeue_request(req);
+
 		sdev->device_busy++;
 
+		/* Switch to host_lock. */
 		spin_unlock(q->queue_lock);
+		scsi_wait_reset(shost);
 		spin_lock(shost->host_lock);
 
+		if (kill || test_bit(SHOST_CANCEL, &shost->shost_state)) {
+			SCSI_LOG_MLQUEUE(3,
+			    printk("%s: rejecting request\n", __FUNCTION__));
+			shost->host_busy++;
+			atomic_inc(&sdev->iorequest_cnt);
+			cmd->result = DID_NO_CONNECT << 16;
+			__scsi_done(cmd);
+			goto relock;
+		}
+
 		if (!scsi_host_queue_ready(q, shost, sdev))
-			goto not_ready;
+			goto requeue_out;
+
 		if (sdev->single_lun) {
-			if (scsi_target(sdev)->starget_sdev_user &&
-			    scsi_target(sdev)->starget_sdev_user != sdev)
-				goto not_ready;
-			scsi_target(sdev)->starget_sdev_user = sdev;
+			struct scsi_target *target = scsi_target(sdev);
+			if (target->starget_sdev_user &&
+			    target->starget_sdev_user != sdev)
+				goto requeue_out;
+			target->starget_sdev_user = sdev;
 		}
+
+		/* Once requeue path is cleaned up, init_cmd_errh can
+		 * be moved to prep_fn() where it belongs. */
+		scsi_init_cmd_errh(cmd);
 		shost->host_busy++;
+		scsi_log_send(cmd);
+		scsi_cmd_get_serial(shost, cmd);
+		scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
 
-		/*
-		 * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will
-		 *		take the lock again.
-		 */
-		spin_unlock_irq(shost->host_lock);
+		cmd->state = SCSI_STATE_QUEUED;
+		cmd->owner = SCSI_OWNER_LOWLEVEL;
 
-		cmd = req->special;
-		if (unlikely(cmd == NULL)) {
-			printk(KERN_CRIT "impossible request in %s.\n"
-					 "please mail a stack trace to "
-					 "linux-scsi@vger.kernel.org",
-					 __FUNCTION__);
-			BUG();
+		ret = shost->hostt->queuecommand(cmd, scsi_done);
+		if (ret) {
+			SCSI_LOG_MLQUEUE(3,
+			    printk("%s: queuecommand deferred request (%d)\n",
+				   __FUNCTION__, ret));
+			/*
+			 * Timer should be deleted while holding the
+			 * host_lock.  Once it gets released, we don't
+			 * know if cmd is still there or not.
+			 */
+			if (scsi_delete_timer(cmd)) {
+				shost->host_busy--;
+				goto block_requeue_out;
+			}
+
+			spin_unlock_irq(shost->host_lock);
+			goto out_unlocked;
 		}
 
-		/*
-		 * Finally, initialize any error handling parameters, and set up
-		 * the timers for timeouts.
-		 */
-		scsi_init_cmd_errh(cmd);
+		atomic_inc(&sdev->iorequest_cnt);
 
-		/*
-		 * Dispatch the command to the low-level driver.
-		 */
-		rtn = scsi_dispatch_cmd(cmd);
-		spin_lock_irq(q->queue_lock);
-		if(rtn) {
-			/* we're refusing the command; because of
-			 * the way locks get dropped, we need to 
-			 * check here if plugging is required */
-			if(sdev->device_busy == 0)
-				blk_plug_device(q);
+	relock:
+		/* Switch back to queue_lock. */
+		spin_unlock(shost->host_lock);
+		spin_lock(q->queue_lock);
 
-			break;
-		}
+		/* The queue could have been plugged underneath us. */
+		if (blk_queue_plugged(q))
+			goto out;
 	}
 
 	goto out;
 
- not_ready:
-	spin_unlock_irq(shost->host_lock);
+ block_requeue_out:
+	if (ret == SCSI_MLQUEUE_DEVICE_BUSY)
+		sdev->device_blocked = sdev->max_device_blocked;
+	else
+		shost->host_blocked = shost->max_host_blocked;
+ requeue_out:
+	/* Switch back to queue_lock */
+	spin_unlock(shost->host_lock);
+	spin_lock(q->queue_lock);
 
-	/*
-	 * lock q, handle tag, requeue req, and decrement device_busy. We
-	 * must return with queue_lock held.
-	 *
-	 * Decrementing device_busy without checking it is OK, as all such
-	 * cases (host limits or settings) should run the queue at some
-	 * later time.
-	 */
-	spin_lock_irq(q->queue_lock);
+	cmd->state = SCSI_STATE_MLQUEUE;
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+
+	SCSI_LOG_MLQUEUE(3,
+	    printk("%s: requeueing request\n", __FUNCTION__));
+
+	req->flags |= REQ_SOFTBARRIER;	/* Don't pass this request. */
 	blk_requeue_request(q, req);
-	sdev->device_busy--;
-	if(sdev->device_busy == 0)
+	if (--sdev->device_busy == 0)
 		blk_plug_device(q);
  out:
-	/* must be careful here...if we trigger the ->remove() function
-	 * we cannot be holding the q lock */
+	/*
+	 * must be careful here...if we trigger the ->remove() function
+	 * we cannot be holding the q lock
+	 */
 	spin_unlock_irq(q->queue_lock);
+ out_unlocked:
 	put_device(&sdev->sdev_gendev);
 	spin_lock_irq(q->queue_lock);
 }
Index: scsi-reqfn-export/drivers/scsi/scsi_priv.h
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_priv.h	2005-05-14 22:35:17.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_priv.h	2005-05-14 22:35:19.000000000 +0900
@@ -58,7 +58,6 @@ extern int scsi_init_hosts(void);
 extern void scsi_exit_hosts(void);
 
 /* scsi.c */
-extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
 extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
 extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
 extern void scsi_done(struct scsi_cmnd *cmd);


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 13:57 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
                   ` (2 preceding siblings ...)
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn() Tejun Heo
@ 2005-05-14 13:57 ` Tejun Heo
  2005-05-14 15:26   ` James Bottomley
  3 siblings, 1 reply; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 13:57 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

04_scsi_reqfn_remove_wait_req_end_io.patch

	As all requests are now terminated via scsi midlayer, we don't
	need to set end_io for special reqs, remove it.

Signed-off-by: Tejun Heo <htejun@gmail.com>

 scsi_lib.c |   11 -----------
 1 files changed, 11 deletions(-)

Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-14 22:35:19.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-14 22:35:19.000000000 +0900
@@ -265,16 +265,6 @@ static void scsi_wait_done(struct scsi_c
 		complete(req->waiting);
 }
 
-/* This is the end routine we get to if a command was never attached
- * to the request.  Simply complete the request without changing
- * rq_status; this will cause a DRIVER_ERROR. */
-static void scsi_wait_req_end_io(struct request *req)
-{
-	BUG_ON(!req->waiting);
-
-	complete(req->waiting);
-}
-
 void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
 		   unsigned bufflen, int timeout, int retries)
 {
@@ -282,7 +272,6 @@ void scsi_wait_req(struct scsi_request *
 	
 	sreq->sr_request->waiting = &wait;
 	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
-	sreq->sr_request->end_io = scsi_wait_req_end_io;
 	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
 			timeout, retries);
 	wait_for_completion(&wait);


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 13:57 ` [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io() Tejun Heo
@ 2005-05-14 15:26   ` James Bottomley
  2005-05-14 15:47     ` Tejun Heo
  0 siblings, 1 reply; 13+ messages in thread
From: James Bottomley @ 2005-05-14 15:26 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

On Sat, 2005-05-14 at 22:57 +0900, Tejun Heo wrote:
> 	As all requests are now terminated via scsi midlayer, we don't
> 	need to set end_io for special reqs, remove it.

This statement is untrue as long as the prep function can return
BLKPREP_KILL, which it still does even after your patch set, so the
scsi_wait_req_end_io() is still necessary to catch this case.

James



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 15:26   ` James Bottomley
@ 2005-05-14 15:47     ` Tejun Heo
  2005-05-14 16:19       ` James Bottomley
  0 siblings, 1 reply; 13+ messages in thread
From: Tejun Heo @ 2005-05-14 15:47 UTC (permalink / raw)
  To: James Bottomley
  Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

 Hello, James.

On Sat, May 14, 2005 at 11:26:23AM -0400, James Bottomley wrote:
> On Sat, 2005-05-14 at 22:57 +0900, Tejun Heo wrote:
> > 	As all requests are now terminated via scsi midlayer, we don't
> > 	need to set end_io for special reqs, remove it.
> 
> This statement is untrue as long as the prep function can return
> BLKPREP_KILL, which it still does even after your patch set, so the
> scsi_wait_req_end_io() is still necessary to catch this case.

 BLKPREP_KILL is only used to kill illegal (unpreparable, way-off)
requests.  Actually, for special requests, the only tests performed
are req->flags and CDB_SIZE tests.  I don't think anyone does/will
submit that illegal requests via scsi_wait_req().  And if so, it will
be a bug.

 I don't feel strong against keeping the end_io routine but, if you
decide to keep the routine, please consider adding a comment
explaining the peculiar path the routine might be used, such that
other people don't have to wander through the code.

 Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 15:47     ` Tejun Heo
@ 2005-05-14 16:19       ` James Bottomley
  2005-05-15  1:15         ` Tejun Heo
  2005-05-15  1:16         ` Tejun Heo
  0 siblings, 2 replies; 13+ messages in thread
From: James Bottomley @ 2005-05-14 16:19 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

On Sun, 2005-05-15 at 00:47 +0900, Tejun Heo wrote:
>  BLKPREP_KILL is only used to kill illegal (unpreparable, way-off)
> requests.  Actually, for special requests, the only tests performed
> are req->flags and CDB_SIZE tests.  I don't think anyone does/will
> submit that illegal requests via scsi_wait_req().  And if so, it will
> be a bug.

True, but without the code you're removing it will simply hang the
system, which isn't a correct response to a detected bug.  And if I had
a shilling for every time someone's predicated a code change on "oh,
users will never do this" ... I'd be reasonably rich.

This also leads naturally into the next observation:  Checking in the
request function should be done.  However, it makes little sense wasting
resources preparing requests we know are going to be killed, so the
correct thing to do seems to be to abstract the checks and do them in
both prep_fn and request_fn.

James



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 16:19       ` James Bottomley
@ 2005-05-15  1:15         ` Tejun Heo
  2005-05-16 16:07           ` James Bottomley
  2005-05-15  1:16         ` Tejun Heo
  1 sibling, 1 reply; 13+ messages in thread
From: Tejun Heo @ 2005-05-15  1:15 UTC (permalink / raw)
  To: James Bottomley
  Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

On Sat, May 14, 2005 at 12:19:07PM -0400, James Bottomley wrote:
> On Sun, 2005-05-15 at 00:47 +0900, Tejun Heo wrote:
> >  BLKPREP_KILL is only used to kill illegal (unpreparable, way-off)
> > requests.  Actually, for special requests, the only tests performed
> > are req->flags and CDB_SIZE tests.  I don't think anyone does/will
> > submit that illegal requests via scsi_wait_req().  And if so, it will
> > be a bug.
> 
> True, but without the code you're removing it will simply hang the
> system, which isn't a correct response to a detected bug.  And if I had
> a shilling for every time someone's predicated a code change on "oh,
> users will never do this" ... I'd be reasonably rich.
> 
> This also leads naturally into the next observation:  Checking in the
> request function should be done.  However, it makes little sense wasting
> resources preparing requests we know are going to be killed, so the
> correct thing to do seems to be to abstract the checks and do them in
> both prep_fn and request_fn.

 I've made two new versions of the same patch.  The first one just
BUG() such cases, and the second one makes scsi_prep_fn() tell
scsi_request_fn() to kill requests instead of doing itself w/
BLKPREP_KILL.  In both cases, I made req->flags error case a BUG().
If you don't like it, feel free to drop that part.

 Oh... one more thing.  I forgot to mention the scsi_kill_requests()
path.  As it's a temporary fix, I just left it as it is (terminate
commands w/ end_that_*).  I guess this patch should be pushed after
removal of that kludge.  But with or without this patch, that path
will leak resources.

 I'm attaching the first version here and the other version in the
next mail.  Please let me know which one you like better.


Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-15 08:49:40.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-15 09:38:25.000000000 +0900
@@ -265,16 +265,6 @@ static void scsi_wait_done(struct scsi_c
 		complete(req->waiting);
 }
 
-/* This is the end routine we get to if a command was never attached
- * to the request.  Simply complete the request without changing
- * rq_status; this will cause a DRIVER_ERROR. */
-static void scsi_wait_req_end_io(struct request *req)
-{
-	BUG_ON(!req->waiting);
-
-	complete(req->waiting);
-}
-
 void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
 		   unsigned bufflen, int timeout, int retries)
 {
@@ -282,7 +272,6 @@ void scsi_wait_req(struct scsi_request *
 	
 	sreq->sr_request->waiting = &wait;
 	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
-	sreq->sr_request->end_io = scsi_wait_req_end_io;
 	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
 			timeout, retries);
 	wait_for_completion(&wait);
@@ -1072,7 +1061,8 @@ static int scsi_prep_fn(struct request_q
 			cmd = req->special;
 	} else {
 		blk_dump_rq_flags(req, "SCSI bad req");
-		return BLKPREP_KILL;
+		BUG();
+		cmd = NULL; /* shut up, gcc */
 	}
 	
 	/* note the overloading of req->special.  When the tag
@@ -1161,7 +1151,13 @@ static int scsi_prep_fn(struct request_q
 	 * request because this will complete at the request level
 	 * (req->end_io), not the scsi command level, so no scsi
 	 * routine will get to free the associated resources.
+	 *
+	 * Due to lack of end_io routine, special requests can't be
+	 * terminated by the block layer.  So, BUG() it and let the
+	 * source of the problem be fixed as they're only used by
+	 * kernel proper.
 	 */
+	BUG_ON(req->flags & REQ_SPECIAL);
 	scsi_release_buffers(cmd);
 	scsi_put_command(cmd);
 	return BLKPREP_KILL;

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-14 16:19       ` James Bottomley
  2005-05-15  1:15         ` Tejun Heo
@ 2005-05-15  1:16         ` Tejun Heo
  1 sibling, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-15  1:16 UTC (permalink / raw)
  To: James Bottomley
  Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

 And, this is the other version.

Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-05-15 08:49:40.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-05-15 10:05:02.000000000 +0900
@@ -265,16 +265,6 @@ static void scsi_wait_done(struct scsi_c
 		complete(req->waiting);
 }
 
-/* This is the end routine we get to if a command was never attached
- * to the request.  Simply complete the request without changing
- * rq_status; this will cause a DRIVER_ERROR. */
-static void scsi_wait_req_end_io(struct request *req)
-{
-	BUG_ON(!req->waiting);
-
-	complete(req->waiting);
-}
-
 void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
 		   unsigned bufflen, int timeout, int retries)
 {
@@ -282,7 +272,6 @@ void scsi_wait_req(struct scsi_request *
 	
 	sreq->sr_request->waiting = &wait;
 	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
-	sreq->sr_request->end_io = scsi_wait_req_end_io;
 	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
 			timeout, retries);
 	wait_for_completion(&wait);
@@ -649,45 +638,6 @@ static void scsi_free_sgtable(struct sca
 }
 
 /*
- * Function:    scsi_release_buffers()
- *
- * Purpose:     Completion processing for block device I/O requests.
- *
- * Arguments:   cmd	- command that we are bailing.
- *
- * Lock status: Assumed that no lock is held upon entry.
- *
- * Returns:     Nothing
- *
- * Notes:       In the event that an upper level driver rejects a
- *		command, we must release resources allocated during
- *		the __init_io() function.  Primarily this would involve
- *		the scatter-gather table, and potentially any bounce
- *		buffers.
- */
-static void scsi_release_buffers(struct scsi_cmnd *cmd)
-{
-	struct request *req = cmd->request;
-
-	/*
-	 * Free up any indirection buffers we allocated for DMA purposes. 
-	 */
-	if (cmd->use_sg)
-		scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
-	else if (cmd->request_buffer != req->buffer)
-		kfree(cmd->request_buffer);
-
-	/*
-	 * Zero these out.  They now point to freed memory, and it is
-	 * dangerous to hang onto the pointers.
-	 */
-	cmd->buffer  = NULL;
-	cmd->bufflen = 0;
-	cmd->request_buffer = NULL;
-	cmd->request_bufflen = 0;
-}
-
-/*
  * Function:    scsi_io_completion()
  *
  * Purpose:     Completion processing for block device I/O requests.
@@ -1072,7 +1022,8 @@ static int scsi_prep_fn(struct request_q
 			cmd = req->special;
 	} else {
 		blk_dump_rq_flags(req, "SCSI bad req");
-		return BLKPREP_KILL;
+		BUG();
+		cmd = NULL; /* shut up, gcc */
 	}
 	
 	/* note the overloading of req->special.  When the tag
@@ -1157,14 +1108,13 @@ static int scsi_prep_fn(struct request_q
 
  kill:
 	/*
-	 * Here we have to release every resource associated with the
-	 * request because this will complete at the request level
-	 * (req->end_io), not the scsi command level, so no scsi
-	 * routine will get to free the associated resources.
+	 * This one is a trash.  Tell scsi_request_fn() to kill it.
+	 * Note that we can't kill directly w/ BLKPREP_KILL here as
+	 * special requests don't have their end_io routine set and
+	 * can't be killed via block layer.
 	 */
-	scsi_release_buffers(cmd);
-	scsi_put_command(cmd);
-	return BLKPREP_KILL;
+	cmd->result = DRIVER_ERROR << 24;
+	return BLKPREP_OK;
 }
 
 /*
@@ -1340,16 +1290,18 @@ static void scsi_request_fn(struct reque
 		cmd = req->special;
 		state = cmd->device->sdev_state;
 
-		if (state == SDEV_OFFLINE || state == SDEV_DEL ||
+		if (driver_byte(cmd->result) == DRIVER_ERROR ||
+		    state == SDEV_OFFLINE || state == SDEV_DEL ||
 		    (state == SDEV_CANCEL && !is_special)) {
-			printk(KERN_ERR
-			       "scsi%d (%d:%d): rejecting I/O to %s\n",
-			       shost->host_no, sdev->id, sdev->lun,
-			       (state == SDEV_OFFLINE ?
-					"offline device" :
-				(state == SDEV_DEL ?
-					"dead device" :
-					"device being removed")));
+			if (driver_byte(cmd->result) != DRIVER_ERROR)
+				printk(KERN_ERR
+				       "scsi%d (%d:%d): rejecting I/O to %s\n",
+				       shost->host_no, sdev->id, sdev->lun,
+				       (state == SDEV_OFFLINE ?
+						"offline device" :
+					(state == SDEV_DEL ?
+						 "dead device" :
+						 "device being removed")));
 			kill = 1;
 		} else if (state == SDEV_BLOCK ||
 			   (state == SDEV_QUIESCE && !is_special) ||

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-15  1:15         ` Tejun Heo
@ 2005-05-16 16:07           ` James Bottomley
  2005-05-16 16:56             ` Tejun Heo
  0 siblings, 1 reply; 13+ messages in thread
From: James Bottomley @ 2005-05-16 16:07 UTC (permalink / raw)
  To: Tejun Heo; +Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

On Sun, 2005-05-15 at 10:15 +0900, Tejun Heo wrote:
>  I've made two new versions of the same patch.  The first one just
> BUG() such cases, and the second one makes scsi_prep_fn() tell
> scsi_request_fn() to kill requests instead of doing itself w/
> BLKPREP_KILL.  In both cases, I made req->flags error case a BUG().
> If you don't like it, feel free to drop that part.
> 
>  Oh... one more thing.  I forgot to mention the scsi_kill_requests()
> path.  As it's a temporary fix, I just left it as it is (terminate
> commands w/ end_that_*).  I guess this patch should be pushed after
> removal of that kludge.  But with or without this patch, that path
> will leak resources.

I suppose it's not surprising that I don't like either.

You remove the code that handles the BLKPREP_KILL case and then contort
the request functions to try not to do it.  We have to handle this case,
it's not optional, so just leave the code that does it in.

James



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io()
  2005-05-16 16:07           ` James Bottomley
@ 2005-05-16 16:56             ` Tejun Heo
  0 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-05-16 16:56 UTC (permalink / raw)
  To: James Bottomley
  Cc: Jens Axboe, Christoph Hellwig, SCSI Mailing List, Linux Kernel

James Bottomley wrote:
> On Sun, 2005-05-15 at 10:15 +0900, Tejun Heo wrote:
> 
>> I've made two new versions of the same patch.  The first one just
>>BUG() such cases, and the second one makes scsi_prep_fn() tell
>>scsi_request_fn() to kill requests instead of doing itself w/
>>BLKPREP_KILL.  In both cases, I made req->flags error case a BUG().
>>If you don't like it, feel free to drop that part.
>>
>> Oh... one more thing.  I forgot to mention the scsi_kill_requests()
>>path.  As it's a temporary fix, I just left it as it is (terminate
>>commands w/ end_that_*).  I guess this patch should be pushed after
>>removal of that kludge.  But with or without this patch, that path
>>will leak resources.
> 
> 
> I suppose it's not surprising that I don't like either.
> 
> You remove the code that handles the BLKPREP_KILL case and then contort
> the request functions to try not to do it.  We have to handle this case,
> it's not optional, so just leave the code that does it in.

 IMHO, as special request BLKPREP_KILL path is a kernel bug, code that
try to handle it normally is unnecessary, but it's your call.

 Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn()
  2005-04-12 10:32 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
@ 2005-04-12 10:32 ` Tejun Heo
  0 siblings, 0 replies; 13+ messages in thread
From: Tejun Heo @ 2005-04-12 10:32 UTC (permalink / raw)
  To: James.Bottomley, axboe, Christoph Hellwig; +Cc: linux-scsi, linux-kernel

02_scsi_reqfn_move_preps_to_prep_fn.patch

	Move request preparations scattered in scsi_request_fn() and
	scsi_dispatch_cmd() into scsi_prep_fn()

	* CDB_SIZE check in scsi_dispatch_cmd()
	* SCSI-2 LUN preparation in scsi_dispatch_cmd()

	No invalid request reaches scsi_request_fn() anymore.

	Note that scsi_init_cmd_errh() is still left in
	scsi_request_fn().  As all requeued requests need its sense
	buffer and result value cleared, we can't move this to
	prep_fn() yet.  This is moved into prep_fn in the following
	requeue path consoildation patchset.

Signed-off-by: Tejun Heo <htejun@gmail.com>

 scsi.c     |   30 ------------------------------
 scsi_lib.c |   17 +++++++++++++++++
 2 files changed, 17 insertions(+), 30 deletions(-)

Index: scsi-reqfn-export/drivers/scsi/scsi.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi.c	2005-04-12 19:27:54.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi.c	2005-04-12 19:27:55.000000000 +0900
@@ -79,15 +79,6 @@
 #define MIN_RESET_PERIOD (15*HZ)
 
 /*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd)	(((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
-				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -566,14 +557,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		goto out;
 	}
 
-	/* 
-	 * If SCSI-2 or lower, store the LUN value in cmnd.
-	 */
-	if (cmd->device->scsi_level <= SCSI_2) {
-		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
-			       (cmd->device->lun << 5 & 0xe0);
-	}
-
 	/*
 	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so
 	 * we can avoid the drive not being ready.
@@ -614,19 +597,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 
 	atomic_inc(&cmd->device->iorequest_cnt);
 
-	/*
-	 * Before we queue this command, check if the command
-	 * length exceeds what the host adapter can handle.
-	 */
-	if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
-		SCSI_LOG_MLQUEUE(3,
-				printk("queuecommand : command too long.\n"));
-		cmd->result = (DID_ABORT << 16);
-
-		scsi_done(cmd);
-		goto out;
-	}
-
 	spin_lock_irqsave(host->host_lock, flags);
 	scsi_cmd_get_serial(host, cmd); 
 
Index: scsi-reqfn-export/drivers/scsi/scsi_lib.c
===================================================================
--- scsi-reqfn-export.orig/drivers/scsi/scsi_lib.c	2005-04-12 19:27:55.000000000 +0900
+++ scsi-reqfn-export/drivers/scsi/scsi_lib.c	2005-04-12 19:27:55.000000000 +0900
@@ -28,6 +28,14 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
+/*
+ * Macro to determine the size of SCSI command. This macro takes vendor
+ * unique commands into account. SCSI commands in groups 6 and 7 are
+ * vendor unique and we will depend upon the command length being
+ * supplied correctly in cmd_len.
+ */
+#define CDB_SIZE(cmd)	(((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
+				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
 
 #define SG_MEMPOOL_NR		(sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool))
 #define SG_MEMPOOL_SIZE		32
@@ -1160,6 +1168,15 @@ static int scsi_prep_fn(struct request_q
 			goto kill;
 	}
 
+	/* Check command length. */
+	if (CDB_SIZE(cmd) > sdev->host->max_cmd_len)
+		goto kill;
+
+	/* If SCSI-2 or lower, store the LUN value in cmnd. */
+	if (cmd->device->scsi_level <= SCSI_2)
+		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
+			(cmd->device->lun << 5 & 0xe0);
+
 	/*
 	 * The request is now prepped, no need to come back here
 	 */


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2005-05-16 16:57 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-05-14 13:57 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
2005-05-14 13:57 ` [PATCH scsi-misc-2.6 01/04] scsi: consolidate error handling out of scsi_init_io() into scsi_prep_fn() Tejun Heo
2005-05-14 13:57 ` [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn() Tejun Heo
2005-05-14 13:57 ` [PATCH scsi-misc-2.6 03/04] scsi: reimplement scsi_request_fn() Tejun Heo
2005-05-14 13:57 ` [PATCH scsi-misc-2.6 04/04] scsi: remove unnecessary scsi_wait_req_end_io() Tejun Heo
2005-05-14 15:26   ` James Bottomley
2005-05-14 15:47     ` Tejun Heo
2005-05-14 16:19       ` James Bottomley
2005-05-15  1:15         ` Tejun Heo
2005-05-16 16:07           ` James Bottomley
2005-05-16 16:56             ` Tejun Heo
2005-05-15  1:16         ` Tejun Heo
  -- strict thread matches above, loose matches on Subject: below --
2005-04-12 10:32 [PATCH scsi-misc-2.6 00/04] scsi: scsi_request_fn() reimplementation Tejun Heo
2005-04-12 10:32 ` [PATCH scsi-misc-2.6 02/04] scsi: move request preps in other places into prep_fn() Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).