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 [EMAIL PROTECTED] 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, [EMAIL PROTECTED] 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 [EMAIL PROTECTED]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to