All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] [PATCH 0/2] blk request timeout handler patches
@ 2007-10-04 18:12 malahal
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
  2007-10-04 18:20 ` [RFC] [PATCH 2/2] " malahal
  0 siblings, 2 replies; 26+ messages in thread
From: malahal @ 2007-10-04 18:12 UTC (permalink / raw)
  To: linux-scsi, jens.axboe

I refreshed the blk layer timeout patch from Mike Christie to 2.6.23-rc8-mm1.
Fixed couple of places where scsi_dispatch_cmd() wasn't stopping timers.

Thanks, Malahal.

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

* [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-04 18:12 [RFC] [PATCH 0/2] blk request timeout handler patches malahal
@ 2007-10-04 18:17 ` malahal
  2007-10-04 18:52   ` Randy Dunlap
                     ` (3 more replies)
  2007-10-04 18:20 ` [RFC] [PATCH 2/2] " malahal
  1 sibling, 4 replies; 26+ messages in thread
From: malahal @ 2007-10-04 18:17 UTC (permalink / raw)
  To: linux-scsi, jens.axboe

Mike Christie's patches refreshed to 2.6.23-rc8-mm1.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Malahal Naineni <malahal@us.ibm.com>


diff -r 3697367c6e4d block/ll_rw_blk.c
--- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
@@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
 
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -243,7 +256,9 @@ static void rq_init(struct request_queue
 {
 	INIT_LIST_HEAD(&rq->queuelist);
 	INIT_LIST_HEAD(&rq->donelist);
-
+	init_timer(&rq->timer);
+
+	rq->timeout = 0;
 	rq->errors = 0;
 	rq->bio = rq->biotail = NULL;
 	INIT_HLIST_NODE(&rq->hash);
@@ -2305,6 +2320,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
 };
 
 /**
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
+ *
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ **/
+int blk_delete_timer(struct request *req)
+{
+	int rtn;
+
+	if (!req->q->rq_timed_out_fn)
+		return 1;
+
+	rtn = del_timer(&req->timer);
+	req->timer.data = (unsigned long)NULL;
+	req->timer.function = NULL;
+
+	return rtn;
+}
+
+EXPORT_SYMBOL_GPL(blk_delete_timer);
+
+static void blk_rq_timed_out(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	switch (q->rq_timed_out_fn(req)) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		return;
+	case BLK_EH_RESET_TIMER:
+		blk_add_timer(req);
+		return;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		return;
+	}
+}
+
+/**
+ * blk_abort_req -- Request request recovery for the specified command
+ * req:		pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req.
+ */
+void blk_abort_req(struct request *req)
+{
+        if (!blk_delete_timer(req))
+                return;
+        blk_rq_timed_out(req);
+}
+
+EXPORT_SYMBOL_GPL(blk_abort_req);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer.  When the request completes, we cancel the timer.
+ **/
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	/*
+	 * If the clock was already running for this command, then
+	 * first delete the timer.  The timer handling code gets rather
+	 * confused if we don't do this.
+	 */
+	if (req->timer.function)
+		del_timer(&req->timer);
+
+	req->timer.data = (unsigned long)req;
+	if (req->timeout)
+		req->timer.expires = jiffies + req->timeout;
+	else
+		req->timer.expires = jiffies + q->rq_timeout;
+	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;
+        add_timer(&req->timer);
+}
+
+EXPORT_SYMBOL_GPL(blk_add_timer);
+
+void __blk_complete_request(struct request *req)
+{
+	struct list_head *cpu_list;
+	unsigned long flags;
+
+	BUG_ON(!req->q->softirq_done_fn);
+
+	local_irq_save(flags);
+
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_add_tail(&req->donelist, cpu_list);
+	raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+	local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL_GPL(__blk_complete_request);
+
+/**
  * blk_complete_request - end I/O on a request
- * @req:      the request being processed
+ * @req:	the request being processed
  *
  * Description:
  *     Ends all I/O on a request. It does not handle partial completions,
@@ -3657,25 +3786,24 @@ static struct notifier_block blk_cpu_not
  *     through a softirq handler. The user must have registered a completion
  *     callback through blk_queue_softirq_done().
  **/
-
 void blk_complete_request(struct request *req)
 {
-	struct list_head *cpu_list;
-	unsigned long flags;
-
-	BUG_ON(!req->q->softirq_done_fn);
-		
-	local_irq_save(flags);
-
-	cpu_list = &__get_cpu_var(blk_cpu_done);
-	list_add_tail(&req->donelist, cpu_list);
-	raise_softirq_irqoff(BLOCK_SOFTIRQ);
-
-	local_irq_restore(flags);
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!blk_delete_timer(req))
+		return;
+
+	__blk_complete_request(req);
 }
 
 EXPORT_SYMBOL(blk_complete_request);
-	
+
 /*
  * queue lock must be held
  */
diff -r 3697367c6e4d drivers/ata/libata-eh.c
--- a/drivers/ata/libata-eh.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/ata/libata-eh.c	Thu Sep 27 00:13:07 2007 -0700
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -312,29 +313,29 @@ static void ata_eh_clear_action(struct a
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -765,7 +766,7 @@ void ata_qc_schedule_eh(struct ata_queue
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_req(qc->scsicmd->request);
 }
 
 /**
diff -r 3697367c6e4d drivers/ata/libata.h
--- a/drivers/ata/libata.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/ata/libata.h	Thu Sep 27 00:13:07 2007 -0700
@@ -149,7 +149,7 @@ extern int ata_bus_probe(struct ata_port
 extern int ata_bus_probe(struct ata_port *ap);
 
 /* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff -r 3697367c6e4d drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/aacraid/aachba.c	Thu Sep 27 00:13:07 2007 -0700
@@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff -r 3697367c6e4d drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/advansys.c	Thu Sep 27 00:13:07 2007 -0700
@@ -5859,7 +5859,7 @@ static void asc_prt_scsi_cmnd(struct scs
 	printk(" serial_number 0x%x, retries %d, allowed %d\n",
 	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-	printk(" timeout_per_command %d\n", s->timeout_per_command);
+	printk(" request timeout %d\n", s->request->timeout);
 
 	printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
 		s->scsi_done, s->done, s->host_scribble, s->result);
diff -r 3697367c6e4d drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/gdth.c	Thu Sep 27 00:13:07 2007 -0700
@@ -728,7 +728,6 @@ int __gdth_execute(struct scsi_device *s
     scp->device = sdev;
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->request_buffer = gdtcmd;
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
@@ -4944,7 +4943,7 @@ static int gdth_queuecommand(Scsi_Cmnd *
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
     else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
 
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
diff -r 3697367c6e4d drivers/scsi/gdth_proc.c
--- a/drivers/scsi/gdth_proc.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/gdth_proc.c	Thu Sep 27 00:13:07 2007 -0700
@@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum
 {
     int oldto;
 
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
+    oldto = scp->request->timeout;
+    scp->request->timeout = timeout;
 
     if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
+        del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) NULL;
+        scp->request->timer.expires = 0;
     } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
+        if (scp->request->timer.data != (unsigned long) NULL) 
+            del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) scp;
+        scp->request->timer.expires = jiffies + timeout;
+        add_timer(&scp->request->timer);
     }
 
     return oldto;
diff -r 3697367c6e4d drivers/scsi/ibmvscsi/ibmvscsi.c
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c	Thu Sep 27 00:13:07 2007 -0700
@@ -732,7 +732,7 @@ static int ibmvscsi_queuecommand(struct 
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff -r 3697367c6e4d drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/ide-scsi.c	Thu Sep 27 00:13:07 2007 -0700
@@ -812,7 +812,7 @@ static int idescsi_queue (struct scsi_cm
 	pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
 		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
diff -r 3697367c6e4d drivers/scsi/ipr.c
--- a/drivers/scsi/ipr.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/ipr.c	Thu Sep 27 00:13:07 2007 -0700
@@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct sc
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff -r 3697367c6e4d drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/ips.c	Thu Sep 27 00:13:07 2007 -0700
@@ -3862,7 +3862,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff -r 3697367c6e4d drivers/scsi/libsas/sas_ata.c
--- a/drivers/scsi/libsas/sas_ata.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/libsas/sas_ata.c	Thu Sep 27 00:13:07 2007 -0700
@@ -407,7 +407,7 @@ void sas_ata_task_abort(struct sas_task 
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_req(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff -r 3697367c6e4d drivers/scsi/libsas/sas_internal.h
--- a/drivers/scsi/libsas/sas_internal.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/libsas/sas_internal.h	Thu Sep 27 00:13:07 2007 -0700
@@ -55,7 +55,7 @@ int  sas_register_ports(struct sas_ha_st
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff -r 3697367c6e4d drivers/scsi/libsas/sas_scsi_host.c
--- a/drivers/scsi/libsas/sas_scsi_host.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/libsas/sas_scsi_host.c	Thu Sep 27 00:13:07 2007 -0700
@@ -654,43 +654,43 @@ out:
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *tas
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_req(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff -r 3697367c6e4d drivers/scsi/megaraid/megaraid_sas.c
--- a/drivers/scsi/megaraid/megaraid_sas.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/megaraid/megaraid_sas.c	Thu Sep 27 00:13:07 2007 -0700
@@ -969,7 +969,7 @@ static int megasas_generic_reset(struct 
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff -r 3697367c6e4d drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/ncr53c8xx.c	Thu Sep 27 00:13:07 2007 -0700
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff -r 3697367c6e4d drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/qla1280.c	Thu Sep 27 00:13:07 2007 -0700
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3167,7 +3167,7 @@ qla1280_32bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff -r 3697367c6e4d drivers/scsi/qla4xxx/ql4_os.c
--- a/drivers/scsi/qla4xxx/ql4_os.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/qla4xxx/ql4_os.c	Thu Sep 27 00:13:07 2007 -0700
@@ -1565,7 +1565,7 @@ static int qla4xxx_eh_device_reset(struc
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
diff -r 3697367c6e4d drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi.c	Thu Sep 27 00:13:07 2007 -0700
@@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struc
 
 		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -479,7 +478,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		 * that the device is no longer present */
 		cmd->result = DID_NO_CONNECT << 16;
 		atomic_inc(&cmd->device->iorequest_cnt);
-		__scsi_done(cmd);
+		__blk_complete_request(cmd->request);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -534,12 +533,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		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);
 
 	/*
@@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -572,7 +571,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 	spin_unlock_irqrestore(host->host_lock, flags);
 	if (rtn) {
-		if (scsi_delete_timer(cmd)) {
+		if (blk_delete_timer(cmd->request)) {
 			atomic_inc(&cmd->device->iodone_cnt);
 			scsi_queue_insert(cmd,
 					  (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
@@ -588,24 +587,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 }
 
 /**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
-
-/**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -620,42 +601,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out any more.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /*
diff -r 3697367c6e4d drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi_error.c	Thu Sep 27 00:13:07 2007 -0700
@@ -113,69 +113,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -183,9 +122,11 @@ int scsi_delete_timer(struct scsi_cmnd *
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  **/
-void scsi_times_out(struct scsi_cmnd *scmd)
-{
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+enum blk_eh_timer_return scsi_times_out(struct request *req)
+{
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -197,22 +138,20 @@ void scsi_times_out(struct scsi_cmnd *sc
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
-	}
+		return BLK_EH_HANDLED;
+	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *
 	int rtn;
 
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
@@ -1678,8 +1616,6 @@ scsi_reset_provider(struct scsi_device *
 	scmd->cmd_len			= 0;
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
-
-	init_timer(&scmd->eh_timeout);
 
 	/*
 	 * Sometimes the command can get back into the timer chain,
diff -r 3697367c6e4d drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi_lib.c	Thu Sep 27 00:13:07 2007 -0700
@@ -1227,7 +1227,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_d
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	cmd->done = scsi_blk_pc_done;
 	return BLKPREP_OK;
 }
@@ -1455,16 +1454,25 @@ static void scsi_kill_request(struct req
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	__blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
+
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
 
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
@@ -1699,6 +1707,7 @@ struct request_queue *scsi_alloc_queue(s
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
diff -r 3697367c6e4d drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi_priv.h	Thu Sep 27 00:13:07 2007 -0700
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@ extern int scsi_dispatch_cmd(struct scsi
 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);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern void scsi_exit_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
diff -r 3697367c6e4d drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi_sysfs.c	Thu Sep 27 00:13:07 2007 -0700
@@ -480,12 +480,15 @@ sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -495,7 +498,7 @@ sdev_store_timeout (struct device *dev, 
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff -r 3697367c6e4d drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/scsi_transport_fc.c	Thu Sep 27 00:13:07 2007 -0700
@@ -1921,15 +1921,15 @@ static int fc_vport_match(struct attribu
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
-
-	return EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
diff -r 3697367c6e4d drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/sd.c	Thu Sep 27 00:14:19 2007 -0700
@@ -337,7 +337,6 @@ static int sd_prep_fn(struct request_que
 	struct gendisk *disk = rq->rq_disk;
 	sector_t block = rq->sector;
 	unsigned int this_count = rq->nr_sectors;
-	unsigned int timeout = sdp->timeout;
 	int ret;
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -506,7 +505,6 @@ static int sd_prep_fn(struct request_que
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -1633,11 +1631,12 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	class_device_initialize(&sdkp->cdev);
diff -r 3697367c6e4d drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/sr.c	Thu Sep 27 00:14:58 2007 -0700
@@ -306,7 +306,7 @@ static void rw_intr(struct scsi_cmnd * S
 
 static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block=0, this_count, s_size;
 	struct scsi_cd *cd;
 	struct scsi_cmnd *SCpnt;
 	struct scsi_device *sdp = q->queuedata;
@@ -435,7 +435,6 @@ static int sr_prep_fn(struct request_que
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -599,6 +598,8 @@ static int sr_probe(struct device *dev)
 	sprintf(disk->disk_name, "sr%d", minor);
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
+
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
 
 	cd->device = sdev;
 	cd->disk = disk;
diff -r 3697367c6e4d drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Thu Sep 27 00:12:13 2007 -0700
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Thu Sep 27 00:13:07 2007 -0700
@@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struc
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff -r 3697367c6e4d include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/include/linux/blkdev.h	Thu Sep 27 00:13:07 2007 -0700
@@ -309,6 +309,7 @@ struct request {
 	void *data;
 	void *sense;
 
+	struct timer_list timer;
 	unsigned int timeout;
 	int retries;
 
@@ -346,6 +347,14 @@ typedef int (merge_bvec_fn) (struct requ
 typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *);
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
+
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -383,6 +392,7 @@ struct request_queue
 	merge_bvec_fn		*merge_bvec_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -452,6 +462,8 @@ struct request_queue
 
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
+
+	unsigned int		rq_timeout;
 
 	/*
 	 * sg stuff
@@ -747,6 +759,10 @@ extern void end_queued_request(struct re
 extern void end_queued_request(struct request *, int);
 extern void end_dequeued_request(struct request *, int);
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_req(struct request *);
+extern int blk_delete_timer(struct request *);
+extern void blk_add_timer(struct request *);
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -758,6 +774,8 @@ extern void blk_complete_request(struct 
 
 static inline void blkdev_dequeue_request(struct request *req)
 {
+	if (req->q->rq_timed_out_fn)
+		blk_add_timer(req);
 	elv_dequeue_request(req->q, req);
 }
 
@@ -781,6 +799,8 @@ extern void blk_queue_merge_bvec(struct 
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern int blk_do_ordered(struct request_queue *, struct request **);
diff -r 3697367c6e4d include/scsi/scsi_cmnd.h
--- a/include/scsi/scsi_cmnd.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/include/scsi/scsi_cmnd.h	Thu Sep 27 00:13:07 2007 -0700
@@ -57,7 +57,6 @@ struct scsi_cmnd {
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -67,7 +66,6 @@ struct scsi_cmnd {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	unsigned request_bufflen;	/* Actual request size */
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 	void *request_buffer;		/* Actual requested buffer */
 
 	/* These elements define the operation we ultimately want to perform */
@@ -127,7 +125,6 @@ extern void __scsi_put_command(struct Sc
 			       struct device *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff -r 3697367c6e4d include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/include/scsi/scsi_host.h	Thu Sep 27 00:13:07 2007 -0700
@@ -41,13 +41,6 @@ struct blk_queue_tags;
 
 #define DISABLE_SG_CHAINING 0
 #define ENABLE_SG_CHAINING 1
-
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
 
 struct scsi_host_template {
 	struct module *module;
@@ -339,7 +332,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff -r 3697367c6e4d include/scsi/scsi_transport.h
--- a/include/scsi/scsi_transport.h	Thu Sep 27 00:12:13 2007 -0700
+++ b/include/scsi/scsi_transport.h	Thu Sep 27 00:13:07 2007 -0700
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@ struct scsi_transport_template {
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Used as callback for the completion of i_t_nexus request

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

* [RFC] [PATCH 2/2] blk request timeout handler patches
  2007-10-04 18:12 [RFC] [PATCH 0/2] blk request timeout handler patches malahal
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
@ 2007-10-04 18:20 ` malahal
  2007-10-04 18:32   ` Randy Dunlap
  1 sibling, 1 reply; 26+ messages in thread
From: malahal @ 2007-10-04 18:20 UTC (permalink / raw)
  To: linux-scsi, jens.axboe

Fix scsi_dispatch_cmd() to stop timers.

Signed-off-by: Malahal Naineni <malahal@us.ibm.com>


diff -r 870bb598c977 drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Thu Sep 27 00:25:38 2007 -0700
+++ b/drivers/scsi/scsi.c	Thu Sep 27 01:04:10 2007 -0700
@@ -471,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* 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);
-		__blk_complete_request(cmd->request);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -491,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		 * future requests should not occur until the device 
 		 * transitions out of the suspend state.
 		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
 
@@ -536,12 +542,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	scsi_log_send(cmd);
 
 	/*
-	 * We will use a queued command if possible, otherwise we will
-	 * emulate the queuing and calling of completion function ourselves.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
-
-	/*
 	 * Before we queue this command, check if the command
 	 * length exceeds what the host adapter can handle.
 	 */
@@ -571,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 	spin_unlock_irqrestore(host->host_lock, flags);
 	if (rtn) {
-		if (blk_delete_timer(cmd->request)) {
-			atomic_inc(&cmd->device->iodone_cnt);
-			scsi_queue_insert(cmd,
-					  (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
-					  rtn : SCSI_MLQUEUE_HOST_BUSY);
-		}
+		scsi_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
diff -r 870bb598c977 drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Thu Sep 27 00:25:38 2007 -0700
+++ b/drivers/scsi/scsi_lib.c	Thu Sep 27 01:16:28 2007 -0700
@@ -160,6 +160,36 @@ int scsi_queue_insert(struct scsi_cmnd *
 
 	return 0;
 }
+
+/*
+ * Function:    scsi_queue_retry()
+ *
+ * Purpose:     Try inserting 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:       This is very similar to scsi_queue_insert except that we
+ *              call this function when we don't know if the blk layer timer
+ *              is active or not. We could implement this either by calling
+ *              blk_delete_timer and inserting in the midlevel queue if we
+ *              successfully delete the timer OR setting appropriate result
+ *              field in the cmd and letting it go through the normal done
+ *              routines which will retry the command. For now, We call
+ *              blk_delete_timer!
+ */
+void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
+{
+	if (blk_delete_timer(cmd->request)) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd, reason);
+	}
+}
+
 
 /**
  * scsi_execute - insert request and wait for the result
diff -r 870bb598c977 drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Thu Sep 27 00:25:38 2007 -0700
+++ b/drivers/scsi/scsi_priv.h	Thu Sep 27 01:03:39 2007 -0700
@@ -64,6 +64,7 @@ extern int scsi_maybe_unblock_host(struc
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);

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

* Re: [RFC] [PATCH 2/2] blk request timeout handler patches
  2007-10-04 18:20 ` [RFC] [PATCH 2/2] " malahal
@ 2007-10-04 18:32   ` Randy Dunlap
  0 siblings, 0 replies; 26+ messages in thread
From: Randy Dunlap @ 2007-10-04 18:32 UTC (permalink / raw)
  To: malahal; +Cc: linux-scsi, jens.axboe

On Thu, 4 Oct 2007 11:20:03 -0700 malahal@us.ibm.com wrote:

> Fix scsi_dispatch_cmd() to stop timers.
> 
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> 
> 
> diff -r 870bb598c977 drivers/scsi/scsi.c
> --- a/drivers/scsi/scsi.c	Thu Sep 27 00:25:38 2007 -0700
> +++ b/drivers/scsi/scsi.c	Thu Sep 27 01:04:10 2007 -0700
> @@ -471,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
>  	unsigned long timeout;
>  	int rtn = 0;
>  
> +	/*
> +	 * We will use a queued command if possible, otherwise we will
> +	 * emulate the queuing and calling of completion function ourselves.
> +	 */
> +	atomic_inc(&cmd->device->iorequest_cnt);
> +
>  	/* 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);
> -		__blk_complete_request(cmd->request);
> +		scsi_done(cmd);
>  		/* return 0 (because the command has been processed) */
>  		goto out;
>  	}
> @@ -491,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
>  		 * future requests should not occur until the device 
>  		 * transitions out of the suspend state.
>  		 */
> -		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
> +
> +		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
>  
>  		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
>  
> @@ -536,12 +542,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
>  	scsi_log_send(cmd);
>  
>  	/*
> -	 * We will use a queued command if possible, otherwise we will
> -	 * emulate the queuing and calling of completion function ourselves.
> -	 */
> -	atomic_inc(&cmd->device->iorequest_cnt);
> -
> -	/*
>  	 * Before we queue this command, check if the command
>  	 * length exceeds what the host adapter can handle.
>  	 */
> @@ -571,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
>  	}
>  	spin_unlock_irqrestore(host->host_lock, flags);
>  	if (rtn) {
> -		if (blk_delete_timer(cmd->request)) {
> -			atomic_inc(&cmd->device->iodone_cnt);
> -			scsi_queue_insert(cmd,
> -					  (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
> -					  rtn : SCSI_MLQUEUE_HOST_BUSY);
> -		}
> +		scsi_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
> +						rtn : SCSI_MLQUEUE_HOST_BUSY);
>  		SCSI_LOG_MLQUEUE(3,
>  		    printk("queuecommand : request rejected\n"));
>  	}
> diff -r 870bb598c977 drivers/scsi/scsi_lib.c
> --- a/drivers/scsi/scsi_lib.c	Thu Sep 27 00:25:38 2007 -0700
> +++ b/drivers/scsi/scsi_lib.c	Thu Sep 27 01:16:28 2007 -0700
> @@ -160,6 +160,36 @@ int scsi_queue_insert(struct scsi_cmnd *
>  
>  	return 0;
>  }
> +
> +/*
> + * Function:    scsi_queue_retry()
> + *
> + * Purpose:     Try inserting 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:       This is very similar to scsi_queue_insert except that we
> + *              call this function when we don't know if the blk layer timer
> + *              is active or not. We could implement this either by calling
> + *              blk_delete_timer and inserting in the midlevel queue if we
> + *              successfully delete the timer OR setting appropriate result
> + *              field in the cmd and letting it go through the normal done
> + *              routines which will retry the command. For now, We call
> + *              blk_delete_timer!
> + */

Please use kernel-doc notation for the function interface doc.
Thanks.

> +void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
> +{
> +	if (blk_delete_timer(cmd->request)) {
> +		atomic_inc(&cmd->device->iodone_cnt);
> +		scsi_queue_insert(cmd, reason);
> +	}
> +}

---
~Randy

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

* Re: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
@ 2007-10-04 18:52   ` Randy Dunlap
  2007-10-04 20:40   ` Salyzyn, Mark
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 26+ messages in thread
From: Randy Dunlap @ 2007-10-04 18:52 UTC (permalink / raw)
  To: malahal; +Cc: linux-scsi, jens.axboe

On Thu, 4 Oct 2007 11:17:50 -0700 malahal@us.ibm.com wrote:

> Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> 
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> 
> 
> diff -r 3697367c6e4d block/ll_rw_blk.c
> --- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
> +++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
> @@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
>  
>  EXPORT_SYMBOL(blk_queue_softirq_done);
>  
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +

Drop that blank line.

> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
>  };
>  
>  /**
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
> + *
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + **/
> +int blk_delete_timer(struct request *req)
> +{
> +	int rtn;
> +
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> +
> +	rtn = del_timer(&req->timer);
> +	req->timer.data = (unsigned long)NULL;
> +	req->timer.function = NULL;
> +
> +	return rtn;
> +}
> +

ditto.

> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	switch (q->rq_timed_out_fn(req)) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		return;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);
> +		return;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		return;
> +	}
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * req:		pointer to the request of interest
> + *

s/req:/@req:/

> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);
> +}
> +

drop blank line between closing } of function and the following
EXPORT_SYMBOL...

> +EXPORT_SYMBOL_GPL(blk_abort_req);
> +
> +/**
> + * blk_add_timer - Start timeout timer for a single request
> + * @req:	request that is about to start running.
> + *
> + * Notes:
> + *    Each request has its own timer, and as it is added to the queue, we
> + *    set up the timer.  When the request completes, we cancel the timer.
> + **/

    */

> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	/*
> +	 * If the clock was already running for this command, then
> +	 * first delete the timer.  The timer handling code gets rather
> +	 * confused if we don't do this.
> +	 */
> +	if (req->timer.function)
> +		del_timer(&req->timer);
> +
> +	req->timer.data = (unsigned long)req;
> +	if (req->timeout)
> +		req->timer.expires = jiffies + req->timeout;
> +	else
> +		req->timer.expires = jiffies + q->rq_timeout;
> +	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;
> +        add_timer(&req->timer);
> +}
> +

drop blank line.  Please just check the rest of them.

> +EXPORT_SYMBOL_GPL(blk_add_timer);
> +
> +/**
>   * blk_complete_request - end I/O on a request
> - * @req:      the request being processed
> + * @req:	the request being processed
>   *
>   * Description:
>   *     Ends all I/O on a request. It does not handle partial completions,
> @@ -3657,25 +3786,24 @@ static struct notifier_block blk_cpu_not
>   *     through a softirq handler. The user must have registered a completion
>   *     callback through blk_queue_softirq_done().
>   **/

    */

> -
>  void blk_complete_request(struct request *req)
>  {


---
~Randy

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

* RE: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
  2007-10-04 18:52   ` Randy Dunlap
@ 2007-10-04 20:40   ` Salyzyn, Mark
  2007-10-05 12:49   ` Jens Axboe
  2007-10-05 12:50   ` [RFC] [PATCH 1/2] " Jens Axboe
  3 siblings, 0 replies; 26+ messages in thread
From: Salyzyn, Mark @ 2007-10-04 20:40 UTC (permalink / raw)
  To: malahal, linux-scsi, jens.axboe

ACK for the trivial portion surrounding aacraid and ips!

Sincerely -- Mark Salyzyn
 
> -----Original Message-----
> From: linux-scsi-owner@vger.kernel.org 
> [mailto:linux-scsi-owner@vger.kernel.org] On Behalf Of 
> malahal@us.ibm.com
> Sent: Thursday, October 04, 2007 2:18 PM
> To: linux-scsi@vger.kernel.org; jens.axboe@oracle.com
> Subject: [RFC] [PATCH 1/2] blk request timeout handler patches
> 
> Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> 
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
. . .
> diff -r 3697367c6e4d drivers/scsi/aacraid/aachba.c
> --- a/drivers/scsi/aacraid/aachba.c	Thu Sep 27 00:12:13 2007 -0700
> +++ b/drivers/scsi/aacraid/aachba.c	Thu Sep 27 00:13:07 2007 -0700
> @@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(
>  	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
>  	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
>  	srbcmd->flags    = cpu_to_le32(flag);
> -	timeout = cmd->timeout_per_command/HZ;
> +	timeout = cmd->request->timeout/HZ;
>  	if (timeout == 0)
>  		timeout = 1;
>  	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
. . .
> diff -r 3697367c6e4d drivers/scsi/ips.c
> --- a/drivers/scsi/ips.c	Thu Sep 27 00:12:13 2007 -0700
> +++ b/drivers/scsi/ips.c	Thu Sep 27 00:13:07 2007 -0700
> @@ -3862,7 +3862,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
>  		scb->cmd.dcdb.segment_4G = 0;
>  		scb->cmd.dcdb.enhanced_sg = 0;
>  
> -		TimeOut = scb->scsi_cmd->timeout_per_command;
> +		TimeOut = scb->scsi_cmd->request->timeout;
>  
>  		if (ha->subsys->param[4] & 0x00100000) {	
> /* If NEW Tape DCDB is Supported */
>  			if (!scb->sg_len) {
. . .

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

* Re: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
  2007-10-04 18:52   ` Randy Dunlap
  2007-10-04 20:40   ` Salyzyn, Mark
@ 2007-10-05 12:49   ` Jens Axboe
  2007-10-08  6:54     ` malahal
  2007-10-09  5:36     ` [RFC] [PATCH 1/1] " malahal
  2007-10-05 12:50   ` [RFC] [PATCH 1/2] " Jens Axboe
  3 siblings, 2 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-05 12:49 UTC (permalink / raw)
  To: linux-scsi

On Thu, Oct 04 2007, malahal@us.ibm.com wrote:
> Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> 
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> 
> 
> diff -r 3697367c6e4d block/ll_rw_blk.c
> --- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
> +++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
> @@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
>  
>  EXPORT_SYMBOL(blk_queue_softirq_done);
>  
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -243,7 +256,9 @@ static void rq_init(struct request_queue
>  {
>  	INIT_LIST_HEAD(&rq->queuelist);
>  	INIT_LIST_HEAD(&rq->donelist);
> -
> +	init_timer(&rq->timer);
> +
> +	rq->timeout = 0;
>  	rq->errors = 0;
>  	rq->bio = rq->biotail = NULL;
>  	INIT_HLIST_NODE(&rq->hash);
> @@ -2305,6 +2320,7 @@ EXPORT_SYMBOL(blk_start_queueing);
>   */
>  void blk_requeue_request(struct request_queue *q, struct request *rq)
>  {
> +	blk_delete_timer(rq);
>  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
>  
>  	if (blk_rq_tagged(rq))
> @@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
>  };
>  
>  /**
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
> + *
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + **/
> +int blk_delete_timer(struct request *req)
> +{
> +	int rtn;
> +
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> +
> +	rtn = del_timer(&req->timer);
> +	req->timer.data = (unsigned long)NULL;
> +	req->timer.function = NULL;
> +
> +	return rtn;
> +}

Hmm, that looks fishy. What if the timer _just_ fired, yet it hasn't
retrieved ->data yet?

> +
> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	switch (q->rq_timed_out_fn(req)) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		return;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);
> +		return;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		return;
> +	}
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * req:		pointer to the request of interest
> + *
> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);
> +}
> +
> +EXPORT_SYMBOL_GPL(blk_abort_req);
> +
> +/**
> + * blk_add_timer - Start timeout timer for a single request
> + * @req:	request that is about to start running.
> + *
> + * Notes:
> + *    Each request has its own timer, and as it is added to the queue, we
> + *    set up the timer.  When the request completes, we cancel the timer.
> + **/
> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	/*
> +	 * If the clock was already running for this command, then
> +	 * first delete the timer.  The timer handling code gets rather
> +	 * confused if we don't do this.
> +	 */
> +	if (req->timer.function)
> +		del_timer(&req->timer);
> +
> +	req->timer.data = (unsigned long)req;
> +	if (req->timeout)
> +		req->timer.expires = jiffies + req->timeout;
> +	else
> +		req->timer.expires = jiffies + q->rq_timeout;
> +	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;

Why the cast?

> +        add_timer(&req->timer);

You have space vs tab issues.

> +}

That's an ugly interface. I'd say it's a bug to call blk_add_timer()
with it already pending, so fix the API.

Apart from that, this has been a TODO item for me for some time. So
thanks for refreshing these, lets see if we can get them beat into
submission and agree on how it should work so we can take this forward.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
                     ` (2 preceding siblings ...)
  2007-10-05 12:49   ` Jens Axboe
@ 2007-10-05 12:50   ` Jens Axboe
  3 siblings, 0 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-05 12:50 UTC (permalink / raw)
  To: linux-scsi; +Cc: malahal


