[SCSI] ibmvscsi: convert to use the data buffer accessors
[safe/jmp/linux-2.6] / drivers / scsi / hosts.c
index 85503fa..bd8e7f3 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/transport_class.h>
+#include <linux/platform_device.h>
 
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
@@ -98,6 +99,7 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
                switch (oldstate) {
                case SHOST_CREATED:
                case SHOST_RUNNING:
+               case SHOST_CANCEL_RECOVERY:
                        break;
                default:
                        goto illegal;
@@ -107,23 +109,42 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
        case SHOST_DEL:
                switch (oldstate) {
                case SHOST_CANCEL:
+               case SHOST_DEL_RECOVERY:
                        break;
                default:
                        goto illegal;
                }
                break;
 
+       case SHOST_CANCEL_RECOVERY:
+               switch (oldstate) {
+               case SHOST_CANCEL:
+               case SHOST_RECOVERY:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
+
+       case SHOST_DEL_RECOVERY:
+               switch (oldstate) {
+               case SHOST_CANCEL_RECOVERY:
+                       break;
+               default:
+                       goto illegal;
+               }
+               break;
        }
        shost->shost_state = state;
        return 0;
 
  illegal:
        SCSI_LOG_ERROR_RECOVERY(1,
-                               dev_printk(KERN_ERR, &shost->shost_gendev,
-                                          "Illegal host state transition"
-                                          "%s->%s\n",
-                                          scsi_host_state_name(oldstate),
-                                          scsi_host_state_name(state)));
+                               shost_printk(KERN_ERR, shost,
+                                            "Illegal host state transition"
+                                            "%s->%s\n",
+                                            scsi_host_state_name(oldstate),
+                                            scsi_host_state_name(state)));
        return -EINVAL;
 }
 EXPORT_SYMBOL(scsi_host_set_state);
@@ -134,17 +155,29 @@ EXPORT_SYMBOL(scsi_host_set_state);
  **/
 void scsi_remove_host(struct Scsi_Host *shost)
 {
-       down(&shost->scan_mutex);
-       scsi_host_set_state(shost, SHOST_CANCEL);
-       up(&shost->scan_mutex);
+       unsigned long flags;
+       mutex_lock(&shost->scan_mutex);
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (scsi_host_set_state(shost, SHOST_CANCEL))
+               if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
+                       spin_unlock_irqrestore(shost->host_lock, flags);
+                       mutex_unlock(&shost->scan_mutex);
+                       return;
+               }
+       spin_unlock_irqrestore(shost->host_lock, flags);
+       mutex_unlock(&shost->scan_mutex);
        scsi_forget_host(shost);
        scsi_proc_host_rm(shost);
 
-       scsi_host_set_state(shost, SHOST_DEL);
+       spin_lock_irqsave(shost->host_lock, flags);
+       if (scsi_host_set_state(shost, SHOST_DEL))
+               BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
+       spin_unlock_irqrestore(shost->host_lock, flags);
 
        transport_unregister_device(&shost->shost_gendev);
        class_device_unregister(&shost->shost_classdev);
        device_del(&shost->shost_gendev);
+       scsi_proc_hostdir_rm(shost->hostt);
 }
 EXPORT_SYMBOL(scsi_remove_host);
 
@@ -230,9 +263,15 @@ static void scsi_host_dev_release(struct device *dev)
                kthread_stop(shost->ehandler);
        if (shost->work_q)
                destroy_workqueue(shost->work_q);
+       if (shost->uspace_req_q) {
+               kfree(shost->uspace_req_q->queuedata);
+               scsi_free_queue(shost->uspace_req_q);
+       }
 
-       scsi_proc_hostdir_rm(shost->hostt);
        scsi_destroy_command_freelist(shost);
+       if (shost->bqt)
+               blk_free_tags(shost->bqt);
+
        kfree(shost->shost_data);
 
        if (parent)
@@ -256,30 +295,18 @@ static void scsi_host_dev_release(struct device *dev)
 struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
 {
        struct Scsi_Host *shost;
-       int gfp_mask = GFP_KERNEL, rval;
+       gfp_t gfp_mask = GFP_KERNEL;
+       int rval;
 
        if (sht->unchecked_isa_dma && privsize)
                gfp_mask |= __GFP_DMA;
 
-        /* Check to see if this host has any error handling facilities */
-        if (!sht->eh_strategy_handler && !sht->eh_abort_handler &&
-           !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler &&
-            !sht->eh_host_reset_handler) {
-               printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n"
-                               "ERROR: This is not a safe way to run your "
-                                       "SCSI host\n"
-                               "ERROR: The error handling must be added to "
-                               "this driver\n", sht->proc_name);
-               dump_stack();
-        }
-
-       shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
+       shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
        if (!shost)
                return NULL;
-       memset(shost, 0, sizeof(struct Scsi_Host) + privsize);
 
-       spin_lock_init(&shost->default_lock);
-       scsi_assign_lock(shost, &shost->default_lock);
+       shost->host_lock = &shost->default_lock;
+       spin_lock_init(shost->host_lock);
        shost->shost_state = SHOST_CREATED;
        INIT_LIST_HEAD(&shost->__devices);
        INIT_LIST_HEAD(&shost->__targets);
@@ -287,7 +314,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        INIT_LIST_HEAD(&shost->starved_list);
        init_waitqueue_head(&shost->host_wait);
 
-       init_MUTEX(&shost->scan_mutex);
+       mutex_init(&shost->scan_mutex);
 
        shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
        shost->dma_channel = 0xff;
@@ -314,17 +341,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        shost->cmd_per_lun = sht->cmd_per_lun;
        shost->unchecked_isa_dma = sht->unchecked_isa_dma;
        shost->use_clustering = sht->use_clustering;
-       shost->ordered_flush = sht->ordered_flush;
        shost->ordered_tag = sht->ordered_tag;
 
-       /*
-        * hosts/devices that do queueing must support ordered tags
-        */
-       if (shost->can_queue > 1 && shost->ordered_flush) {
-               printk(KERN_ERR "scsi: ordered flushes don't support queueing\n");
-               shost->ordered_flush = 0;
-       }
-
        if (sht->max_host_blocked)
                shost->max_host_blocked = sht->max_host_blocked;
        else
@@ -417,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
        struct class_device *cdev;
        struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
 
-       down_read(&class->subsys.rwsem);
+       down(&class->sem);
        list_for_each_entry(cdev, &class->children, node) {
                p = class_to_shost(cdev);
                if (p->host_no == hostnum) {
@@ -425,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
                        break;
                }
        }
-       up_read(&class->subsys.rwsem);
+       up(&class->sem);
 
        return shost;
 }
@@ -476,7 +494,9 @@ EXPORT_SYMBOL(scsi_is_host_device);
  * @work:      Work to queue for execution.
  *
  * Return value:
- *     0 on success / != 0 for error
+ *     1 - work queued for execution
+ *     0 - work is already queued
+ *     -EINVAL - work queue doesn't exist
  **/
 int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
 {