Merge branch 'for-jeff' of git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6
[sfrench/cifs-2.6.git] / drivers / scsi / scsi_lib.c
index 14ad2a785a34d142d5585336bcdd58c54136697e..4a602853a98e72f89b94757c4b9e56b87587ad53 100644 (file)
@@ -308,7 +308,7 @@ struct scsi_io_context {
 
 static kmem_cache_t *scsi_io_context_cache;
 
-static void scsi_end_async(struct request *req)
+static void scsi_end_async(struct request *req, int uptodate)
 {
        struct scsi_io_context *sioc = req->end_io_data;
 
@@ -436,6 +436,7 @@ free_bios:
  * scsi_execute_async - insert request
  * @sdev:      scsi device
  * @cmd:       scsi command
+ * @cmd_len:   length of scsi cdb
  * @data_direction: data direction
  * @buffer:    data buffer (this can be a kernel buffer or scatterlist)
  * @bufflen:   len of buffer
@@ -445,7 +446,7 @@ free_bios:
  * @flags:     or into request flags
  **/
 int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
-                      int data_direction, void *buffer, unsigned bufflen,
+                      int cmd_len, int data_direction, void *buffer, unsigned bufflen,
                       int use_sg, int timeout, int retries, void *privdata,
                       void (*done)(void *, char *, int, int), gfp_t gfp)
 {
@@ -472,7 +473,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
        if (err)
                goto free_req;
 
-       req->cmd_len = COMMAND_SIZE(cmd[0]);
+       req->cmd_len = cmd_len;
        memcpy(req->cmd, cmd, req->cmd_len);
        req->sense = sioc->sense;
        req->sense_len = 0;
@@ -791,7 +792,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
        spin_lock_irqsave(q->queue_lock, flags);
        if (blk_rq_tagged(req))
                blk_queue_end_tag(q, req);
-       end_that_request_last(req);
+       end_that_request_last(req, uptodate);
        spin_unlock_irqrestore(q->queue_lock, flags);
 
        /*
@@ -932,9 +933,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
        int sense_valid = 0;
        int sense_deferred = 0;
 
-       if (blk_complete_barrier_rq(q, req, good_bytes >> 9))
-               return;
-
        /*
         * Free up any indirection buffers we allocated for DMA purposes. 
         * For the case of a READ, we need to copy the data out of the
@@ -1199,38 +1197,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
        return BLKPREP_KILL;
 }
 
-static int scsi_prepare_flush_fn(request_queue_t *q, struct request *rq)
-{
-       struct scsi_device *sdev = q->queuedata;
-       struct scsi_driver *drv;
-
-       if (sdev->sdev_state == SDEV_RUNNING) {
-               drv = *(struct scsi_driver **) rq->rq_disk->private_data;
-
-               if (drv->prepare_flush)
-                       return drv->prepare_flush(q, rq);
-       }
-
-       return 0;
-}
-
-static void scsi_end_flush_fn(request_queue_t *q, struct request *rq)
-{
-       struct scsi_device *sdev = q->queuedata;
-       struct request *flush_rq = rq->end_io_data;
-       struct scsi_driver *drv;
-
-       if (flush_rq->errors) {
-               printk("scsi: barrier error, disabling flush support\n");
-               blk_queue_ordered(q, QUEUE_ORDERED_NONE);
-       }
-
-       if (sdev->sdev_state == SDEV_RUNNING) {
-               drv = *(struct scsi_driver **) rq->rq_disk->private_data;
-               drv->end_flush(q, rq);
-       }
-}
-
 static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
                               sector_t *error_sector)
 {
@@ -1247,7 +1213,7 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
        return -EOPNOTSUPP;
 }
 
-static void scsi_generic_done(struct scsi_cmnd *cmd)
+static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
 {
        BUG_ON(!blk_pc_request(cmd->request));
        /*
@@ -1259,6 +1225,26 @@ static void scsi_generic_done(struct scsi_cmnd *cmd)
        scsi_io_completion(cmd, cmd->bufflen, 0);
 }
 
+static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+{
+       struct request *req = cmd->request;
+
+       BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
+       memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
+       cmd->cmd_len = req->cmd_len;
+       if (!req->data_len)
+               cmd->sc_data_direction = DMA_NONE;
+       else if (rq_data_dir(req) == WRITE)
+               cmd->sc_data_direction = DMA_TO_DEVICE;
+       else
+               cmd->sc_data_direction = DMA_FROM_DEVICE;
+       
+       cmd->transfersize = req->data_len;
+       cmd->allowed = req->retries;
+       cmd->timeout_per_command = req->timeout;
+       cmd->done = scsi_blk_pc_done;
+}
+
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
        struct scsi_device *sdev = q->queuedata;
@@ -1354,7 +1340,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
         * happening now.
         */
        if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-               struct scsi_driver *drv;
                int ret;
 
                /*
@@ -1386,27 +1371,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                /*
                 * Initialize the actual SCSI command for this request.
                 */
-               if (req->rq_disk) {
+               if (req->flags & REQ_BLOCK_PC) {
+                       scsi_setup_blk_pc_cmnd(cmd);
+               } else if (req->rq_disk) {
+                       struct scsi_driver *drv;
+
                        drv = *(struct scsi_driver **)req->rq_disk->private_data;
                        if (unlikely(!drv->init_command(cmd))) {
                                scsi_release_buffers(cmd);
                                scsi_put_command(cmd);
                                goto kill;
                        }
-               } else {
-                       memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
-                       cmd->cmd_len = req->cmd_len;
-                       if (rq_data_dir(req) == WRITE)
-                               cmd->sc_data_direction = DMA_TO_DEVICE;
-                       else if (req->data_len)
-                               cmd->sc_data_direction = DMA_FROM_DEVICE;
-                       else
-                               cmd->sc_data_direction = DMA_NONE;
-                       
-                       cmd->transfersize = req->data_len;
-                       cmd->allowed = req->retries;
-                       cmd->timeout_per_command = req->timeout;
-                       cmd->done = scsi_generic_done;
                }
        }
 
@@ -1519,6 +1494,41 @@ static void scsi_kill_request(struct request *req, request_queue_t *q)
        __scsi_done(cmd);
 }
 
+static void scsi_softirq_done(struct request *rq)
+{
+       struct scsi_cmnd *cmd = rq->completion_data;
+       unsigned long wait_for = cmd->allowed * cmd->timeout_per_command;
+       int disposition;
+
+       INIT_LIST_HEAD(&cmd->eh_entry);
+
+       disposition = scsi_decide_disposition(cmd);
+       if (disposition != SUCCESS &&
+           time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) {
+               sdev_printk(KERN_ERR, cmd->device,
+                           "timing out command, waited %lus\n",
+                           wait_for/HZ);
+               disposition = SUCCESS;
+       }
+                       
+       scsi_log_completion(cmd, disposition);
+
+       switch (disposition) {
+               case SUCCESS:
+                       scsi_finish_command(cmd);
+                       break;
+               case NEEDS_RETRY:
+                       scsi_retry_command(cmd);
+                       break;
+               case ADD_TO_MLQUEUE:
+                       scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+                       break;
+               default:
+                       if (!scsi_eh_scmd_add(cmd, 0))
+                               scsi_finish_command(cmd);
+       }
+}
+
 /*
  * Function:    scsi_request_fn()
  *
@@ -1693,17 +1703,7 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
        blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
        blk_queue_segment_boundary(q, shost->dma_boundary);
        blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
-
-       /*
-        * ordered tags are superior to flush ordering
-        */
-       if (shost->ordered_tag)
-               blk_queue_ordered(q, QUEUE_ORDERED_TAG);
-       else if (shost->ordered_flush) {
-               blk_queue_ordered(q, QUEUE_ORDERED_FLUSH);
-               q->prepare_flush_fn = scsi_prepare_flush_fn;
-               q->end_flush_fn = scsi_end_flush_fn;
-       }
+       blk_queue_softirq_done(q, scsi_softirq_done);
 
        if (!shost->use_clustering)
                clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);