vserver 1.9.5.x5
[linux-2.6.git] / drivers / scsi / scsi.c
index 4cff61b..ab4c237 100644 (file)
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
 #include <scsi/scsi_host.h>
-#include "scsi.h"
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_request.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -92,6 +98,9 @@ static unsigned long serial_number;
  * After the system is up, you may enable logging via the /proc interface.
  */
 unsigned int scsi_logging_level;
+#if defined(CONFIG_SCSI_LOGGING)
+EXPORT_SYMBOL(scsi_logging_level);
+#endif
 
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
        "Direct-Access    ",
@@ -109,6 +118,7 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
        "RAID             ",
        "Enclosure        ",
 };
+EXPORT_SYMBOL(scsi_device_types);
 
 /*
  * Function:    scsi_allocate_request
@@ -141,6 +151,7 @@ struct scsi_request *scsi_allocate_request(struct scsi_device *sdev,
 
        return sreq;
 }
+EXPORT_SYMBOL(scsi_allocate_request);
 
 void __scsi_release_request(struct scsi_request *sreq)
 {
@@ -181,6 +192,7 @@ void scsi_release_request(struct scsi_request *sreq)
        __scsi_release_request(sreq);
        kfree(sreq);
 }
+EXPORT_SYMBOL(scsi_release_request);
 
 struct scsi_host_cmd_pool {
        kmem_cache_t    *slab;
@@ -238,7 +250,13 @@ static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
  */
 struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
 {
-       struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask);
+       struct scsi_cmnd *cmd;
+
+       /* Bail if we can't get a reference to the device */
+       if (!get_device(&dev->sdev_gendev))
+               return NULL;
+
+       cmd = __scsi_get_command(dev->host, gfp_mask);
 
        if (likely(cmd != NULL)) {
                unsigned long flags;
@@ -252,10 +270,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
                spin_lock_irqsave(&dev->list_lock, flags);
                list_add_tail(&cmd->list, &dev->cmd_list);
                spin_unlock_irqrestore(&dev->list_lock, flags);
-       }
+       } else
+               put_device(&dev->sdev_gendev);
 
        return cmd;
 }                              
+EXPORT_SYMBOL(scsi_get_command);
 
 /*
  * Function:   scsi_put_command()
@@ -270,7 +290,8 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
  */
 void scsi_put_command(struct scsi_cmnd *cmd)
 {
-       struct Scsi_Host *shost = cmd->device->host;
+       struct scsi_device *sdev = cmd->device;
+       struct Scsi_Host *shost = sdev->host;
        unsigned long flags;
        
        /* serious error if the command hasn't come from a device list */
@@ -288,7 +309,10 @@ void scsi_put_command(struct scsi_cmnd *cmd)
 
        if (likely(cmd != NULL))
                kmem_cache_free(shost->cmd_pool->slab, cmd);
+
+       put_device(&sdev->sdev_gendev);
 }
+EXPORT_SYMBOL(scsi_put_command);
 
 /*
  * Function:   scsi_setup_command_freelist()
@@ -400,7 +424,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
                         * output in scsi_log_completion.
                         */
                        printk("                 ");
-                       print_command(cmd->cmnd);
+                       scsi_print_command(cmd);
                        if (level > 3) {
                                printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
                                       " done = 0x%p, queuecommand 0x%p\n",
@@ -468,13 +492,13 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
                                printk("UNKNOWN");
                        }
                        printk(" %8x ", cmd->result);
-                       print_command(cmd->cmnd);
+                       scsi_print_command(cmd);
                        if (status_byte(cmd->result) & CHECK_CONDITION) {
                                /*
                                 * XXX The print_sense formatting/prefix
                                 * doesn't match this function.
                                 */
-                               print_sense("", cmd);
+                               scsi_print_sense("", cmd);
                        }
                        if (level > 3) {
                                printk(KERN_INFO "scsi host busy %d failed %d\n",
@@ -512,6 +536,26 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                /* return 0 (because the command has been processed) */
                goto out;
        }
+
+       /* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
+       if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+               /* 
+                * in SDEV_BLOCK, the command is just put back on the device
+                * queue.  The suspend state has already blocked the queue so
+                * future requests should not occur until the device 
+                * transitions out of the suspend state.
+                */
+               scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+               SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
+
+               /*
+                * NOTE: rtn is still zero here because we don't need the
+                * queue to be plugged on return (it's already stopped)
+                */
+               goto out;
+       }
+
        /* Assign a unique nonzero serial_number. */
        /* XXX(hch): this is racy */
        if (++serial_number == 0)
