]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/s390/cio/ccwgroup.c
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
[linux-2.6.git] / drivers / s390 / cio / ccwgroup.c
index 918e6fce2573fcd9fe18e61a41c6d26fd3872c56..22ce765d537e9f0bccbca4c769131c07b3c03574 100644 (file)
@@ -104,8 +104,9 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const
        rc = device_schedule_callback(dev, ccwgroup_ungroup_callback);
 out:
        if (rc) {
-               /* Release onoff "lock" when ungrouping failed. */
-               atomic_set(&gdev->onoff, 0);
+               if (rc != -EAGAIN)
+                       /* Release onoff "lock" when ungrouping failed. */
+                       atomic_set(&gdev->onoff, 0);
                return rc;
        }
        return count;
@@ -314,16 +315,32 @@ error:
 }
 EXPORT_SYMBOL(ccwgroup_create_from_string);
 
-static int __init
-init_ccwgroup (void)
+static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
+                            void *data);
+
+static struct notifier_block ccwgroup_nb = {
+       .notifier_call = ccwgroup_notifier
+};
+
+static int __init init_ccwgroup(void)
 {
-       return bus_register (&ccwgroup_bus_type);
+       int ret;
+
+       ret = bus_register(&ccwgroup_bus_type);
+       if (ret)
+               return ret;
+
+       ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
+       if (ret)
+               bus_unregister(&ccwgroup_bus_type);
+
+       return ret;
 }
 
-static void __exit
-cleanup_ccwgroup (void)
+static void __exit cleanup_ccwgroup(void)
 {
-       bus_unregister (&ccwgroup_bus_type);
+       bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb);
+       bus_unregister(&ccwgroup_bus_type);
 }
 
 module_init(init_ccwgroup);
@@ -391,27 +408,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
        unsigned long value;
        int ret;
 
-       gdev = to_ccwgroupdev(dev);
        if (!dev->driver)
-               return count;
+               return -ENODEV;
+
+       gdev = to_ccwgroupdev(dev);
+       gdrv = to_ccwgroupdrv(dev->driver);
 
-       gdrv = to_ccwgroupdrv (gdev->dev.driver);
        if (!try_module_get(gdrv->owner))
                return -EINVAL;
 
        ret = strict_strtoul(buf, 0, &value);
        if (ret)
                goto out;
-       ret = count;
+
        if (value == 1)
-               ccwgroup_set_online(gdev);
+               ret = ccwgroup_set_online(gdev);
        else if (value == 0)
-               ccwgroup_set_offline(gdev);
+               ret = ccwgroup_set_offline(gdev);
        else
                ret = -EINVAL;
 out:
        module_put(gdrv->owner);
-       return ret;
+       return (ret == 0) ? count : ret;
 }
 
 static ssize_t
@@ -453,13 +471,18 @@ ccwgroup_remove (struct device *dev)
        struct ccwgroup_device *gdev;
        struct ccwgroup_driver *gdrv;
 
+       device_remove_file(dev, &dev_attr_online);
+       device_remove_file(dev, &dev_attr_ungroup);
+
+       if (!dev->driver)
+               return 0;
+
        gdev = to_ccwgroupdev(dev);
        gdrv = to_ccwgroupdrv(dev->driver);
 
-       device_remove_file(dev, &dev_attr_online);
-
-       if (gdrv && gdrv->remove)
+       if (gdrv->remove)
                gdrv->remove(gdev);
+
        return 0;
 }
 
@@ -468,9 +491,13 @@ static void ccwgroup_shutdown(struct device *dev)
        struct ccwgroup_device *gdev;
        struct ccwgroup_driver *gdrv;
 
+       if (!dev->driver)
+               return;
+
        gdev = to_ccwgroupdev(dev);
        gdrv = to_ccwgroupdrv(dev->driver);
-       if (gdrv && gdrv->shutdown)
+
+       if (gdrv->shutdown)
                gdrv->shutdown(gdev);
 }
 
@@ -483,6 +510,19 @@ static struct bus_type ccwgroup_bus_type = {
        .shutdown = ccwgroup_shutdown,
 };
 
+
+static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action,
+                            void *data)
+{
+       struct device *dev = data;
+
+       if (action == BUS_NOTIFY_UNBIND_DRIVER)
+               device_schedule_callback(dev, ccwgroup_ungroup_callback);
+
+       return NOTIFY_OK;
+}
+
+
 /**
  * ccwgroup_driver_register() - register a ccw group driver
  * @cdriver: driver to be registered