Correct comments in genrtc.c to refer to correct /proc file.
[powerpc.git] / drivers / scsi / scsi_sysfs.c
index e1a9166..67a38a1 100644 (file)
@@ -218,16 +218,16 @@ static void scsi_device_cls_release(struct class_device *class_dev)
        put_device(&sdev->sdev_gendev);
 }
 
-static void scsi_device_dev_release_usercontext(void *data)
+static void scsi_device_dev_release_usercontext(struct work_struct *work)
 {
-       struct device *dev = data;
        struct scsi_device *sdev;
        struct device *parent;
        struct scsi_target *starget;
        unsigned long flags;
 
-       parent = dev->parent;
-       sdev = to_scsi_device(dev);
+       sdev = container_of(work, struct scsi_device, ew.work);
+
+       parent = sdev->sdev_gendev.parent;
        starget = to_scsi_target(parent);
 
        spin_lock_irqsave(sdev->host->host_lock, flags);
@@ -258,7 +258,7 @@ static void scsi_device_dev_release_usercontext(void *data)
 static void scsi_device_dev_release(struct device *dev)
 {
        struct scsi_device *sdp = to_scsi_device(dev);
-       execute_in_process_context(scsi_device_dev_release_usercontext, dev,
+       execute_in_process_context(scsi_device_dev_release_usercontext,
                                   &sdp->ew);
 }
 
@@ -276,8 +276,22 @@ 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_uevent(struct device *dev, char **envp, int num_envp,
+                          char *buffer, int buffer_size)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       int i = 0;
+       int length = 0;
+
+       add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+                      "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
+       envp[i] = NULL;
+       return 0;
+}
+
 static int scsi_bus_suspend(struct device * dev, pm_message_t state)
 {
+       struct device_driver *drv = dev->driver;
        struct scsi_device *sdev = to_scsi_device(dev);
        struct scsi_host_template *sht = sdev->host->hostt;
        int err;
@@ -286,28 +300,51 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state)
        if (err)
                return err;
 
-       if (sht->suspend)
+       /* call HLD suspend first */
+       if (drv && drv->suspend) {
+               err = drv->suspend(dev, state);
+               if (err)
+                       return err;
+       }
+
+       /* then, call host suspend */
+       if (sht->suspend) {
                err = sht->suspend(sdev, state);
+               if (err) {
+                       if (drv && drv->resume)
+                               drv->resume(dev);
+                       return err;
+               }
+       }
 
-       return err;
+       return 0;
 }
 
 static int scsi_bus_resume(struct device * dev)
 {
+       struct device_driver *drv = dev->driver;
        struct scsi_device *sdev = to_scsi_device(dev);
        struct scsi_host_template *sht = sdev->host->hostt;
-       int err = 0;
+       int err = 0, err2 = 0;
 
+       /* call host resume first */
        if (sht->resume)
                err = sht->resume(sdev);
 
+       /* then, call HLD resume */
+       if (drv && drv->resume)
+               err2 = drv->resume(dev);
+
        scsi_device_resume(sdev);
-       return err;
+
+       /* favor LLD failure */
+       return err ? err : err2;;
 }
 
 struct bus_type scsi_bus_type = {
         .name          = "scsi",
         .match         = scsi_bus_match,
+       .uevent         = scsi_bus_uevent,
        .suspend        = scsi_bus_suspend,
        .resume         = scsi_bus_resume,
 };
@@ -452,10 +489,22 @@ store_rescan_field (struct device *dev, struct device_attribute *attr, const cha
 }
 static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
 
+static void sdev_store_delete_callback(struct device *dev)
+{
+       scsi_remove_device(to_scsi_device(dev));
+}
+
 static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf,
                                 size_t count)
 {
-       scsi_remove_device(to_scsi_device(dev));
+       int rc;
+
+       /* An attribute cannot be unregistered by one of its own methods,
+        * so we have to use this roundabout approach.
+        */
+       rc = device_schedule_callback(dev, sdev_store_delete_callback);
+       if (rc)
+               count = rc;
        return count;
 };
 static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
@@ -535,6 +584,14 @@ show_sdev_iostat(iorequest_cnt);
 show_sdev_iostat(iodone_cnt);
 show_sdev_iostat(ioerr_cnt);
 
+static ssize_t
+sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct scsi_device *sdev;
+       sdev = to_scsi_device(dev);
+       return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type);
+}
+static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
 
 /* Default template for device attributes.  May NOT be modified */
 static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -554,6 +611,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
        &dev_attr_iorequest_cnt,
        &dev_attr_iodone_cnt,
        &dev_attr_ioerr_cnt,
+       &dev_attr_modalias,
        NULL
 };
 
@@ -922,7 +980,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
        snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
                 "%d:%d:%d:%d", sdev->host->host_no,
                 sdev->channel, sdev->id, sdev->lun);
-       sdev->scsi_level = SCSI_2;
+       sdev->scsi_level = starget->scsi_level;
        transport_setup_device(&sdev->sdev_gendev);
        spin_lock_irqsave(shost->host_lock, flags);
        list_add_tail(&sdev->same_target_siblings, &starget->devices);