@@ -570,9 +614,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                                printk("queuecommand : command too long.\n"));
                cmd->result = (DID_ABORT << 16);
 
-               spin_lock_irqsave(host->host_lock, flags);
                scsi_done(cmd);
-               spin_unlock_irqrestore(host->host_lock, flags);
                goto out;
        }
 
@@ -689,8 +731,6 @@ static DEFINE_PER_CPU(struct list_head, scsi_done_q);
  */
 void scsi_done(struct scsi_cmnd *cmd)
 {
-       unsigned long 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
@@ -701,6 +741,14 @@ void scsi_done(struct scsi_cmnd *cmd)
         */
        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)
+{
+       unsigned long flags;
 
        /*
         * Set the serial numbers back to zero
@@ -877,7 +925,7 @@ EXPORT_SYMBOL(scsi_finish_command);
  */
 void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 {
-       static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(device_request_lock);
        unsigned long flags;
 
        /*
@@ -885,15 +933,16 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
         */
        if (tags <= 0)
                return;
-       /*
-        * Limit max queue depth on a single lun to 256 for now.  Remember,
-        * we allocate a struct scsi_command for each of these and keep it
-        * around forever.  Too deep of a depth just wastes memory.
-        */
-       if (tags > 256)
-               return;
 
        spin_lock_irqsave(&device_request_lock, flags);
+       spin_lock(sdev->request_queue->queue_lock);
+
+       /* 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;
+
        sdev->queue_depth = tags;
        switch (tagged) {
                case MSG_ORDERED_TAG:
@@ -914,8 +963,11 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
                        sdev->queue_depth = tags;
                        break;
        }
+ out:
+       spin_unlock(sdev->request_queue->queue_lock);
        spin_unlock_irqrestore(&device_request_lock, flags);
 }
+EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
 /*
  * Function:   scsi_track_queue_full()
@@ -966,6 +1018,7 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
        return depth;
 }
+EXPORT_SYMBOL(scsi_track_queue_full);
 
 /**
  * scsi_device_get  -  get an addition reference to a scsi_device
@@ -977,8 +1030,6 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
  */
 int scsi_device_get(struct scsi_device *sdev)
 {
-       if(!sdev)
-               return -ENXIO;
        if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
                return -ENXIO;
        if (!get_device(&sdev->sdev_gendev))
@@ -1020,6 +1071,7 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
                /* skip devices that we can't get a reference to */
                if (!scsi_device_get(next))
                        break;
+               next = NULL;
                list = list->next;
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
@@ -1030,6 +1082,28 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
 }
 EXPORT_SYMBOL(__scsi_iterate_devices);
 
+/**
+ * starget_for_each_device  -  helper to walk all devices of a target
+ * @starget:   target whose devices we want to iterate over.
+ *
+ * This traverses over each devices of @shost.  The devices have
+ * a reference that must be released by scsi_host_put when breaking
+ * out of the loop.
+ */
+void starget_for_each_device(struct scsi_target *starget, void * data,
+                    void (*fn)(struct scsi_device *, void *))
+{
+       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+       struct scsi_device *sdev;
+
+       shost_for_each_device(sdev, shost) {
+               if ((sdev->channel == starget->channel) &&
+                   (sdev->id == starget->id))
+                       fn(sdev, data);
+       }
+}
+EXPORT_SYMBOL(starget_for_each_device);
+
 /**
  * scsi_device_lookup - find a device given the host (UNLOCKED)
  * @shost:     SCSI host pointer
@@ -1090,8 +1164,8 @@ EXPORT_SYMBOL(scsi_device_lookup);
 
 /**
  * scsi_device_cancel - cancel outstanding IO to this device
- * @sdev:      pointer to struct scsi_device
- * @data:      pointer to cancel value.
+ * @sdev:      Pointer to struct scsi_device
+ * @recovery:  Boolean instructing function to recover device or not.
  *
  **/
 int scsi_device_cancel(struct scsi_device *sdev, int recovery)
@@ -1133,6 +1207,7 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
 
        return 0;
 }
+EXPORT_SYMBOL(scsi_device_cancel);
 
 #ifdef CONFIG_HOTPLUG_CPU
 static int scsi_cpu_notify(struct notifier_block *self,