(resend, with proper CC - stupid mutt)

On Thu, Oct 04 2007, malahal@us.ibm.com wrote:
> Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> 
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> 
> 
> diff -r 3697367c6e4d block/ll_rw_blk.c
> --- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
> +++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
> @@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
>  
>  EXPORT_SYMBOL(blk_queue_softirq_done);
>  
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -243,7 +256,9 @@ static void rq_init(struct request_queue
>  {
>  	INIT_LIST_HEAD(&rq->queuelist);
>  	INIT_LIST_HEAD(&rq->donelist);
> -
> +	init_timer(&rq->timer);
> +
> +	rq->timeout = 0;
>  	rq->errors = 0;
>  	rq->bio = rq->biotail = NULL;
>  	INIT_HLIST_NODE(&rq->hash);
> @@ -2305,6 +2320,7 @@ EXPORT_SYMBOL(blk_start_queueing);
>   */
>  void blk_requeue_request(struct request_queue *q, struct request *rq)
>  {
> +	blk_delete_timer(rq);
>  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
>  
>  	if (blk_rq_tagged(rq))
> @@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
>  };
>  
>  /**
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
> + *
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + **/
> +int blk_delete_timer(struct request *req)
> +{
> +	int rtn;
> +
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> +
> +	rtn = del_timer(&req->timer);
> +	req->timer.data = (unsigned long)NULL;
> +	req->timer.function = NULL;
> +
> +	return rtn;
> +}

Hmm, that looks fishy. What if the timer _just_ fired, yet it hasn't
retrieved ->data yet?

> +
> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	switch (q->rq_timed_out_fn(req)) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		return;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);
> +		return;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		return;
> +	}
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * req:		pointer to the request of interest
> + *
> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);
> +}
> +
> +EXPORT_SYMBOL_GPL(blk_abort_req);
> +
> +/**
> + * blk_add_timer - Start timeout timer for a single request
> + * @req:	request that is about to start running.
> + *
> + * Notes:
> + *    Each request has its own timer, and as it is added to the queue, we
> + *    set up the timer.  When the request completes, we cancel the timer.
> + **/
> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +
> +	/*
> +	 * If the clock was already running for this command, then
> +	 * first delete the timer.  The timer handling code gets rather
> +	 * confused if we don't do this.
> +	 */
> +	if (req->timer.function)
> +		del_timer(&req->timer);
> +
> +	req->timer.data = (unsigned long)req;
> +	if (req->timeout)
> +		req->timer.expires = jiffies + req->timeout;
> +	else
> +		req->timer.expires = jiffies + q->rq_timeout;
> +	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;

Why the cast?

> +        add_timer(&req->timer);

You have space vs tab issues.

> +}

That's an ugly interface. I'd say it's a bug to call blk_add_timer()
with it already pending, so fix the API.

Apart from that, this has been a TODO item for me for some time. So
thanks for refreshing these, lets see if we can get them beat into
submission and agree on how it should work so we can take this forward.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-05 12:49   ` Jens Axboe
@ 2007-10-08  6:54     ` malahal
  2007-10-08  7:04       ` Jens Axboe
  2007-10-09  5:36     ` [RFC] [PATCH 1/1] " malahal
  1 sibling, 1 reply; 26+ messages in thread
From: malahal @ 2007-10-08  6:54 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-scsi

Jens Axboe [jens.axboe@oracle.com] wrote:
> On Thu, Oct 04 2007, malahal@us.ibm.com wrote:
> > Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> > 
> > Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> > Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> > 
> > 
> > diff -r 3697367c6e4d block/ll_rw_blk.c
> > --- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
> > +++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
> > @@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
> >  
> >  EXPORT_SYMBOL(blk_queue_softirq_done);
> >  
> > +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> > +{
> > +	q->rq_timeout = timeout;
> > +}
> > +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> > +
> > +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> > +{
> > +	q->rq_timed_out_fn = fn;
> > +}
> > +
> > +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> > +
> >  /**
> >   * blk_queue_make_request - define an alternate make_request function for a device
> >   * @q:  the request queue for the device to be affected
> > @@ -243,7 +256,9 @@ static void rq_init(struct request_queue
> >  {
> >  	INIT_LIST_HEAD(&rq->queuelist);
> >  	INIT_LIST_HEAD(&rq->donelist);
> > -
> > +	init_timer(&rq->timer);
> > +
> > +	rq->timeout = 0;
> >  	rq->errors = 0;
> >  	rq->bio = rq->biotail = NULL;
> >  	INIT_HLIST_NODE(&rq->hash);
> > @@ -2305,6 +2320,7 @@ EXPORT_SYMBOL(blk_start_queueing);
> >   */
> >  void blk_requeue_request(struct request_queue *q, struct request *rq)
> >  {
> > +	blk_delete_timer(rq);
> >  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
> >  
> >  	if (blk_rq_tagged(rq))
> > @@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
> >  };
> >  
> >  /**
> > + * blk_delete_timer - Delete/cancel timer for a given function.
> > + * @req:	request that we are canceling timer for
> > + *
> > + * Return value:
> > + *     1 if we were able to detach the timer.  0 if we blew it, and the
> > + *     timer function has already started to run.
> > + **/
> > +int blk_delete_timer(struct request *req)
> > +{
> > +	int rtn;
> > +
> > +	if (!req->q->rq_timed_out_fn)
> > +		return 1;
> > +
> > +	rtn = del_timer(&req->timer);
> > +	req->timer.data = (unsigned long)NULL;
> > +	req->timer.function = NULL;
> > +
> > +	return rtn;
> > +}
> 
> Hmm, that looks fishy. What if the timer _just_ fired, yet it hasn't
> retrieved ->data yet?
> 

Looks like it is just copied from the SCSI code. More over _run_timers()
copies data and function on to stack variables before calling the timer
function. So, I don't think there is a problem here but assuming that
implementation detail is bad! I would like modify the above function to
reinitialize data and function fields only if del_timer() returns TRUE.
Please let me know if that is OK.

> > +
> > +EXPORT_SYMBOL_GPL(blk_delete_timer);
> > +
> > +static void blk_rq_timed_out(struct request *req)
> > +{
> > +	struct request_queue *q = req->q;
> > +
> > +	switch (q->rq_timed_out_fn(req)) {
> > +	case BLK_EH_HANDLED:
> > +		__blk_complete_request(req);
> > +		return;
> > +	case BLK_EH_RESET_TIMER:
> > +		blk_add_timer(req);
> > +		return;
> > +	case BLK_EH_NOT_HANDLED:
> > +		/*
> > +		 * LLD handles this for now but in the future
> > +		 * we can send a request msg to abort the command
> > +		 * and we can move more of the generic scsi eh code to
> > +		 * the blk layer.
> > +		 */
> > +		return;
> > +	}
> > +}
> > +
> > +/**
> > + * blk_abort_req -- Request request recovery for the specified command
> > + * req:		pointer to the request of interest
> > + *
> > + * This function requests that the block layer start recovery for the
> > + * request by deleting the timer and calling the q's timeout function.
> > + * LLDDs who implement their own error recovery MAY ignore the timeout
> > + * event if they generated blk_abort_req.
> > + */
> > +void blk_abort_req(struct request *req)
> > +{
> > +        if (!blk_delete_timer(req))
> > +                return;
> > +        blk_rq_timed_out(req);
> > +}
> > +
> > +EXPORT_SYMBOL_GPL(blk_abort_req);
> > +
> > +/**
> > + * blk_add_timer - Start timeout timer for a single request
> > + * @req:	request that is about to start running.
> > + *
> > + * Notes:
> > + *    Each request has its own timer, and as it is added to the queue, we
> > + *    set up the timer.  When the request completes, we cancel the timer.
> > + **/
> > +void blk_add_timer(struct request *req)
> > +{
> > +	struct request_queue *q = req->q;
> > +
> > +	/*
> > +	 * If the clock was already running for this command, then
> > +	 * first delete the timer.  The timer handling code gets rather
> > +	 * confused if we don't do this.
> > +	 */
> > +	if (req->timer.function)
> > +		del_timer(&req->timer);
> > +
> > +	req->timer.data = (unsigned long)req;
> > +	if (req->timeout)
> > +		req->timer.expires = jiffies + req->timeout;
> > +	else
> > +		req->timer.expires = jiffies + q->rq_timeout;
> > +	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;
> 
> Why the cast?
> 

Because blk_rq_timed_out() doesn't take "unsigned long" as its input
parameter. Again, copied from SCSI.

> > +        add_timer(&req->timer);
> 
> You have space vs tab issues.
> 
> > +}
> 
> That's an ugly interface. I'd say it's a bug to call blk_add_timer()
> with it already pending, so fix the API.

blk_add_timer is also called from the timer function (blk_rq_timed_out) if
BLK_EH_RESET_TIMER is retuned. This is also copied from SCSI! Please let me
know if you want to do it some other way.

Thanks, Malahal.

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

* Re: [RFC] [PATCH 1/2] blk request timeout handler patches
  2007-10-08  6:54     ` malahal
@ 2007-10-08  7:04       ` Jens Axboe
  0 siblings, 0 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-08  7:04 UTC (permalink / raw)
  To: linux-scsi

On Sun, Oct 07 2007, malahal@us.ibm.com wrote:
> Jens Axboe [jens.axboe@oracle.com] wrote:
> > On Thu, Oct 04 2007, malahal@us.ibm.com wrote:
> > > Mike Christie's patches refreshed to 2.6.23-rc8-mm1.
> > > 
> > > Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> > > Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> > > 
> > > 
> > > diff -r 3697367c6e4d block/ll_rw_blk.c
> > > --- a/block/ll_rw_blk.c	Thu Sep 27 00:12:13 2007 -0700
> > > +++ b/block/ll_rw_blk.c	Thu Sep 27 00:13:07 2007 -0700
> > > @@ -181,6 +181,19 @@ void blk_queue_softirq_done(struct reque
> > >  
> > >  EXPORT_SYMBOL(blk_queue_softirq_done);
> > >  
> > > +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> > > +{
> > > +	q->rq_timeout = timeout;
> > > +}
> > > +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> > > +
> > > +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> > > +{
> > > +	q->rq_timed_out_fn = fn;
> > > +}
> > > +
> > > +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> > > +
> > >  /**
> > >   * blk_queue_make_request - define an alternate make_request function for a device
> > >   * @q:  the request queue for the device to be affected
> > > @@ -243,7 +256,9 @@ static void rq_init(struct request_queue
> > >  {
> > >  	INIT_LIST_HEAD(&rq->queuelist);
> > >  	INIT_LIST_HEAD(&rq->donelist);
> > > -
> > > +	init_timer(&rq->timer);
> > > +
> > > +	rq->timeout = 0;
> > >  	rq->errors = 0;
> > >  	rq->bio = rq->biotail = NULL;
> > >  	INIT_HLIST_NODE(&rq->hash);
> > > @@ -2305,6 +2320,7 @@ EXPORT_SYMBOL(blk_start_queueing);
> > >   */
> > >  void blk_requeue_request(struct request_queue *q, struct request *rq)
> > >  {
> > > +	blk_delete_timer(rq);
> > >  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
> > >  
> > >  	if (blk_rq_tagged(rq))
> > > @@ -3647,8 +3663,121 @@ static struct notifier_block blk_cpu_not
> > >  };
> > >  
> > >  /**
> > > + * blk_delete_timer - Delete/cancel timer for a given function.
> > > + * @req:	request that we are canceling timer for
> > > + *
> > > + * Return value:
> > > + *     1 if we were able to detach the timer.  0 if we blew it, and the
> > > + *     timer function has already started to run.
> > > + **/
> > > +int blk_delete_timer(struct request *req)
> > > +{
> > > +	int rtn;
> > > +
> > > +	if (!req->q->rq_timed_out_fn)
> > > +		return 1;
> > > +
> > > +	rtn = del_timer(&req->timer);
> > > +	req->timer.data = (unsigned long)NULL;
> > > +	req->timer.function = NULL;
> > > +
> > > +	return rtn;
> > > +}
> > 
> > Hmm, that looks fishy. What if the timer _just_ fired, yet it hasn't
> > retrieved ->data yet?
> > 
> 
> Looks like it is just copied from the SCSI code. More over _run_timers()
> copies data and function on to stack variables before calling the timer
> function. So, I don't think there is a problem here but assuming that
> implementation detail is bad! I would like modify the above function to
> reinitialize data and function fields only if del_timer() returns TRUE.
> Please let me know if that is OK.

I guess it could be OK, but it then deserves a big fat comment
describing why it is ok.

> > > +
> > > +EXPORT_SYMBOL_GPL(blk_delete_timer);
> > > +
> > > +static void blk_rq_timed_out(struct request *req)
> > > +{
> > > +	struct request_queue *q = req->q;
> > > +
> > > +	switch (q->rq_timed_out_fn(req)) {
> > > +	case BLK_EH_HANDLED:
> > > +		__blk_complete_request(req);
> > > +		return;
> > > +	case BLK_EH_RESET_TIMER:
> > > +		blk_add_timer(req);
> > > +		return;
> > > +	case BLK_EH_NOT_HANDLED:
> > > +		/*
> > > +		 * LLD handles this for now but in the future
> > > +		 * we can send a request msg to abort the command
> > > +		 * and we can move more of the generic scsi eh code to
> > > +		 * the blk layer.
> > > +		 */
> > > +		return;
> > > +	}
> > > +}
> > > +
> > > +/**
> > > + * blk_abort_req -- Request request recovery for the specified command
> > > + * req:		pointer to the request of interest
> > > + *
> > > + * This function requests that the block layer start recovery for the
> > > + * request by deleting the timer and calling the q's timeout function.
> > > + * LLDDs who implement their own error recovery MAY ignore the timeout
> > > + * event if they generated blk_abort_req.
> > > + */
> > > +void blk_abort_req(struct request *req)
> > > +{
> > > +        if (!blk_delete_timer(req))
> > > +                return;
> > > +        blk_rq_timed_out(req);
> > > +}
> > > +
> > > +EXPORT_SYMBOL_GPL(blk_abort_req);
> > > +
> > > +/**
> > > + * blk_add_timer - Start timeout timer for a single request
> > > + * @req:	request that is about to start running.
> > > + *
> > > + * Notes:
> > > + *    Each request has its own timer, and as it is added to the queue, we
> > > + *    set up the timer.  When the request completes, we cancel the timer.
> > > + **/
> > > +void blk_add_timer(struct request *req)
> > > +{
> > > +	struct request_queue *q = req->q;
> > > +
> > > +	/*
> > > +	 * If the clock was already running for this command, then
> > > +	 * first delete the timer.  The timer handling code gets rather
> > > +	 * confused if we don't do this.
> > > +	 */
> > > +	if (req->timer.function)
> > > +		del_timer(&req->timer);
> > > +
> > > +	req->timer.data = (unsigned long)req;
> > > +	if (req->timeout)
> > > +		req->timer.expires = jiffies + req->timeout;
> > > +	else
> > > +		req->timer.expires = jiffies + q->rq_timeout;
> > > +	req->timer.function = (void (*)(unsigned long))blk_rq_timed_out;
> > 
> > Why the cast?
> > 
> 
> Because blk_rq_timed_out() doesn't take "unsigned long" as its input
> parameter. Again, copied from SCSI.

Don't copy stuff from SCSI just because you can, it's allowed to fix
things up along the way! I'd propose adding blk_rq_timed_out_timer()
ala:

static void blk_rq_timed_out_timer(unsigned long data)
{
        struct request *rq = (struct request *) data;

        blk_rq_timed_out(rq);
}

and using that to get rid of the cast.

> 
> > > +        add_timer(&req->timer);
> > 
> > You have space vs tab issues.
> > 
> > > +}
> > 
> > That's an ugly interface. I'd say it's a bug to call blk_add_timer()
> > with it already pending, so fix the API.
> 
> blk_add_timer is also called from the timer function (blk_rq_timed_out) if
> BLK_EH_RESET_TIMER is retuned. This is also copied from SCSI! Please let me
> know if you want to do it some other way.

I thought I just did :-)

Delete the timer first, the API you are proposing isn't very nice.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-05 12:49   ` Jens Axboe
  2007-10-08  6:54     ` malahal
@ 2007-10-09  5:36     ` malahal
  2007-10-09  9:14       ` Jens Axboe
  2007-10-09 12:00       ` Matthew Wilcox
  1 sibling, 2 replies; 26+ messages in thread
From: malahal @ 2007-10-09  5:36 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-scsi

Thank you Randy, Jens for your suggestions. I folded the second patch as
it is just a clean up. Here is the fixed one patch version.

Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: Malahal Naineni <malahal@us.ibm.com>

Thanks, Malahal.

diff -r 2cd6b249e335 block/ll_rw_blk.c
--- a/block/ll_rw_blk.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/block/ll_rw_blk.c	Mon Oct 08 18:30:34 2007 -0700
@@ -181,6 +181,18 @@ void blk_queue_softirq_done(struct reque
 
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -243,7 +255,9 @@ static void rq_init(struct request_queue
 {
 	INIT_LIST_HEAD(&rq->queuelist);
 	INIT_LIST_HEAD(&rq->donelist);
-
+	init_timer(&rq->timer);
+
+	rq->timeout = 0;
 	rq->errors = 0;
 	rq->bio = rq->biotail = NULL;
 	INIT_HLIST_NODE(&rq->hash);
@@ -2305,6 +2319,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -3647,8 +3662,103 @@ static struct notifier_block blk_cpu_not
 };
 
 /**
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
+ *
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ */
+int blk_delete_timer(struct request *req)
+{
+	if (!req->q->rq_timed_out_fn)
+		return 1;
+
+	return del_timer(&req->timer);
+}
+EXPORT_SYMBOL_GPL(blk_delete_timer);
+
+static void blk_rq_timed_out(unsigned long data)
+{
+	struct request *req = (struct request *)data;
+	struct request_queue *q = req->q;
+
+	switch (q->rq_timed_out_fn(req)) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		return;
+	case BLK_EH_RESET_TIMER:
+		blk_add_timer(req);
+		return;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		return;
+	}
+}
+
+/**
+ * blk_abort_req -- Request request recovery for the specified command
+ * @req:	pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req.
+ */
+void blk_abort_req(struct request *req)
+{
+        if (!blk_delete_timer(req))
+                return;
+        blk_rq_timed_out(req);
+}
+EXPORT_SYMBOL_GPL(blk_abort_req);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer.  When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	req->timer.data = (unsigned long)req;
+	if (req->timeout)
+		req->timer.expires = jiffies + req->timeout;
+	else
+		req->timer.expires = jiffies + q->rq_timeout;
+	req->timer.function = blk_rq_timed_out;
+	add_timer(&req->timer);
+}
+EXPORT_SYMBOL_GPL(blk_add_timer);
+
+void __blk_complete_request(struct request *req)
+{
+	struct list_head *cpu_list;
+	unsigned long flags;
+
+	BUG_ON(!req->q->softirq_done_fn);
+
+	local_irq_save(flags);
+
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_add_tail(&req->donelist, cpu_list);
+	raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+	local_irq_restore(flags);
+}
+
+/**
  * blk_complete_request - end I/O on a request
- * @req:      the request being processed
+ * @req:	the request being processed
  *
  * Description:
  *     Ends all I/O on a request. It does not handle partial completions,
@@ -3656,26 +3766,24 @@ static struct notifier_block blk_cpu_not
  *     through requeueing. The actual completion happens out-of-order,
  *     through a softirq handler. The user must have registered a completion
  *     callback through blk_queue_softirq_done().
- **/
-
+ */
 void blk_complete_request(struct request *req)
 {
-	struct list_head *cpu_list;
-	unsigned long flags;
-
-	BUG_ON(!req->q->softirq_done_fn);
-		
-	local_irq_save(flags);
-
-	cpu_list = &__get_cpu_var(blk_cpu_done);
-	list_add_tail(&req->donelist, cpu_list);
-	raise_softirq_irqoff(BLOCK_SOFTIRQ);
-
-	local_irq_restore(flags);
-}
-
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!blk_delete_timer(req))
+		return;
+
+	__blk_complete_request(req);
+}
 EXPORT_SYMBOL(blk_complete_request);
-	
+
 /*
  * queue lock must be held
  */
