]> err.no Git - linux-2.6/blobdiff - drivers/s390/cio/device.c
[PATCH] s390: Fix modalias for ccw devices
[linux-2.6] / drivers / s390 / cio / device.c
index 85908cacc3b82966e27ee58c4f9ed491313d193c..062fb100d94c17035c5b0cd30ef47930637f9e3e 100644 (file)
@@ -1,12 +1,11 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.131 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 #include <linux/config.h>
@@ -107,33 +106,29 @@ ccw_uevent (struct device *dev, char **envp, int num_envp,
        return 0;
 }
 
-struct bus_type ccw_bus_type = {
-       .name  = "ccw",
-       .match = &ccw_bus_match,
-       .uevent = &ccw_uevent,
-};
+struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct device *);
-static int io_subchannel_remove (struct device *);
+static int io_subchannel_probe (struct subchannel *);
+static int io_subchannel_remove (struct subchannel *);
 void io_subchannel_irq (struct device *);
 static int io_subchannel_notify(struct device *, int);
 static void io_subchannel_verify(struct device *);
 static void io_subchannel_ioterm(struct device *);
-static void io_subchannel_shutdown(struct device *);
+static void io_subchannel_shutdown(struct subchannel *);
 
 struct css_driver io_subchannel_driver = {
        .subchannel_type = SUBCHANNEL_TYPE_IO,
        .drv = {
                .name = "io_subchannel",
                .bus  = &css_bus_type,
-               .probe = &io_subchannel_probe,
-               .remove = &io_subchannel_remove,
-               .shutdown = &io_subchannel_shutdown,
        },
        .irq = io_subchannel_irq,
        .notify = io_subchannel_notify,
        .verify = io_subchannel_verify,
        .termination = io_subchannel_ioterm,
+       .probe = io_subchannel_probe,
+       .remove = io_subchannel_remove,
+       .shutdown = io_subchannel_shutdown,
 };
 
 struct workqueue_struct *ccw_device_work;
@@ -259,7 +254,7 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
        struct ccw_device_id *id = &(cdev->id);
        int ret;
 
-       ret = sprintf(buf, "ccw:t%04Xm%02x",
+       ret = sprintf(buf, "ccw:t%04Xm%02X",
                        id->cu_type, id->cu_model);
        if (id->dev_type != 0)
                ret += sprintf(buf + ret, "dt%04Xdm%02X\n",
@@ -374,7 +369,7 @@ online_store (struct device *dev, struct device_attribute *attr, const char *buf
        int i, force, ret;
        char *tmp;
 
-       if (atomic_compare_and_swap(0, 1, &cdev->private->onoff))
+       if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
                return -EAGAIN;
 
        if (cdev->drv && !try_module_get(cdev->drv->owner)) {
@@ -535,7 +530,8 @@ ccw_device_register(struct ccw_device *cdev)
 }
 
 struct match_data {
-       unsigned int  devno;
+       unsigned int devno;
+       unsigned int ssid;
        struct ccw_device * sibling;
 };
 
@@ -548,6 +544,7 @@ match_devno(struct device * dev, void * data)
        cdev = to_ccwdev(dev);
        if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
            (cdev->private->devno == d->devno) &&
+           (cdev->private->ssid == d->ssid) &&
            (cdev != d->sibling)) {
                cdev->private->state = DEV_STATE_NOT_OPER;
                return 1;
@@ -556,11 +553,13 @@ match_devno(struct device * dev, void * data)
 }
 
 static struct ccw_device *
-get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling)
+get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid,
+                        struct ccw_device *sibling)
 {
        struct device *dev;
        struct match_data data = {
-               .devno  = devno,
+               .devno   = devno,
+               .ssid    = ssid,
                .sibling = sibling,
        };
 
@@ -616,13 +615,13 @@ ccw_device_do_unreg_rereg(void *data)
 
                need_rename = 1;
                other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev,
-                                                     cdev);
+                                                     sch->schid.ssid, cdev);
                if (other_cdev) {
                        struct subchannel *other_sch;
 
                        other_sch = to_subchannel(other_cdev->dev.parent);
                        if (get_device(&other_sch->dev)) {
-                               stsch(other_sch->irq, &other_sch->schib);
+                               stsch(other_sch->schid, &other_sch->schib);
                                if (other_sch->schib.pmcw.dnv) {
                                        other_sch->schib.pmcw.intparm = 0;
                                        cio_modify(other_sch);
@@ -639,8 +638,8 @@ ccw_device_do_unreg_rereg(void *data)
        if (test_and_clear_bit(1, &cdev->private->registered))
                device_del(&cdev->dev);
        if (need_rename)
-               snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
-                         sch->schib.pmcw.dev);
+               snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
+                         sch->schid.ssid, sch->schib.pmcw.dev);
        PREPARE_WORK(&cdev->private->kick_work,
                     ccw_device_add_changed, (void *)cdev);
        queue_work(ccw_device_work, &cdev->private->kick_work);
@@ -769,18 +768,20 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
        sch->dev.driver_data = cdev;
        sch->driver = &io_subchannel_driver;
        cdev->ccwlock = &sch->lock;
+
        /* Init private data. */
        priv = cdev->private;
        priv->devno = sch->schib.pmcw.dev;
-       priv->irq = sch->irq;
+       priv->ssid = sch->schid.ssid;
+       priv->sch_no = sch->schid.sch_no;
        priv->state = DEV_STATE_NOT_OPER;
        INIT_LIST_HEAD(&priv->cmb_list);
        init_waitqueue_head(&priv->wait_q);
        init_timer(&priv->timer);
 
        /* Set an initial name for the device. */
-       snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
-                 sch->schib.pmcw.dev);
+       snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
+                 sch->schid.ssid, sch->schib.pmcw.dev);
 
        /* Increase counter of devices currently in recognition. */
        atomic_inc(&ccw_device_init_count);
