]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/scsi_sysfs.c
[PATCH] atyfb: Fix interlaced modes
[linux-2.6-omap-h63xx.git] / drivers / scsi / scsi_sysfs.c
index dae59d1da07a720b11f2f74b5696263a8d863e3b..ea7f3a43357235f3287efe594e41f9799b2fa0aa 100644 (file)
@@ -21,7 +21,7 @@
 #include "scsi_priv.h"
 #include "scsi_logging.h"
 
-static struct {
+static const struct {
        enum scsi_device_state  value;
        char                    *name;
 } sdev_states[] = {
@@ -48,7 +48,7 @@ const char *scsi_device_state_name(enum scsi_device_state state)
        return name;
 }
 
-static struct {
+static const struct {
        enum scsi_host_state    value;
        char                    *name;
 } shost_states[] = {
@@ -57,6 +57,8 @@ static struct {
        { SHOST_CANCEL, "cancel" },
        { SHOST_DEL, "deleted" },
        { SHOST_RECOVERY, "recovery" },
+       { SHOST_CANCEL_RECOVERY, "cancel/recovery" },
+       { SHOST_DEL_RECOVERY, "deleted/recovery", },
 };
 const char *scsi_host_state_name(enum scsi_host_state state)
 {
@@ -261,9 +263,40 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
        return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
 }
 
+static int scsi_bus_suspend(struct device * dev, pm_message_t state)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct scsi_host_template *sht = sdev->host->hostt;
+       int err;
+
+       err = scsi_device_quiesce(sdev);
+       if (err)
+               return err;
+
+       if (sht->suspend)
+               err = sht->suspend(sdev);
+
+       return err;
+}
+
+static int scsi_bus_resume(struct device * dev)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct scsi_host_template *sht = sdev->host->hostt;
+       int err = 0;
+
+       if (sht->resume)
+               err = sht->resume(sdev);
+
+       scsi_device_resume(sdev);
+       return err;
+}
+
 struct bus_type scsi_bus_type = {
         .name          = "scsi",
         .match         = scsi_bus_match,
+       .suspend        = scsi_bus_suspend,
+       .resume         = scsi_bus_resume,
 };
 
 int scsi_sysfs_register(void)
@@ -653,7 +686,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
                        error = attr_add(&sdev->sdev_gendev,
                                        sdev->host->hostt->sdev_attrs[i]);
                        if (error) {
-                               scsi_remove_device(sdev);
+                               __scsi_remove_device(sdev);
                                goto out;
                        }
                }
@@ -667,7 +700,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
                                                        scsi_sysfs_sdev_attrs[i]);
                        error = device_create_file(&sdev->sdev_gendev, attr);
                        if (error) {
-                               scsi_remove_device(sdev);
+                               __scsi_remove_device(sdev);
                                goto out;
                        }
                }
@@ -687,6 +720,23 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
        return error;
 }
 
+void __scsi_remove_device(struct scsi_device *sdev)
+{
+       struct device *dev = &sdev->sdev_gendev;
+
+       if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
+               return;
+
+       class_device_unregister(&sdev->sdev_classdev);
+       transport_remove_device(dev);
+       device_del(dev);
+       scsi_device_set_state(sdev, SDEV_DEL);
+       if (sdev->host->hostt->slave_destroy)
+               sdev->host->hostt->slave_destroy(sdev);
+       transport_destroy_device(dev);
+       put_device(dev);
+}
+
 /**
  * scsi_remove_device - unregister a device from the scsi bus
  * @sdev:      scsi_device to unregister
@@ -696,17 +746,7 @@ void scsi_remove_device(struct scsi_device *sdev)
        struct Scsi_Host *shost = sdev->host;
 
        down(&shost->scan_mutex);
-       if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
-               goto out;
-
-       class_device_unregister(&sdev->sdev_classdev);
-       device_del(&sdev->sdev_gendev);
-       scsi_device_set_state(sdev, SDEV_DEL);
-       if (sdev->host->hostt->slave_destroy)
-               sdev->host->hostt->slave_destroy(sdev);
-       transport_unregister_device(&sdev->sdev_gendev);
-       put_device(&sdev->sdev_gendev);
-out:
+       __scsi_remove_device(sdev);
        up(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_remove_device);
@@ -715,17 +755,20 @@ void __scsi_remove_target(struct scsi_target *starget)
 {
        struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
        unsigned long flags;
-       struct scsi_device *sdev, *tmp;
+       struct scsi_device *sdev;
 
        spin_lock_irqsave(shost->host_lock, flags);
        starget->reap_ref++;
-       list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
+ restart:
+       list_for_each_entry(sdev, &shost->__devices, siblings) {
                if (sdev->channel != starget->channel ||
-                   sdev->id != starget->id)
+                   sdev->id != starget->id ||
+                   sdev->sdev_state == SDEV_DEL)
                        continue;
                spin_unlock_irqrestore(shost->host_lock, flags);
                scsi_remove_device(sdev);
                spin_lock_irqsave(shost->host_lock, flags);
+               goto restart;
        }
        spin_unlock_irqrestore(shost->host_lock, flags);
        scsi_target_reap(starget);