vserver 2.0 rc7
[linux-2.6.git] / drivers / scsi / scsi.c
index 12f8187..184bcae 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"
 #define CDB_SIZE(cmd)  (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
                                COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
 
-/*
- * Data declarations.
- */
-unsigned long scsi_pid;
-static unsigned long serial_number;
-
 /*
  * Note - the initial logging level can be set here to log events at boot time.
  * 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 +112,7 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
        "RAID             ",
        "Enclosure        ",
 };
+EXPORT_SYMBOL(scsi_device_types);
 
 /*
  * Function:    scsi_allocate_request
@@ -141,6 +145,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 +186,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 +244,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 +264,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 +284,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 +303,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 +418,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 +486,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
+                                * XXX The scsi_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",
@@ -486,6 +504,21 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
 }
 #endif
 
+/* 
+ * Assign a serial number and pid to the request for error recovery
+ * and debugging purposes.  Protected by the Host_Lock of host.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+       cmd->serial_number = host->cmd_serial_number++;
+       if (cmd->serial_number == 0) 
+               cmd->serial_number = host->cmd_serial_number++;
+       
+       cmd->pid = host->cmd_pid++;
+       if (cmd->pid == 0)
+               cmd->pid = host->cmd_pid++;
+}
+
 /*
  * Function:    scsi_dispatch_command
  *
@@ -508,16 +541,30 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
                 * returns an immediate error upwards, and signals
                 * that the device is no longer present */
                cmd->result = DID_NO_CONNECT << 16;
-               scsi_done(cmd);
+               atomic_inc(&cmd->device->iorequest_cnt);
+               __scsi_done(cmd);
                /* return 0 (because the command has been processed) */
                goto out;
        }
-       /* Assign a unique nonzero serial_number. */
-       /* XXX(hch): this is racy */
-       if (++serial_number == 0)
-               serial_number = 1;
-       cmd->serial_number = serial_number;
-       cmd->pid = scsi_pid++;
+
+       /* 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;
+       }
 
        /* 
         * If SCSI-2 or lower, store the LUN value in cmnd.
@@ -549,6 +596,10 @@ 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);
@@ -561,6 +612,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
        cmd->state = SCSI_STATE_QUEUED;
        cmd->owner = SCSI_OWNER_LOWLEVEL;
 
+       atomic_inc(&cmd->device->iorequest_cnt);
+
        /*
         * Before we queue this command, check if the command
         * length exceeds what the host adapter can handle.
@@ -570,13 +623,13 @@ 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;
        }
 
        spin_lock_irqsave(host->host_lock, flags);
+       scsi_cmd_get_serial(host, cmd); 
+
        if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
                cmd->result = (DID_NO_CONNECT << 16);
                scsi_done(cmd);
@@ -585,6 +638,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
        }
        spin_unlock_irqrestore(host->host_lock, flags);
        if (rtn) {
+               atomic_inc(&cmd->device->iodone_cnt);
                scsi_queue_insert(cmd,
                                (rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
                                 rtn : SCSI_MLQUEUE_HOST_BUSY);
@@ -632,7 +686,6 @@ void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq)
        cmd->request = sreq->sr_request;
        memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd));
        cmd->serial_number = 0;
-       cmd->serial_number_at_timeout = 0;
        cmd->bufflen = sreq->sr_bufflen;
        cmd->buffer = sreq->sr_buffer;
        cmd->retries = 0;
@@ -662,7 +715,6 @@ void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq)
        /*
         * Start the timer ticking.
         */
-       cmd->internal_timeout = NORMAL_TIMEOUT;
        cmd->abort_reason = 0;
        cmd->result = 0;
 
@@ -689,8 +741,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,15 +751,26 @@ 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
         */
        cmd->serial_number = 0;
-       cmd->serial_number_at_timeout = 0;
        cmd->state = SCSI_STATE_BHQUEUE;
        cmd->owner = SCSI_OWNER_BH_HANDLER;
 
+       atomic_inc(&cmd->device->iodone_cnt);
+       if (cmd->result)
+               atomic_inc(&cmd->device->ioerr_cnt);
+
        /*
         * Next, enqueue the command into the done queue.
         * It is a per-CPU queue, so we just disable local interrupts
@@ -872,12 +933,9 @@ EXPORT_SYMBOL(scsi_finish_command);
  *             the right thing depending on whether or not the device is
  *             currently active and whether or not it even has the
  *             command blocks built yet.
- *
- * XXX(hch):   What exactly is device_request_lock trying to protect?
  */
 void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
 {
-       static spinlock_t device_request_lock = SPIN_LOCK_UNLOCKED;
        unsigned long flags;
 
        /*
@@ -885,15 +943,15 @@ 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_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;
+
        sdev->queue_depth = tags;
        switch (tagged) {
                case MSG_ORDERED_TAG:
@@ -914,8 +972,10 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
                        sdev->queue_depth = tags;
                        break;
        }
-       spin_unlock_irqrestore(&device_request_lock, flags);
+ out:
+       spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
 }
+EXPORT_SYMBOL(scsi_adjust_queue_depth);
 
 /*
  * Function:   scsi_track_queue_full()
@@ -966,6 +1026,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
@@ -1018,6 +1079,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);
@@ -1028,6 +1090,82 @@ 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_by_target - find a device given the target (UNLOCKED)
+ * @starget:   SCSI target pointer
+ * @lun:       SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @lun for a give
+ * @starget. The returned scsi_device does not have an additional
+ * reference.  You must hold the host's host_lock over this call and
+ * any access to the returned scsi_device.
+ *
+ * Note:  The only reason why drivers would want to use this is because
+ * they're need to access the device list in irq context.  Otherwise you
+ * really want to use scsi_device_lookup_by_target instead.
+ **/
+struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
+                                                  uint lun)
+{
+       struct scsi_device *sdev;
+
+       list_for_each_entry(sdev, &starget->devices, same_target_siblings) {
+               if (sdev->lun ==lun)
+                       return sdev;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL(__scsi_device_lookup_by_target);
+
+/**
+ * scsi_device_lookup_by_target - find a device given the target
+ * @starget:   SCSI target pointer
+ * @lun:       SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @channel, @id, @lun for a
+ * give host.  The returned scsi_device has an additional reference that
+ * needs to be release with scsi_host_put once you're done with it.
+ **/
+struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
+                                                uint lun)
+{
+       struct scsi_device *sdev;
+       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+       unsigned long flags;
+
+       spin_lock_irqsave(shost->host_lock, flags);
+       sdev = __scsi_device_lookup_by_target(starget, lun);
+       if (sdev && scsi_device_get(sdev))
+               sdev = NULL;
+       spin_unlock_irqrestore(shost->host_lock, flags);
+
+       return sdev;
+}
+EXPORT_SYMBOL(scsi_device_lookup_by_target);
+
 /**
  * scsi_device_lookup - find a device given the host (UNLOCKED)
  * @shost:     SCSI host pointer
@@ -1088,8 +1226,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)
@@ -1131,6 +1269,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,