@@ -797,14 +798,12 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
 }
 
 static int
-io_subchannel_probe (struct device *pdev)
+io_subchannel_probe (struct subchannel *sch)
 {
-       struct subchannel *sch;
        struct ccw_device *cdev;
        int rc;
        unsigned long flags;
 
-       sch = to_subchannel(pdev);
        if (sch->dev.driver_data) {
                /*
                 * This subchannel already has an associated ccw_device.
@@ -840,7 +839,7 @@ io_subchannel_probe (struct device *pdev)
        memset(cdev->private, 0, sizeof(struct ccw_device_private));
        atomic_set(&cdev->private->onoff, 0);
        cdev->dev = (struct device) {
-               .parent = pdev,
+               .parent = &sch->dev,
                .release = ccw_device_release,
        };
        INIT_LIST_HEAD(&cdev->private->kick_work.entry);
@@ -853,7 +852,7 @@ io_subchannel_probe (struct device *pdev)
                return -ENODEV;
        }
 
-       rc = io_subchannel_recog(cdev, to_subchannel(pdev));
+       rc = io_subchannel_recog(cdev, sch);
        if (rc) {
                spin_lock_irqsave(&sch->lock, flags);
                sch->dev.driver_data = NULL;
@@ -877,17 +876,17 @@ ccw_device_unregister(void *data)
 }
 
 static int
-io_subchannel_remove (struct device *dev)
+io_subchannel_remove (struct subchannel *sch)
 {
        struct ccw_device *cdev;
        unsigned long flags;
 
-       if (!dev->driver_data)
+       if (!sch->dev.driver_data)
                return 0;
-       cdev = dev->driver_data;
+       cdev = sch->dev.driver_data;
        /* Set ccw device to not operational and drop reference. */
        spin_lock_irqsave(cdev->ccwlock, flags);
-       dev->driver_data = NULL;
+       sch->dev.driver_data = NULL;
        cdev->private->state = DEV_STATE_NOT_OPER;
        spin_unlock_irqrestore(cdev->ccwlock, flags);
        /*
@@ -942,16 +941,14 @@ io_subchannel_ioterm(struct device *dev)
 }
 
 static void
-io_subchannel_shutdown(struct device *dev)
+io_subchannel_shutdown(struct subchannel *sch)
 {
-       struct subchannel *sch;
        struct ccw_device *cdev;
        int ret;
 
-       sch = to_subchannel(dev);
-       cdev = dev->driver_data;
+       cdev = sch->dev.driver_data;
 
-       if (cio_is_console(sch->irq))
+       if (cio_is_console(sch->schid))
                return;
        if (!sch->schib.pmcw.ena)
                /* Nothing to do. */
@@ -986,10 +983,6 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
        cdev->dev = (struct device) {
                .parent = &sch->dev,
        };
-       /* Initialize the subchannel structure */
-       sch->dev.parent = &css_bus_device;
-       sch->dev.bus = &css_bus_type;
-
        rc = io_subchannel_recog(cdev, sch);
        if (rc)
                return rc;
@@ -1019,7 +1012,7 @@ ccw_device_probe_console(void)
        int ret;
 
        if (xchg(&console_cdev_in_use, 1) != 0)
-               return NULL;
+               return ERR_PTR(-EBUSY);
        sch = cio_probe_console();
        if (IS_ERR(sch)) {
                console_cdev_in_use = 0;
@@ -1127,6 +1120,14 @@ ccw_device_remove (struct device *dev)
        return 0;
 }
 
+struct bus_type ccw_bus_type = {
+       .name   = "ccw",
+       .match  = ccw_bus_match,
+       .uevent = ccw_uevent,
+       .probe  = ccw_device_probe,
+       .remove = ccw_device_remove,
+};
+
 int
 ccw_driver_register (struct ccw_driver *cdriver)
 {
@@ -1134,8 +1135,6 @@ ccw_driver_register (struct ccw_driver *cdriver)
 
        drv->bus = &ccw_bus_type;
        drv->name = cdriver->name;
-       drv->probe = ccw_device_probe;
-       drv->remove = ccw_device_remove;
 
        return driver_register(drv);
 }
@@ -1146,6 +1145,16 @@ ccw_driver_unregister (struct ccw_driver *cdriver)
        driver_unregister(&cdriver->driver);
 }
 
+/* Helper func for qdio. */
+struct subchannel_id
+ccw_device_get_subchannel_id(struct ccw_device *cdev)
+{
+       struct subchannel *sch;
+
+       sch = to_subchannel(cdev->dev.parent);
+       return sch->schid;
+}
+
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_online);
 EXPORT_SYMBOL(ccw_device_set_offline);
@@ -1155,3 +1164,4 @@ EXPORT_SYMBOL(get_ccwdev_by_busid);
 EXPORT_SYMBOL(ccw_bus_type);
 EXPORT_SYMBOL(ccw_device_work);
 EXPORT_SYMBOL(ccw_device_notify_work);
+EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id);