diff -r 2cd6b249e335 drivers/ata/libata-eh.c
--- a/drivers/ata/libata-eh.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/ata/libata-eh.c	Thu Sep 27 09:57:53 2007 -0700
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -312,29 +313,29 @@ static void ata_eh_clear_action(struct a
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -765,7 +766,7 @@ void ata_qc_schedule_eh(struct ata_queue
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_req(qc->scsicmd->request);
 }
 
 /**
diff -r 2cd6b249e335 drivers/ata/libata.h
--- a/drivers/ata/libata.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/ata/libata.h	Thu Sep 27 09:57:53 2007 -0700
@@ -149,7 +149,7 @@ extern int ata_bus_probe(struct ata_port
 extern int ata_bus_probe(struct ata_port *ap);
 
 /* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff -r 2cd6b249e335 drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/aacraid/aachba.c	Thu Sep 27 09:57:53 2007 -0700
@@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff -r 2cd6b249e335 drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/advansys.c	Thu Sep 27 09:57:53 2007 -0700
@@ -5859,7 +5859,7 @@ static void asc_prt_scsi_cmnd(struct scs
 	printk(" serial_number 0x%x, retries %d, allowed %d\n",
 	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-	printk(" timeout_per_command %d\n", s->timeout_per_command);
+	printk(" request timeout %d\n", s->request->timeout);
 
 	printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
 		s->scsi_done, s->done, s->host_scribble, s->result);
diff -r 2cd6b249e335 drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/gdth.c	Thu Sep 27 09:57:53 2007 -0700
@@ -728,7 +728,6 @@ int __gdth_execute(struct scsi_device *s
     scp->device = sdev;
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->request_buffer = gdtcmd;
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
@@ -4944,7 +4943,7 @@ static int gdth_queuecommand(Scsi_Cmnd *
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
     else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
 
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
diff -r 2cd6b249e335 drivers/scsi/gdth_proc.c
--- a/drivers/scsi/gdth_proc.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/gdth_proc.c	Thu Sep 27 09:57:53 2007 -0700
@@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum
 {
     int oldto;
 
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
+    oldto = scp->request->timeout;
+    scp->request->timeout = timeout;
 
     if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
+        del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) NULL;
+        scp->request->timer.expires = 0;
     } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
+        if (scp->request->timer.data != (unsigned long) NULL) 
+            del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) scp;
+        scp->request->timer.expires = jiffies + timeout;
+        add_timer(&scp->request->timer);
     }
 
     return oldto;
diff -r 2cd6b249e335 drivers/scsi/ibmvscsi/ibmvscsi.c
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c	Thu Sep 27 09:57:53 2007 -0700
@@ -732,7 +732,7 @@ static int ibmvscsi_queuecommand(struct 
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff -r 2cd6b249e335 drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/ide-scsi.c	Thu Sep 27 09:57:53 2007 -0700
@@ -812,7 +812,7 @@ static int idescsi_queue (struct scsi_cm
 	pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
 		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
diff -r 2cd6b249e335 drivers/scsi/ipr.c
--- a/drivers/scsi/ipr.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/ipr.c	Thu Sep 27 09:57:53 2007 -0700
@@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct sc
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff -r 2cd6b249e335 drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/ips.c	Thu Sep 27 09:57:53 2007 -0700
@@ -3862,7 +3862,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff -r 2cd6b249e335 drivers/scsi/libsas/sas_ata.c
--- a/drivers/scsi/libsas/sas_ata.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/libsas/sas_ata.c	Thu Sep 27 09:57:53 2007 -0700
@@ -407,7 +407,7 @@ void sas_ata_task_abort(struct sas_task 
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_req(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff -r 2cd6b249e335 drivers/scsi/libsas/sas_internal.h
--- a/drivers/scsi/libsas/sas_internal.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/libsas/sas_internal.h	Thu Sep 27 09:57:53 2007 -0700
@@ -55,7 +55,7 @@ int  sas_register_ports(struct sas_ha_st
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff -r 2cd6b249e335 drivers/scsi/libsas/sas_scsi_host.c
--- a/drivers/scsi/libsas/sas_scsi_host.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/libsas/sas_scsi_host.c	Thu Sep 27 09:57:53 2007 -0700
@@ -654,43 +654,43 @@ out:
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *tas
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_req(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff -r 2cd6b249e335 drivers/scsi/megaraid/megaraid_sas.c
--- a/drivers/scsi/megaraid/megaraid_sas.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/megaraid/megaraid_sas.c	Thu Sep 27 09:57:53 2007 -0700
@@ -969,7 +969,7 @@ static int megasas_generic_reset(struct 
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff -r 2cd6b249e335 drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/ncr53c8xx.c	Thu Sep 27 09:57:53 2007 -0700
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff -r 2cd6b249e335 drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/qla1280.c	Thu Sep 27 09:57:53 2007 -0700
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3167,7 +3167,7 @@ qla1280_32bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff -r 2cd6b249e335 drivers/scsi/qla4xxx/ql4_os.c
--- a/drivers/scsi/qla4xxx/ql4_os.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/qla4xxx/ql4_os.c	Thu Sep 27 09:57:53 2007 -0700
@@ -1565,7 +1565,7 @@ static int qla4xxx_eh_device_reset(struc
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
diff -r 2cd6b249e335 drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi.c	Mon Oct 08 11:51:50 2007 -0700
@@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struc
 
 		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* 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);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		 * future requests should not occur until the device 
 		 * transitions out of the suspend state.
 		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
 
@@ -534,19 +539,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		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.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
 
 	/*
 	 * Before we queue this command, check if the command
@@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
@@ -586,24 +581,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
 	return rtn;
 }
-
-/**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
 
 /**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
@@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out any more.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /*
diff -r 2cd6b249e335 drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi_error.c	Thu Sep 27 09:57:53 2007 -0700
@@ -113,69 +113,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -183,9 +122,11 @@ int scsi_delete_timer(struct scsi_cmnd *
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  **/
-void scsi_times_out(struct scsi_cmnd *scmd)
-{
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+enum blk_eh_timer_return scsi_times_out(struct request *req)
+{
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -197,22 +138,20 @@ void scsi_times_out(struct scsi_cmnd *sc
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
-	}
+		return BLK_EH_HANDLED;
+	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *
 	int rtn;
 
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
@@ -1678,8 +1616,6 @@ scsi_reset_provider(struct scsi_device *
 	scmd->cmd_len			= 0;
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
-
-	init_timer(&scmd->eh_timeout);
 
 	/*
 	 * Sometimes the command can get back into the timer chain,
diff -r 2cd6b249e335 drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi_lib.c	Mon Oct 08 11:51:50 2007 -0700
@@ -159,6 +159,29 @@ int scsi_queue_insert(struct scsi_cmnd *
 	scsi_run_queue(q);
 
 	return 0;
+}
+
+/**
+ * scsi_queue_retry - Try inserting a command in the midlevel queue.
+ *
+ * @cmd:	command that we are adding to queue.
+ * @reason:	why we are inserting command to queue.
+ *
+ * Notes:       This is very similar to scsi_queue_insert except that we
+ *              call this function when we don't know if the blk layer timer
+ *              is active or not. We could implement this either by calling
+ *              blk_delete_timer and inserting in the midlevel queue if we
+ *              successfully delete the timer OR setting appropriate result
+ *              field in the cmd and letting it go through the normal done
+ *              routines which will retry the command. For now, We call
+ *              blk_delete_timer!
+ */
+void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
+{
+	if (blk_delete_timer(cmd->request)) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd, reason);
+	}
 }
 
 /**
@@ -1227,7 +1250,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_d
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	cmd->done = scsi_blk_pc_done;
 	return BLKPREP_OK;
 }
@@ -1455,16 +1477,25 @@ static void scsi_kill_request(struct req
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	__blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
+
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
 
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
@@ -1699,6 +1730,7 @@ struct request_queue *scsi_alloc_queue(s
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
diff -r 2cd6b249e335 drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi_priv.h	Mon Oct 08 11:51:50 2007 -0700
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@ extern int scsi_dispatch_cmd(struct scsi
 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);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern void scsi_exit_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
@@ -67,6 +64,7 @@ extern int scsi_maybe_unblock_host(struc
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
diff -r 2cd6b249e335 drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi_sysfs.c	Thu Sep 27 09:57:53 2007 -0700
@@ -480,12 +480,15 @@ sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -495,7 +498,7 @@ sdev_store_timeout (struct device *dev, 
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff -r 2cd6b249e335 drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/scsi_transport_fc.c	Thu Sep 27 09:57:53 2007 -0700
@@ -1921,15 +1921,15 @@ static int fc_vport_match(struct attribu
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
-
-	return EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
diff -r 2cd6b249e335 drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/sd.c	Thu Sep 27 09:57:53 2007 -0700
@@ -337,7 +337,6 @@ static int sd_prep_fn(struct request_que
 	struct gendisk *disk = rq->rq_disk;
 	sector_t block = rq->sector;
 	unsigned int this_count = rq->nr_sectors;
-	unsigned int timeout = sdp->timeout;
 	int ret;
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -506,7 +505,6 @@ static int sd_prep_fn(struct request_que
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -1633,11 +1631,12 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	class_device_initialize(&sdkp->cdev);
diff -r 2cd6b249e335 drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/sr.c	Thu Sep 27 09:57:53 2007 -0700
@@ -306,7 +306,7 @@ static void rw_intr(struct scsi_cmnd * S
 
 static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block=0, this_count, s_size;
 	struct scsi_cd *cd;
 	struct scsi_cmnd *SCpnt;
 	struct scsi_device *sdp = q->queuedata;
@@ -435,7 +435,6 @@ static int sr_prep_fn(struct request_que
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -599,6 +598,8 @@ static int sr_probe(struct device *dev)
 	sprintf(disk->disk_name, "sr%d", minor);
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
+
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
 
 	cd->device = sdev;
 	cd->disk = disk;
diff -r 2cd6b249e335 drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Thu Sep 27 09:56:25 2007 -0700
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Thu Sep 27 09:57:53 2007 -0700
@@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struc
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff -r 2cd6b249e335 include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/include/linux/blkdev.h	Thu Sep 27 09:57:53 2007 -0700
@@ -309,6 +309,7 @@ struct request {
 	void *data;
 	void *sense;
 
+	struct timer_list timer;
 	unsigned int timeout;
 	int retries;
 
@@ -346,6 +347,14 @@ typedef int (merge_bvec_fn) (struct requ
 typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *);
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
+
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -383,6 +392,7 @@ struct request_queue
 	merge_bvec_fn		*merge_bvec_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -452,6 +462,8 @@ struct request_queue
 
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
+
+	unsigned int		rq_timeout;
 
 	/*
 	 * sg stuff
@@ -747,6 +759,10 @@ extern void end_queued_request(struct re
 extern void end_queued_request(struct request *, int);
 extern void end_dequeued_request(struct request *, int);
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_req(struct request *);
+extern int blk_delete_timer(struct request *);
+extern void blk_add_timer(struct request *);
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -758,6 +774,8 @@ extern void blk_complete_request(struct 
 
 static inline void blkdev_dequeue_request(struct request *req)
 {
+	if (req->q->rq_timed_out_fn)
+		blk_add_timer(req);
 	elv_dequeue_request(req->q, req);
 }
 
@@ -781,6 +799,8 @@ extern void blk_queue_merge_bvec(struct 
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern int blk_do_ordered(struct request_queue *, struct request **);
diff -r 2cd6b249e335 include/scsi/scsi_cmnd.h
--- a/include/scsi/scsi_cmnd.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/include/scsi/scsi_cmnd.h	Thu Sep 27 09:57:53 2007 -0700
@@ -57,7 +57,6 @@ struct scsi_cmnd {
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -67,7 +66,6 @@ struct scsi_cmnd {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	unsigned request_bufflen;	/* Actual request size */
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 	void *request_buffer;		/* Actual requested buffer */
 
 	/* These elements define the operation we ultimately want to perform */
@@ -127,7 +125,6 @@ extern void __scsi_put_command(struct Sc
 			       struct device *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff -r 2cd6b249e335 include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/include/scsi/scsi_host.h	Thu Sep 27 09:57:53 2007 -0700
@@ -41,13 +41,6 @@ struct blk_queue_tags;
 
 #define DISABLE_SG_CHAINING 0
 #define ENABLE_SG_CHAINING 1
-
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
 
 struct scsi_host_template {
 	struct module *module;
@@ -339,7 +332,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff -r 2cd6b249e335 include/scsi/scsi_transport.h
--- a/include/scsi/scsi_transport.h	Thu Sep 27 09:56:25 2007 -0700
+++ b/include/scsi/scsi_transport.h	Thu Sep 27 09:57:53 2007 -0700
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@ struct scsi_transport_template {
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Used as callback for the completion of i_t_nexus request

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09  5:36     ` [RFC] [PATCH 1/1] " malahal
@ 2007-10-09  9:14       ` Jens Axboe
  2007-10-09 14:26         ` malahal
  2007-10-09 12:00       ` Matthew Wilcox
  1 sibling, 1 reply; 26+ messages in thread
From: Jens Axboe @ 2007-10-09  9:14 UTC (permalink / raw)
  To: linux-scsi; +Cc: malahal

On Mon, Oct 08 2007, malahal@us.ibm.com wrote:
> Thank you Randy, Jens for your suggestions. I folded the second patch as
> it is just a clean up. Here is the fixed one patch version.
> 
> Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
> Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
> 
> Thanks, Malahal.
> 
> diff -r 2cd6b249e335 block/ll_rw_blk.c
> --- a/block/ll_rw_blk.c	Thu Sep 27 09:56:25 2007 -0700
> +++ b/block/ll_rw_blk.c	Mon Oct 08 18:30:34 2007 -0700
> @@ -181,6 +181,18 @@ void blk_queue_softirq_done(struct reque
>  
>  EXPORT_SYMBOL(blk_queue_softirq_done);
>  
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -243,7 +255,9 @@ static void rq_init(struct request_queue
>  {
>  	INIT_LIST_HEAD(&rq->queuelist);
>  	INIT_LIST_HEAD(&rq->donelist);
> -
> +	init_timer(&rq->timer);
> +
> +	rq->timeout = 0;
>  	rq->errors = 0;
>  	rq->bio = rq->biotail = NULL;
>  	INIT_HLIST_NODE(&rq->hash);
> @@ -2305,6 +2319,7 @@ EXPORT_SYMBOL(blk_start_queueing);
>   */
>  void blk_requeue_request(struct request_queue *q, struct request *rq)
>  {
> +	blk_delete_timer(rq);
>  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
>  
>  	if (blk_rq_tagged(rq))
> @@ -3647,8 +3662,103 @@ static struct notifier_block blk_cpu_not
>  };
>  
>  /**
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
> + *
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + */
> +int blk_delete_timer(struct request *req)
> +{
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> +
> +	return del_timer(&req->timer);
> +}
> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(unsigned long data)
> +{
> +	struct request *req = (struct request *)data;
> +	struct request_queue *q = req->q;
> +
> +	switch (q->rq_timed_out_fn(req)) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		return;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);
> +		return;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		return;
> +	}
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * @req:	pointer to the request of interest
> + *
> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);

You didn't do as I described. Did you try to compile this? It'll throw a
warning because of the pointer -> unsigned long cast. You need an extra
function to convert this cleanly. A cast would do of course, but I think
the extra function is a lot cleaner.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09  5:36     ` [RFC] [PATCH 1/1] " malahal
  2007-10-09  9:14       ` Jens Axboe
@ 2007-10-09 12:00       ` Matthew Wilcox
  2007-10-09 12:15         ` Jens Axboe
  1 sibling, 1 reply; 26+ messages in thread
From: Matthew Wilcox @ 2007-10-09 12:00 UTC (permalink / raw)
  To: Jens Axboe, linux-scsi

On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> Thank you Randy, Jens for your suggestions. I folded the second patch as
> it is just a clean up. Here is the fixed one patch version.

I was thinking about this (in the context of shrinking scsi_cmnd --
obviously, things are not improved if we simply move the timer to request
instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
need one per network packet.  I appreciate we had one per scsi_cmnd and
this patch is just moving it upwards in the hierarchy, but perhaps we
can do better.

What if we have one timer per request queue instead?  It needs to expire
as soon as the earliest request timer would expire, then needs to be
reset to the next earliest one.  We might walk the request queue more
frequently, but we'd save 48 bytes in the struct request.

-- 
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09 12:00       ` Matthew Wilcox
@ 2007-10-09 12:15         ` Jens Axboe
  2007-10-09 15:56           ` James Bottomley
  0 siblings, 1 reply; 26+ messages in thread
From: Jens Axboe @ 2007-10-09 12:15 UTC (permalink / raw)
  To: Matthew Wilcox; +Cc: linux-scsi

On Tue, Oct 09 2007, Matthew Wilcox wrote:
> On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > it is just a clean up. Here is the fixed one patch version.
> 
> I was thinking about this (in the context of shrinking scsi_cmnd --
> obviously, things are not improved if we simply move the timer to request
> instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> need one per network packet.  I appreciate we had one per scsi_cmnd and
> this patch is just moving it upwards in the hierarchy, but perhaps we
> can do better.
> 
> What if we have one timer per request queue instead?  It needs to expire
> as soon as the earliest request timer would expire, then needs to be
> reset to the next earliest one.  We might walk the request queue more
> frequently, but we'd save 48 bytes in the struct request.

I agree, adding a full timer to each request is not nice. You jump over
the actual implementation details of having just one timer in the queue
though, it's pretty cheap to just say it can be done :-). You need to
track each request anyways. If all drivers used the block layer tagging
it would be easy since we are tracking each pending request in that
case, but right now they don't. So pending requests may very well be
outside of block layer knowledge.

You'd also end up using lots of extra cycles to find and move the timer
when it expires (not likely) or is deleted (most likely). I'd greatly
prefer the space overhead in this case, even if it is quite costly.

There's also the issue of fiddling with just one vs many timers,
potentially more cache bouncy.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09  9:14       ` Jens Axboe
@ 2007-10-09 14:26         ` malahal
  0 siblings, 0 replies; 26+ messages in thread
From: malahal @ 2007-10-09 14:26 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-scsi

Here is another attempt! Thank you.


diff -r 1b51503899a0 block/ll_rw_blk.c
--- a/block/ll_rw_blk.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/block/ll_rw_blk.c	Tue Oct 09 07:00:51 2007 -0700
@@ -181,6 +181,18 @@ void blk_queue_softirq_done(struct reque
 
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -243,7 +255,9 @@ static void rq_init(struct request_queue
 {
 	INIT_LIST_HEAD(&rq->queuelist);
 	INIT_LIST_HEAD(&rq->donelist);
-
+	init_timer(&rq->timer);
+
+	rq->timeout = 0;
 	rq->errors = 0;
 	rq->bio = rq->biotail = NULL;
 	INIT_HLIST_NODE(&rq->hash);
@@ -2305,6 +2319,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -3647,8 +3662,109 @@ static struct notifier_block blk_cpu_not
 };
 
 /**
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
+ *
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ */
+int blk_delete_timer(struct request *req)
+{
+	if (!req->q->rq_timed_out_fn)
+		return 1;
+
+	return del_timer(&req->timer);
+}
+EXPORT_SYMBOL_GPL(blk_delete_timer);
+
+static void blk_rq_timed_out(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	switch (q->rq_timed_out_fn(req)) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		return;
+	case BLK_EH_RESET_TIMER:
+		blk_add_timer(req);
+		return;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		return;
+	}
+}
+
+static void blk_rq_timed_out_timer(unsigned long data)
+{
+	struct request *req = (struct request *)data;
+
+	blk_rq_timed_out(req);
+}
+
+/**
+ * blk_abort_req -- Request request recovery for the specified command
+ * @req:	pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req.
+ */
+void blk_abort_req(struct request *req)
+{
+        if (!blk_delete_timer(req))
+                return;
+        blk_rq_timed_out(req);
+}
+EXPORT_SYMBOL_GPL(blk_abort_req);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer.  When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+
+	req->timer.data = (unsigned long)req;
+	if (req->timeout)
+		req->timer.expires = jiffies + req->timeout;
+	else
+		req->timer.expires = jiffies + q->rq_timeout;
+	req->timer.function = blk_rq_timed_out_timer;
+	add_timer(&req->timer);
+}
+EXPORT_SYMBOL_GPL(blk_add_timer);
+
+void __blk_complete_request(struct request *req)
+{
+	struct list_head *cpu_list;
+	unsigned long flags;
+
+	BUG_ON(!req->q->softirq_done_fn);
+
+	local_irq_save(flags);
+
+	cpu_list = &__get_cpu_var(blk_cpu_done);
+	list_add_tail(&req->donelist, cpu_list);
+	raise_softirq_irqoff(BLOCK_SOFTIRQ);
+
+	local_irq_restore(flags);
+}
+
+/**
  * blk_complete_request - end I/O on a request
- * @req:      the request being processed
+ * @req:	the request being processed
  *
  * Description:
  *     Ends all I/O on a request. It does not handle partial completions,
@@ -3656,26 +3772,24 @@ static struct notifier_block blk_cpu_not
  *     through requeueing. The actual completion happens out-of-order,
  *     through a softirq handler. The user must have registered a completion
  *     callback through blk_queue_softirq_done().
- **/
-
+ */
 void blk_complete_request(struct request *req)
 {
-	struct list_head *cpu_list;
-	unsigned long flags;
-
-	BUG_ON(!req->q->softirq_done_fn);
-		
-	local_irq_save(flags);
-
-	cpu_list = &__get_cpu_var(blk_cpu_done);
-	list_add_tail(&req->donelist, cpu_list);
-	raise_softirq_irqoff(BLOCK_SOFTIRQ);
-
-	local_irq_restore(flags);
-}
-
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!blk_delete_timer(req))
+		return;
+
+	__blk_complete_request(req);
+}
 EXPORT_SYMBOL(blk_complete_request);
-	
+
 /*
  * queue lock must be held
  */
diff -r 1b51503899a0 drivers/ata/libata-eh.c
--- a/drivers/ata/libata-eh.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/ata/libata-eh.c	Mon Oct 08 21:57:34 2007 -0700
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -312,29 +313,29 @@ static void ata_eh_clear_action(struct a
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -765,7 +766,7 @@ void ata_qc_schedule_eh(struct ata_queue
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_req(qc->scsicmd->request);
 }
 
 /**
diff -r 1b51503899a0 drivers/ata/libata.h
--- a/drivers/ata/libata.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/ata/libata.h	Mon Oct 08 21:57:34 2007 -0700
@@ -149,7 +149,7 @@ extern int ata_bus_probe(struct ata_port
 extern int ata_bus_probe(struct ata_port *ap);
 
 /* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff -r 1b51503899a0 drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/aacraid/aachba.c	Mon Oct 08 21:57:34 2007 -0700
@@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff -r 1b51503899a0 drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/advansys.c	Mon Oct 08 21:57:34 2007 -0700
@@ -5859,7 +5859,7 @@ static void asc_prt_scsi_cmnd(struct scs
 	printk(" serial_number 0x%x, retries %d, allowed %d\n",
 	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-	printk(" timeout_per_command %d\n", s->timeout_per_command);
+	printk(" request timeout %d\n", s->request->timeout);
 
 	printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
 		s->scsi_done, s->done, s->host_scribble, s->result);
diff -r 1b51503899a0 drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/gdth.c	Mon Oct 08 21:57:34 2007 -0700
@@ -728,7 +728,6 @@ int __gdth_execute(struct scsi_device *s
     scp->device = sdev;
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->request_buffer = gdtcmd;
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
@@ -4944,7 +4943,7 @@ static int gdth_queuecommand(Scsi_Cmnd *
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
     else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
 
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
diff -r 1b51503899a0 drivers/scsi/gdth_proc.c
--- a/drivers/scsi/gdth_proc.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/gdth_proc.c	Mon Oct 08 21:57:34 2007 -0700
@@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum
 {
     int oldto;
 
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
+    oldto = scp->request->timeout;
+    scp->request->timeout = timeout;
 
     if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
+        del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) NULL;
+        scp->request->timer.expires = 0;
     } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
+        if (scp->request->timer.data != (unsigned long) NULL) 
+            del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) scp;
+        scp->request->timer.expires = jiffies + timeout;
+        add_timer(&scp->request->timer);
     }
 
     return oldto;
diff -r 1b51503899a0 drivers/scsi/ibmvscsi/ibmvscsi.c
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c	Mon Oct 08 21:57:34 2007 -0700
@@ -732,7 +732,7 @@ static int ibmvscsi_queuecommand(struct 
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff -r 1b51503899a0 drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/ide-scsi.c	Mon Oct 08 21:57:34 2007 -0700
@@ -812,7 +812,7 @@ static int idescsi_queue (struct scsi_cm
 	pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
 		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
diff -r 1b51503899a0 drivers/scsi/ipr.c
--- a/drivers/scsi/ipr.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/ipr.c	Mon Oct 08 21:57:34 2007 -0700
@@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct sc
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff -r 1b51503899a0 drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/ips.c	Mon Oct 08 21:57:34 2007 -0700
@@ -3862,7 +3862,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * 
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff -r 1b51503899a0 drivers/scsi/libsas/sas_ata.c
--- a/drivers/scsi/libsas/sas_ata.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/libsas/sas_ata.c	Mon Oct 08 21:57:34 2007 -0700
@@ -407,7 +407,7 @@ void sas_ata_task_abort(struct sas_task 
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_req(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff -r 1b51503899a0 drivers/scsi/libsas/sas_internal.h
--- a/drivers/scsi/libsas/sas_internal.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/libsas/sas_internal.h	Mon Oct 08 21:57:34 2007 -0700
@@ -55,7 +55,7 @@ int  sas_register_ports(struct sas_ha_st
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff -r 1b51503899a0 drivers/scsi/libsas/sas_scsi_host.c
--- a/drivers/scsi/libsas/sas_scsi_host.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/libsas/sas_scsi_host.c	Mon Oct 08 21:57:34 2007 -0700
@@ -654,43 +654,43 @@ out:
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *tas
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_req(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff -r 1b51503899a0 drivers/scsi/megaraid/megaraid_sas.c
--- a/drivers/scsi/megaraid/megaraid_sas.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/megaraid/megaraid_sas.c	Mon Oct 08 21:57:34 2007 -0700
@@ -969,7 +969,7 @@ static int megasas_generic_reset(struct 
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff -r 1b51503899a0 drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/ncr53c8xx.c	Mon Oct 08 21:57:34 2007 -0700
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff -r 1b51503899a0 drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/qla1280.c	Mon Oct 08 21:57:34 2007 -0700
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3167,7 +3167,7 @@ qla1280_32bit_start_scsi(struct scsi_qla
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff -r 1b51503899a0 drivers/scsi/qla4xxx/ql4_os.c
--- a/drivers/scsi/qla4xxx/ql4_os.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/qla4xxx/ql4_os.c	Mon Oct 08 21:57:34 2007 -0700
@@ -1565,7 +1565,7 @@ static int qla4xxx_eh_device_reset(struc
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
diff -r 1b51503899a0 drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi.c	Mon Oct 08 21:57:34 2007 -0700
@@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struc
 
 		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* 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);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		 * future requests should not occur until the device 
 		 * transitions out of the suspend state.
 		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
 
@@ -534,19 +539,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 		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.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
 
 	/*
 	 * Before we queue this command, check if the command
@@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	}
 	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
@@ -586,24 +581,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *
 	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
 	return rtn;
 }
-
-/**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
 
 /**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
@@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out any more.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /*
diff -r 1b51503899a0 drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi_error.c	Mon Oct 08 21:57:34 2007 -0700
@@ -113,69 +113,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *s
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -183,9 +122,11 @@ int scsi_delete_timer(struct scsi_cmnd *
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  **/
-void scsi_times_out(struct scsi_cmnd *scmd)
-{
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+enum blk_eh_timer_return scsi_times_out(struct request *req)
+{
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -197,22 +138,20 @@ void scsi_times_out(struct scsi_cmnd *sc
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
-	}
+		return BLK_EH_HANDLED;
+	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *
 	int rtn;
 
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
@@ -1678,8 +1616,6 @@ scsi_reset_provider(struct scsi_device *
 	scmd->cmd_len			= 0;
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
-
-	init_timer(&scmd->eh_timeout);
 
 	/*
 	 * Sometimes the command can get back into the timer chain,
diff -r 1b51503899a0 drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi_lib.c	Mon Oct 08 21:57:34 2007 -0700
@@ -159,6 +159,29 @@ int scsi_queue_insert(struct scsi_cmnd *
 	scsi_run_queue(q);
 
 	return 0;
+}
+
+/**
+ * scsi_queue_retry - Try inserting a command in the midlevel queue.
+ *
+ * @cmd:	command that we are adding to queue.
+ * @reason:	why we are inserting command to queue.
+ *
+ * Notes:       This is very similar to scsi_queue_insert except that we
+ *              call this function when we don't know if the blk layer timer
+ *              is active or not. We could implement this either by calling
+ *              blk_delete_timer and inserting in the midlevel queue if we
+ *              successfully delete the timer OR setting appropriate result
+ *              field in the cmd and letting it go through the normal done
+ *              routines which will retry the command. For now, We call
+ *              blk_delete_timer!
+ */
+void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
+{
+	if (blk_delete_timer(cmd->request)) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd, reason);
+	}
 }
 
 /**
@@ -1227,7 +1250,6 @@ int scsi_setup_blk_pc_cmnd(struct scsi_d
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	cmd->done = scsi_blk_pc_done;
 	return BLKPREP_OK;
 }
@@ -1455,16 +1477,25 @@ static void scsi_kill_request(struct req
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	__blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
+
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
 
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
@@ -1699,6 +1730,7 @@ struct request_queue *scsi_alloc_queue(s
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
diff -r 1b51503899a0 drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi_priv.h	Mon Oct 08 21:57:34 2007 -0700
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@ extern int scsi_dispatch_cmd(struct scsi
 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);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern void scsi_exit_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
@@ -67,6 +64,7 @@ extern int scsi_maybe_unblock_host(struc
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
diff -r 1b51503899a0 drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi_sysfs.c	Mon Oct 08 21:57:34 2007 -0700
@@ -480,12 +480,15 @@ sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -495,7 +498,7 @@ sdev_store_timeout (struct device *dev, 
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff -r 1b51503899a0 drivers/scsi/scsi_transport_fc.c
--- a/drivers/scsi/scsi_transport_fc.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/scsi_transport_fc.c	Mon Oct 08 21:57:34 2007 -0700
@@ -1921,15 +1921,15 @@ static int fc_vport_match(struct attribu
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
-
-	return EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
diff -r 1b51503899a0 drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/sd.c	Mon Oct 08 21:57:34 2007 -0700
@@ -337,7 +337,6 @@ static int sd_prep_fn(struct request_que
 	struct gendisk *disk = rq->rq_disk;
 	sector_t block = rq->sector;
 	unsigned int this_count = rq->nr_sectors;
-	unsigned int timeout = sdp->timeout;
 	int ret;
 
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -506,7 +505,6 @@ static int sd_prep_fn(struct request_que
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -1633,11 +1631,12 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	class_device_initialize(&sdkp->cdev);
diff -r 1b51503899a0 drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/sr.c	Mon Oct 08 21:57:34 2007 -0700
@@ -306,7 +306,7 @@ static void rw_intr(struct scsi_cmnd * S
 
 static int sr_prep_fn(struct request_queue *q, struct request *rq)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block=0, this_count, s_size;
 	struct scsi_cd *cd;
 	struct scsi_cmnd *SCpnt;
 	struct scsi_device *sdp = q->queuedata;
@@ -435,7 +435,6 @@ static int sr_prep_fn(struct request_que
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -599,6 +598,8 @@ static int sr_probe(struct device *dev)
 	sprintf(disk->disk_name, "sr%d", minor);
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
+
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
 
 	cd->device = sdev;
 	cd->disk = disk;
diff -r 1b51503899a0 drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Thu Sep 27 00:25:15 2007 -0700
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon Oct 08 21:57:34 2007 -0700
@@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struc
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff -r 1b51503899a0 include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/include/linux/blkdev.h	Mon Oct 08 21:57:34 2007 -0700
@@ -309,6 +309,7 @@ struct request {
 	void *data;
 	void *sense;
 
+	struct timer_list timer;
 	unsigned int timeout;
 	int retries;
 
@@ -346,6 +347,14 @@ typedef int (merge_bvec_fn) (struct requ
 typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *);
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
+
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -383,6 +392,7 @@ struct request_queue
 	merge_bvec_fn		*merge_bvec_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -452,6 +462,8 @@ struct request_queue
 
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
+
+	unsigned int		rq_timeout;
 
 	/*
 	 * sg stuff
@@ -747,6 +759,10 @@ extern void end_queued_request(struct re
 extern void end_queued_request(struct request *, int);
 extern void end_dequeued_request(struct request *, int);
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_req(struct request *);
+extern int blk_delete_timer(struct request *);
+extern void blk_add_timer(struct request *);
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -758,6 +774,8 @@ extern void blk_complete_request(struct 
 
 static inline void blkdev_dequeue_request(struct request *req)
 {
+	if (req->q->rq_timed_out_fn)
+		blk_add_timer(req);
 	elv_dequeue_request(req->q, req);
 }
 
@@ -781,6 +799,8 @@ extern void blk_queue_merge_bvec(struct 
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern int blk_do_ordered(struct request_queue *, struct request **);
diff -r 1b51503899a0 include/scsi/scsi_cmnd.h
--- a/include/scsi/scsi_cmnd.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/include/scsi/scsi_cmnd.h	Mon Oct 08 21:57:34 2007 -0700
@@ -57,7 +57,6 @@ struct scsi_cmnd {
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -67,7 +66,6 @@ struct scsi_cmnd {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	unsigned request_bufflen;	/* Actual request size */
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 	void *request_buffer;		/* Actual requested buffer */
 
 	/* These elements define the operation we ultimately want to perform */
@@ -127,7 +125,6 @@ extern void __scsi_put_command(struct Sc
 			       struct device *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff -r 1b51503899a0 include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/include/scsi/scsi_host.h	Mon Oct 08 21:57:34 2007 -0700
@@ -41,13 +41,6 @@ struct blk_queue_tags;
 
 #define DISABLE_SG_CHAINING 0
 #define ENABLE_SG_CHAINING 1
-
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
 
 struct scsi_host_template {
 	struct module *module;
@@ -339,7 +332,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff -r 1b51503899a0 include/scsi/scsi_transport.h
--- a/include/scsi/scsi_transport.h	Thu Sep 27 00:25:15 2007 -0700
+++ b/include/scsi/scsi_transport.h	Mon Oct 08 21:57:34 2007 -0700
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@ struct scsi_transport_template {
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Used as callback for the completion of i_t_nexus request

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09 12:15         ` Jens Axboe
@ 2007-10-09 15:56           ` James Bottomley
  2007-10-09 17:23             ` malahal
  2007-10-10 12:25             ` Jens Axboe
  0 siblings, 2 replies; 26+ messages in thread
From: James Bottomley @ 2007-10-09 15:56 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Matthew Wilcox, linux-scsi

On Tue, 2007-10-09 at 14:15 +0200, Jens Axboe wrote:
> On Tue, Oct 09 2007, Matthew Wilcox wrote:
> > On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > > it is just a clean up. Here is the fixed one patch version.
> > 
> > I was thinking about this (in the context of shrinking scsi_cmnd --
> > obviously, things are not improved if we simply move the timer to request
> > instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> > need one per network packet.  I appreciate we had one per scsi_cmnd and
> > this patch is just moving it upwards in the hierarchy, but perhaps we
> > can do better.
> > 
> > What if we have one timer per request queue instead?  It needs to expire
> > as soon as the earliest request timer would expire, then needs to be
> > reset to the next earliest one.  We might walk the request queue more
> > frequently, but we'd save 48 bytes in the struct request.
> 
> I agree, adding a full timer to each request is not nice. You jump over
> the actual implementation details of having just one timer in the queue
> though, it's pretty cheap to just say it can be done :-). You need to
> track each request anyways. If all drivers used the block layer tagging
> it would be easy since we are tracking each pending request in that
> case, but right now they don't. So pending requests may very well be
> outside of block layer knowledge.

Can't we handle this a bit like the Linux timer infrastructure?  Instead
of a timer per cmnd we have one per queue that's reset by commands
returning?  If we retained a linked list of commands in timer order and
expiry times, that's still going to save us an unsigned long and two
pointers over struct timer_list.

> You'd also end up using lots of extra cycles to find and move the timer
> when it expires (not likely) or is deleted (most likely). I'd greatly
> prefer the space overhead in this case, even if it is quite costly.

If there's another command on the linked list, you mod_timer otherwise
you del_timer_sync.  Returning commands obviously delete from this list.

> There's also the issue of fiddling with just one vs many timers,
> potentially more cache bouncy.

Yes, I agree it's more fiddly.

The beauty is that I think it can all be done at the block layer via
helpers ... so it becomes Somebody Else's Problem from the SCSI point of
view ...

James


James



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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09 15:56           ` James Bottomley
@ 2007-10-09 17:23             ` malahal
  2007-10-10 12:25             ` Jens Axboe
  1 sibling, 0 replies; 26+ messages in thread
From: malahal @ 2007-10-09 17:23 UTC (permalink / raw)
  To: James Bottomley; +Cc: Jens Axboe, Matthew Wilcox, linux-scsi

If we don't need precise timeout, we can have one single timer running
at regular intervals, say every second. We also record the exact number
of requests that are supposed to be done in a particular interval. This
is done by computing the 'interval index' of a request, incrementing it
when we send the request and decrementing the same when the request is
completed. Timer can detect if all requests are done for that interval
by looking at the 'interval number'

In this method, timer can detect a timeout but doesn't know which
command has timed out though. Aborting all pending requests is one
option. As we don't start timer for each request, there is no need to
stop any timer when the request is done.

Thanks, Malahal.

James Bottomley [James.Bottomley@SteelEye.com] wrote:
> On Tue, 2007-10-09 at 14:15 +0200, Jens Axboe wrote:
> > On Tue, Oct 09 2007, Matthew Wilcox wrote:
> > > On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > > > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > > > it is just a clean up. Here is the fixed one patch version.
> > > 
> > > I was thinking about this (in the context of shrinking scsi_cmnd --
> > > obviously, things are not improved if we simply move the timer to request
> > > instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> > > need one per network packet.  I appreciate we had one per scsi_cmnd and
> > > this patch is just moving it upwards in the hierarchy, but perhaps we
> > > can do better.
> > > 
> > > What if we have one timer per request queue instead?  It needs to expire
> > > as soon as the earliest request timer would expire, then needs to be
> > > reset to the next earliest one.  We might walk the request queue more
> > > frequently, but we'd save 48 bytes in the struct request.
> > 
> > I agree, adding a full timer to each request is not nice. You jump over
> > the actual implementation details of having just one timer in the queue
> > though, it's pretty cheap to just say it can be done :-). You need to
> > track each request anyways. If all drivers used the block layer tagging
> > it would be easy since we are tracking each pending request in that
> > case, but right now they don't. So pending requests may very well be
> > outside of block layer knowledge.
> 
> Can't we handle this a bit like the Linux timer infrastructure?  Instead
> of a timer per cmnd we have one per queue that's reset by commands
> returning?  If we retained a linked list of commands in timer order and
> expiry times, that's still going to save us an unsigned long and two
> pointers over struct timer_list.
> 
> > You'd also end up using lots of extra cycles to find and move the timer
> > when it expires (not likely) or is deleted (most likely). I'd greatly
> > prefer the space overhead in this case, even if it is quite costly.
> 
> If there's another command on the linked list, you mod_timer otherwise
> you del_timer_sync.  Returning commands obviously delete from this list.
> 
> > There's also the issue of fiddling with just one vs many timers,
> > potentially more cache bouncy.
> 
> Yes, I agree it's more fiddly.
> 
> The beauty is that I think it can all be done at the block layer via
> helpers ... so it becomes Somebody Else's Problem from the SCSI point of
> view ...
> 
> James

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-09 15:56           ` James Bottomley
  2007-10-09 17:23             ` malahal
@ 2007-10-10 12:25             ` Jens Axboe
  2007-10-10 16:58               ` malahal
  2007-10-11 18:01               ` malahal
  1 sibling, 2 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-10 12:25 UTC (permalink / raw)
  To: James Bottomley; +Cc: Matthew Wilcox, linux-scsi, malahal

On Tue, Oct 09 2007, James Bottomley wrote:
> On Tue, 2007-10-09 at 14:15 +0200, Jens Axboe wrote:
> > On Tue, Oct 09 2007, Matthew Wilcox wrote:
> > > On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > > > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > > > it is just a clean up. Here is the fixed one patch version.
> > > 
> > > I was thinking about this (in the context of shrinking scsi_cmnd --
> > > obviously, things are not improved if we simply move the timer to request
> > > instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> > > need one per network packet.  I appreciate we had one per scsi_cmnd and
> > > this patch is just moving it upwards in the hierarchy, but perhaps we
> > > can do better.
> > > 
> > > What if we have one timer per request queue instead?  It needs to expire
> > > as soon as the earliest request timer would expire, then needs to be
> > > reset to the next earliest one.  We might walk the request queue more
> > > frequently, but we'd save 48 bytes in the struct request.
> > 
> > I agree, adding a full timer to each request is not nice. You jump over
> > the actual implementation details of having just one timer in the queue
> > though, it's pretty cheap to just say it can be done :-). You need to
> > track each request anyways. If all drivers used the block layer tagging
> > it would be easy since we are tracking each pending request in that
> > case, but right now they don't. So pending requests may very well be
> > outside of block layer knowledge.
> 
> Can't we handle this a bit like the Linux timer infrastructure?  Instead
> of a timer per cmnd we have one per queue that's reset by commands
> returning?  If we retained a linked list of commands in timer order and
> expiry times, that's still going to save us an unsigned long and two
> pointers over struct timer_list.

Here's an approach that uses a single timer. I purposely do not sort
commands in expiry times, as that would introduce an O(N) operation far
out weighing the IO scheduling cost, pretty silly for a timeout
mechanism that supposedly should never trigger. Or we could waste more
memory and fewer cycles (but still far more cycles than we need) by
sorting in some sort of tree.

So I don't sort the list, instead I push the cost of locating expired
request to the timeout handler. It should really only run, when a
request times out. Timeout is then reset to next command timeout
(rounded), if further commands exist. It also doesn't fiddle with the
timer unless an incoming command has a lower timeout than the current
one.

Totally untested...

diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index ed39313..cb3210a 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -42,6 +42,7 @@ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
 static void init_request_from_bio(struct request *req, struct bio *bio);
 static int __make_request(struct request_queue *q, struct bio *bio);
 static struct io_context *current_io_context(gfp_t gfp_flags, int node);
+static void blk_rq_timed_out_timer(unsigned long);
 
 /*
  * For the allocated request tables
@@ -177,6 +178,18 @@ void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
 
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -239,7 +252,9 @@ static void rq_init(struct request_queue *q, struct request *rq)
 {
 	INIT_LIST_HEAD(&rq->queuelist);
 	INIT_LIST_HEAD(&rq->donelist);
+	INIT_LIST_HEAD(&rq->timeout_list);
 
+	rq->timeout = 0;
 	rq->errors = 0;
 	rq->bio = rq->biotail = NULL;
 	INIT_HLIST_NODE(&rq->hash);
@@ -1851,6 +1866,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 		return NULL;
 
 	init_timer(&q->unplug_timer);
+	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
+	INIT_LIST_HEAD(&q->timeout_list);
 
 	snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
 	q->kobj.ktype = &queue_ktype;
@@ -2271,6 +2288,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -3600,24 +3618,132 @@ static struct notifier_block __devinitdata blk_cpu_notifier = {
 };
 
 /**
- * blk_complete_request - end I/O on a request
- * @req:      the request being processed
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
  *
- * Description:
- *     Ends all I/O on a request. It does not handle partial completions,
- *     unless the driver actually implements this in its completion callback
- *     through requeueing. Theh actual completion happens out-of-order,
- *     through a softirq handler. The user must have registered a completion
- *     callback through blk_queue_softirq_done().
- **/
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ */
+int blk_delete_timer(struct request *req)
+{
+	if (!req->q->rq_timed_out_fn)
+		return 1;
 
-void blk_complete_request(struct request *req)
+	if (!list_empty(&req->timeout_list)) {
+		list_del_init(&req->timeout_list);
+		return 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(blk_delete_timer);
+
+static void blk_rq_timed_out(struct request *req)
+{
+	struct request_queue *q = req->q;
+	enum blk_eh_timer_return ret;
+
+	ret = q->rq_timed_out_fn(req);
+	switch (ret) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		break;
+	case BLK_EH_RESET_TIMER:
+		blk_add_timer(req);
+		break;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		break;
+	default:
+		printk(KERN_ERR "block: bad eh return: %d\n", ret);
+		break;
+	}
+}
+
+static void blk_rq_timed_out_timer(unsigned long data)
+{
+	struct request_queue *q = (struct request_queue *) data;
+	unsigned long flags, next = 0;
+	struct request *rq, *tmp;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) {
+		if (!next || time_before(next, rq->timeout))
+			next = rq->timeout;
+		if (time_after_eq(jiffies, rq->timeout))
+			blk_rq_timed_out(rq);
+	}
+
+	if (next)
+		mod_timer(&q->timeout, round_jiffies(next));
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/**
+ * blk_abort_req -- Request request recovery for the specified command
+ * @req:	pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req.
+ */
+void blk_abort_req(struct request *req)
+{
+        if (!blk_delete_timer(req))
+                return;
+        blk_rq_timed_out(req);
+}
+EXPORT_SYMBOL_GPL(blk_abort_req);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer.  When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+	unsigned long expiry;
+
+	BUG_ON(!list_empty(&req->timeout_list));
+
+	if (req->timeout)
+		expiry = jiffies + req->timeout;
+	else
+		expiry = jiffies + q->rq_timeout;
+
+	req->timeout = expiry;
+	list_add_tail(&req->timeout_list, &q->timeout_list);
+
+	/*
+	 * This is for timeout purposes, round to next second
+	 */
+	expiry = round_jiffies(expiry);
+
+	if (!timer_pending(&q->timeout) || time_before(expiry, q->timeout.expires))
+		mod_timer(&q->timeout, expiry);
+}
+EXPORT_SYMBOL_GPL(blk_add_timer);
+
+void __blk_complete_request(struct request *req)
 {
 	struct list_head *cpu_list;
 	unsigned long flags;
 
 	BUG_ON(!req->q->softirq_done_fn);
-		
+
 	local_irq_save(flags);
 
 	cpu_list = &__get_cpu_var(blk_cpu_done);
@@ -3627,8 +3753,34 @@ void blk_complete_request(struct request *req)
 	local_irq_restore(flags);
 }
 
+/**
+ * blk_complete_request - end I/O on a request
+ * @req:	the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions,
+ *     unless the driver actually implements this in its completion callback
+ *     through requeueing. Theh actual completion happens out-of-order,
+ *     through a softirq handler. The user must have registered a completion
+ *     callback through blk_queue_softirq_done().
+ */
+void blk_complete_request(struct request *req)
+{
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!blk_delete_timer(req))
+		return;
+
+	__blk_complete_request(req);
+}
 EXPORT_SYMBOL(blk_complete_request);
-	
+
 /*
  * queue lock must be held
  */
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ac6ceed..017a236 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -244,29 +245,29 @@ static void ata_eh_clear_action(struct ata_device *dev,
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -692,7 +693,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_req(qc->scsicmd->request);
 }
 
 /**
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 564cd23..6021b9c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -148,7 +148,7 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 
 /* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6800e57..6fa65c8 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 79c0b6e..d139075 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7901,7 +7901,7 @@ static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
 	printk(" serial_number 0x%x, retries %d, allowed %d\n",
 	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-	printk(" timeout_per_command %d\n", s->timeout_per_command);
+	printk(" request timeout %d\n", s->request->timeout);
 
 	printk
 	    (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 55e4d2d..c5fc436 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -733,7 +733,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
     scp->device = sdev;
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->request_buffer = gdtcmd;
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
@@ -4948,7 +4947,7 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
     else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
 
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 32982eb..22a9013 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
 {
     int oldto;
 
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
+    oldto = scp->request->timeout;
+    scp->request->timeout = timeout;
 
     if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
+        del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) NULL;
+        scp->request->timer.expires = 0;
     } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
+        if (scp->request->timer.data != (unsigned long) NULL) 
+            del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) scp;
+        scp->request->timer.expires = jiffies + timeout;
+        add_timer(&scp->request->timer);
     }
 
     return oldto;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5ecc63d..04dbe3b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -726,7 +726,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1cc01ac..2035923 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -916,7 +916,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eaf..b351f14 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 492a51b..c81dd8f 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -3860,7 +3860,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5e573ef..f3ae2df 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -408,7 +408,7 @@ void sas_ata_task_abort(struct sas_task *task)
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_req(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 2b8213b..13ac4a3 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7663841..6d6867c 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -654,43 +654,43 @@ out:
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *task)
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_req(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index ebb948c..84c0eb4 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -969,7 +969,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 030ba49..39c2d4b 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 54d8bdf..f5d5b2a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index b1d565c..005eb66 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1564,7 +1564,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a5de1a8..e67eb6e 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 
 		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* 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);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 		 * future requests should not occur until the device 
 		 * transitions out of the suspend state.
 		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
 
@@ -534,21 +539,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 		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.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
-
-	/*
 	 * Before we queue this command, check if the command
 	 * length exceeds what the host adapter can handle.
 	 */
@@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	}
 	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
@@ -588,24 +583,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 }
 
 /**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
-
-/**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out any more.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /*
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8a525ab..4475648 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  **/
-void scsi_times_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return scsi_times_out(struct request *req)
 {
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd)
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
+		return BLK_EH_HANDLED;
 	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 	int rtn;
 
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
@@ -1679,8 +1617,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
 
-	init_timer(&scmd->eh_timeout);
-
 	/*
 	 * Sometimes the command can get back into the timer chain,
 	 * so use the pid as an identifier.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a417a6f..d9c7581 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -162,6 +162,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
 }
 
 /**
+ * scsi_queue_retry - Try inserting a command in the midlevel queue.
+ *
+ * @cmd:	command that we are adding to queue.
+ * @reason:	why we are inserting command to queue.
+ *
+ * Notes:       This is very similar to scsi_queue_insert except that we
+ *              call this function when we don't know if the blk layer timer
+ *              is active or not. We could implement this either by calling
+ *              blk_delete_timer and inserting in the midlevel queue if we
+ *              successfully delete the timer OR setting appropriate result
+ *              field in the cmd and letting it go through the normal done
+ *              routines which will retry the command. For now, We call
+ *              blk_delete_timer!
+ */
+void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
+{
+	if (blk_delete_timer(cmd->request)) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd, reason);
+	}
+}
+
+/**
  * scsi_execute - insert request and wait for the result
  * @sdev:	scsi device
  * @cmd:	scsi command
@@ -1115,7 +1138,6 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	cmd->done = scsi_blk_pc_done;
 	return BLKPREP_OK;
 }
@@ -1354,17 +1376,26 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	__blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
 
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
+
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
 	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
@@ -1581,6 +1612,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index ee8efe8..4c29a95 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void);
 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);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
@@ -67,6 +64,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 34cdce6..59d1570 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -443,12 +443,15 @@ sdev_rd_attr (vendor, "%.8s\n");
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -458,7 +461,7 @@ sdev_store_timeout (struct device *dev, struct device_attribute *attr, const cha
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 4705725..0aef522 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1920,15 +1920,15 @@ static int fc_vport_match(struct attribute_container *cont,
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116f..7720698 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -338,7 +338,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
 	struct gendisk *disk = rq->rq_disk;
 	sector_t block = rq->sector;
 	unsigned int this_count = SCpnt->request_bufflen >> 9;
-	unsigned int timeout = sdp->timeout;
 
 	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
 					"sd_init_command: block=%llu, "
@@ -489,7 +488,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -1629,11 +1627,12 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	class_device_initialize(&sdkp->cdev);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 902eb11..cb73d58 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -298,7 +298,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
 
 static int sr_init_command(struct scsi_cmnd * SCpnt)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block=0, this_count, s_size;
 	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
 
 	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
@@ -407,7 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -570,6 +569,8 @@ static int sr_probe(struct device *dev)
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
 
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
+
 	cd->device = sdev;
 	cd->disk = disk;
 	cd->driver = &sr_template;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 3db2232..702f730 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index b126c6f..bb59cdb 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -309,7 +309,8 @@ struct request {
 	void *data;
 	void *sense;
 
-	unsigned int timeout;
+	unsigned long timeout;
+	struct list_head timeout_list;
 	int retries;
 
 	/*
@@ -348,6 +349,14 @@ typedef int (issue_flush_fn) (struct request_queue *, struct gendisk *, sector_t
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
 
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
+
 enum blk_queue_state {
 	Queue_down,
 	Queue_up,
@@ -385,6 +394,7 @@ struct request_queue
 	issue_flush_fn		*issue_flush_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -455,6 +465,10 @@ struct request_queue
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
 
+	unsigned int		rq_timeout;
+	struct			timer_list timeout;
+	struct list_head	timeout_list;
+
 	/*
 	 * sg stuff
 	 */
@@ -733,6 +747,10 @@ extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *, int);
 extern void end_request(struct request *req, int uptodate);
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_req(struct request *);
+extern int blk_delete_timer(struct request *);
+extern void blk_add_timer(struct request *);
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -744,6 +762,8 @@ extern void blk_complete_request(struct request *);
 
 static inline void blkdev_dequeue_request(struct request *req)
 {
+	if (req->q->rq_timed_out_fn)
+		blk_add_timer(req);
 	elv_dequeue_request(req->q, req);
 }
 
@@ -767,6 +787,8 @@ extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern void blk_queue_issue_flush_fn(struct request_queue *, issue_flush_fn *);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 53e1705..5841369 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -56,7 +56,6 @@ struct scsi_cmnd {
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -66,7 +65,6 @@ struct scsi_cmnd {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	unsigned request_bufflen;	/* Actual request size */
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 	void *request_buffer;		/* Actual requested buffer */
 
 	/* These elements define the operation we ultimately want to perform */
@@ -126,7 +124,6 @@ extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
 			       struct device *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 3b8a6a8..165ccaf 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -36,13 +36,6 @@ struct blk_queue_tags;
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
 
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
-
 struct scsi_host_template {
 	struct module *module;
 	const char *name;
@@ -336,7 +329,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index 3c18baa..23e8d97 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@ struct scsi_transport_template {
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 };
 
 #define transport_class_to_shost(tc) \

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-10 12:25             ` Jens Axboe
@ 2007-10-10 16:58               ` malahal
  2007-10-10 17:04                 ` Jens Axboe
  2007-10-11 18:01               ` malahal
  1 sibling, 1 reply; 26+ messages in thread
From: malahal @ 2007-10-10 16:58 UTC (permalink / raw)
  To: Jens Axboe; +Cc: James Bottomley, Matthew Wilcox, linux-scsi

I don't see blk_delete_timer() actually calling mod_timer/del_timer at
all.  Doesn't that mean, your timer would eventually expire for no
reason and walk through the list unnecessarily?

Thanks, Malahal.

Jens Axboe [jens.axboe@oracle.com] wrote:
> On Tue, Oct 09 2007, James Bottomley wrote:
> > On Tue, 2007-10-09 at 14:15 +0200, Jens Axboe wrote:
> > > On Tue, Oct 09 2007, Matthew Wilcox wrote:
> > > > On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > > > > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > > > > it is just a clean up. Here is the fixed one patch version.
> > > > 
> > > > I was thinking about this (in the context of shrinking scsi_cmnd --
> > > > obviously, things are not improved if we simply move the timer to request
> > > > instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> > > > need one per network packet.  I appreciate we had one per scsi_cmnd and
> > > > this patch is just moving it upwards in the hierarchy, but perhaps we
> > > > can do better.
> > > > 
> > > > What if we have one timer per request queue instead?  It needs to expire
> > > > as soon as the earliest request timer would expire, then needs to be
> > > > reset to the next earliest one.  We might walk the request queue more
> > > > frequently, but we'd save 48 bytes in the struct request.
> > > 
> > > I agree, adding a full timer to each request is not nice. You jump over
> > > the actual implementation details of having just one timer in the queue
> > > though, it's pretty cheap to just say it can be done :-). You need to
> > > track each request anyways. If all drivers used the block layer tagging
> > > it would be easy since we are tracking each pending request in that
> > > case, but right now they don't. So pending requests may very well be
> > > outside of block layer knowledge.
> > 
> > Can't we handle this a bit like the Linux timer infrastructure?  Instead
> > of a timer per cmnd we have one per queue that's reset by commands
> > returning?  If we retained a linked list of commands in timer order and
> > expiry times, that's still going to save us an unsigned long and two
> > pointers over struct timer_list.
> 
> Here's an approach that uses a single timer. I purposely do not sort
> commands in expiry times, as that would introduce an O(N) operation far
> out weighing the IO scheduling cost, pretty silly for a timeout
> mechanism that supposedly should never trigger. Or we could waste more
> memory and fewer cycles (but still far more cycles than we need) by
> sorting in some sort of tree.
> 
> So I don't sort the list, instead I push the cost of locating expired
> request to the timeout handler. It should really only run, when a
> request times out. Timeout is then reset to next command timeout
> (rounded), if further commands exist. It also doesn't fiddle with the
> timer unless an incoming command has a lower timeout than the current
> one.
> 
> Totally untested...
> 
> diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
> index ed39313..cb3210a 100644
> --- a/block/ll_rw_blk.c
> +++ b/block/ll_rw_blk.c
> @@ -42,6 +42,7 @@ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
>  static void init_request_from_bio(struct request *req, struct bio *bio);
>  static int __make_request(struct request_queue *q, struct bio *bio);
>  static struct io_context *current_io_context(gfp_t gfp_flags, int node);
> +static void blk_rq_timed_out_timer(unsigned long);
> 
>  /*
>   * For the allocated request tables
> @@ -177,6 +178,18 @@ void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
> 
>  EXPORT_SYMBOL(blk_queue_softirq_done);
> 
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -239,7 +252,9 @@ static void rq_init(struct request_queue *q, struct request *rq)
>  {
>  	INIT_LIST_HEAD(&rq->queuelist);
>  	INIT_LIST_HEAD(&rq->donelist);
> +	INIT_LIST_HEAD(&rq->timeout_list);
> 
> +	rq->timeout = 0;
>  	rq->errors = 0;
>  	rq->bio = rq->biotail = NULL;
>  	INIT_HLIST_NODE(&rq->hash);
> @@ -1851,6 +1866,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
>  		return NULL;
> 
>  	init_timer(&q->unplug_timer);
> +	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
> +	INIT_LIST_HEAD(&q->timeout_list);
> 
>  	snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
>  	q->kobj.ktype = &queue_ktype;
> @@ -2271,6 +2288,7 @@ EXPORT_SYMBOL(blk_start_queueing);
>   */
>  void blk_requeue_request(struct request_queue *q, struct request *rq)
>  {
> +	blk_delete_timer(rq);
>  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
> 
>  	if (blk_rq_tagged(rq))
> @@ -3600,24 +3618,132 @@ static struct notifier_block __devinitdata blk_cpu_notifier = {
>  };
> 
>  /**
> - * blk_complete_request - end I/O on a request
> - * @req:      the request being processed
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
>   *
> - * Description:
> - *     Ends all I/O on a request. It does not handle partial completions,
> - *     unless the driver actually implements this in its completion callback
> - *     through requeueing. Theh actual completion happens out-of-order,
> - *     through a softirq handler. The user must have registered a completion
> - *     callback through blk_queue_softirq_done().
> - **/
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + */
> +int blk_delete_timer(struct request *req)
> +{
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> 
> -void blk_complete_request(struct request *req)
> +	if (!list_empty(&req->timeout_list)) {
> +		list_del_init(&req->timeout_list);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +	enum blk_eh_timer_return ret;
> +
> +	ret = q->rq_timed_out_fn(req);
> +	switch (ret) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		break;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);
> +		break;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		break;
> +	default:
> +		printk(KERN_ERR "block: bad eh return: %d\n", ret);
> +		break;
> +	}
> +}
> +
> +static void blk_rq_timed_out_timer(unsigned long data)
> +{
> +	struct request_queue *q = (struct request_queue *) data;
> +	unsigned long flags, next = 0;
> +	struct request *rq, *tmp;
> +
> +	spin_lock_irqsave(q->queue_lock, flags);
> +
> +	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) {
> +		if (!next || time_before(next, rq->timeout))
> +			next = rq->timeout;
> +		if (time_after_eq(jiffies, rq->timeout))
> +			blk_rq_timed_out(rq);
> +	}
> +
> +	if (next)
> +		mod_timer(&q->timeout, round_jiffies(next));
> +
> +	spin_unlock_irqrestore(q->queue_lock, flags);
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * @req:	pointer to the request of interest
> + *
> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);
> +}
> +EXPORT_SYMBOL_GPL(blk_abort_req);
> +
> +/**
> + * blk_add_timer - Start timeout timer for a single request
> + * @req:	request that is about to start running.
> + *
> + * Notes:
> + *    Each request has its own timer, and as it is added to the queue, we
> + *    set up the timer.  When the request completes, we cancel the timer.
> + */
> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +	unsigned long expiry;
> +
> +	BUG_ON(!list_empty(&req->timeout_list));
> +
> +	if (req->timeout)
> +		expiry = jiffies + req->timeout;
> +	else
> +		expiry = jiffies + q->rq_timeout;
> +
> +	req->timeout = expiry;
> +	list_add_tail(&req->timeout_list, &q->timeout_list);
> +
> +	/*
> +	 * This is for timeout purposes, round to next second
> +	 */
> +	expiry = round_jiffies(expiry);
> +
> +	if (!timer_pending(&q->timeout) || time_before(expiry, q->timeout.expires))
> +		mod_timer(&q->timeout, expiry);
> +}
> +EXPORT_SYMBOL_GPL(blk_add_timer);
> +
> +void __blk_complete_request(struct request *req)
>  {
>  	struct list_head *cpu_list;
>  	unsigned long flags;
> 
>  	BUG_ON(!req->q->softirq_done_fn);
> -		
> +
>  	local_irq_save(flags);
> 
>  	cpu_list = &__get_cpu_var(blk_cpu_done);
> @@ -3627,8 +3753,34 @@ void blk_complete_request(struct request *req)
>  	local_irq_restore(flags);
>  }
> 
> +/**
> + * blk_complete_request - end I/O on a request
> + * @req:	the request being processed
> + *
> + * Description:
> + *     Ends all I/O on a request. It does not handle partial completions,
> + *     unless the driver actually implements this in its completion callback
> + *     through requeueing. Theh actual completion happens out-of-order,
> + *     through a softirq handler. The user must have registered a completion
> + *     callback through blk_queue_softirq_done().
> + */
> +void blk_complete_request(struct request *req)
> +{
> +	/*
> +	 * We don't have to worry about this one timing out any more.
> +	 * If we are unable to remove the timer, then the command
> +	 * has already timed out.  In which case, we have no choice but to
> +	 * let the timeout function run, as we have no idea where in fact
> +	 * that function could really be.  It might be on another processor,
> +	 * etc, etc.
> +	 */
> +	if (!blk_delete_timer(req))
> +		return;
> +
> +	__blk_complete_request(req);
> +}
>  EXPORT_SYMBOL(blk_complete_request);
> -	
> +
>  /*
>   * queue lock must be held
>   */
> diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
> index ac6ceed..017a236 100644
> --- a/drivers/ata/libata-eh.c
> +++ b/drivers/ata/libata-eh.c
> @@ -33,6 +33,7 @@
>   */
> 
>  #include <linux/kernel.h>
> +#include <linux/blkdev.h>
>  #include <scsi/scsi.h>
>  #include <scsi/scsi_host.h>
>  #include <scsi/scsi_eh.h>
> @@ -244,29 +245,29 @@ static void ata_eh_clear_action(struct ata_device *dev,
>   *	RETURNS:
>   *	EH_HANDLED or EH_NOT_HANDLED
>   */
> -enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
> +enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
>  {
>  	struct Scsi_Host *host = cmd->device->host;
>  	struct ata_port *ap = ata_shost_to_port(host);
>  	unsigned long flags;
>  	struct ata_queued_cmd *qc;
> -	enum scsi_eh_timer_return ret;
> +	enum blk_eh_timer_return ret;
> 
>  	DPRINTK("ENTER\n");
> 
>  	if (ap->ops->error_handler) {
> -		ret = EH_NOT_HANDLED;
> +		ret = BLK_EH_NOT_HANDLED;
>  		goto out;
>  	}
> 
> -	ret = EH_HANDLED;
> +	ret = BLK_EH_HANDLED;
>  	spin_lock_irqsave(ap->lock, flags);
>  	qc = ata_qc_from_tag(ap, ap->active_tag);
>  	if (qc) {
>  		WARN_ON(qc->scsicmd != cmd);
>  		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
>  		qc->err_mask |= AC_ERR_TIMEOUT;
> -		ret = EH_NOT_HANDLED;
> +		ret = BLK_EH_NOT_HANDLED;
>  	}
>  	spin_unlock_irqrestore(ap->lock, flags);
> 
> @@ -692,7 +693,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
>  	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
>  	 * this function completes.
>  	 */
> -	scsi_req_abort_cmd(qc->scsicmd);
> +	blk_abort_req(qc->scsicmd->request);
>  }
> 
>  /**
> diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
> index 564cd23..6021b9c 100644
> --- a/drivers/ata/libata.h
> +++ b/drivers/ata/libata.h
> @@ -148,7 +148,7 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
>  extern int ata_bus_probe(struct ata_port *ap);
> 
>  /* libata-eh.c */
> -extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
> +extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
>  extern void ata_scsi_error(struct Scsi_Host *host);
>  extern void ata_port_wait_eh(struct ata_port *ap);
>  extern void ata_eh_fastdrain_timerfn(unsigned long arg);
> diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
> index 6800e57..6fa65c8 100644
> --- a/drivers/scsi/aacraid/aachba.c
> +++ b/drivers/scsi/aacraid/aachba.c
> @@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
>  	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
>  	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
>  	srbcmd->flags    = cpu_to_le32(flag);
> -	timeout = cmd->timeout_per_command/HZ;
> +	timeout = cmd->request->timeout/HZ;
>  	if (timeout == 0)
>  		timeout = 1;
>  	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
> diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
> index 79c0b6e..d139075 100644
> --- a/drivers/scsi/advansys.c
> +++ b/drivers/scsi/advansys.c
> @@ -7901,7 +7901,7 @@ static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
>  	printk(" serial_number 0x%x, retries %d, allowed %d\n",
>  	       (unsigned)s->serial_number, s->retries, s->allowed);
> 
> -	printk(" timeout_per_command %d\n", s->timeout_per_command);
> +	printk(" request timeout %d\n", s->request->timeout);
> 
>  	printk
>  	    (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
> diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
> index 55e4d2d..c5fc436 100644
> --- a/drivers/scsi/gdth.c
> +++ b/drivers/scsi/gdth.c
> @@ -733,7 +733,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
>      scp->device = sdev;
>      /* use request field to save the ptr. to completion struct. */
>      scp->request = (struct request *)&wait;
> -    scp->timeout_per_command = timeout*HZ;
>      scp->request_buffer = gdtcmd;
>      scp->cmd_len = 12;
>      memcpy(scp->cmnd, cmnd, 12);
> @@ -4948,7 +4947,7 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
>      if (scp->done == gdth_scsi_done)
>          priority = scp->SCp.this_residual;
>      else
> -        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
> +        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
> 
>      gdth_putq( hanum, scp, priority );
>      gdth_next( hanum );
> diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
> index 32982eb..22a9013 100644
> --- a/drivers/scsi/gdth_proc.c
> +++ b/drivers/scsi/gdth_proc.c
> @@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
>  {
>      int oldto;
> 
> -    oldto = scp->timeout_per_command;
> -    scp->timeout_per_command = timeout;
> +    oldto = scp->request->timeout;
> +    scp->request->timeout = timeout;
> 
>      if (timeout == 0) {
> -        del_timer(&scp->eh_timeout);
> -        scp->eh_timeout.data = (unsigned long) NULL;
> -        scp->eh_timeout.expires = 0;
> +        del_timer(&scp->request->timer);
> +        scp->request->timer.data = (unsigned long) NULL;
> +        scp->request->timer.expires = 0;
>      } else {
> -        if (scp->eh_timeout.data != (unsigned long) NULL) 
> -            del_timer(&scp->eh_timeout);
> -        scp->eh_timeout.data = (unsigned long) scp;
> -        scp->eh_timeout.expires = jiffies + timeout;
> -        add_timer(&scp->eh_timeout);
> +        if (scp->request->timer.data != (unsigned long) NULL) 
> +            del_timer(&scp->request->timer);
> +        scp->request->timer.data = (unsigned long) scp;
> +        scp->request->timer.expires = jiffies + timeout;
> +        add_timer(&scp->request->timer);
>      }
> 
>      return oldto;
> diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
> index 5ecc63d..04dbe3b 100644
> --- a/drivers/scsi/ibmvscsi/ibmvscsi.c
> +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
> @@ -726,7 +726,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
>  	init_event_struct(evt_struct,
>  			  handle_cmd_rsp,
>  			  VIOSRP_SRP_FORMAT,
> -			  cmnd->timeout_per_command/HZ);
> +			  cmnd->request->timeout/HZ);
> 
>  	evt_struct->cmnd = cmnd;
>  	evt_struct->cmnd_done = done;
> diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
> index 1cc01ac..2035923 100644
> --- a/drivers/scsi/ide-scsi.c
> +++ b/drivers/scsi/ide-scsi.c
> @@ -916,7 +916,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
>  	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
>  	pc->scsi_cmd = cmd;
>  	pc->done = done;
> -	pc->timeout = jiffies + cmd->timeout_per_command;
> +	pc->timeout = jiffies + cmd->request->timeout;
> 
>  	if (should_transform(drive, cmd))
>  		set_bit(PC_TRANSFORM, &pc->flags);
> diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
> index f142eaf..b351f14 100644
> --- a/drivers/scsi/ipr.c
> +++ b/drivers/scsi/ipr.c
> @@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
>  			sdev->no_uld_attach = 1;
>  		}
>  		if (ipr_is_vset_device(res)) {
> -			sdev->timeout = IPR_VSET_RW_TIMEOUT;
> +			blk_queue_rq_timeout(sdev->request_queue,
> +					     IPR_VSET_RW_TIMEOUT);
>  			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
>  		}
>  		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
> diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
> index 492a51b..c81dd8f 100644
> --- a/drivers/scsi/ips.c
> +++ b/drivers/scsi/ips.c
> @@ -3860,7 +3860,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
>  		scb->cmd.dcdb.segment_4G = 0;
>  		scb->cmd.dcdb.enhanced_sg = 0;
> 
> -		TimeOut = scb->scsi_cmd->timeout_per_command;
> +		TimeOut = scb->scsi_cmd->request->timeout;
> 
>  		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
>  			if (!scb->sg_len) {
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 5e573ef..f3ae2df 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -408,7 +408,7 @@ void sas_ata_task_abort(struct sas_task *task)
> 
>  	/* Bounce SCSI-initiated commands to the SCSI EH */
>  	if (qc->scsicmd) {
> -		scsi_req_abort_cmd(qc->scsicmd);
> +		blk_abort_req(qc->scsicmd->request);
>  		scsi_schedule_eh(qc->scsicmd->device->host);
>  		return;
>  	}
> diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
> index 2b8213b..13ac4a3 100644
> --- a/drivers/scsi/libsas/sas_internal.h
> +++ b/drivers/scsi/libsas/sas_internal.h
> @@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
>  int  sas_register_ports(struct sas_ha_struct *sas_ha);
>  void sas_unregister_ports(struct sas_ha_struct *sas_ha);
> 
> -enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
> +enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
> 
>  int  sas_init_queue(struct sas_ha_struct *sas_ha);
>  int  sas_init_events(struct sas_ha_struct *sas_ha);
> diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
> index 7663841..6d6867c 100644
> --- a/drivers/scsi/libsas/sas_scsi_host.c
> +++ b/drivers/scsi/libsas/sas_scsi_host.c
> @@ -654,43 +654,43 @@ out:
>  	return;
>  }
> 
> -enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
> +enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
>  {
>  	struct sas_task *task = TO_SAS_TASK(cmd);
>  	unsigned long flags;
> 
>  	if (!task) {
> -		cmd->timeout_per_command /= 2;
> +		cmd->request->timeout /= 2;
>  		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
> -			    cmd, task, (cmd->timeout_per_command ?
> -			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
> -		if (!cmd->timeout_per_command)
> -			return EH_NOT_HANDLED;
> -		return EH_RESET_TIMER;
> +			    cmd, task, (cmd->request->timeout ?
> +			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
> +		if (!cmd->request->timeout)
> +			return BLK_EH_NOT_HANDLED;
> +		return BLK_EH_RESET_TIMER;
>  	}
> 
>  	spin_lock_irqsave(&task->task_state_lock, flags);
>  	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
>  	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
>  		spin_unlock_irqrestore(&task->task_state_lock, flags);
> -		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
> -			    cmd, task);
> -		return EH_HANDLED;
> +		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
> +			    "BLK_EH_HANDLED\n", cmd, task);
> +		return BLK_EH_HANDLED;
>  	}
>  	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
>  		spin_unlock_irqrestore(&task->task_state_lock, flags);
>  		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
> -			    "EH_RESET_TIMER\n",
> +			    "BLK_EH_RESET_TIMER\n",
>  			    cmd, task);
> -		return EH_RESET_TIMER;
> +		return BLK_EH_RESET_TIMER;
>  	}
>  	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
>  	spin_unlock_irqrestore(&task->task_state_lock, flags);
> 
> -	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
> +	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
>  		    cmd, task);
> 
> -	return EH_NOT_HANDLED;
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
> @@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *task)
>  		return;
>  	}
> 
> -	scsi_req_abort_cmd(sc);
> +	blk_abort_req(sc->request);
>  	scsi_schedule_eh(sc->device->host);
>  }
> 
> diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
> index ebb948c..84c0eb4 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.c
> +++ b/drivers/scsi/megaraid/megaraid_sas.c
> @@ -969,7 +969,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
>   * cmd has not been completed within the timeout period.
>   */
>  static enum
> -scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> +blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
>  {
>  	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
>  	struct megasas_instance *instance;
> @@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> 
>  	if (time_after(jiffies, scmd->jiffies_at_alloc +
>  				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
> -		return EH_NOT_HANDLED;
> +		return BLK_EH_NOT_HANDLED;
>  	}
> 
>  	instance = cmd->instance;
> @@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> 
>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>  	}
> -	return EH_RESET_TIMER;
> +	return BLK_EH_RESET_TIMER;
>  }
> 
>  /**
> diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
> index 030ba49..39c2d4b 100644
> --- a/drivers/scsi/ncr53c8xx.c
> +++ b/drivers/scsi/ncr53c8xx.c
> @@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
>  	**
>  	**----------------------------------------------------
>  	*/
> -	if (np->settle_time && cmd->timeout_per_command >= HZ) {
> -		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
> +	if (np->settle_time && cmd->request->timeout >= HZ) {
> +		u_long tlimit = jiffies + cmd->request->timeout - HZ;
>  		if (time_after(np->settle_time, tlimit))
>  			np->settle_time = tlimit;
>  	}
> diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
> index 54d8bdf..f5d5b2a 100644
> --- a/drivers/scsi/qla1280.c
> +++ b/drivers/scsi/qla1280.c
> @@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
>  	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
> 
>  	/* Set ISP command timeout. */
> -	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
> +	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
> 
>  	/* Set device target ID and LUN */
>  	pkt->lun = SCSI_LUN_32(cmd);
> @@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
>  	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
> 
>  	/* Set ISP command timeout. */
> -	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
> +	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
> 
>  	/* Set device target ID and LUN */
>  	pkt->lun = SCSI_LUN_32(cmd);
> diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
> index b1d565c..005eb66 100644
> --- a/drivers/scsi/qla4xxx/ql4_os.c
> +++ b/drivers/scsi/qla4xxx/ql4_os.c
> @@ -1564,7 +1564,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
>  	DEBUG2(printk(KERN_INFO
>  		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
>  		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
> -		      cmd, jiffies, cmd->timeout_per_command / HZ,
> +		      cmd, jiffies, cmd->request->timeout / HZ,
>  		      ha->dpc_flags, cmd->result, cmd->allowed));
> 
>  	/* FIXME: wait for hba to go online */
> diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
> index a5de1a8..e67eb6e 100644
> --- a/drivers/scsi/scsi.c
> +++ b/drivers/scsi/scsi.c
> @@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
> 
>  		memset(cmd, 0, sizeof(*cmd));
>  		cmd->device = dev;
> -		init_timer(&cmd->eh_timeout);
>  		INIT_LIST_HEAD(&cmd->list);
>  		spin_lock_irqsave(&dev->list_lock, flags);
>  		list_add_tail(&cmd->list, &dev->cmd_list);
> @@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	unsigned long timeout;
>  	int rtn = 0;
> 
> +	/*
> +	 * We will use a queued command if possible, otherwise we will
> +	 * emulate the queuing and calling of completion function ourselves.
> +	 */
> +	atomic_inc(&cmd->device->iorequest_cnt);
> +
>  	/* 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);
> +		scsi_done(cmd);
>  		/* return 0 (because the command has been processed) */
>  		goto out;
>  	}
> @@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  		 * future requests should not occur until the device 
>  		 * transitions out of the suspend state.
>  		 */
> -		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
> +
> +		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
> 
>  		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
> 
> @@ -534,21 +539,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  		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.
> -	 */
> -	atomic_inc(&cmd->device->iorequest_cnt);
> -
> -	/*
>  	 * Before we queue this command, check if the command
>  	 * length exceeds what the host adapter can handle.
>  	 */
> @@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	}
> 
>  	spin_lock_irqsave(host->host_lock, flags);
> +	/* 
> +	 * AK: unlikely race here: for some reason the timer could
> +	 * expire before the serial number is set up below.
> +	 *
> +	 * TODO: kill serial or move to blk layer
> +	 */
>  	scsi_cmd_get_serial(host, cmd); 
> 
>  	if (unlikely(host->shost_state == SHOST_DEL)) {
> @@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	}
>  	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
> +						rtn : SCSI_MLQUEUE_HOST_BUSY);
>  		SCSI_LOG_MLQUEUE(3,
>  		    printk("queuecommand : request rejected\n"));
>  	}
> @@ -588,24 +583,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  }
> 
>  /**
> - * scsi_req_abort_cmd -- Request command recovery for the specified command
> - * cmd: pointer to the SCSI command of interest
> - *
> - * This function requests that SCSI Core start recovery for the
> - * command by deleting the timer and adding the command to the eh
> - * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
> - * implement their own error recovery MAY ignore the timeout event if
> - * they generated scsi_req_abort_cmd.
> - */
> -void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
> -{
> -	if (!scsi_delete_timer(cmd))
> -		return;
> -	scsi_times_out(cmd);
> -}
> -EXPORT_SYMBOL(scsi_req_abort_cmd);
> -
> -/**
>   * scsi_done - Enqueue the finished SCSI command into the done queue.
>   * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
>   * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
> @@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
>   */
>  static void scsi_done(struct scsi_cmnd *cmd)
>  {
> -	/*
> -	 * We don't have to worry about this one timing out any more.
> -	 * If we are unable to remove the timer, then the command
> -	 * has already timed out.  In which case, we have no choice but to
> -	 * let the timeout function run, as we have no idea where in fact
> -	 * that function could really be.  It might be on another processor,
> -	 * etc, etc.
> -	 */
> -	if (!scsi_delete_timer(cmd))
> -		return;
> -	__scsi_done(cmd);
> -}
> -
> -/* Private entry to scsi_done() to complete a command when the timer
> - * isn't running --- used by scsi_times_out */
> -void __scsi_done(struct scsi_cmnd *cmd)
> -{
> -	struct request *rq = cmd->request;
> -
> -	/*
> -	 * Set the serial numbers back to zero
> -	 */
> -	cmd->serial_number = 0;
> -
> -	atomic_inc(&cmd->device->iodone_cnt);
> -	if (cmd->result)
> -		atomic_inc(&cmd->device->ioerr_cnt);
> -
> -	BUG_ON(!rq);
> -
> -	/*
> -	 * The uptodate/nbytes values don't matter, as we allow partial
> -	 * completes and thus will check this in the softirq callback
> -	 */
> -	rq->completion_data = cmd;
> -	blk_complete_request(rq);
> +	blk_complete_request(cmd->request);
>  }
> 
>  /*
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 8a525ab..4475648 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
>  }
> 
>  /**
> - * scsi_add_timer - Start timeout timer for a single scsi command.
> - * @scmd:	scsi command that is about to start running.
> - * @timeout:	amount of time to allow this command to run.
> - * @complete:	timeout function to call if timer isn't canceled.
> - *
> - * Notes:
> - *    This should be turned into an inline function.  Each scsi command
> - *    has its own timer, and as it is added to the queue, we set up the
> - *    timer.  When the command completes, we cancel the timer.
> - **/
> -void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
> -		    void (*complete)(struct scsi_cmnd *))
> -{
> -
> -	/*
> -	 * If the clock was already running for this command, then
> -	 * first delete the timer.  The timer handling code gets rather
> -	 * confused if we don't do this.
> -	 */
> -	if (scmd->eh_timeout.function)
> -		del_timer(&scmd->eh_timeout);
> -
> -	scmd->eh_timeout.data = (unsigned long)scmd;
> -	scmd->eh_timeout.expires = jiffies + timeout;
> -	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
> -
> -	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
> -					  " %d, (%p)\n", __FUNCTION__,
> -					  scmd, timeout, complete));
> -
> -	add_timer(&scmd->eh_timeout);
> -}
> -
> -/**
> - * scsi_delete_timer - Delete/cancel timer for a given function.
> - * @scmd:	Cmd that we are canceling timer for
> - *
> - * Notes:
> - *     This should be turned into an inline function.
> - *
> - * Return value:
> - *     1 if we were able to detach the timer.  0 if we blew it, and the
> - *     timer function has already started to run.
> - **/
> -int scsi_delete_timer(struct scsi_cmnd *scmd)
> -{
> -	int rtn;
> -
> -	rtn = del_timer(&scmd->eh_timeout);
> -
> -	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
> -					 " rtn: %d\n", __FUNCTION__,
> -					 scmd, rtn));
> -
> -	scmd->eh_timeout.data = (unsigned long)NULL;
> -	scmd->eh_timeout.function = NULL;
> -
> -	return rtn;
> -}
> -
> -/**
>   * scsi_times_out - Timeout function for normal scsi commands.
> - * @scmd:	Cmd that is timing out.
> + * @req:	request that is timing out.
>   *
>   * Notes:
>   *     We do not need to lock this.  There is the potential for a race
> @@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
>   *     normal completion function determines that the timer has already
>   *     fired, then it mustn't do anything.
>   **/
> -void scsi_times_out(struct scsi_cmnd *scmd)
> +enum blk_eh_timer_return scsi_times_out(struct request *req)
>  {
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	struct scsi_cmnd *scmd = req->special;
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
> 
>  	scsi_log_completion(scmd, TIMEOUT_ERROR);
> 
> @@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd)
>  		eh_timed_out = NULL;
> 
>  	if (eh_timed_out)
> -		switch (eh_timed_out(scmd)) {
> -		case EH_HANDLED:
> -			__scsi_done(scmd);
> -			return;
> -		case EH_RESET_TIMER:
> -			scsi_add_timer(scmd, scmd->timeout_per_command,
> -				       scsi_times_out);
> -			return;
> -		case EH_NOT_HANDLED:
> +		rtn = eh_timed_out(scmd);
> +		switch (rtn) {
> +		case BLK_EH_NOT_HANDLED:
>  			break;
> +		default:
> +			return rtn;
>  		}
> 
>  	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
>  		scmd->result |= DID_TIME_OUT << 16;
> -		__scsi_done(scmd);
> +		return BLK_EH_HANDLED;
>  	}
> +
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  /**
> @@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
>  	int rtn;
> 
>  	scmd->request = &req;
> -	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
> 
>  	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
>      
> @@ -1679,8 +1617,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
> 
>  	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
> 
> -	init_timer(&scmd->eh_timeout);
> -
>  	/*
>  	 * Sometimes the command can get back into the timer chain,
>  	 * so use the pid as an identifier.
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index a417a6f..d9c7581 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -162,6 +162,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
>  }
> 
>  /**
> + * scsi_queue_retry - Try inserting a command in the midlevel queue.
> + *
> + * @cmd:	command that we are adding to queue.
> + * @reason:	why we are inserting command to queue.
> + *
> + * Notes:       This is very similar to scsi_queue_insert except that we
> + *              call this function when we don't know if the blk layer timer
> + *              is active or not. We could implement this either by calling
> + *              blk_delete_timer and inserting in the midlevel queue if we
> + *              successfully delete the timer OR setting appropriate result
> + *              field in the cmd and letting it go through the normal done
> + *              routines which will retry the command. For now, We call
> + *              blk_delete_timer!
> + */
> +void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
> +{
> +	if (blk_delete_timer(cmd->request)) {
> +		atomic_inc(&cmd->device->iodone_cnt);
> +		scsi_queue_insert(cmd, reason);
> +	}
> +}
> +
> +/**
>   * scsi_execute - insert request and wait for the result
>   * @sdev:	scsi device
>   * @cmd:	scsi command
> @@ -1115,7 +1138,6 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
>  	
>  	cmd->transfersize = req->data_len;
>  	cmd->allowed = req->retries;
> -	cmd->timeout_per_command = req->timeout;
>  	cmd->done = scsi_blk_pc_done;
>  	return BLKPREP_OK;
>  }
> @@ -1354,17 +1376,26 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
>  	spin_unlock(shost->host_lock);
>  	spin_lock(sdev->request_queue->queue_lock);
> 
> -	__scsi_done(cmd);
> +	__blk_complete_request(req);
>  }
> 
>  static void scsi_softirq_done(struct request *rq)
>  {
> -	struct scsi_cmnd *cmd = rq->completion_data;
> -	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
> +	struct scsi_cmnd *cmd = rq->special;
> +	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
>  	int disposition;
> 
>  	INIT_LIST_HEAD(&cmd->eh_entry);
> 
> +	/*
> +	 * Set the serial numbers back to zero
> +	 */
> +	cmd->serial_number = 0;
> +	
> +	atomic_inc(&cmd->device->iodone_cnt);
> +	if (cmd->result)
> +		atomic_inc(&cmd->device->ioerr_cnt);
> +
>  	disposition = scsi_decide_disposition(cmd);
>  	if (disposition != SUCCESS &&
>  	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
> @@ -1581,6 +1612,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
> 
>  	blk_queue_prep_rq(q, scsi_prep_fn);
>  	blk_queue_softirq_done(q, scsi_softirq_done);
> +	blk_queue_rq_timed_out(q, scsi_times_out);
>  	return q;
>  }
> 
> diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
> index ee8efe8..4c29a95 100644
> --- a/drivers/scsi/scsi_priv.h
> +++ b/drivers/scsi/scsi_priv.h
> @@ -4,6 +4,7 @@
>  #include <linux/device.h>
> 
>  struct request_queue;
> +struct request;
>  struct scsi_cmnd;
>  struct scsi_device;
>  struct scsi_host_template;
> @@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void);
>  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);
>  #ifdef CONFIG_SCSI_LOGGING
>  void scsi_log_send(struct scsi_cmnd *cmd);
>  void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
> @@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void);
>  extern void scsi_exit_devinfo(void);
> 
>  /* scsi_error.c */
> -extern void scsi_add_timer(struct scsi_cmnd *, int,
> -		void (*)(struct scsi_cmnd *));
> -extern int scsi_delete_timer(struct scsi_cmnd *);
> -extern void scsi_times_out(struct scsi_cmnd *cmd);
> +extern enum blk_eh_timer_return scsi_times_out(struct request *req);
>  extern int scsi_error_handler(void *host);
>  extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
>  extern void scsi_eh_wakeup(struct Scsi_Host *shost);
> @@ -67,6 +64,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
>  extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
>  extern void scsi_device_unbusy(struct scsi_device *sdev);
>  extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
> +extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
>  extern void scsi_next_command(struct scsi_cmnd *cmd);
>  extern void scsi_run_host_queues(struct Scsi_Host *shost);
>  extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
> index 34cdce6..59d1570 100644
> --- a/drivers/scsi/scsi_sysfs.c
> +++ b/drivers/scsi/scsi_sysfs.c
> @@ -443,12 +443,15 @@ sdev_rd_attr (vendor, "%.8s\n");
>  sdev_rd_attr (model, "%.16s\n");
>  sdev_rd_attr (rev, "%.4s\n");
> 
> +/*
> + * TODO: can we make these symlinks to the block layer ones?
> + */
>  static ssize_t
>  sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
>  {
>  	struct scsi_device *sdev;
>  	sdev = to_scsi_device(dev);
> -	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
> +	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
>  }
> 
>  static ssize_t
> @@ -458,7 +461,7 @@ sdev_store_timeout (struct device *dev, struct device_attribute *attr, const cha
>  	int timeout;
>  	sdev = to_scsi_device(dev);
>  	sscanf (buf, "%d\n", &timeout);
> -	sdev->timeout = timeout * HZ;
> +	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
>  	return count;
>  }
>  static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
> index 4705725..0aef522 100644
> --- a/drivers/scsi/scsi_transport_fc.c
> +++ b/drivers/scsi/scsi_transport_fc.c
> @@ -1920,15 +1920,15 @@ static int fc_vport_match(struct attribute_container *cont,
>   * Notes:
>   *	This routine assumes no locks are held on entry.
>   **/
> -static enum scsi_eh_timer_return
> +static enum blk_eh_timer_return
>  fc_timed_out(struct scsi_cmnd *scmd)
>  {
>  	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
> 
>  	if (rport->port_state == FC_PORTSTATE_BLOCKED)
> -		return EH_RESET_TIMER;
> +		return BLK_EH_RESET_TIMER;
> 
> -	return EH_NOT_HANDLED;
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  /*
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index 2c6116f..7720698 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -338,7 +338,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
>  	struct gendisk *disk = rq->rq_disk;
>  	sector_t block = rq->sector;
>  	unsigned int this_count = SCpnt->request_bufflen >> 9;
> -	unsigned int timeout = sdp->timeout;
> 
>  	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
>  					"sd_init_command: block=%llu, "
> @@ -489,7 +488,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
>  	SCpnt->transfersize = sdp->sector_size;
>  	SCpnt->underflow = this_count << 9;
>  	SCpnt->allowed = SD_MAX_RETRIES;
> -	SCpnt->timeout_per_command = timeout;
> 
>  	/*
>  	 * This is the completion routine we use.  This is matched in terms
> @@ -1629,11 +1627,12 @@ static int sd_probe(struct device *dev)
>  	sdkp->index = index;
>  	sdkp->openers = 0;
> 
> -	if (!sdp->timeout) {
> +	if (!sdp->request_queue->rq_timeout) {
>  		if (sdp->type != TYPE_MOD)
> -			sdp->timeout = SD_TIMEOUT;
> +			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
>  		else
> -			sdp->timeout = SD_MOD_TIMEOUT;
> +			blk_queue_rq_timeout(sdp->request_queue,
> +					     SD_MOD_TIMEOUT);
>  	}
> 
>  	class_device_initialize(&sdkp->cdev);
> diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
> index 902eb11..cb73d58 100644
> --- a/drivers/scsi/sr.c
> +++ b/drivers/scsi/sr.c
> @@ -298,7 +298,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
> 
>  static int sr_init_command(struct scsi_cmnd * SCpnt)
>  {
> -	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
> +	int block=0, this_count, s_size;
>  	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
> 
>  	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
> @@ -407,7 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
>  	SCpnt->transfersize = cd->device->sector_size;
>  	SCpnt->underflow = this_count << 9;
>  	SCpnt->allowed = MAX_RETRIES;
> -	SCpnt->timeout_per_command = timeout;
> 
>  	/*
>  	 * This is the completion routine we use.  This is matched in terms
> @@ -570,6 +569,8 @@ static int sr_probe(struct device *dev)
>  	disk->fops = &sr_bdops;
>  	disk->flags = GENHD_FL_CD;
> 
> +	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
> +
>  	cd->device = sdev;
>  	cd->disk = disk;
>  	cd->driver = &sr_template;
> diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
> index 3db2232..702f730 100644
> --- a/drivers/scsi/sym53c8xx_2/sym_glue.c
> +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
> @@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
>  	 *  Shorten our settle_time if needed for 
>  	 *  this command not to time out.
>  	 */
> -	if (np->s.settle_time_valid && cmd->timeout_per_command) {
> -		unsigned long tlimit = jiffies + cmd->timeout_per_command;
> +	if (np->s.settle_time_valid && cmd->request->timeout) {
> +		unsigned long tlimit = jiffies + cmd->request->timeout;
>  		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
>  		if (time_after(np->s.settle_time, tlimit)) {
>  			np->s.settle_time = tlimit;
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index b126c6f..bb59cdb 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -309,7 +309,8 @@ struct request {
>  	void *data;
>  	void *sense;
> 
> -	unsigned int timeout;
> +	unsigned long timeout;
> +	struct list_head timeout_list;
>  	int retries;
> 
>  	/*
> @@ -348,6 +349,14 @@ typedef int (issue_flush_fn) (struct request_queue *, struct gendisk *, sector_t
>  typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
>  typedef void (softirq_done_fn)(struct request *);
> 
> +enum blk_eh_timer_return {
> +	BLK_EH_NOT_HANDLED,
> +	BLK_EH_HANDLED,
> +	BLK_EH_RESET_TIMER,
> +};
> +
> +typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
> +
>  enum blk_queue_state {
>  	Queue_down,
>  	Queue_up,
> @@ -385,6 +394,7 @@ struct request_queue
>  	issue_flush_fn		*issue_flush_fn;
>  	prepare_flush_fn	*prepare_flush_fn;
>  	softirq_done_fn		*softirq_done_fn;
> +	rq_timed_out_fn		*rq_timed_out_fn;
> 
>  	/*
>  	 * Dispatch queue sorting
> @@ -455,6 +465,10 @@ struct request_queue
>  	unsigned int		nr_sorted;
>  	unsigned int		in_flight;
> 
> +	unsigned int		rq_timeout;
> +	struct			timer_list timeout;
> +	struct list_head	timeout_list;
> +
>  	/*
>  	 * sg stuff
>  	 */
> @@ -733,6 +747,10 @@ extern int end_that_request_chunk(struct request *, int, int);
>  extern void end_that_request_last(struct request *, int);
>  extern void end_request(struct request *req, int uptodate);
>  extern void blk_complete_request(struct request *);
> +extern void __blk_complete_request(struct request *);
> +extern void blk_abort_req(struct request *);
> +extern int blk_delete_timer(struct request *);
> +extern void blk_add_timer(struct request *);
> 
>  /*
>   * end_that_request_first/chunk() takes an uptodate argument. we account
> @@ -744,6 +762,8 @@ extern void blk_complete_request(struct request *);
> 
>  static inline void blkdev_dequeue_request(struct request *req)
>  {
> +	if (req->q->rq_timed_out_fn)
> +		blk_add_timer(req);
>  	elv_dequeue_request(req->q, req);
>  }
> 
> @@ -767,6 +787,8 @@ extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
>  extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
>  extern void blk_queue_dma_alignment(struct request_queue *, int);
>  extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
> +extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
> +extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
>  extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
>  extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
>  extern void blk_queue_issue_flush_fn(struct request_queue *, issue_flush_fn *);
> diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
> index 53e1705..5841369 100644
> --- a/include/scsi/scsi_cmnd.h
> +++ b/include/scsi/scsi_cmnd.h
> @@ -56,7 +56,6 @@ struct scsi_cmnd {
> 
>  	int retries;
>  	int allowed;
> -	int timeout_per_command;
> 
>  	unsigned char cmd_len;
>  	enum dma_data_direction sc_data_direction;
> @@ -66,7 +65,6 @@ struct scsi_cmnd {
>  	unsigned char cmnd[MAX_COMMAND_SIZE];
>  	unsigned request_bufflen;	/* Actual request size */
> 
> -	struct timer_list eh_timeout;	/* Used to time out the command. */
>  	void *request_buffer;		/* Actual requested buffer */
> 
>  	/* These elements define the operation we ultimately want to perform */
> @@ -126,7 +124,6 @@ extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
>  			       struct device *);
>  extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
>  extern void scsi_finish_command(struct scsi_cmnd *cmd);
> -extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
> 
>  extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
>  				 size_t *offset, size_t *len);
> diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> index 3b8a6a8..165ccaf 100644
> --- a/include/scsi/scsi_host.h
> +++ b/include/scsi/scsi_host.h
> @@ -36,13 +36,6 @@ struct blk_queue_tags;
>  #define DISABLE_CLUSTERING 0
>  #define ENABLE_CLUSTERING 1
> 
> -enum scsi_eh_timer_return {
> -	EH_NOT_HANDLED,
> -	EH_HANDLED,
> -	EH_RESET_TIMER,
> -};
> -
> -
>  struct scsi_host_template {
>  	struct module *module;
>  	const char *name;
> @@ -336,7 +329,7 @@ struct scsi_host_template {
>  	 *
>  	 * Status: OPTIONAL
>  	 */
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> 
>  	/*
>  	 * Name of proc directory
> diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
> index 3c18baa..23e8d97 100644
> --- a/include/scsi/scsi_transport.h
> +++ b/include/scsi/scsi_transport.h
> @@ -21,6 +21,7 @@
>  #define SCSI_TRANSPORT_H
> 
>  #include <linux/transport_class.h>
> +#include <linux/blkdev.h>
>  #include <scsi/scsi_host.h>
>  #include <scsi/scsi_device.h>
> 
> @@ -64,7 +65,7 @@ struct scsi_transport_template {
>  	 *			begin counting again
>  	 * EH_NOT_HANDLED	Begin normal error recovery
>  	 */
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
>  };
> 
>  #define transport_class_to_shost(tc) \
> 
> -- 
> Jens Axboe
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-10 16:58               ` malahal
@ 2007-10-10 17:04                 ` Jens Axboe
  0 siblings, 0 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-10 17:04 UTC (permalink / raw)
  To: James Bottomley, Matthew Wilcox, linux-scsi

On Wed, Oct 10 2007, malahal@us.ibm.com wrote:
> I don't see blk_delete_timer() actually calling mod_timer/del_timer at
> all.  Doesn't that mean, your timer would eventually expire for no
> reason and walk through the list unnecessarily?

Please stop top posting, thanks.

Yeah, it can only remove the request from the list. We could delete the
timer as well if the list is now empty, I'll now add that check.

It's part of the "design" that the timer may fire and find nothing to
do, my theory is that this is much cheaper than making the enqueue path
more costly. The latter is an absolute no-no, I'd much rather take the
one-timer-per-request hit than start engaging in any type of expiry
sorting or similar at request add time.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-10 12:25             ` Jens Axboe
  2007-10-10 16:58               ` malahal
@ 2007-10-11 18:01               ` malahal
  2007-10-11 18:24                 ` Jens Axboe
  1 sibling, 1 reply; 26+ messages in thread
From: malahal @ 2007-10-11 18:01 UTC (permalink / raw)
  To: Jens Axboe; +Cc: James Bottomley, Matthew Wilcox, linux-scsi

Jens Axboe [jens.axboe@oracle.com] wrote:
> On Tue, Oct 09 2007, James Bottomley wrote:
> > On Tue, 2007-10-09 at 14:15 +0200, Jens Axboe wrote:
> > > On Tue, Oct 09 2007, Matthew Wilcox wrote:
> > > > On Mon, Oct 08, 2007 at 10:36:10PM -0700, malahal@us.ibm.com wrote:
> > > > > Thank you Randy, Jens for your suggestions. I folded the second patch as
> > > > > it is just a clean up. Here is the fixed one patch version.
> > > > 
> > > > I was thinking about this (in the context of shrinking scsi_cmnd --
> > > > obviously, things are not improved if we simply move the timer to request
> > > > instead of scsi_cmnd).  Why do we need a timer _per request_?  We don't
> > > > need one per network packet.  I appreciate we had one per scsi_cmnd and
> > > > this patch is just moving it upwards in the hierarchy, but perhaps we
> > > > can do better.
> > > > 
> > > > What if we have one timer per request queue instead?  It needs to expire
> > > > as soon as the earliest request timer would expire, then needs to be
> > > > reset to the next earliest one.  We might walk the request queue more
> > > > frequently, but we'd save 48 bytes in the struct request.
> > > 
> > > I agree, adding a full timer to each request is not nice. You jump over
> > > the actual implementation details of having just one timer in the queue
> > > though, it's pretty cheap to just say it can be done :-). You need to
> > > track each request anyways. If all drivers used the block layer tagging
> > > it would be easy since we are tracking each pending request in that
> > > case, but right now they don't. So pending requests may very well be
> > > outside of block layer knowledge.
> > 
> > Can't we handle this a bit like the Linux timer infrastructure?  Instead
> > of a timer per cmnd we have one per queue that's reset by commands
> > returning?  If we retained a linked list of commands in timer order and
> > expiry times, that's still going to save us an unsigned long and two
> > pointers over struct timer_list.
> 
> Here's an approach that uses a single timer. I purposely do not sort
> commands in expiry times, as that would introduce an O(N) operation far
> out weighing the IO scheduling cost, pretty silly for a timeout
> mechanism that supposedly should never trigger. Or we could waste more
> memory and fewer cycles (but still far more cycles than we need) by
> sorting in some sort of tree.
> 
> So I don't sort the list, instead I push the cost of locating expired
> request to the timeout handler. It should really only run, when a
> request times out. Timeout is then reset to next command timeout
> (rounded), if further commands exist. It also doesn't fiddle with the
> timer unless an incoming command has a lower timeout than the current
> one.
> 
> Totally untested...
> 
> diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
> index ed39313..cb3210a 100644
> --- a/block/ll_rw_blk.c
> +++ b/block/ll_rw_blk.c
> @@ -42,6 +42,7 @@ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
>  static void init_request_from_bio(struct request *req, struct bio *bio);
>  static int __make_request(struct request_queue *q, struct bio *bio);
>  static struct io_context *current_io_context(gfp_t gfp_flags, int node);
> +static void blk_rq_timed_out_timer(unsigned long);
> 
>  /*
>   * For the allocated request tables
> @@ -177,6 +178,18 @@ void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
> 
>  EXPORT_SYMBOL(blk_queue_softirq_done);
> 
> +void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
> +{
> +	q->rq_timeout = timeout;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
> +
> +void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
> +{
> +	q->rq_timed_out_fn = fn;
> +}
> +EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
> +
>  /**
>   * blk_queue_make_request - define an alternate make_request function for a device
>   * @q:  the request queue for the device to be affected
> @@ -239,7 +252,9 @@ static void rq_init(struct request_queue *q, struct request *rq)
>  {
>  	INIT_LIST_HEAD(&rq->queuelist);
>  	INIT_LIST_HEAD(&rq->donelist);
> +	INIT_LIST_HEAD(&rq->timeout_list);
> 
> +	rq->timeout = 0;
>  	rq->errors = 0;
>  	rq->bio = rq->biotail = NULL;
>  	INIT_HLIST_NODE(&rq->hash);
> @@ -1851,6 +1866,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
>  		return NULL;
> 
>  	init_timer(&q->unplug_timer);
> +	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
> +	INIT_LIST_HEAD(&q->timeout_list);
> 
>  	snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
>  	q->kobj.ktype = &queue_ktype;
> @@ -2271,6 +2288,7 @@ EXPORT_SYMBOL(blk_start_queueing);
>   */
>  void blk_requeue_request(struct request_queue *q, struct request *rq)
>  {
> +	blk_delete_timer(rq);
>  	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
> 
>  	if (blk_rq_tagged(rq))
> @@ -3600,24 +3618,132 @@ static struct notifier_block __devinitdata blk_cpu_notifier = {
>  };
> 
>  /**
> - * blk_complete_request - end I/O on a request
> - * @req:      the request being processed
> + * blk_delete_timer - Delete/cancel timer for a given function.
> + * @req:	request that we are canceling timer for
>   *
> - * Description:
> - *     Ends all I/O on a request. It does not handle partial completions,
> - *     unless the driver actually implements this in its completion callback
> - *     through requeueing. Theh actual completion happens out-of-order,
> - *     through a softirq handler. The user must have registered a completion
> - *     callback through blk_queue_softirq_done().
> - **/
> + * Return value:
> + *     1 if we were able to detach the timer.  0 if we blew it, and the
> + *     timer function has already started to run.
> + */
> +int blk_delete_timer(struct request *req)
> +{
> +	if (!req->q->rq_timed_out_fn)
> +		return 1;
> 
> -void blk_complete_request(struct request *req)
> +	if (!list_empty(&req->timeout_list)) {

This could race with timeout handler. In other words, this routine may
return 1 while blk_rq_timed_out() is running on the request.

> +		list_del_init(&req->timeout_list);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(blk_delete_timer);
> +
> +static void blk_rq_timed_out(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +	enum blk_eh_timer_return ret;
> +
> +	ret = q->rq_timed_out_fn(req);
> +	switch (ret) {
> +	case BLK_EH_HANDLED:
> +		__blk_complete_request(req);
> +		break;
> +	case BLK_EH_RESET_TIMER:
> +		blk_add_timer(req);

You will need to delete the req from the timeout_list before calling
blk_add_timer again. You may need to remove the req from the list in
other cases too.

> +		break;
> +	case BLK_EH_NOT_HANDLED:
> +		/*
> +		 * LLD handles this for now but in the future
> +		 * we can send a request msg to abort the command
> +		 * and we can move more of the generic scsi eh code to
> +		 * the blk layer.
> +		 */
> +		break;
> +	default:
> +		printk(KERN_ERR "block: bad eh return: %d\n", ret);
> +		break;
> +	}
> +}
> +
> +static void blk_rq_timed_out_timer(unsigned long data)
> +{
> +	struct request_queue *q = (struct request_queue *) data;
> +	unsigned long flags, next = 0;
> +	struct request *rq, *tmp;
> +
> +	spin_lock_irqsave(q->queue_lock, flags);
> +
> +	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) {
> +		if (!next || time_before(next, rq->timeout))
> +			next = rq->timeout;
> +		if (time_after_eq(jiffies, rq->timeout))
> +			blk_rq_timed_out(rq);
> +	}
> +
> +	if (next)
> +		mod_timer(&q->timeout, round_jiffies(next));
> +
> +	spin_unlock_irqrestore(q->queue_lock, flags);
> +}
> +
> +/**
> + * blk_abort_req -- Request request recovery for the specified command
> + * @req:	pointer to the request of interest
> + *
> + * This function requests that the block layer start recovery for the
> + * request by deleting the timer and calling the q's timeout function.
> + * LLDDs who implement their own error recovery MAY ignore the timeout
> + * event if they generated blk_abort_req.
> + */
> +void blk_abort_req(struct request *req)
> +{
> +        if (!blk_delete_timer(req))
> +                return;
> +        blk_rq_timed_out(req);
> +}
> +EXPORT_SYMBOL_GPL(blk_abort_req);
> +
> +/**
> + * blk_add_timer - Start timeout timer for a single request
> + * @req:	request that is about to start running.
> + *
> + * Notes:
> + *    Each request has its own timer, and as it is added to the queue, we
> + *    set up the timer.  When the request completes, we cancel the timer.
> + */
> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +	unsigned long expiry;
> +
> +	BUG_ON(!list_empty(&req->timeout_list));
> +
> +	if (req->timeout)
> +		expiry = jiffies + req->timeout;
> +	else
> +		expiry = jiffies + q->rq_timeout;
> +
> +	req->timeout = expiry;
> +	list_add_tail(&req->timeout_list, &q->timeout_list);
> +
> +	/*
> +	 * This is for timeout purposes, round to next second
> +	 */
> +	expiry = round_jiffies(expiry);
> +
> +	if (!timer_pending(&q->timeout) || time_before(expiry, q->timeout.expires))
> +		mod_timer(&q->timeout, expiry);
> +}
> +EXPORT_SYMBOL_GPL(blk_add_timer);
> +
> +void __blk_complete_request(struct request *req)
>  {
>  	struct list_head *cpu_list;
>  	unsigned long flags;
> 
>  	BUG_ON(!req->q->softirq_done_fn);
> -		
> +
>  	local_irq_save(flags);
> 
>  	cpu_list = &__get_cpu_var(blk_cpu_done);
> @@ -3627,8 +3753,34 @@ void blk_complete_request(struct request *req)
>  	local_irq_restore(flags);
>  }
> 
> +/**
> + * blk_complete_request - end I/O on a request
> + * @req:	the request being processed
> + *
> + * Description:
> + *     Ends all I/O on a request. It does not handle partial completions,
> + *     unless the driver actually implements this in its completion callback
> + *     through requeueing. Theh actual completion happens out-of-order,
> + *     through a softirq handler. The user must have registered a completion
> + *     callback through blk_queue_softirq_done().
> + */
> +void blk_complete_request(struct request *req)
> +{
> +	/*
> +	 * We don't have to worry about this one timing out any more.
> +	 * If we are unable to remove the timer, then the command
> +	 * has already timed out.  In which case, we have no choice but to
> +	 * let the timeout function run, as we have no idea where in fact
> +	 * that function could really be.  It might be on another processor,
> +	 * etc, etc.
> +	 */
> +	if (!blk_delete_timer(req))
> +		return;
> +
> +	__blk_complete_request(req);
> +}
>  EXPORT_SYMBOL(blk_complete_request);
> -	
> +
>  /*
>   * queue lock must be held
>   */
> diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
> index ac6ceed..017a236 100644
> --- a/drivers/ata/libata-eh.c
> +++ b/drivers/ata/libata-eh.c
> @@ -33,6 +33,7 @@
>   */
> 
>  #include <linux/kernel.h>
> +#include <linux/blkdev.h>
>  #include <scsi/scsi.h>
>  #include <scsi/scsi_host.h>
>  #include <scsi/scsi_eh.h>
> @@ -244,29 +245,29 @@ static void ata_eh_clear_action(struct ata_device *dev,
>   *	RETURNS:
>   *	EH_HANDLED or EH_NOT_HANDLED
>   */
> -enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
> +enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
>  {
>  	struct Scsi_Host *host = cmd->device->host;
>  	struct ata_port *ap = ata_shost_to_port(host);
>  	unsigned long flags;
>  	struct ata_queued_cmd *qc;
> -	enum scsi_eh_timer_return ret;
> +	enum blk_eh_timer_return ret;
> 
>  	DPRINTK("ENTER\n");
> 
>  	if (ap->ops->error_handler) {
> -		ret = EH_NOT_HANDLED;
> +		ret = BLK_EH_NOT_HANDLED;
>  		goto out;
>  	}
> 
> -	ret = EH_HANDLED;
> +	ret = BLK_EH_HANDLED;
>  	spin_lock_irqsave(ap->lock, flags);
>  	qc = ata_qc_from_tag(ap, ap->active_tag);
>  	if (qc) {
>  		WARN_ON(qc->scsicmd != cmd);
>  		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
>  		qc->err_mask |= AC_ERR_TIMEOUT;
> -		ret = EH_NOT_HANDLED;
> +		ret = BLK_EH_NOT_HANDLED;
>  	}
>  	spin_unlock_irqrestore(ap->lock, flags);
> 
> @@ -692,7 +693,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
>  	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
>  	 * this function completes.
>  	 */
> -	scsi_req_abort_cmd(qc->scsicmd);
> +	blk_abort_req(qc->scsicmd->request);
>  }
> 
>  /**
> diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
> index 564cd23..6021b9c 100644
> --- a/drivers/ata/libata.h
> +++ b/drivers/ata/libata.h
> @@ -148,7 +148,7 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
>  extern int ata_bus_probe(struct ata_port *ap);
> 
>  /* libata-eh.c */
> -extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
> +extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
>  extern void ata_scsi_error(struct Scsi_Host *host);
>  extern void ata_port_wait_eh(struct ata_port *ap);
>  extern void ata_eh_fastdrain_timerfn(unsigned long arg);
> diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
> index 6800e57..6fa65c8 100644
> --- a/drivers/scsi/aacraid/aachba.c
> +++ b/drivers/scsi/aacraid/aachba.c
> @@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
>  	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
>  	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
>  	srbcmd->flags    = cpu_to_le32(flag);
> -	timeout = cmd->timeout_per_command/HZ;
> +	timeout = cmd->request->timeout/HZ;
>  	if (timeout == 0)
>  		timeout = 1;
>  	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
> diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
> index 79c0b6e..d139075 100644
> --- a/drivers/scsi/advansys.c
> +++ b/drivers/scsi/advansys.c
> @@ -7901,7 +7901,7 @@ static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
>  	printk(" serial_number 0x%x, retries %d, allowed %d\n",
>  	       (unsigned)s->serial_number, s->retries, s->allowed);
> 
> -	printk(" timeout_per_command %d\n", s->timeout_per_command);
> +	printk(" request timeout %d\n", s->request->timeout);
> 
>  	printk
>  	    (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
> diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
> index 55e4d2d..c5fc436 100644
> --- a/drivers/scsi/gdth.c
> +++ b/drivers/scsi/gdth.c
> @@ -733,7 +733,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
>      scp->device = sdev;
>      /* use request field to save the ptr. to completion struct. */
>      scp->request = (struct request *)&wait;
> -    scp->timeout_per_command = timeout*HZ;
>      scp->request_buffer = gdtcmd;
>      scp->cmd_len = 12;
>      memcpy(scp->cmnd, cmnd, 12);
> @@ -4948,7 +4947,7 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
>      if (scp->done == gdth_scsi_done)
>          priority = scp->SCp.this_residual;
>      else
> -        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
> +        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
> 
>      gdth_putq( hanum, scp, priority );
>      gdth_next( hanum );
> diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
> index 32982eb..22a9013 100644
> --- a/drivers/scsi/gdth_proc.c
> +++ b/drivers/scsi/gdth_proc.c
> @@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
>  {
>      int oldto;
> 
> -    oldto = scp->timeout_per_command;
> -    scp->timeout_per_command = timeout;
> +    oldto = scp->request->timeout;
> +    scp->request->timeout = timeout;
> 
>      if (timeout == 0) {
> -        del_timer(&scp->eh_timeout);
> -        scp->eh_timeout.data = (unsigned long) NULL;
> -        scp->eh_timeout.expires = 0;
> +        del_timer(&scp->request->timer);
> +        scp->request->timer.data = (unsigned long) NULL;
> +        scp->request->timer.expires = 0;
>      } else {
> -        if (scp->eh_timeout.data != (unsigned long) NULL) 
> -            del_timer(&scp->eh_timeout);
> -        scp->eh_timeout.data = (unsigned long) scp;
> -        scp->eh_timeout.expires = jiffies + timeout;
> -        add_timer(&scp->eh_timeout);
> +        if (scp->request->timer.data != (unsigned long) NULL) 
> +            del_timer(&scp->request->timer);
> +        scp->request->timer.data = (unsigned long) scp;
> +        scp->request->timer.expires = jiffies + timeout;
> +        add_timer(&scp->request->timer);
>      }
> 
>      return oldto;
> diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
> index 5ecc63d..04dbe3b 100644
> --- a/drivers/scsi/ibmvscsi/ibmvscsi.c
> +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
> @@ -726,7 +726,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
>  	init_event_struct(evt_struct,
>  			  handle_cmd_rsp,
>  			  VIOSRP_SRP_FORMAT,
> -			  cmnd->timeout_per_command/HZ);
> +			  cmnd->request->timeout/HZ);
> 
>  	evt_struct->cmnd = cmnd;
>  	evt_struct->cmnd_done = done;
> diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
> index 1cc01ac..2035923 100644
> --- a/drivers/scsi/ide-scsi.c
> +++ b/drivers/scsi/ide-scsi.c
> @@ -916,7 +916,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
>  	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
>  	pc->scsi_cmd = cmd;
>  	pc->done = done;
> -	pc->timeout = jiffies + cmd->timeout_per_command;
> +	pc->timeout = jiffies + cmd->request->timeout;
> 
>  	if (should_transform(drive, cmd))
>  		set_bit(PC_TRANSFORM, &pc->flags);
> diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
> index f142eaf..b351f14 100644
> --- a/drivers/scsi/ipr.c
> +++ b/drivers/scsi/ipr.c
> @@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
>  			sdev->no_uld_attach = 1;
>  		}
>  		if (ipr_is_vset_device(res)) {
> -			sdev->timeout = IPR_VSET_RW_TIMEOUT;
> +			blk_queue_rq_timeout(sdev->request_queue,
> +					     IPR_VSET_RW_TIMEOUT);
>  			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
>  		}
>  		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
> diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
> index 492a51b..c81dd8f 100644
> --- a/drivers/scsi/ips.c
> +++ b/drivers/scsi/ips.c
> @@ -3860,7 +3860,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
>  		scb->cmd.dcdb.segment_4G = 0;
>  		scb->cmd.dcdb.enhanced_sg = 0;
> 
> -		TimeOut = scb->scsi_cmd->timeout_per_command;
> +		TimeOut = scb->scsi_cmd->request->timeout;
> 
>  		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
>  			if (!scb->sg_len) {
> diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
> index 5e573ef..f3ae2df 100644
> --- a/drivers/scsi/libsas/sas_ata.c
> +++ b/drivers/scsi/libsas/sas_ata.c
> @@ -408,7 +408,7 @@ void sas_ata_task_abort(struct sas_task *task)
> 
>  	/* Bounce SCSI-initiated commands to the SCSI EH */
>  	if (qc->scsicmd) {
> -		scsi_req_abort_cmd(qc->scsicmd);
> +		blk_abort_req(qc->scsicmd->request);
>  		scsi_schedule_eh(qc->scsicmd->device->host);
>  		return;
>  	}
> diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
> index 2b8213b..13ac4a3 100644
> --- a/drivers/scsi/libsas/sas_internal.h
> +++ b/drivers/scsi/libsas/sas_internal.h
> @@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
>  int  sas_register_ports(struct sas_ha_struct *sas_ha);
>  void sas_unregister_ports(struct sas_ha_struct *sas_ha);
> 
> -enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
> +enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
> 
>  int  sas_init_queue(struct sas_ha_struct *sas_ha);
>  int  sas_init_events(struct sas_ha_struct *sas_ha);
> diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
> index 7663841..6d6867c 100644
> --- a/drivers/scsi/libsas/sas_scsi_host.c
> +++ b/drivers/scsi/libsas/sas_scsi_host.c
> @@ -654,43 +654,43 @@ out:
>  	return;
>  }
> 
> -enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
> +enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
>  {
>  	struct sas_task *task = TO_SAS_TASK(cmd);
>  	unsigned long flags;
> 
>  	if (!task) {
> -		cmd->timeout_per_command /= 2;
> +		cmd->request->timeout /= 2;
>  		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
> -			    cmd, task, (cmd->timeout_per_command ?
> -			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
> -		if (!cmd->timeout_per_command)
> -			return EH_NOT_HANDLED;
> -		return EH_RESET_TIMER;
> +			    cmd, task, (cmd->request->timeout ?
> +			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
> +		if (!cmd->request->timeout)
> +			return BLK_EH_NOT_HANDLED;
> +		return BLK_EH_RESET_TIMER;
>  	}
> 
>  	spin_lock_irqsave(&task->task_state_lock, flags);
>  	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
>  	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
>  		spin_unlock_irqrestore(&task->task_state_lock, flags);
> -		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
> -			    cmd, task);
> -		return EH_HANDLED;
> +		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
> +			    "BLK_EH_HANDLED\n", cmd, task);
> +		return BLK_EH_HANDLED;
>  	}
>  	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
>  		spin_unlock_irqrestore(&task->task_state_lock, flags);
>  		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
> -			    "EH_RESET_TIMER\n",
> +			    "BLK_EH_RESET_TIMER\n",
>  			    cmd, task);
> -		return EH_RESET_TIMER;
> +		return BLK_EH_RESET_TIMER;
>  	}
>  	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
>  	spin_unlock_irqrestore(&task->task_state_lock, flags);
> 
> -	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
> +	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
>  		    cmd, task);
> 
> -	return EH_NOT_HANDLED;
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
> @@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *task)
>  		return;
>  	}
> 
> -	scsi_req_abort_cmd(sc);
> +	blk_abort_req(sc->request);
>  	scsi_schedule_eh(sc->device->host);
>  }
> 
> diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
> index ebb948c..84c0eb4 100644
> --- a/drivers/scsi/megaraid/megaraid_sas.c
> +++ b/drivers/scsi/megaraid/megaraid_sas.c
> @@ -969,7 +969,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
>   * cmd has not been completed within the timeout period.
>   */
>  static enum
> -scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> +blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
>  {
>  	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
>  	struct megasas_instance *instance;
> @@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> 
>  	if (time_after(jiffies, scmd->jiffies_at_alloc +
>  				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
> -		return EH_NOT_HANDLED;
> +		return BLK_EH_NOT_HANDLED;
>  	}
> 
>  	instance = cmd->instance;
> @@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
> 
>  		spin_unlock_irqrestore(instance->host->host_lock, flags);
>  	}
> -	return EH_RESET_TIMER;
> +	return BLK_EH_RESET_TIMER;
>  }
> 
>  /**
> diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
> index 030ba49..39c2d4b 100644
> --- a/drivers/scsi/ncr53c8xx.c
> +++ b/drivers/scsi/ncr53c8xx.c
> @@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
>  	**
>  	**----------------------------------------------------
>  	*/
> -	if (np->settle_time && cmd->timeout_per_command >= HZ) {
> -		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
> +	if (np->settle_time && cmd->request->timeout >= HZ) {
> +		u_long tlimit = jiffies + cmd->request->timeout - HZ;
>  		if (time_after(np->settle_time, tlimit))
>  			np->settle_time = tlimit;
>  	}
> diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
> index 54d8bdf..f5d5b2a 100644
> --- a/drivers/scsi/qla1280.c
> +++ b/drivers/scsi/qla1280.c
> @@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
>  	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
> 
>  	/* Set ISP command timeout. */
> -	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
> +	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
> 
>  	/* Set device target ID and LUN */
>  	pkt->lun = SCSI_LUN_32(cmd);
> @@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
>  	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
> 
>  	/* Set ISP command timeout. */
> -	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
> +	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
> 
>  	/* Set device target ID and LUN */
>  	pkt->lun = SCSI_LUN_32(cmd);
> diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
> index b1d565c..005eb66 100644
> --- a/drivers/scsi/qla4xxx/ql4_os.c
> +++ b/drivers/scsi/qla4xxx/ql4_os.c
> @@ -1564,7 +1564,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
>  	DEBUG2(printk(KERN_INFO
>  		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
>  		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
> -		      cmd, jiffies, cmd->timeout_per_command / HZ,
> +		      cmd, jiffies, cmd->request->timeout / HZ,
>  		      ha->dpc_flags, cmd->result, cmd->allowed));
> 
>  	/* FIXME: wait for hba to go online */
> diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
> index a5de1a8..e67eb6e 100644
> --- a/drivers/scsi/scsi.c
> +++ b/drivers/scsi/scsi.c
> @@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
> 
>  		memset(cmd, 0, sizeof(*cmd));
>  		cmd->device = dev;
> -		init_timer(&cmd->eh_timeout);
>  		INIT_LIST_HEAD(&cmd->list);
>  		spin_lock_irqsave(&dev->list_lock, flags);
>  		list_add_tail(&cmd->list, &dev->cmd_list);
> @@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	unsigned long timeout;
>  	int rtn = 0;
> 
> +	/*
> +	 * We will use a queued command if possible, otherwise we will
> +	 * emulate the queuing and calling of completion function ourselves.
> +	 */
> +	atomic_inc(&cmd->device->iorequest_cnt);
> +
>  	/* 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);
> +		scsi_done(cmd);
>  		/* return 0 (because the command has been processed) */
>  		goto out;
>  	}
> @@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  		 * future requests should not occur until the device 
>  		 * transitions out of the suspend state.
>  		 */
> -		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
> +
> +		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
> 
>  		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
> 
> @@ -534,21 +539,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  		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.
> -	 */
> -	atomic_inc(&cmd->device->iorequest_cnt);
> -
> -	/*
>  	 * Before we queue this command, check if the command
>  	 * length exceeds what the host adapter can handle.
>  	 */
> @@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	}
> 
>  	spin_lock_irqsave(host->host_lock, flags);
> +	/* 
> +	 * AK: unlikely race here: for some reason the timer could
> +	 * expire before the serial number is set up below.
> +	 *
> +	 * TODO: kill serial or move to blk layer
> +	 */
>  	scsi_cmd_get_serial(host, cmd); 
> 
>  	if (unlikely(host->shost_state == SHOST_DEL)) {
> @@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  	}
>  	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
> +						rtn : SCSI_MLQUEUE_HOST_BUSY);
>  		SCSI_LOG_MLQUEUE(3,
>  		    printk("queuecommand : request rejected\n"));
>  	}
> @@ -588,24 +583,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
>  }
> 
>  /**
> - * scsi_req_abort_cmd -- Request command recovery for the specified command
> - * cmd: pointer to the SCSI command of interest
> - *
> - * This function requests that SCSI Core start recovery for the
> - * command by deleting the timer and adding the command to the eh
> - * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
> - * implement their own error recovery MAY ignore the timeout event if
> - * they generated scsi_req_abort_cmd.
> - */
> -void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
> -{
> -	if (!scsi_delete_timer(cmd))
> -		return;
> -	scsi_times_out(cmd);
> -}
> -EXPORT_SYMBOL(scsi_req_abort_cmd);
> -
> -/**
>   * scsi_done - Enqueue the finished SCSI command into the done queue.
>   * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
>   * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
> @@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
>   */
>  static void scsi_done(struct scsi_cmnd *cmd)
>  {
> -	/*
> -	 * We don't have to worry about this one timing out any more.
> -	 * If we are unable to remove the timer, then the command
> -	 * has already timed out.  In which case, we have no choice but to
> -	 * let the timeout function run, as we have no idea where in fact
> -	 * that function could really be.  It might be on another processor,
> -	 * etc, etc.
> -	 */
> -	if (!scsi_delete_timer(cmd))
> -		return;
> -	__scsi_done(cmd);
> -}
> -
> -/* Private entry to scsi_done() to complete a command when the timer
> - * isn't running --- used by scsi_times_out */
> -void __scsi_done(struct scsi_cmnd *cmd)
> -{
> -	struct request *rq = cmd->request;
> -
> -	/*
> -	 * Set the serial numbers back to zero
> -	 */
> -	cmd->serial_number = 0;
> -
> -	atomic_inc(&cmd->device->iodone_cnt);
> -	if (cmd->result)
> -		atomic_inc(&cmd->device->ioerr_cnt);
> -
> -	BUG_ON(!rq);
> -
> -	/*
> -	 * The uptodate/nbytes values don't matter, as we allow partial
> -	 * completes and thus will check this in the softirq callback
> -	 */
> -	rq->completion_data = cmd;
> -	blk_complete_request(rq);
> +	blk_complete_request(cmd->request);
>  }
> 
>  /*
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index 8a525ab..4475648 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
>  }
> 
>  /**
> - * scsi_add_timer - Start timeout timer for a single scsi command.
> - * @scmd:	scsi command that is about to start running.
> - * @timeout:	amount of time to allow this command to run.
> - * @complete:	timeout function to call if timer isn't canceled.
> - *
> - * Notes:
> - *    This should be turned into an inline function.  Each scsi command
> - *    has its own timer, and as it is added to the queue, we set up the
> - *    timer.  When the command completes, we cancel the timer.
> - **/
> -void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
> -		    void (*complete)(struct scsi_cmnd *))
> -{
> -
> -	/*
> -	 * If the clock was already running for this command, then
> -	 * first delete the timer.  The timer handling code gets rather
> -	 * confused if we don't do this.
> -	 */
> -	if (scmd->eh_timeout.function)
> -		del_timer(&scmd->eh_timeout);
> -
> -	scmd->eh_timeout.data = (unsigned long)scmd;
> -	scmd->eh_timeout.expires = jiffies + timeout;
> -	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
> -
> -	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
> -					  " %d, (%p)\n", __FUNCTION__,
> -					  scmd, timeout, complete));
> -
> -	add_timer(&scmd->eh_timeout);
> -}
> -
> -/**
> - * scsi_delete_timer - Delete/cancel timer for a given function.
> - * @scmd:	Cmd that we are canceling timer for
> - *
> - * Notes:
> - *     This should be turned into an inline function.
> - *
> - * Return value:
> - *     1 if we were able to detach the timer.  0 if we blew it, and the
> - *     timer function has already started to run.
> - **/
> -int scsi_delete_timer(struct scsi_cmnd *scmd)
> -{
> -	int rtn;
> -
> -	rtn = del_timer(&scmd->eh_timeout);
> -
> -	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
> -					 " rtn: %d\n", __FUNCTION__,
> -					 scmd, rtn));
> -
> -	scmd->eh_timeout.data = (unsigned long)NULL;
> -	scmd->eh_timeout.function = NULL;
> -
> -	return rtn;
> -}
> -
> -/**
>   * scsi_times_out - Timeout function for normal scsi commands.
> - * @scmd:	Cmd that is timing out.
> + * @req:	request that is timing out.
>   *
>   * Notes:
>   *     We do not need to lock this.  There is the potential for a race
> @@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
>   *     normal completion function determines that the timer has already
>   *     fired, then it mustn't do anything.
>   **/
> -void scsi_times_out(struct scsi_cmnd *scmd)
> +enum blk_eh_timer_return scsi_times_out(struct request *req)
>  {
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	struct scsi_cmnd *scmd = req->special;
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
> 
>  	scsi_log_completion(scmd, TIMEOUT_ERROR);
> 
> @@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd)
>  		eh_timed_out = NULL;
> 
>  	if (eh_timed_out)
> -		switch (eh_timed_out(scmd)) {
> -		case EH_HANDLED:
> -			__scsi_done(scmd);
> -			return;
> -		case EH_RESET_TIMER:
> -			scsi_add_timer(scmd, scmd->timeout_per_command,
> -				       scsi_times_out);
> -			return;
> -		case EH_NOT_HANDLED:
> +		rtn = eh_timed_out(scmd);
> +		switch (rtn) {
> +		case BLK_EH_NOT_HANDLED:
>  			break;
> +		default:
> +			return rtn;
>  		}
> 
>  	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
>  		scmd->result |= DID_TIME_OUT << 16;
> -		__scsi_done(scmd);
> +		return BLK_EH_HANDLED;
>  	}
> +
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  /**
> @@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
>  	int rtn;
> 
>  	scmd->request = &req;
> -	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
> 
>  	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
>      
> @@ -1679,8 +1617,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
> 
>  	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
> 
> -	init_timer(&scmd->eh_timeout);
> -
>  	/*
>  	 * Sometimes the command can get back into the timer chain,
>  	 * so use the pid as an identifier.
> diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
> index a417a6f..d9c7581 100644
> --- a/drivers/scsi/scsi_lib.c
> +++ b/drivers/scsi/scsi_lib.c
> @@ -162,6 +162,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
>  }
> 
>  /**
> + * scsi_queue_retry - Try inserting a command in the midlevel queue.
> + *
> + * @cmd:	command that we are adding to queue.
> + * @reason:	why we are inserting command to queue.
> + *
> + * Notes:       This is very similar to scsi_queue_insert except that we
> + *              call this function when we don't know if the blk layer timer
> + *              is active or not. We could implement this either by calling
> + *              blk_delete_timer and inserting in the midlevel queue if we
> + *              successfully delete the timer OR setting appropriate result
> + *              field in the cmd and letting it go through the normal done
> + *              routines which will retry the command. For now, We call
> + *              blk_delete_timer!
> + */
> +void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
> +{
> +	if (blk_delete_timer(cmd->request)) {
> +		atomic_inc(&cmd->device->iodone_cnt);
> +		scsi_queue_insert(cmd, reason);
> +	}
> +}
> +
> +/**
>   * scsi_execute - insert request and wait for the result
>   * @sdev:	scsi device
>   * @cmd:	scsi command
> @@ -1115,7 +1138,6 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
>  	
>  	cmd->transfersize = req->data_len;
>  	cmd->allowed = req->retries;
> -	cmd->timeout_per_command = req->timeout;
>  	cmd->done = scsi_blk_pc_done;
>  	return BLKPREP_OK;
>  }
> @@ -1354,17 +1376,26 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
>  	spin_unlock(shost->host_lock);
>  	spin_lock(sdev->request_queue->queue_lock);
> 
> -	__scsi_done(cmd);
> +	__blk_complete_request(req);
>  }
> 
>  static void scsi_softirq_done(struct request *rq)
>  {
> -	struct scsi_cmnd *cmd = rq->completion_data;
> -	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
> +	struct scsi_cmnd *cmd = rq->special;
> +	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
>  	int disposition;
> 
>  	INIT_LIST_HEAD(&cmd->eh_entry);
> 
> +	/*
> +	 * Set the serial numbers back to zero
> +	 */
> +	cmd->serial_number = 0;
> +	
> +	atomic_inc(&cmd->device->iodone_cnt);
> +	if (cmd->result)
> +		atomic_inc(&cmd->device->ioerr_cnt);
> +
>  	disposition = scsi_decide_disposition(cmd);
>  	if (disposition != SUCCESS &&
>  	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
> @@ -1581,6 +1612,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
> 
>  	blk_queue_prep_rq(q, scsi_prep_fn);
>  	blk_queue_softirq_done(q, scsi_softirq_done);
> +	blk_queue_rq_timed_out(q, scsi_times_out);
>  	return q;
>  }
> 
> diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
> index ee8efe8..4c29a95 100644
> --- a/drivers/scsi/scsi_priv.h
> +++ b/drivers/scsi/scsi_priv.h
> @@ -4,6 +4,7 @@
>  #include <linux/device.h>
> 
>  struct request_queue;
> +struct request;
>  struct scsi_cmnd;
>  struct scsi_device;
>  struct scsi_host_template;
> @@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void);
>  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);
>  #ifdef CONFIG_SCSI_LOGGING
>  void scsi_log_send(struct scsi_cmnd *cmd);
>  void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
> @@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void);
>  extern void scsi_exit_devinfo(void);
> 
>  /* scsi_error.c */
> -extern void scsi_add_timer(struct scsi_cmnd *, int,
> -		void (*)(struct scsi_cmnd *));
> -extern int scsi_delete_timer(struct scsi_cmnd *);
> -extern void scsi_times_out(struct scsi_cmnd *cmd);
> +extern enum blk_eh_timer_return scsi_times_out(struct request *req);
>  extern int scsi_error_handler(void *host);
>  extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
>  extern void scsi_eh_wakeup(struct Scsi_Host *shost);
> @@ -67,6 +64,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
>  extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
>  extern void scsi_device_unbusy(struct scsi_device *sdev);
>  extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
> +extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
>  extern void scsi_next_command(struct scsi_cmnd *cmd);
>  extern void scsi_run_host_queues(struct Scsi_Host *shost);
>  extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
> diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
> index 34cdce6..59d1570 100644
> --- a/drivers/scsi/scsi_sysfs.c
> +++ b/drivers/scsi/scsi_sysfs.c
> @@ -443,12 +443,15 @@ sdev_rd_attr (vendor, "%.8s\n");
>  sdev_rd_attr (model, "%.16s\n");
>  sdev_rd_attr (rev, "%.4s\n");
> 
> +/*
> + * TODO: can we make these symlinks to the block layer ones?
> + */
>  static ssize_t
>  sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
>  {
>  	struct scsi_device *sdev;
>  	sdev = to_scsi_device(dev);
> -	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
> +	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
>  }
> 
>  static ssize_t
> @@ -458,7 +461,7 @@ sdev_store_timeout (struct device *dev, struct device_attribute *attr, const cha
>  	int timeout;
>  	sdev = to_scsi_device(dev);
>  	sscanf (buf, "%d\n", &timeout);
> -	sdev->timeout = timeout * HZ;
> +	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
>  	return count;
>  }
>  static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
> diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
> index 4705725..0aef522 100644
> --- a/drivers/scsi/scsi_transport_fc.c
> +++ b/drivers/scsi/scsi_transport_fc.c
> @@ -1920,15 +1920,15 @@ static int fc_vport_match(struct attribute_container *cont,
>   * Notes:
>   *	This routine assumes no locks are held on entry.
>   **/
> -static enum scsi_eh_timer_return
> +static enum blk_eh_timer_return
>  fc_timed_out(struct scsi_cmnd *scmd)
>  {
>  	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
> 
>  	if (rport->port_state == FC_PORTSTATE_BLOCKED)
> -		return EH_RESET_TIMER;
> +		return BLK_EH_RESET_TIMER;
> 
> -	return EH_NOT_HANDLED;
> +	return BLK_EH_NOT_HANDLED;
>  }
> 
>  /*
> diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
> index 2c6116f..7720698 100644
> --- a/drivers/scsi/sd.c
> +++ b/drivers/scsi/sd.c
> @@ -338,7 +338,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
>  	struct gendisk *disk = rq->rq_disk;
>  	sector_t block = rq->sector;
>  	unsigned int this_count = SCpnt->request_bufflen >> 9;
> -	unsigned int timeout = sdp->timeout;
> 
>  	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
>  					"sd_init_command: block=%llu, "
> @@ -489,7 +488,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
>  	SCpnt->transfersize = sdp->sector_size;
>  	SCpnt->underflow = this_count << 9;
>  	SCpnt->allowed = SD_MAX_RETRIES;
> -	SCpnt->timeout_per_command = timeout;
> 
>  	/*
>  	 * This is the completion routine we use.  This is matched in terms
> @@ -1629,11 +1627,12 @@ static int sd_probe(struct device *dev)
>  	sdkp->index = index;
>  	sdkp->openers = 0;
> 
> -	if (!sdp->timeout) {
> +	if (!sdp->request_queue->rq_timeout) {
>  		if (sdp->type != TYPE_MOD)
> -			sdp->timeout = SD_TIMEOUT;
> +			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
>  		else
> -			sdp->timeout = SD_MOD_TIMEOUT;
> +			blk_queue_rq_timeout(sdp->request_queue,
> +					     SD_MOD_TIMEOUT);
>  	}
> 
>  	class_device_initialize(&sdkp->cdev);
> diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
> index 902eb11..cb73d58 100644
> --- a/drivers/scsi/sr.c
> +++ b/drivers/scsi/sr.c
> @@ -298,7 +298,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
> 
>  static int sr_init_command(struct scsi_cmnd * SCpnt)
>  {
> -	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
> +	int block=0, this_count, s_size;
>  	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
> 
>  	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
> @@ -407,7 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
>  	SCpnt->transfersize = cd->device->sector_size;
>  	SCpnt->underflow = this_count << 9;
>  	SCpnt->allowed = MAX_RETRIES;
> -	SCpnt->timeout_per_command = timeout;
> 
>  	/*
>  	 * This is the completion routine we use.  This is matched in terms
> @@ -570,6 +569,8 @@ static int sr_probe(struct device *dev)
>  	disk->fops = &sr_bdops;
>  	disk->flags = GENHD_FL_CD;
> 
> +	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
> +
>  	cd->device = sdev;
>  	cd->disk = disk;
>  	cd->driver = &sr_template;
> diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
> index 3db2232..702f730 100644
> --- a/drivers/scsi/sym53c8xx_2/sym_glue.c
> +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
> @@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
>  	 *  Shorten our settle_time if needed for 
>  	 *  this command not to time out.
>  	 */
> -	if (np->s.settle_time_valid && cmd->timeout_per_command) {
> -		unsigned long tlimit = jiffies + cmd->timeout_per_command;
> +	if (np->s.settle_time_valid && cmd->request->timeout) {
> +		unsigned long tlimit = jiffies + cmd->request->timeout;
>  		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
>  		if (time_after(np->s.settle_time, tlimit)) {
>  			np->s.settle_time = tlimit;
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index b126c6f..bb59cdb 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -309,7 +309,8 @@ struct request {
>  	void *data;
>  	void *sense;
> 
> -	unsigned int timeout;
> +	unsigned long timeout;
> +	struct list_head timeout_list;
>  	int retries;
> 
>  	/*
> @@ -348,6 +349,14 @@ typedef int (issue_flush_fn) (struct request_queue *, struct gendisk *, sector_t
>  typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
>  typedef void (softirq_done_fn)(struct request *);
> 
> +enum blk_eh_timer_return {
> +	BLK_EH_NOT_HANDLED,
> +	BLK_EH_HANDLED,
> +	BLK_EH_RESET_TIMER,
> +};
> +
> +typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
> +
>  enum blk_queue_state {
>  	Queue_down,
>  	Queue_up,
> @@ -385,6 +394,7 @@ struct request_queue
>  	issue_flush_fn		*issue_flush_fn;
>  	prepare_flush_fn	*prepare_flush_fn;
>  	softirq_done_fn		*softirq_done_fn;
> +	rq_timed_out_fn		*rq_timed_out_fn;
> 
>  	/*
>  	 * Dispatch queue sorting
> @@ -455,6 +465,10 @@ struct request_queue
>  	unsigned int		nr_sorted;
>  	unsigned int		in_flight;
> 
> +	unsigned int		rq_timeout;
> +	struct			timer_list timeout;
> +	struct list_head	timeout_list;
> +
>  	/*
>  	 * sg stuff
>  	 */
> @@ -733,6 +747,10 @@ extern int end_that_request_chunk(struct request *, int, int);
>  extern void end_that_request_last(struct request *, int);
>  extern void end_request(struct request *req, int uptodate);
>  extern void blk_complete_request(struct request *);
> +extern void __blk_complete_request(struct request *);
> +extern void blk_abort_req(struct request *);
> +extern int blk_delete_timer(struct request *);
> +extern void blk_add_timer(struct request *);
> 
>  /*
>   * end_that_request_first/chunk() takes an uptodate argument. we account
> @@ -744,6 +762,8 @@ extern void blk_complete_request(struct request *);
> 
>  static inline void blkdev_dequeue_request(struct request *req)
>  {
> +	if (req->q->rq_timed_out_fn)
> +		blk_add_timer(req);
>  	elv_dequeue_request(req->q, req);
>  }
> 
> @@ -767,6 +787,8 @@ extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
>  extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
>  extern void blk_queue_dma_alignment(struct request_queue *, int);
>  extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
> +extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
> +extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
>  extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
>  extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
>  extern void blk_queue_issue_flush_fn(struct request_queue *, issue_flush_fn *);
> diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
> index 53e1705..5841369 100644
> --- a/include/scsi/scsi_cmnd.h
> +++ b/include/scsi/scsi_cmnd.h
> @@ -56,7 +56,6 @@ struct scsi_cmnd {
> 
>  	int retries;
>  	int allowed;
> -	int timeout_per_command;
> 
>  	unsigned char cmd_len;
>  	enum dma_data_direction sc_data_direction;
> @@ -66,7 +65,6 @@ struct scsi_cmnd {
>  	unsigned char cmnd[MAX_COMMAND_SIZE];
>  	unsigned request_bufflen;	/* Actual request size */
> 
> -	struct timer_list eh_timeout;	/* Used to time out the command. */
>  	void *request_buffer;		/* Actual requested buffer */
> 
>  	/* These elements define the operation we ultimately want to perform */
> @@ -126,7 +124,6 @@ extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
>  			       struct device *);
>  extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
>  extern void scsi_finish_command(struct scsi_cmnd *cmd);
> -extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
> 
>  extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
>  				 size_t *offset, size_t *len);
> diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
> index 3b8a6a8..165ccaf 100644
> --- a/include/scsi/scsi_host.h
> +++ b/include/scsi/scsi_host.h
> @@ -36,13 +36,6 @@ struct blk_queue_tags;
>  #define DISABLE_CLUSTERING 0
>  #define ENABLE_CLUSTERING 1
> 
> -enum scsi_eh_timer_return {
> -	EH_NOT_HANDLED,
> -	EH_HANDLED,
> -	EH_RESET_TIMER,
> -};
> -
> -
>  struct scsi_host_template {
>  	struct module *module;
>  	const char *name;
> @@ -336,7 +329,7 @@ struct scsi_host_template {
>  	 *
>  	 * Status: OPTIONAL
>  	 */
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> 
>  	/*
>  	 * Name of proc directory
> diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
> index 3c18baa..23e8d97 100644
> --- a/include/scsi/scsi_transport.h
> +++ b/include/scsi/scsi_transport.h
> @@ -21,6 +21,7 @@
>  #define SCSI_TRANSPORT_H
> 
>  #include <linux/transport_class.h>
> +#include <linux/blkdev.h>
>  #include <scsi/scsi_host.h>
>  #include <scsi/scsi_device.h>
> 
> @@ -64,7 +65,7 @@ struct scsi_transport_template {
>  	 *			begin counting again
>  	 * EH_NOT_HANDLED	Begin normal error recovery
>  	 */
> -	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
> +	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
>  };
> 
>  #define transport_class_to_shost(tc) \
> 
> -- 
> Jens Axboe
> 
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-11 18:01               ` malahal
@ 2007-10-11 18:24                 ` Jens Axboe
  2007-10-11 18:33                   ` Jens Axboe
  0 siblings, 1 reply; 26+ messages in thread
From: Jens Axboe @ 2007-10-11 18:24 UTC (permalink / raw)
  To: James Bottomley, Matthew Wilcox, linux-scsi

On Thu, Oct 11 2007, malahal@us.ibm.com wrote:
> > @@ -3600,24 +3618,132 @@ static struct notifier_block __devinitdata blk_cpu_notifier = {
> >  };
> > 
> >  /**
> > - * blk_complete_request - end I/O on a request
> > - * @req:      the request being processed
> > + * blk_delete_timer - Delete/cancel timer for a given function.
> > + * @req:	request that we are canceling timer for
> >   *
> > - * Description:
> > - *     Ends all I/O on a request. It does not handle partial completions,
> > - *     unless the driver actually implements this in its completion callback
> > - *     through requeueing. Theh actual completion happens out-of-order,
> > - *     through a softirq handler. The user must have registered a completion
> > - *     callback through blk_queue_softirq_done().
> > - **/
> > + * Return value:
> > + *     1 if we were able to detach the timer.  0 if we blew it, and the
> > + *     timer function has already started to run.
> > + */
> > +int blk_delete_timer(struct request *req)
> > +{
> > +	if (!req->q->rq_timed_out_fn)
> > +		return 1;
> > 
> > -void blk_complete_request(struct request *req)
> > +	if (!list_empty(&req->timeout_list)) {
> 
> This could race with timeout handler. In other words, this routine may
> return 1 while blk_rq_timed_out() is running on the request.

My current code is fine, it deletes the request from the list before
calling blk_rq_timed_out().

> > +	ret = q->rq_timed_out_fn(req);
> > +	switch (ret) {
> > +	case BLK_EH_HANDLED:
> > +		__blk_complete_request(req);
> > +		break;
> > +	case BLK_EH_RESET_TIMER:
> > +		blk_add_timer(req);
> 
> You will need to delete the req from the timeout_list before calling
> blk_add_timer again. You may need to remove the req from the list in
> other cases too.

Yep, that is exactly what I did.

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-11 18:24                 ` Jens Axboe
@ 2007-10-11 18:33                   ` Jens Axboe
  2007-10-23  1:45                     ` malahal
  0 siblings, 1 reply; 26+ messages in thread
From: Jens Axboe @ 2007-10-11 18:33 UTC (permalink / raw)
  To: James Bottomley, Matthew Wilcox, linux-scsi

On Thu, Oct 11 2007, Jens Axboe wrote:
> On Thu, Oct 11 2007, malahal@us.ibm.com wrote:
> > > @@ -3600,24 +3618,132 @@ static struct notifier_block __devinitdata blk_cpu_notifier = {
> > >  };
> > > 
> > >  /**
> > > - * blk_complete_request - end I/O on a request
> > > - * @req:      the request being processed
> > > + * blk_delete_timer - Delete/cancel timer for a given function.
> > > + * @req:	request that we are canceling timer for
> > >   *
> > > - * Description:
> > > - *     Ends all I/O on a request. It does not handle partial completions,
> > > - *     unless the driver actually implements this in its completion callback
> > > - *     through requeueing. Theh actual completion happens out-of-order,
> > > - *     through a softirq handler. The user must have registered a completion
> > > - *     callback through blk_queue_softirq_done().
> > > - **/
> > > + * Return value:
> > > + *     1 if we were able to detach the timer.  0 if we blew it, and the
> > > + *     timer function has already started to run.
> > > + */
> > > +int blk_delete_timer(struct request *req)
> > > +{
> > > +	if (!req->q->rq_timed_out_fn)
> > > +		return 1;
> > > 
> > > -void blk_complete_request(struct request *req)
> > > +	if (!list_empty(&req->timeout_list)) {
> > 
> > This could race with timeout handler. In other words, this routine may
> > return 1 while blk_rq_timed_out() is running on the request.
> 
> My current code is fine, it deletes the request from the list before
> calling blk_rq_timed_out().

Current code is below, btw. Not a lot of changes, iirc it's just the
delete-always, a missing export, delete timer on empty list.

diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index cd9d2c5..0833715 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -45,6 +45,7 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node);
 static void blk_recalc_rq_segments(struct request *rq);
 static void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 			    struct bio *bio);
+static void blk_rq_timed_out_timer(unsigned long data);
 
 /*
  * For the allocated request tables
@@ -180,6 +181,18 @@ void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
 
 EXPORT_SYMBOL(blk_queue_softirq_done);
 
+void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
+{
+	q->rq_timeout = timeout;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timeout);
+
+void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn)
+{
+	q->rq_timed_out_fn = fn;
+}
+EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -242,7 +255,9 @@ static void rq_init(struct request_queue *q, struct request *rq)
 {
 	INIT_LIST_HEAD(&rq->queuelist);
 	INIT_LIST_HEAD(&rq->donelist);
+	INIT_LIST_HEAD(&rq->timeout_list);
 
+	rq->timeout = 0;
 	rq->errors = 0;
 	rq->bio = rq->biotail = NULL;
 	INIT_HLIST_NODE(&rq->hash);
@@ -1853,6 +1868,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 		return NULL;
 
 	init_timer(&q->unplug_timer);
+	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
+	INIT_LIST_HEAD(&q->timeout_list);
 
 	snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
 	q->kobj.ktype = &queue_ktype;
@@ -2273,6 +2290,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
+	blk_delete_timer(rq);
 	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
 
 	if (blk_rq_tagged(rq))
@@ -3552,30 +3570,151 @@ static int __cpuinit blk_cpu_notify(struct notifier_block *self, unsigned long a
 	return NOTIFY_OK;
 }
 
-
 static struct notifier_block blk_cpu_notifier __cpuinitdata = {
 	.notifier_call	= blk_cpu_notify,
 };
 
 /**
- * blk_complete_request - end I/O on a request
- * @req:      the request being processed
+ * blk_delete_timer - Delete/cancel timer for a given function.
+ * @req:	request that we are canceling timer for
  *
- * Description:
- *     Ends all I/O on a request. It does not handle partial completions,
- *     unless the driver actually implements this in its completion callback
- *     through requeueing. Theh actual completion happens out-of-order,
- *     through a softirq handler. The user must have registered a completion
- *     callback through blk_queue_softirq_done().
- **/
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run. Caller must hold queue lock.
+ */
+int blk_delete_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
 
-void blk_complete_request(struct request *req)
+	/*
+	 * Nothing to detach
+	 */
+	if (!q->rq_timed_out_fn)
+		return 1;
+
+	/*
+	 * Not on the list, must have already been scheduled (or never added)
+	 */
+	if (list_empty(&req->timeout_list))
+		return 0;
+
+	list_del_init(&req->timeout_list);
+
+	if (list_empty(&q->timeout_list))
+		del_timer(&q->timeout);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(blk_delete_timer);
+
+static void blk_rq_timed_out(struct request *req)
+{
+	struct request_queue *q = req->q;
+	enum blk_eh_timer_return ret;
+
+	ret = q->rq_timed_out_fn(req);
+	switch (ret) {
+	case BLK_EH_HANDLED:
+		__blk_complete_request(req);
+		break;
+	case BLK_EH_RESET_TIMER:
+		blk_add_timer(req);
+		break;
+	case BLK_EH_NOT_HANDLED:
+		/*
+		 * LLD handles this for now but in the future
+		 * we can send a request msg to abort the command
+		 * and we can move more of the generic scsi eh code to
+		 * the blk layer.
+		 */
+		break;
+	default:
+		printk(KERN_ERR "block: bad eh return: %d\n", ret);
+		break;
+	}
+}
+
+static void blk_rq_timed_out_timer(unsigned long data)
+{
+	struct request_queue *q = (struct request_queue *) data;
+	unsigned long flags, next = 0;
+	struct request *rq, *tmp;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) {
+		if (!next || time_before(next, rq->timeout))
+			next = rq->timeout;
+		if (time_after_eq(jiffies, rq->timeout)) {
+			list_del_init(&rq->timeout_list);
+			blk_rq_timed_out(rq);
+		}
+	}
+
+	if (next)
+		mod_timer(&q->timeout, round_jiffies(next));
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/**
+ * blk_abort_request -- Request request recovery for the specified command
+ * @req:	pointer to the request of interest
+ *
+ * This function requests that the block layer start recovery for the
+ * request by deleting the timer and calling the q's timeout function.
+ * LLDDs who implement their own error recovery MAY ignore the timeout
+ * event if they generated blk_abort_req. Must hold queue lock.
+ */
+void blk_abort_request(struct request *req)
+{
+        if (!blk_delete_timer(req))
+                return;
+        blk_rq_timed_out(req);
+}
+EXPORT_SYMBOL_GPL(blk_abort_request);
+
+/**
+ * blk_add_timer - Start timeout timer for a single request
+ * @req:	request that is about to start running.
+ *
+ * Notes:
+ *    Each request has its own timer, and as it is added to the queue, we
+ *    set up the timer. When the request completes, we cancel the timer.
+ */
+void blk_add_timer(struct request *req)
+{
+	struct request_queue *q = req->q;
+	unsigned long expiry;
+
+	BUG_ON(!list_empty(&req->timeout_list));
+
+	if (req->timeout)
+		req->timeout += jiffies;
+	else
+		req->timeout = jiffies + q->rq_timeout;
+
+	list_add_tail(&req->timeout_list, &q->timeout_list);
+
+	/*
+	 * If the timer isn't already pending or this timeout is earlier
+	 * than an existing one, modify the timer. Round to next nearest
+	 * second.
+	 */
+	expiry = round_jiffies(req->timeout);
+	if (!timer_pending(&q->timeout) ||
+	    time_before(expiry, q->timeout.expires))
+		mod_timer(&q->timeout, expiry);
+}
+EXPORT_SYMBOL_GPL(blk_add_timer);
+
+void __blk_complete_request(struct request *req)
 {
 	struct list_head *cpu_list;
 	unsigned long flags;
 
 	BUG_ON(!req->q->softirq_done_fn);
-		
+
 	local_irq_save(flags);
 
 	cpu_list = &__get_cpu_var(blk_cpu_done);
@@ -3584,9 +3723,36 @@ void blk_complete_request(struct request *req)
 
 	local_irq_restore(flags);
 }
+EXPORT_SYMBOL(__blk_complete_request);
 
+/**
+ * blk_complete_request - end I/O on a request
+ * @req:	the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions,
+ *     unless the driver actually implements this in its completion callback
+ *     through requeueing. Theh actual completion happens out-of-order,
+ *     through a softirq handler. The user must have registered a completion
+ *     callback through blk_queue_softirq_done().
+ */
+void blk_complete_request(struct request *req)
+{
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!blk_delete_timer(req))
+		return;
+
+	__blk_complete_request(req);
+}
 EXPORT_SYMBOL(blk_complete_request);
-	
+
 /*
  * queue lock must be held
  */
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ac6ceed..045de4d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -244,29 +245,29 @@ static void ata_eh_clear_action(struct ata_device *dev,
  *	RETURNS:
  *	EH_HANDLED or EH_NOT_HANDLED
  */
-enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct Scsi_Host *host = cmd->device->host;
 	struct ata_port *ap = ata_shost_to_port(host);
 	unsigned long flags;
 	struct ata_queued_cmd *qc;
-	enum scsi_eh_timer_return ret;
+	enum blk_eh_timer_return ret;
 
 	DPRINTK("ENTER\n");
 
 	if (ap->ops->error_handler) {
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 		goto out;
 	}
 
-	ret = EH_HANDLED;
+	ret = BLK_EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
 	qc = ata_qc_from_tag(ap, ap->active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
 		qc->err_mask |= AC_ERR_TIMEOUT;
-		ret = EH_NOT_HANDLED;
+		ret = BLK_EH_NOT_HANDLED;
 	}
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -692,7 +693,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
 	 * Note that ATA_QCFLAG_FAILED is unconditionally set after
 	 * this function completes.
 	 */
-	scsi_req_abort_cmd(qc->scsicmd);
+	blk_abort_request(qc->scsicmd->request);
 }
 
 /**
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 564cd23..6021b9c 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -148,7 +148,7 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 
 /* libata-eh.c */
-extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
 extern void ata_eh_fastdrain_timerfn(unsigned long arg);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6800e57..6fa65c8 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -1125,7 +1125,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd
 	srbcmd->id       = cpu_to_le32(scmd_id(cmd));
 	srbcmd->lun      = cpu_to_le32(cmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	timeout = cmd->timeout_per_command/HZ;
+	timeout = cmd->request->timeout/HZ;
 	if (timeout == 0)
 		timeout = 1;
 	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 79c0b6e..d139075 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7901,7 +7901,7 @@ static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
 	printk(" serial_number 0x%x, retries %d, allowed %d\n",
 	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-	printk(" timeout_per_command %d\n", s->timeout_per_command);
+	printk(" request timeout %d\n", s->request->timeout);
 
 	printk
 	    (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 55e4d2d..c5fc436 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -733,7 +733,6 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
     scp->device = sdev;
     /* use request field to save the ptr. to completion struct. */
     scp->request = (struct request *)&wait;
-    scp->timeout_per_command = timeout*HZ;
     scp->request_buffer = gdtcmd;
     scp->cmd_len = 12;
     memcpy(scp->cmnd, cmnd, 12);
@@ -4948,7 +4947,7 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
     else
-        gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+        gdth_update_timeout(hanum, scp, scp->request->timeout* 6);
 
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 32982eb..22a9013 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
 {
     int oldto;
 
-    oldto = scp->timeout_per_command;
-    scp->timeout_per_command = timeout;
+    oldto = scp->request->timeout;
+    scp->request->timeout = timeout;
 
     if (timeout == 0) {
-        del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) NULL;
-        scp->eh_timeout.expires = 0;
+        del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) NULL;
+        scp->request->timer.expires = 0;
     } else {
-        if (scp->eh_timeout.data != (unsigned long) NULL) 
-            del_timer(&scp->eh_timeout);
-        scp->eh_timeout.data = (unsigned long) scp;
-        scp->eh_timeout.expires = jiffies + timeout;
-        add_timer(&scp->eh_timeout);
+        if (scp->request->timer.data != (unsigned long) NULL) 
+            del_timer(&scp->request->timer);
+        scp->request->timer.data = (unsigned long) scp;
+        scp->request->timer.expires = jiffies + timeout;
+        add_timer(&scp->request->timer);
     }
 
     return oldto;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5ecc63d..04dbe3b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -726,7 +726,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
 	init_event_struct(evt_struct,
 			  handle_cmd_rsp,
 			  VIOSRP_SRP_FORMAT,
-			  cmnd->timeout_per_command/HZ);
+			  cmnd->request->timeout/HZ);
 
 	evt_struct->cmnd = cmnd;
 	evt_struct->cmnd_done = done;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1cc01ac..2035923 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -916,7 +916,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
 	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
 	pc->scsi_cmd = cmd;
 	pc->done = done;
-	pc->timeout = jiffies + cmd->timeout_per_command;
+	pc->timeout = jiffies + cmd->request->timeout;
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eaf..b351f14 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3654,7 +3654,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
 			sdev->no_uld_attach = 1;
 		}
 		if (ipr_is_vset_device(res)) {
-			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_rq_timeout(sdev->request_queue,
+					     IPR_VSET_RW_TIMEOUT);
 			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
 		}
 		if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 492a51b..c81dd8f 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -3860,7 +3860,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
 		scb->cmd.dcdb.segment_4G = 0;
 		scb->cmd.dcdb.enhanced_sg = 0;
 
-		TimeOut = scb->scsi_cmd->timeout_per_command;
+		TimeOut = scb->scsi_cmd->request->timeout;
 
 		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
 			if (!scb->sg_len) {
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5e573ef..f3ae2df 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -408,7 +408,7 @@ void sas_ata_task_abort(struct sas_task *task)
 
 	/* Bounce SCSI-initiated commands to the SCSI EH */
 	if (qc->scsicmd) {
-		scsi_req_abort_cmd(qc->scsicmd);
+		blk_abort_req(qc->scsicmd->request);
 		scsi_schedule_eh(qc->scsicmd->device->host);
 		return;
 	}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 2b8213b..13ac4a3 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -55,7 +55,7 @@ void sas_unregister_phys(struct sas_ha_struct *sas_ha);
 int  sas_register_ports(struct sas_ha_struct *sas_ha);
 void sas_unregister_ports(struct sas_ha_struct *sas_ha);
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
 
 int  sas_init_queue(struct sas_ha_struct *sas_ha);
 int  sas_init_events(struct sas_ha_struct *sas_ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7663841..6d6867c 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -654,43 +654,43 @@ out:
 	return;
 }
 
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
 {
 	struct sas_task *task = TO_SAS_TASK(cmd);
 	unsigned long flags;
 
 	if (!task) {
-		cmd->timeout_per_command /= 2;
+		cmd->request->timeout /= 2;
 		SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
-			    cmd, task, (cmd->timeout_per_command ?
-			    "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
-		if (!cmd->timeout_per_command)
-			return EH_NOT_HANDLED;
-		return EH_RESET_TIMER;
+			    cmd, task, (cmd->request->timeout ?
+			    "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+		if (!cmd->request->timeout)
+			return BLK_EH_NOT_HANDLED;
+		return BLK_EH_RESET_TIMER;
 	}
 
 	spin_lock_irqsave(&task->task_state_lock, flags);
 	BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
 	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
-		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
-			    cmd, task);
-		return EH_HANDLED;
+		SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+			    "BLK_EH_HANDLED\n", cmd, task);
+		return BLK_EH_HANDLED;
 	}
 	if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
 		spin_unlock_irqrestore(&task->task_state_lock, flags);
 		SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
-			    "EH_RESET_TIMER\n",
+			    "BLK_EH_RESET_TIMER\n",
 			    cmd, task);
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 	}
 	task->task_state_flags |= SAS_TASK_STATE_ABORTED;
 	spin_unlock_irqrestore(&task->task_state_lock, flags);
 
-	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+	SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
 		    cmd, task);
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
@@ -1020,7 +1020,7 @@ void sas_task_abort(struct sas_task *task)
 		return;
 	}
 
-	scsi_req_abort_cmd(sc);
+	blk_abort_req(sc->request);
 	scsi_schedule_eh(sc->device->host);
 }
 
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index ebb948c..84c0eb4 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -969,7 +969,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
  * cmd has not been completed within the timeout period.
  */
 static enum
-scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 {
 	struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr;
 	struct megasas_instance *instance;
@@ -977,7 +977,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
 	if (time_after(jiffies, scmd->jiffies_at_alloc +
 				(MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) {
-		return EH_NOT_HANDLED;
+		return BLK_EH_NOT_HANDLED;
 	}
 
 	instance = cmd->instance;
@@ -991,7 +991,7 @@ scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
 
 		spin_unlock_irqrestore(instance->host->host_lock, flags);
 	}
-	return EH_RESET_TIMER;
+	return BLK_EH_RESET_TIMER;
 }
 
 /**
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 030ba49..39c2d4b 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -4170,8 +4170,8 @@ static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ) {
-		u_long tlimit = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->request->timeout >= HZ) {
+		u_long tlimit = jiffies + cmd->request->timeout - HZ;
 		if (time_after(np->settle_time, tlimit))
 			np->settle_time = tlimit;
 	}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 54d8bdf..f5d5b2a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
@@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 	/* Set ISP command timeout. */
-	pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
+	pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ);
 
 	/* Set device target ID and LUN */
 	pkt->lun = SCSI_LUN_32(cmd);
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index b1d565c..005eb66 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1564,7 +1564,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
 	DEBUG2(printk(KERN_INFO
 		      "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
 		      "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
-		      cmd, jiffies, cmd->timeout_per_command / HZ,
+		      cmd, jiffies, cmd->request->timeout / HZ,
 		      ha->dpc_flags, cmd->result, cmd->allowed));
 
 	/* FIXME: wait for hba to go online */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a5de1a8..e67eb6e 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -203,7 +203,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask)
 
 		memset(cmd, 0, sizeof(*cmd));
 		cmd->device = dev;
-		init_timer(&cmd->eh_timeout);
 		INIT_LIST_HEAD(&cmd->list);
 		spin_lock_irqsave(&dev->list_lock, flags);
 		list_add_tail(&cmd->list, &dev->cmd_list);
@@ -472,14 +471,19 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	unsigned long timeout;
 	int rtn = 0;
 
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	atomic_inc(&cmd->device->iorequest_cnt);
+
 	/* 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);
+		scsi_done(cmd);
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
@@ -492,7 +496,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 		 * future requests should not occur until the device 
 		 * transitions out of the suspend state.
 		 */
-		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		scsi_queue_retry(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
 		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
 
@@ -534,21 +539,9 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 		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.
-	 */
-	atomic_inc(&cmd->device->iorequest_cnt);
-
-	/*
 	 * Before we queue this command, check if the command
 	 * length exceeds what the host adapter can handle.
 	 */
@@ -562,6 +555,12 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	}
 
 	spin_lock_irqsave(host->host_lock, flags);
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 *
+	 * TODO: kill serial or move to blk layer
+	 */
 	scsi_cmd_get_serial(host, cmd); 
 
 	if (unlikely(host->shost_state == SHOST_DEL)) {
@@ -572,12 +571,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 	}
 	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_queue_retry(cmd, (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+						rtn : SCSI_MLQUEUE_HOST_BUSY);
 		SCSI_LOG_MLQUEUE(3,
 		    printk("queuecommand : request rejected\n"));
 	}
@@ -588,24 +583,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
 }
 
 /**
- * scsi_req_abort_cmd -- Request command recovery for the specified command
- * cmd: pointer to the SCSI command of interest
- *
- * This function requests that SCSI Core start recovery for the
- * command by deleting the timer and adding the command to the eh
- * queue.  It can be called by either LLDDs or SCSI Core.  LLDDs who
- * implement their own error recovery MAY ignore the timeout event if
- * they generated scsi_req_abort_cmd.
- */
-void scsi_req_abort_cmd(struct scsi_cmnd *cmd)
-{
-	if (!scsi_delete_timer(cmd))
-		return;
-	scsi_times_out(cmd);
-}
-EXPORT_SYMBOL(scsi_req_abort_cmd);
-
-/**
  * scsi_done - Enqueue the finished SCSI command into the done queue.
  * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
  * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -620,42 +597,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd);
  */
 static void scsi_done(struct scsi_cmnd *cmd)
 {
-	/*
-	 * We don't have to worry about this one timing out any more.
-	 * If we are unable to remove the timer, then the command
-	 * has already timed out.  In which case, we have no choice but to
-	 * let the timeout function run, as we have no idea where in fact
-	 * that function could really be.  It might be on another processor,
-	 * etc, etc.
-	 */
-	if (!scsi_delete_timer(cmd))
-		return;
-	__scsi_done(cmd);
-}
-
-/* Private entry to scsi_done() to complete a command when the timer
- * isn't running --- used by scsi_times_out */
-void __scsi_done(struct scsi_cmnd *cmd)
-{
-	struct request *rq = cmd->request;
-
-	/*
-	 * Set the serial numbers back to zero
-	 */
-	cmd->serial_number = 0;
-
-	atomic_inc(&cmd->device->iodone_cnt);
-	if (cmd->result)
-		atomic_inc(&cmd->device->ioerr_cnt);
-
-	BUG_ON(!rq);
-
-	/*
-	 * The uptodate/nbytes values don't matter, as we allow partial
-	 * completes and thus will check this in the softirq callback
-	 */
-	rq->completion_data = cmd;
-	blk_complete_request(rq);
+	blk_complete_request(cmd->request);
 }
 
 /*
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8a525ab..4475648 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -112,69 +112,8 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
 }
 
 /**
- * scsi_add_timer - Start timeout timer for a single scsi command.
- * @scmd:	scsi command that is about to start running.
- * @timeout:	amount of time to allow this command to run.
- * @complete:	timeout function to call if timer isn't canceled.
- *
- * Notes:
- *    This should be turned into an inline function.  Each scsi command
- *    has its own timer, and as it is added to the queue, we set up the
- *    timer.  When the command completes, we cancel the timer.
- **/
-void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
-		    void (*complete)(struct scsi_cmnd *))
-{
-
-	/*
-	 * If the clock was already running for this command, then
-	 * first delete the timer.  The timer handling code gets rather
-	 * confused if we don't do this.
-	 */
-	if (scmd->eh_timeout.function)
-		del_timer(&scmd->eh_timeout);
-
-	scmd->eh_timeout.data = (unsigned long)scmd;
-	scmd->eh_timeout.expires = jiffies + timeout;
-	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
-					  " %d, (%p)\n", __FUNCTION__,
-					  scmd, timeout, complete));
-
-	add_timer(&scmd->eh_timeout);
-}
-
-/**
- * scsi_delete_timer - Delete/cancel timer for a given function.
- * @scmd:	Cmd that we are canceling timer for
- *
- * Notes:
- *     This should be turned into an inline function.
- *
- * Return value:
- *     1 if we were able to detach the timer.  0 if we blew it, and the
- *     timer function has already started to run.
- **/
-int scsi_delete_timer(struct scsi_cmnd *scmd)
-{
-	int rtn;
-
-	rtn = del_timer(&scmd->eh_timeout);
-
-	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
-					 " rtn: %d\n", __FUNCTION__,
-					 scmd, rtn));
-
-	scmd->eh_timeout.data = (unsigned long)NULL;
-	scmd->eh_timeout.function = NULL;
-
-	return rtn;
-}
-
-/**
  * scsi_times_out - Timeout function for normal scsi commands.
- * @scmd:	Cmd that is timing out.
+ * @req:	request that is timing out.
  *
  * Notes:
  *     We do not need to lock this.  There is the potential for a race
@@ -182,9 +121,11 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
  *     normal completion function determines that the timer has already
  *     fired, then it mustn't do anything.
  **/
-void scsi_times_out(struct scsi_cmnd *scmd)
+enum blk_eh_timer_return scsi_times_out(struct request *req)
 {
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	struct scsi_cmnd *scmd = req->special;
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
 
 	scsi_log_completion(scmd, TIMEOUT_ERROR);
 
@@ -196,22 +137,20 @@ void scsi_times_out(struct scsi_cmnd *scmd)
 		eh_timed_out = NULL;
 
 	if (eh_timed_out)
-		switch (eh_timed_out(scmd)) {
-		case EH_HANDLED:
-			__scsi_done(scmd);
-			return;
-		case EH_RESET_TIMER:
-			scsi_add_timer(scmd, scmd->timeout_per_command,
-				       scsi_times_out);
-			return;
-		case EH_NOT_HANDLED:
+		rtn = eh_timed_out(scmd);
+		switch (rtn) {
+		case BLK_EH_NOT_HANDLED:
 			break;
+		default:
+			return rtn;
 		}
 
 	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
 		scmd->result |= DID_TIME_OUT << 16;
-		__scsi_done(scmd);
+		return BLK_EH_HANDLED;
 	}
+
+	return BLK_EH_NOT_HANDLED;
 }
 
 /**
@@ -1666,7 +1605,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 	int rtn;
 
 	scmd->request = &req;
-	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
 
 	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
     
@@ -1679,8 +1617,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
 
 	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
 
-	init_timer(&scmd->eh_timeout);
-
 	/*
 	 * Sometimes the command can get back into the timer chain,
 	 * so use the pid as an identifier.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 604f4d7..210503f 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -162,6 +162,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
 }
 
 /**
+ * scsi_queue_retry - Try inserting a command in the midlevel queue.
+ *
+ * @cmd:	command that we are adding to queue.
+ * @reason:	why we are inserting command to queue.
+ *
+ * Notes:       This is very similar to scsi_queue_insert except that we
+ *              call this function when we don't know if the blk layer timer
+ *              is active or not. We could implement this either by calling
+ *              blk_delete_timer and inserting in the midlevel queue if we
+ *              successfully delete the timer OR setting appropriate result
+ *              field in the cmd and letting it go through the normal done
+ *              routines which will retry the command. For now, We call
+ *              blk_delete_timer!
+ */
+void scsi_queue_retry(struct scsi_cmnd *cmd, int reason)
+{
+	if (blk_delete_timer(cmd->request)) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd, reason);
+	}
+}
+
+/**
  * scsi_execute - insert request and wait for the result
  * @sdev:	scsi device
  * @cmd:	scsi command
@@ -1102,7 +1125,6 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
 	
 	cmd->transfersize = req->data_len;
 	cmd->allowed = req->retries;
-	cmd->timeout_per_command = req->timeout;
 	cmd->done = scsi_blk_pc_done;
 	return BLKPREP_OK;
 }
@@ -1341,17 +1363,26 @@ static void scsi_kill_request(struct request *req, struct request_queue *q)
 	spin_unlock(shost->host_lock);
 	spin_lock(sdev->request_queue->queue_lock);
 
-	__scsi_done(cmd);
+	__blk_complete_request(req);
 }
 
 static void scsi_softirq_done(struct request *rq)
 {
-	struct scsi_cmnd *cmd = rq->completion_data;
-	unsigned long wait_for = (cmd->allowed + 1) * cmd->timeout_per_command;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned long wait_for = (cmd->allowed + 1) * rq->timeout;
 	int disposition;
 
 	INIT_LIST_HEAD(&cmd->eh_entry);
 
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
+
 	disposition = scsi_decide_disposition(cmd);
 	if (disposition != SUCCESS &&
 	    time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
@@ -1568,6 +1599,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
+	blk_queue_rq_timed_out(q, scsi_times_out);
 	return q;
 }
 
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index ee8efe8..4c29a95 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -4,6 +4,7 @@
 #include <linux/device.h>
 
 struct request_queue;
+struct request;
 struct scsi_cmnd;
 struct scsi_device;
 struct scsi_host_template;
@@ -27,7 +28,6 @@ extern void scsi_exit_hosts(void);
 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);
 #ifdef CONFIG_SCSI_LOGGING
 void scsi_log_send(struct scsi_cmnd *cmd);
 void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
@@ -49,10 +49,7 @@ extern int __init scsi_init_devinfo(void);
 extern void scsi_exit_devinfo(void);
 
 /* scsi_error.c */
-extern void scsi_add_timer(struct scsi_cmnd *, int,
-		void (*)(struct scsi_cmnd *));
-extern int scsi_delete_timer(struct scsi_cmnd *);
-extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern enum blk_eh_timer_return scsi_times_out(struct request *req);
 extern int scsi_error_handler(void *host);
 extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
 extern void scsi_eh_wakeup(struct Scsi_Host *shost);
@@ -67,6 +64,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
 extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
 extern void scsi_device_unbusy(struct scsi_device *sdev);
 extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_queue_retry(struct scsi_cmnd *cmd, int reason);
 extern void scsi_next_command(struct scsi_cmnd *cmd);
 extern void scsi_run_host_queues(struct Scsi_Host *shost);
 extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 34cdce6..59d1570 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -443,12 +443,15 @@ sdev_rd_attr (vendor, "%.8s\n");
 sdev_rd_attr (model, "%.16s\n");
 sdev_rd_attr (rev, "%.4s\n");
 
+/*
+ * TODO: can we make these symlinks to the block layer ones?
+ */
 static ssize_t
 sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_device *sdev;
 	sdev = to_scsi_device(dev);
-	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+	return snprintf (buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ);
 }
 
 static ssize_t
@@ -458,7 +461,7 @@ sdev_store_timeout (struct device *dev, struct device_attribute *attr, const cha
 	int timeout;
 	sdev = to_scsi_device(dev);
 	sscanf (buf, "%d\n", &timeout);
-	sdev->timeout = timeout * HZ;
+	blk_queue_rq_timeout(sdev->request_queue, timeout * HZ);
 	return count;
 }
 static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 4705725..0aef522 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1920,15 +1920,15 @@ static int fc_vport_match(struct attribute_container *cont,
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-static enum scsi_eh_timer_return
+static enum blk_eh_timer_return
 fc_timed_out(struct scsi_cmnd *scmd)
 {
 	struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device));
 
 	if (rport->port_state == FC_PORTSTATE_BLOCKED)
-		return EH_RESET_TIMER;
+		return BLK_EH_RESET_TIMER;
 
-	return EH_NOT_HANDLED;
+	return BLK_EH_NOT_HANDLED;
 }
 
 /*
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116f..7720698 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -338,7 +338,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
 	struct gendisk *disk = rq->rq_disk;
 	sector_t block = rq->sector;
 	unsigned int this_count = SCpnt->request_bufflen >> 9;
-	unsigned int timeout = sdp->timeout;
 
 	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
 					"sd_init_command: block=%llu, "
@@ -489,7 +488,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
 	SCpnt->transfersize = sdp->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = SD_MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -1629,11 +1627,12 @@ static int sd_probe(struct device *dev)
 	sdkp->index = index;
 	sdkp->openers = 0;
 
-	if (!sdp->timeout) {
+	if (!sdp->request_queue->rq_timeout) {
 		if (sdp->type != TYPE_MOD)
-			sdp->timeout = SD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
 		else
-			sdp->timeout = SD_MOD_TIMEOUT;
+			blk_queue_rq_timeout(sdp->request_queue,
+					     SD_MOD_TIMEOUT);
 	}
 
 	class_device_initialize(&sdkp->cdev);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 902eb11..cb73d58 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -298,7 +298,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
 
 static int sr_init_command(struct scsi_cmnd * SCpnt)
 {
-	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	int block=0, this_count, s_size;
 	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
 
 	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
@@ -407,7 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
 	SCpnt->transfersize = cd->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 	SCpnt->allowed = MAX_RETRIES;
-	SCpnt->timeout_per_command = timeout;
 
 	/*
 	 * This is the completion routine we use.  This is matched in terms
@@ -570,6 +569,8 @@ static int sr_probe(struct device *dev)
 	disk->fops = &sr_bdops;
 	disk->flags = GENHD_FL_CD;
 
+	blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
+
 	cd->device = sdev;
 	cd->disk = disk;
 	cd->driver = &sr_template;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 3db2232..702f730 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -571,8 +571,8 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
 	 *  Shorten our settle_time if needed for 
 	 *  this command not to time out.
 	 */
-	if (np->s.settle_time_valid && cmd->timeout_per_command) {
-		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+	if (np->s.settle_time_valid && cmd->request->timeout) {
+		unsigned long tlimit = jiffies + cmd->request->timeout;
 		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
 		if (time_after(np->s.settle_time, tlimit)) {
 			np->s.settle_time = tlimit;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 95be0ac..54fc5d7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -309,7 +309,8 @@ struct request {
 	void *data;
 	void *sense;
 
-	unsigned int timeout;
+	unsigned long timeout;
+	struct list_head timeout_list;
 	int retries;
 
 	/*
@@ -348,6 +349,14 @@ typedef int (issue_flush_fn) (struct request_queue *, struct gendisk *, sector_t
 typedef void (prepare_flush_fn) (struct request_queue *, struct request *);
 typedef void (softirq_done_fn)(struct request *);
 
+enum blk_eh_timer_return {
+	BLK_EH_NOT_HANDLED,
+	BLK_EH_HANDLED,
+	BLK_EH_RESET_TIMER,
+};
+
+typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *);
+
 enum blk_queue_state {
 	Queue_down,
 	Queue_up,
@@ -385,6 +394,7 @@ struct request_queue
 	issue_flush_fn		*issue_flush_fn;
 	prepare_flush_fn	*prepare_flush_fn;
 	softirq_done_fn		*softirq_done_fn;
+	rq_timed_out_fn		*rq_timed_out_fn;
 
 	/*
 	 * Dispatch queue sorting
@@ -455,6 +465,10 @@ struct request_queue
 	unsigned int		nr_sorted;
 	unsigned int		in_flight;
 
+	unsigned int		rq_timeout;
+	struct			timer_list timeout;
+	struct list_head	timeout_list;
+
 	/*
 	 * sg stuff
 	 */
@@ -745,6 +759,10 @@ extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *, int);
 extern void end_request(struct request *req, int uptodate);
 extern void blk_complete_request(struct request *);
+extern void __blk_complete_request(struct request *);
+extern void blk_abort_request(struct request *);
+extern int blk_delete_timer(struct request *);
+extern void blk_add_timer(struct request *);
 
 /*
  * end_that_request_first/chunk() takes an uptodate argument. we account
@@ -756,6 +774,8 @@ extern void blk_complete_request(struct request *);
 
 static inline void blkdev_dequeue_request(struct request *req)
 {
+	if (req->q->rq_timed_out_fn)
+		blk_add_timer(req);
 	elv_dequeue_request(req->q, req);
 }
 
@@ -779,6 +799,8 @@ extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn);
 extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
+extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
+extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 extern int blk_queue_ordered(struct request_queue *, unsigned, prepare_flush_fn *);
 extern void blk_queue_issue_flush_fn(struct request_queue *, issue_flush_fn *);
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 53e1705..5841369 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -56,7 +56,6 @@ struct scsi_cmnd {
 
 	int retries;
 	int allowed;
-	int timeout_per_command;
 
 	unsigned char cmd_len;
 	enum dma_data_direction sc_data_direction;
@@ -66,7 +65,6 @@ struct scsi_cmnd {
 	unsigned char cmnd[MAX_COMMAND_SIZE];
 	unsigned request_bufflen;	/* Actual request size */
 
-	struct timer_list eh_timeout;	/* Used to time out the command. */
 	void *request_buffer;		/* Actual requested buffer */
 
 	/* These elements define the operation we ultimately want to perform */
@@ -126,7 +124,6 @@ extern void __scsi_put_command(struct Scsi_Host *, struct scsi_cmnd *,
 			       struct device *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd);
 
 extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
 				 size_t *offset, size_t *len);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 3b8a6a8..165ccaf 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -36,13 +36,6 @@ struct blk_queue_tags;
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
 
-enum scsi_eh_timer_return {
-	EH_NOT_HANDLED,
-	EH_HANDLED,
-	EH_RESET_TIMER,
-};
-
-
 struct scsi_host_template {
 	struct module *module;
 	const char *name;
@@ -336,7 +329,7 @@ struct scsi_host_template {
 	 *
 	 * Status: OPTIONAL
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 
 	/*
 	 * Name of proc directory
diff --git a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
index 3c18baa..23e8d97 100644
--- a/include/scsi/scsi_transport.h
+++ b/include/scsi/scsi_transport.h
@@ -21,6 +21,7 @@
 #define SCSI_TRANSPORT_H
 
 #include <linux/transport_class.h>
+#include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
 
@@ -64,7 +65,7 @@ struct scsi_transport_template {
 	 *			begin counting again
 	 * EH_NOT_HANDLED	Begin normal error recovery
 	 */
-	enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+	enum blk_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
 };
 
 #define transport_class_to_shost(tc) \

-- 
Jens Axboe


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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-11 18:33                   ` Jens Axboe
@ 2007-10-23  1:45                     ` malahal
  2007-10-23  6:30                       ` malahal
  2007-10-23 11:59                       ` Jens Axboe
  0 siblings, 2 replies; 26+ messages in thread
From: malahal @ 2007-10-23  1:45 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-scsi

Jens Axboe [jens.axboe@oracle.com] wrote:
> Current code is below, btw. Not a lot of changes, iirc it's just the
> delete-always, a missing export, delete timer on empty list.
> 
> +void blk_add_timer(struct request *req)
> +{
> +	struct request_queue *q = req->q;
> +	unsigned long expiry;
> +
> +	BUG_ON(!list_empty(&req->timeout_list));
> +
> +	if (req->timeout)
> +		req->timeout += jiffies;
> +	else
> +		req->timeout = jiffies + q->rq_timeout;
> +

The meaning of req->timeout is changed here. It was a timeout value, now
it became an expiry time. If we happen to requeue the request, its
timeout would be incorrect. Found using scsi_debug! Maybe, make it a
bitfield to avoid another field...

> +	list_add_tail(&req->timeout_list, &q->timeout_list);
> +
> +	/*
> +	 * If the timer isn't already pending or this timeout is earlier
> +	 * than an existing one, modify the timer. Round to next nearest
> +	 * second.
> +	 */
> +	expiry = round_jiffies(req->timeout);
> +	if (!timer_pending(&q->timeout) ||
> +	    time_before(expiry, q->timeout.expires))
> +		mod_timer(&q->timeout, expiry);

How about changing q->timeout to q->timer?

> diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
> index 32982eb..22a9013 100644
> --- a/drivers/scsi/gdth_proc.c
> +++ b/drivers/scsi/gdth_proc.c
> @@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
>  {
>      int oldto;
> 
> -    oldto = scp->timeout_per_command;
> -    scp->timeout_per_command = timeout;
> +    oldto = scp->request->timeout;
> +    scp->request->timeout = timeout;
> 
>      if (timeout == 0) {
> -        del_timer(&scp->eh_timeout);
> -        scp->eh_timeout.data = (unsigned long) NULL;
> -        scp->eh_timeout.expires = 0;
> +        del_timer(&scp->request->timer);
> +        scp->request->timer.data = (unsigned long) NULL;
> +        scp->request->timer.expires = 0;

request doesn't have "timer" field, code compilation fails for this
file.

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-23  1:45                     ` malahal
@ 2007-10-23  6:30                       ` malahal
  2007-10-23 11:59                       ` Jens Axboe
  1 sibling, 0 replies; 26+ messages in thread
From: malahal @ 2007-10-23  6:30 UTC (permalink / raw)
  To: Jens Axboe, linux-scsi

malahal@us.ibm.com [malahal@us.ibm.com] wrote:
> Jens Axboe [jens.axboe@oracle.com] wrote:
> > Current code is below, btw. Not a lot of changes, iirc it's just the
> > delete-always, a missing export, delete timer on empty list.
> > 
> > +void blk_add_timer(struct request *req)
> > +{
> > +	struct request_queue *q = req->q;
> > +	unsigned long expiry;
> > +
> > +	BUG_ON(!list_empty(&req->timeout_list));
> > +
> > +	if (req->timeout)
> > +		req->timeout += jiffies;
> > +	else
> > +		req->timeout = jiffies + q->rq_timeout;
> > +
> 
> The meaning of req->timeout is changed here. It was a timeout value, now
> it became an expiry time. If we happen to requeue the request, its
> timeout would be incorrect. Found using scsi_debug! Maybe, make it a
> bitfield to avoid another field...

Sorry, bitfield won't work!

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

* Re: [RFC] [PATCH 1/1] blk request timeout handler patches
  2007-10-23  1:45                     ` malahal
  2007-10-23  6:30                       ` malahal
@ 2007-10-23 11:59                       ` Jens Axboe
  1 sibling, 0 replies; 26+ messages in thread
From: Jens Axboe @ 2007-10-23 11:59 UTC (permalink / raw)
  To: linux-scsi

On Mon, Oct 22 2007, malahal@us.ibm.com wrote:
> Jens Axboe [jens.axboe@oracle.com] wrote:
> > Current code is below, btw. Not a lot of changes, iirc it's just the
> > delete-always, a missing export, delete timer on empty list.
> > 
> > +void blk_add_timer(struct request *req)
> > +{
> > +	struct request_queue *q = req->q;
> > +	unsigned long expiry;
> > +
> > +	BUG_ON(!list_empty(&req->timeout_list));
> > +
> > +	if (req->timeout)
> > +		req->timeout += jiffies;
> > +	else
> > +		req->timeout = jiffies + q->rq_timeout;
> > +
> 
> The meaning of req->timeout is changed here. It was a timeout value, now
> it became an expiry time. If we happen to requeue the request, its
> timeout would be incorrect. Found using scsi_debug! Maybe, make it a
> bitfield to avoid another field...

Yes, I did that deliberately, did expect some fallout... Note how I
changed ->timeout to be an unsigned long as well.

> > +	list_add_tail(&req->timeout_list, &q->timeout_list);
> > +
> > +	/*
> > +	 * If the timer isn't already pending or this timeout is earlier
> > +	 * than an existing one, modify the timer. Round to next nearest
> > +	 * second.
> > +	 */
> > +	expiry = round_jiffies(req->timeout);
> > +	if (!timer_pending(&q->timeout) ||
> > +	    time_before(expiry, q->timeout.expires))
> > +		mod_timer(&q->timeout, expiry);
> 
> How about changing q->timeout to q->timer?

There are more timers in the queue, ->timer doesn't tell you what it's
for. I considered ->timeout_timer, but it's a bit long.

> > diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
> > index 32982eb..22a9013 100644
> > --- a/drivers/scsi/gdth_proc.c
> > +++ b/drivers/scsi/gdth_proc.c
> > @@ -846,19 +846,19 @@ static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
> >  {
> >      int oldto;
> > 
> > -    oldto = scp->timeout_per_command;
> > -    scp->timeout_per_command = timeout;
> > +    oldto = scp->request->timeout;
> > +    scp->request->timeout = timeout;
> > 
> >      if (timeout == 0) {
> > -        del_timer(&scp->eh_timeout);
> > -        scp->eh_timeout.data = (unsigned long) NULL;
> > -        scp->eh_timeout.expires = 0;
> > +        del_timer(&scp->request->timer);
> > +        scp->request->timer.data = (unsigned long) NULL;
> > +        scp->request->timer.expires = 0;
> 
> request doesn't have "timer" field, code compilation fails for this
> file.

Thanks, will fix that up.

-- 
Jens Axboe


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

end of thread, other threads:[~2007-10-23 12:01 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-04 18:12 [RFC] [PATCH 0/2] blk request timeout handler patches malahal
2007-10-04 18:17 ` [RFC] [PATCH 1/2] " malahal
2007-10-04 18:52   ` Randy Dunlap
2007-10-04 20:40   ` Salyzyn, Mark
2007-10-05 12:49   ` Jens Axboe
2007-10-08  6:54     ` malahal
2007-10-08  7:04       ` Jens Axboe
2007-10-09  5:36     ` [RFC] [PATCH 1/1] " malahal
2007-10-09  9:14       ` Jens Axboe
2007-10-09 14:26         ` malahal
2007-10-09 12:00       ` Matthew Wilcox
2007-10-09 12:15         ` Jens Axboe
2007-10-09 15:56           ` James Bottomley
2007-10-09 17:23             ` malahal
2007-10-10 12:25             ` Jens Axboe
2007-10-10 16:58               ` malahal
2007-10-10 17:04                 ` Jens Axboe
2007-10-11 18:01               ` malahal
2007-10-11 18:24                 ` Jens Axboe
2007-10-11 18:33                   ` Jens Axboe
2007-10-23  1:45                     ` malahal
2007-10-23  6:30                       ` malahal
2007-10-23 11:59                       ` Jens Axboe
2007-10-05 12:50   ` [RFC] [PATCH 1/2] " Jens Axboe
2007-10-04 18:20 ` [RFC] [PATCH 2/2] " malahal
2007-10-04 18:32   ` Randy Dunlap

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.