]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi.c
[SCSI] add inline functions for recognising created and blocked states
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi.c
index 110e776d1a078cbd24cfdb795f7fec16cf95f1c3..762a8797e0be79fa2e48bef488b306fdc1fa35d8 100644 (file)
@@ -197,10 +197,42 @@ static void
 scsi_pool_free_command(struct scsi_host_cmd_pool *pool,
                         struct scsi_cmnd *cmd)
 {
+       if (cmd->prot_sdb)
+               kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb);
+
        kmem_cache_free(pool->sense_slab, cmd->sense_buffer);
        kmem_cache_free(pool->cmd_slab, cmd);
 }
 
+/**
+ * scsi_host_alloc_command - internal function to allocate command
+ * @shost:     SCSI host whose pool to allocate from
+ * @gfp_mask:  mask for the allocation
+ *
+ * Returns a fully allocated command with sense buffer and protection
+ * data buffer (where applicable) or NULL on failure
+ */
+static struct scsi_cmnd *
+scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
+{
+       struct scsi_cmnd *cmd;
+
+       cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+       if (!cmd)
+               return NULL;
+
+       if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) {
+               cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask);
+
+               if (!cmd->prot_sdb) {
+                       scsi_pool_free_command(shost->cmd_pool, cmd);
+                       return NULL;
+               }
+       }
+
+       return cmd;
+}
+
 /**
  * __scsi_get_command - Allocate a struct scsi_cmnd
  * @shost: host to transmit command
@@ -214,7 +246,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
        struct scsi_cmnd *cmd;
        unsigned char *buf;
 
-       cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+       cmd = scsi_host_alloc_command(shost, gfp_mask);
 
        if (unlikely(!cmd)) {
                unsigned long flags;
@@ -457,7 +489,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
        /*
         * Get one backup command for this host.
         */
-       cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
+       cmd = scsi_host_alloc_command(shost, gfp_mask);
        if (!cmd) {
                scsi_put_host_cmd_pool(gfp_mask);
                shost->cmd_pool = NULL;
@@ -632,13 +664,14 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                goto out;
        }
 
-       /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
-       if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+       /* Check to see if the scsi lld made this device blocked. */
+       if (unlikely(scsi_device_blocked(cmd->device))) {
                /* 
-                * in SDEV_BLOCK, the command is just put back on the device
-                * queue.  The suspend state has already blocked the queue so
-                * future requests should not occur until the device 
-                * transitions out of the suspend state.
+                * in blocked state, the command is just put back on
+                * the device queue.  The suspend state has already
+                * blocked the queue so future requests should not
+                * occur until the device transitions out of the
+                * suspend state.
                 */
                scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
 
@@ -855,9 +888,18 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
 
        good_bytes = scsi_bufflen(cmd);
         if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+               int old_good_bytes = good_bytes;
                drv = scsi_cmd_to_driver(cmd);
                if (drv->done)
                        good_bytes = drv->done(cmd);
+               /*
+                * USB may not give sense identifying bad sector and
+                * simply return a residue instead, so subtract off the
+                * residue if drv->done() error processing indicates no
+                * change to the completion length.
+                */
+               if (good_bytes == old_good_bytes)
+                       good_bytes -= scsi_get_resid(cmd);
        }
        scsi_io_completion(cmd, good_bytes);
 }
@@ -893,11 +935,20 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 
        spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
 
-       /* Check to see if the queue is managed by the block layer.
-        * If it is, and we fail to adjust the depth, exit. */
-       if (blk_queue_tagged(sdev->request_queue) &&
-           blk_queue_resize_tags(sdev->request_queue, tags) != 0)
-               goto out;
+       /*
+        * Check to see if the queue is managed by the block layer.
+        * If it is, and we fail to adjust the depth, exit.
+        *
+        * Do not resize the tag map if it is a host wide share bqt,
+        * because the size should be the hosts's can_queue. If there
+        * is more IO than the LLD's can_queue (so there are not enuogh
+        * tags) request_fn's host queue ready check will handle it.
+        */
+       if (!sdev->host->bqt) {
+               if (blk_queue_tagged(sdev->request_queue) &&
+                   blk_queue_resize_tags(sdev->request_queue, tags) != 0)
+                       goto out;
+       }
 
        sdev->queue_depth = tags;
        switch (tagged) {