]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] s390: common i/o layer.
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 26 Sep 2003 01:01:09 +0000 (18:01 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Fri, 26 Sep 2003 01:01:09 +0000 (18:01 -0700)
 - Remove initialization of device.name.
 - Don't do put_device after failed get_device in get_ccwdev_by_busid.
 - Fix read_dev_chars and read_conf_data.
 - Call interrupt function of ccw device if path verification has been started.
 - Replace atomic_return_add by atomic_add_return in qdio.
 - Use wait_event instead of homegrown wait loop.
 - Fix reestablish queue problem.
 - Add ungroup attribute to ccw_group devices and add links from each
   ccw device of a group to the group device.
 - Use BUS_ID_SIZE instead of DEVICE_ID_SIZE.
 - Delay path verification if a basic sense is required.
 - Move qdio shutdown code from qdio_free to qdio_shutdown.

15 files changed:
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_status.c
drivers/s390/cio/qdio.c
drivers/s390/cio/qdio.h
drivers/s390/net/cu3088.c
include/asm-s390/qdio.h

index 95e6a57c9167f0bda3ecffc6640741b8eb716605..4953cd97ce43e6412e42457838e25cd975e543aa 100644 (file)
@@ -1,11 +1,12 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.7 $
+ *   $Revision: 1.15 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -14,6 +15,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/ctype.h>
+#include <linux/dcache.h>
 
 #include <asm/semaphore.h>
 #include <asm/ccwdev.h>
@@ -56,6 +58,45 @@ static struct bus_type ccwgroup_bus_type = {
        .hotplug = ccwgroup_hotplug,
 };
 
+static inline void
+__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
+{
+       int i;
+       char str[8];
+
+       for (i = 0; i < gdev->count; i++) {
+               sprintf(str, "cdev%d", i);
+               sysfs_remove_link(&gdev->dev.kobj, str);
+               /* Hack: Make sure we act on still valid subdirs. */
+               if (atomic_read(&gdev->cdev[i]->dev.kobj.dentry->d_count))
+                       sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+                                         "group_device");
+       }
+       
+}
+
+/*
+ * Provide an 'ungroup' attribute so the user can remove group devices no
+ * longer needed or accidentially created. Saves memory :)
+ */
+static ssize_t
+ccwgroup_ungroup_store(struct device *dev, const char *buf, size_t count)
+{
+       struct ccwgroup_device *gdev;
+
+       gdev = to_ccwgroupdev(dev);
+
+       if (gdev->state != CCWGROUP_OFFLINE)
+               return -EINVAL;
+
+       __ccwgroup_remove_symlinks(gdev);
+       device_unregister(dev);
+
+       return count;
+}
+
+static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
+
 static void
 ccwgroup_release (struct device *dev)
 {
@@ -69,6 +110,40 @@ ccwgroup_release (struct device *dev)
        kfree(gdev);
 }
 
+static inline int
+__ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
+{
+       char str[8];
+       int i, rc;
+
+       for (i = 0; i < gdev->count; i++) {
+               rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, &gdev->dev.kobj,
+                                      "group_device");
+               if (rc) {
+                       for (--i; i >= 0; i--)
+                               sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+                                                 "group_device");
+                       return rc;
+               }
+       }
+       for (i = 0; i < gdev->count; i++) {
+               sprintf(str, "cdev%d", i);
+               rc = sysfs_create_link(&gdev->dev.kobj, &gdev->cdev[i]->dev.kobj,
+                                      str);
+               if (rc) {
+                       for (--i; i >= 0; i--) {
+                               sprintf(str, "cdev%d", i);
+                               sysfs_remove_link(&gdev->dev.kobj, str);
+                       }
+                       for (i = 0; i < gdev->count; i++)
+                               sysfs_remove_link(&gdev->cdev[i]->dev.kobj,
+                                                 "group_device");
+                       return rc;
+               }
+       }
+       return 0;
+}
+
 /*
  * try to add a new ccwgroup device for one driver
  * argc and argv[] are a list of bus_id's of devices
@@ -82,6 +157,7 @@ ccwgroup_create(struct device *root,
 {
        struct ccwgroup_device *gdev;
        int i;
+       int rc;
 
        if (argc > 256) /* disallow dumb users */
                return -EINVAL;
@@ -90,6 +166,8 @@ ccwgroup_create(struct device *root,
        if (!gdev)
                return -ENOMEM;
 
+       memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0]));
+
        for (i = 0; i < argc; i++) {
                gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
 
@@ -97,8 +175,10 @@ ccwgroup_create(struct device *root,
                 * order to be grouped */
                if (!gdev->cdev[i]
                    || gdev->cdev[i]->id.driver_info !=
-                      gdev->cdev[0]->id.driver_info)
+                   gdev->cdev[0]->id.driver_info) {
+                       rc = -EINVAL;
                        goto error;
+               }
        }
 
        *gdev = (struct ccwgroup_device) {
@@ -114,9 +194,24 @@ ccwgroup_create(struct device *root,
        snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
                        gdev->cdev[0]->dev.bus_id);
 
-       /* TODO: make symlinks for sysfs */
-       return device_register(&gdev->dev);
+       rc = device_register(&gdev->dev);
+       
+       if (rc)
+               goto error;
+
+       rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
+
+       if (rc) {
+               device_unregister(&gdev->dev);
+               goto error;
+       }
+
+       rc = __ccwgroup_create_symlinks(gdev);
+       if (!rc)
+               return 0;
 
+       device_remove_file(&gdev->dev, &dev_attr_ungroup);
+       device_unregister(&gdev->dev);
 error:
        for (i = 0; i < argc; i++)
                if (gdev->cdev[i])
@@ -124,7 +219,7 @@ error:
 
        kfree(gdev);
 
-       return -EINVAL;
+       return rc;
 }
 
 static int __init
@@ -213,7 +308,7 @@ ccwgroup_online_show (struct device *dev, char *buf)
 
        online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE);
 
-       return sprintf(buf, online ? "yes\n" : "no\n");
+       return sprintf(buf, online ? "1\n" : "0\n");
 }
 
 static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
@@ -286,9 +381,59 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
        return 0;
 }
 
+static inline struct ccwgroup_device *
+__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
+{
+       struct ccwgroup_device *gdev;
+       struct list_head *entry;
+       struct device *dev;
+       int i, found;
+
+       /*
+        * Find groupdevice cdev belongs to.
+        * Unfortunately, we can't use bus_for_each_dev() because of the
+        * semaphore (and return value of fn() is int).
+        */
+       if (!get_bus(&ccwgroup_bus_type))
+               return NULL;
+
+       gdev = NULL;
+       down_read(&ccwgroup_bus_type.subsys.rwsem);
+
+       list_for_each(entry, &ccwgroup_bus_type.devices.list) {
+               dev = get_device(container_of(entry, struct device, bus_list));
+               found = 0;
+               if (!dev)
+                       continue;
+               gdev = to_ccwgroupdev(dev);
+               for (i = 0; i < gdev->count && (!found); i++) {
+                       if (gdev->cdev[i] == cdev)
+                               found = 1;
+               }
+               if (found)
+                       break;
+               put_device(dev);
+               gdev = NULL;
+       }
+       up_read(&ccwgroup_bus_type.subsys.rwsem);
+       put_bus(&ccwgroup_bus_type);
+
+       return gdev;
+}
+
 int
 ccwgroup_remove_ccwdev(struct ccw_device *cdev)
 {
+       struct ccwgroup_device *gdev;
+
+       /* If one of its devices is gone, the whole group is done for. */
+       gdev = __ccwgroup_get_gdev_by_cdev(cdev);
+       if (gdev) {
+               ccwgroup_set_offline(gdev);
+               __ccwgroup_remove_symlinks(gdev);
+               device_unregister(&gdev->dev);
+               put_device(&gdev->dev);
+       }
        return 0;
 }
 
index a2dea7728301334444ce9722399cadd9f608027b..88032fc796eca0b6c57be4b09131ee9d31d865e5 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.74 $
+ *   $Revision: 1.77 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
@@ -865,9 +865,7 @@ new_channel_path(int chpid, int status)
        chp->state = status;
        chp->dev.parent = &css_bus_device;
 
-       snprintf(chp->dev.name, DEVICE_NAME_SIZE,
-                "channel path %x", chpid);
-       snprintf(chp->dev.bus_id, DEVICE_ID_SIZE, "chp%x", chpid);
+       snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
 
        /* make it known to the system */
        ret = device_register(&chp->dev);
index ebe3d05b223e20b8813b9bea4dd6a704f78be9d8..4e840d087ef133e43249cec9f5b4e6a498ae0dc8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.100 $
+ *   $Revision: 1.105 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
@@ -277,11 +277,6 @@ cio_halt(struct subchannel *sch)
        if (!sch)
                return -ENODEV;
 
-       /*
-        * we ignore the halt_io() request if ending_status was received but
-        *  a SENSE operation is waiting for completion.
-        */
-
        sprintf (dbf_txt, "haltIO%x", sch->irq);
        CIO_TRACE_EVENT (2, dbf_txt);
 
@@ -316,10 +311,6 @@ cio_clear(struct subchannel *sch)
 
        if (!sch)
                return -ENODEV;
-       /*
-        * we ignore the clear_io() request if ending_status was received but
-        *  a SENSE operation is waiting for completion.
-        */
 
        sprintf (dbf_txt, "clearIO%x", sch->irq);
        CIO_TRACE_EVENT (2, dbf_txt);
@@ -380,7 +371,7 @@ cio_cancel (struct subchannel *sch)
 }
 
 /*
- * Function: cio_cancel
+ * Function: cio_modify
  * Issues a "Modify Subchannel" on the specified subchannel
  */
 static int
@@ -469,11 +460,6 @@ cio_disable_subchannel (struct subchannel *sch)
        sprintf (dbf_txt, "dissch%x", sch->irq);
        CIO_TRACE_EVENT (2, dbf_txt);
 
-       /*
-        * If device isn't operational we have to perform delayed
-        *  disabling when the next interrupt occurs - unless the
-        *  irq is re-requested prior to the interrupt to occur.
-        */
        ccode = stsch (sch->irq, &sch->schib);
        if (ccode == 3)         /* Not operational. */
                return -ENODEV;
index 3cdf5c817e766b670f1cbb74d263b12a77ee7156..e5e4d04dc3036207fe4f1c35df397dc5af83f730 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.43 $
+ *   $Revision: 1.49 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
@@ -27,7 +27,6 @@ unsigned int highest_subchannel;
 int css_init_done = 0;
 
 struct device css_bus_device = {
-       .name   = "Channel Subsystem 0",
        .bus_id = "css0",
 };
 
@@ -79,17 +78,6 @@ css_free_subchannel(int irq)
 static int
 css_register_subchannel(struct subchannel *sch)
 {
-       static const char *subchannel_types[] = {
-               "I/O Subchannel",
-               "CHSC Subchannel",
-               "Message Subchannel",
-               "ADM Subchannel",
-               "undefined subchannel type 4",
-               "undefined subchannel type 5",
-               "undefined subchannel type 6",
-               "undefined subchannel type 7",
-               "undefined subchannel type 8",
-       };
        int ret;
 
        /* Initialize the subchannel structure */
@@ -97,8 +85,7 @@ css_register_subchannel(struct subchannel *sch)
        sch->dev.bus = &css_bus_type;
 
        /* Set a name for the subchannel */
-       strlcpy (sch->dev.name, subchannel_types[sch->st], DEVICE_NAME_SIZE);
-       snprintf (sch->dev.bus_id, DEVICE_ID_SIZE, "0:%04x", sch->irq);
+       snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", sch->irq);
 
        /* make it known to the system */
        ret = device_register(&sch->dev);
index 270ec4ec200dc7bce654bf75be00182e2458216b..e9e78ff2ce7b6d501362652eb909967f465ade07 100644 (file)
@@ -78,6 +78,7 @@ struct ccw_device_private {
                unsigned int pgid_single:1; /* use single path for Set PGID */
                unsigned int esid:1;        /* Ext. SenseID supported by HW */
                unsigned int dosense:1;     /* delayed SENSE required */
+               unsigned int doverify:1;    /* delayed path verification */
        } __attribute__((packed)) flags;
        unsigned long intparm;  /* user interruption parameter */
        struct qdio_irq *qdio_data;
index f9b0a7f3409ca08f9a9660f9534e3122c64d4ab6..66932d56cc228634b68622919df40c4bf474c98b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.60 $
+ *   $Revision: 1.70 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
@@ -229,7 +229,7 @@ online_show (struct device *dev, char *buf)
 {
        struct ccw_device *cdev = to_ccwdev(dev);
 
-       return sprintf(buf, cdev->online ? "yes\n" : "no\n");
+       return sprintf(buf, cdev->online ? "1\n" : "0\n");
 }
 
 void
@@ -537,8 +537,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
        init_timer(&cdev->private->timer);
 
        /* Set an initial name for the device. */
-       snprintf (cdev->dev.name, DEVICE_NAME_SIZE,"ccw device");
-       snprintf (cdev->dev.bus_id, DEVICE_ID_SIZE, "0:%04x",
+       snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x",
                  sch->schib.pmcw.dev);
 
        /* Increase counter of devices currently in recognition. */
@@ -679,6 +678,7 @@ ccw_device_probe_console(void)
                console_cdev_in_use = 0;
                return ERR_PTR(ret);
        }
+       console_cdev.online = 1;
        return &console_cdev;
 }
 #endif
@@ -702,10 +702,12 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
        list_for_each_entry(d, &drv->devices, driver_list) {
                dev = get_device(d);
 
-               if (dev && !strncmp(bus_id, dev->bus_id, DEVICE_ID_SIZE))
+               if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE))
                        break;
-               else
+               else if (dev) {
                        put_device(dev);
+                       dev = NULL;
+               }
        }
        up_read(&drv->bus->subsys.rwsem);
        put_driver(drv);
index d2f1a5e6fbf69f4799a4338616ac8502e8310b5e..b45dcca99304f53d4cc570ffecd2f2ede2357698 100644 (file)
@@ -15,8 +15,6 @@ enum dev_state {
        DEV_STATE_DISBAND_PGID,
        DEV_STATE_BOXED,
        /* states to wait for i/o completion before doing something */
-       DEV_STATE_ONLINE_VERIFY,
-       DEV_STATE_W4SENSE_VERIFY,
        DEV_STATE_CLEAR_VERIFY,
        DEV_STATE_TIMEOUT_KILL,
        /* last element! */
@@ -95,7 +93,7 @@ void ccw_device_disband_start(struct ccw_device *);
 void ccw_device_disband_irq(struct ccw_device *, enum dev_event);
 void ccw_device_disband_done(struct ccw_device *, int);
 
-void ccw_device_call_handler(struct ccw_device *);
+int ccw_device_call_handler(struct ccw_device *);
 
 void ccw_device_add_stlck(void *);
 int ccw_device_stlck(struct ccw_device *);
index d9d1c621b9813fbcb13c83bbe3355929371374fc..32a89f3a36405ed0c6f03240d78d11d1b6a5bbbf 100644 (file)
@@ -269,6 +269,7 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
+       cdev->private->flags.doverify = 0;
        switch (err) {
        case 0:
                ccw_device_done(cdev, DEV_STATE_ONLINE);
@@ -419,13 +420,21 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
 {
        struct subchannel *sch;
 
-       sch = to_subchannel(cdev->dev.parent);
+       if (!cdev->private->options.pgroup)
+               return;
        if (cdev->private->state == DEV_STATE_W4SENSE) {
-               cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
+               cdev->private->flags.doverify = 1;
                return;
        }
-       if (sch->schib.scsw.actl != 0) {
-               cdev->private->state = DEV_STATE_ONLINE_VERIFY;
+       sch = to_subchannel(cdev->dev.parent);
+       if (sch->schib.scsw.actl != 0 ||
+           (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
+               /*
+                * No final status yet or final status not yet delivered
+                * to the device driver. Can't do path verfication now,
+                * delay until final status was delivered.
+                */
+               cdev->private->flags.doverify = 1;
                return;
        }
        /* Device is idle, we can do the path verification. */
@@ -453,19 +462,14 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
        ccw_device_accumulate_irb(cdev, irb);
        if (cdev->private->flags.dosense) {
                if (ccw_device_do_sense(cdev, irb) == 0) {
-                       /* Check if we have to trigger path verification. */
-                       if (irb->esw.esw0.erw.pvrf)
-                               cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
-                       else
-                               cdev->private->state = DEV_STATE_W4SENSE;
+                       cdev->private->state = DEV_STATE_W4SENSE;
                }
                return;
        }
-       if (irb->esw.esw0.erw.pvrf)
-               /* Try to start path verification. */
+       /* Call the handler. */
+       if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
+               /* Start delayed path verification. */
                ccw_device_online_verify(cdev, 0);
-       /* No basic sense required, call the handler. */
-       ccw_device_call_handler(cdev);
 }
 
 /*
@@ -485,32 +489,6 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                              ERR_PTR(-ETIMEDOUT));
 }
 
-static void
-ccw_device_irq_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
-       struct irb *irb;
-
-       irb = (struct irb *) __LC_IRB;
-       /* Check for unsolicited interrupt. */
-       if (irb->scsw.stctl ==
-                       (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-               if (cdev->handler)
-                       cdev->handler (cdev, 0, irb);
-               return;
-       }
-       /* Accumulate status and find out if a basic sense is needed. */
-       ccw_device_accumulate_irb(cdev, irb);
-       if (cdev->private->flags.dosense) {
-               if (ccw_device_do_sense(cdev, irb) == 0)
-                       cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
-               return;
-       }
-       /* Try to start delayed device verification. */
-       ccw_device_online_verify(cdev, 0);
-       /* No basic sense required, call the handler. */
-       ccw_device_call_handler(cdev);
-}
-
 /*
  * Got an interrupt for a basic sense.
  */
@@ -530,46 +508,15 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
        /* Add basic sense info to irb. */
        ccw_device_accumulate_basic_sense(cdev, irb);
        if (cdev->private->flags.dosense) {
-               /* Check if we have to trigger path verification. */
-               if (irb->esw.esw0.erw.pvrf)
-                       cdev->private->state = DEV_STATE_W4SENSE_VERIFY;
                /* Another basic sense is needed. */
                ccw_device_do_sense(cdev, irb);
                return;
        }
        cdev->private->state = DEV_STATE_ONLINE;
-       if (irb->esw.esw0.erw.pvrf)
-               /* Try to start path verification. */
-               ccw_device_online_verify(cdev, 0);
        /* Call the handler. */
-       ccw_device_call_handler(cdev);
-}
-
-static void
-ccw_device_w4sense_verify(struct ccw_device *cdev, enum dev_event dev_event)
-{
-       struct irb *irb;
-
-       irb = (struct irb *) __LC_IRB;
-       /* Check for unsolicited interrupt. */
-       if (irb->scsw.stctl ==
-                       (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
-               if (cdev->handler)
-                       cdev->handler (cdev, 0, irb);
-               return;
-       }
-       /* Add basic sense info to irb. */
-       ccw_device_accumulate_basic_sense(cdev, irb);
-       if (cdev->private->flags.dosense) {
-               /* Another basic sense is needed. */
-               ccw_device_do_sense(cdev, irb);
-               return;
-       }
-       cdev->private->state = DEV_STATE_ONLINE_VERIFY;
-       /* Start delayed device verification. */
-       ccw_device_online_verify(cdev, 0);
-       /* Call the handler. */
-       ccw_device_call_handler(cdev);
+       if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
+               /* Start delayed path verification. */
+               ccw_device_online_verify(cdev, 0);
 }
 
 static void
@@ -718,18 +665,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_VERIFY]      ccw_device_nop,
        },
        /* states to wait for i/o completion before doing something */
-       [DEV_STATE_ONLINE_VERIFY] {
-               [DEV_EVENT_NOTOPER]     ccw_device_online_notoper,
-               [DEV_EVENT_INTERRUPT]   ccw_device_irq_verify,
-               [DEV_EVENT_TIMEOUT]     ccw_device_nop,
-               [DEV_EVENT_VERIFY]      ccw_device_nop,
-       },
-       [DEV_STATE_W4SENSE_VERIFY] {
-               [DEV_EVENT_NOTOPER]     ccw_device_online_notoper,
-               [DEV_EVENT_INTERRUPT]   ccw_device_w4sense_verify,
-               [DEV_EVENT_TIMEOUT]     ccw_device_nop,
-               [DEV_EVENT_VERIFY]      ccw_device_nop,
-       },
        [DEV_STATE_CLEAR_VERIFY] {
                [DEV_EVENT_NOTOPER]     ccw_device_online_notoper,
                [DEV_EVENT_INTERRUPT]   ccw_device_clear_verify,
index 1f091b58a8bb38baae41a170dc2b5f9f8d87d909..d77036a4ec2b9b93cd69d3c6b09cf6805e841bb8 100644 (file)
@@ -342,3 +342,4 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
        }
 }
 
+EXPORT_SYMBOL(diag210);
index 3f434fc74d94cda21566741b9ca64575567832c7..87acb211ff910b4f5a736b7bfbd8951a5657dc4f 100644 (file)
@@ -50,9 +50,7 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
        if (!cdev)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
-           cdev->private->state != DEV_STATE_W4SENSE &&
-           cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
-           cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
+           cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
        if (!sch)
@@ -76,7 +74,8 @@ ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
        if (!sch)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE ||
-           sch->schib.scsw.actl != 0)
+           sch->schib.scsw.actl != 0 ||
+           cdev->private->flags.doverify)
                return -EBUSY;
        ret = cio_set_options (sch, flags);
        if (ret)
@@ -113,9 +112,7 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
        if (!cdev)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
-           cdev->private->state != DEV_STATE_W4SENSE &&
-           cdev->private->state != DEV_STATE_ONLINE_VERIFY &&
-           cdev->private->state != DEV_STATE_W4SENSE_VERIFY)
+           cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
        if (!sch)
@@ -145,7 +142,7 @@ ccw_device_resume(struct ccw_device *cdev)
 /*
  * Pass interrupt to device driver.
  */
-void
+int
 ccw_device_call_handler(struct ccw_device *cdev)
 {
        struct subchannel *sch;
@@ -167,7 +164,7 @@ ccw_device_call_handler(struct ccw_device *cdev)
            !(stctl & SCSW_STCTL_INTER_STATUS) &&
            !(cdev->private->options.fast &&
              (stctl & SCSW_STCTL_PRIM_STATUS)))
-               return;
+               return 0;
 
        /*
         * Now we are ready to call the device driver interrupt handler.
@@ -180,6 +177,8 @@ ccw_device_call_handler(struct ccw_device *cdev)
         * Clear the old and now useless interrupt response block.
         */
        memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+       return 1;
 }
 
 /*
@@ -190,6 +189,8 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
 {
        int ciw_cnt;
 
+       if (cdev->private->flags.esid == 0)
+               return NULL;
        for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++)
                if (cdev->private->senseid.ciw[ciw_cnt].ct == ct)
                        return cdev->private->senseid.ciw + ciw_cnt;
@@ -211,25 +212,89 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
 static void
 ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
 {
+       if (!ip)
+               /* unsolicited interrupt */
+               return;
+
+       /* Abuse intparm for error reporting. */
+       if (IS_ERR(irb))
+               cdev->private->intparm = -EIO;
+       else if ((irb->scsw.dstat !=
+                 (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
+                (irb->scsw.cstat != 0)) {
+               /*
+                * We didn't get channel end / device end. Check if path
+                * verification has been started; we can retry after it has
+                * finished. We also retry unit checks except for command reject
+                * or intervention required.
+                */
+                if (cdev->private->flags.doverify ||
+                        cdev->private->state == DEV_STATE_VERIFY)
+                        cdev->private->intparm = -EAGAIN;
+                if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+                    !(irb->ecw[0] &
+                      (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
+                        cdev->private->intparm = -EAGAIN;
+                else
+                        cdev->private->intparm = -EIO;
+                        
+       } else
+               cdev->private->intparm = 0;
+       wake_up(&cdev->private->wait_q);
+}
+
+static inline int
+__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic,
+                       unsigned long flags)
+{
+       int ret;
        struct subchannel *sch;
 
        sch = to_subchannel(cdev->dev.parent);
-       if (!IS_ERR(irb))
-               memcpy(&sch->schib.scsw, &irb->scsw, sizeof(struct scsw));
-       wake_up(&cdev->private->wait_q);
+       do {
+               ret = cio_start (sch, ccw, magic, 0);
+               if ((ret == -EBUSY) || (ret == -EACCES)) {
+                       /* Try again later. */
+                       schedule_timeout(1);
+                       continue;
+               }
+               if (ret != 0)
+                       /* Non-retryable error. */
+                       break;
+               /* Wait for end of request. */
+               cdev->private->intparm = magic;
+               spin_unlock_irqrestore(&sch->lock, flags);
+               wait_event(cdev->private->wait_q,
+                          (cdev->private->intparm == -EIO) ||
+                          (cdev->private->intparm == -EAGAIN) ||
+                          (cdev->private->intparm == 0));
+               spin_lock_irqsave(&sch->lock, flags);
+               /* Check at least for channel end / device end */
+               if (cdev->private->intparm == -EIO) {
+                       /* Non-retryable error. */
+                       ret = -EIO;
+                       break;
+               }
+               if (cdev->private->intparm == 0)
+                       /* Success. */
+                       break;
+               /* Try again later. */
+               schedule_timeout(1);
+       } while (1);
+
+       return ret;
 }
 
-/*
- * This routine returns the characteristics for the device
- *  specified. Some old devices might not provide the necessary
- *  command code information during SenseID processing. In this
- *  case the function returns -EINVAL. Otherwise the function
- *  allocates a decice specific data buffer and provides the
- *  device characteristics together with the buffer size. Its
- *  the callers responability to release the kernel memory if
- *  not longer needed. In case of persistent I/O problems -EBUSY
- *  is returned.
- */
+/**
+ * read_dev_chars() - read device characteristics
+ * @param cdev   target ccw device
+ * @param buffer pointer to buffer for rdc data
+ * @param length size of rdc data
+ * @returns 0 for success, negative error value on failure
+ *
+ * Context:
+ *   called for online device, lock not held
+ **/
 int
 read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
 {
@@ -237,13 +302,11 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
        char dbf_txt[15];
        unsigned long flags;
        struct subchannel *sch;
-       int retry;
        int ret;
+       struct ccw1 *rdc_ccw;
 
        if (!cdev)
                return -ENODEV;
-       if (cdev->private->state != DEV_STATE_ONLINE)
-               return -EINVAL;
        if (!buffer || !length)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
@@ -251,44 +314,38 @@ read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
        sprintf (dbf_txt, "rddevch%x", sch->irq);
        CIO_TRACE_EVENT (4, dbf_txt);
 
-       cdev->private->iccws[0].cmd_code = CCW_CMD_RDC;
-       cdev->private->iccws[0].count = length;
-       cdev->private->iccws[0].flags = CCW_FLAG_SLI;
-       ret = set_normalized_cda (cdev->private->iccws, (*buffer));
-       if (ret != 0)
+       rdc_ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+       if (!rdc_ccw)
+               return -ENOMEM;
+       memset(rdc_ccw, 0, sizeof(struct ccw1));
+       rdc_ccw->cmd_code = CCW_CMD_RDC;
+       rdc_ccw->count = length;
+       rdc_ccw->flags = CCW_FLAG_SLI;
+       ret = set_normalized_cda (rdc_ccw, (*buffer));
+       if (ret != 0) {
+               kfree(rdc_ccw);
                return ret;
+       }
 
        spin_lock_irqsave(&sch->lock, flags);
        /* Save interrupt handler. */
        handler = cdev->handler;
        /* Temporarily install own handler. */
        cdev->handler = ccw_device_wake_up;
-       for (retry = 5; retry > 0; retry--) {
-               /* 0x00524443 == ebcdic "RDC" */
-               ret = cio_start (sch, cdev->private->iccws, 0x00524443, 0);
-               if (ret == -ENODEV)
-                       break;
-               if (ret == 0) {
-                       /* Wait for end of request. */
-                       spin_unlock_irqrestore(&sch->lock, flags);
-                       wait_event(cdev->private->wait_q,
-                                  sch->schib.scsw.actl == 0);
-                       spin_lock_irqsave(&sch->lock, flags);
-                       /* Check at least for channel end / device end */
-                       if ((sch->schib.scsw.dstat !=
-                            (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-                           (sch->schib.scsw.cstat != 0)) {
-                               ret = -EIO;
-                               continue;
-                       }
-                       break;
-               }
-       }
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               ret = -ENODEV;
+       else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+               ret = -EBUSY;
+       else
+               /* 0x00D9C4C3 == ebcdic "RDC" */
+               ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, flags);
+
        /* Restore interrupt handler. */
        cdev->handler = handler;
        spin_unlock_irqrestore(&sch->lock, flags);
 
-       clear_normalized_cda (cdev->private->iccws);
+       clear_normalized_cda (rdc_ccw);
+       kfree(rdc_ccw);
 
        return ret;
 }
@@ -305,15 +362,11 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
        struct ciw *ciw;
        unsigned long flags;
        char *rcd_buf;
-       int retry;
        int ret;
+       struct ccw1 *rcd_ccw;
 
        if (!cdev)
                return -ENODEV;
-       if (cdev->private->state != DEV_STATE_ONLINE)
-               return -EINVAL;
-       if (cdev->private->flags.esid == 0)
-               return -EOPNOTSUPP;
        if (!buffer || !length)
                return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
@@ -328,40 +381,34 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
        if (!ciw || ciw->cmd == 0)
                return -EOPNOTSUPP;
 
+       rcd_ccw = kmalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+       if (!rcd_ccw)
+               return -ENOMEM;
+       memset(rcd_ccw, 0, sizeof(struct ccw1));
        rcd_buf = kmalloc(ciw->count, GFP_KERNEL | GFP_DMA);
-       if (!rcd_buf)
+       if (!rcd_buf) {
+               kfree(rcd_ccw);
                return -ENOMEM;
+       }
        memset (rcd_buf, 0, ciw->count);
-       cdev->private->iccws[0].cmd_code = ciw->cmd;
-       cdev->private->iccws[0].cda = (__u32) __pa (rcd_buf);
-       cdev->private->iccws[0].count = ciw->count;
-       cdev->private->iccws[0].flags = CCW_FLAG_SLI;
+       rcd_ccw->cmd_code = ciw->cmd;
+       rcd_ccw->cda = (__u32) __pa (rcd_buf);
+       rcd_ccw->count = ciw->count;
+       rcd_ccw->flags = CCW_FLAG_SLI;
 
        spin_lock_irqsave(&sch->lock, flags);
        /* Save interrupt handler. */
        handler = cdev->handler;
        /* Temporarily install own handler. */
        cdev->handler = ccw_device_wake_up;
-       for (ret = 0, retry = 5; retry > 0; retry--) {
-               /* 0x00524344 == ebcdic "RCD" */
-               ret = cio_start (sch, cdev->private->iccws, 0x00524344, 0);
-               if (ret == -ENODEV)
-                       break;
-               if (ret)
-                       continue;
-               /* Wait for end of request. */
-               spin_unlock_irqrestore(&sch->lock, flags);
-               wait_event(cdev->private->wait_q, sch->schib.scsw.actl == 0);
-               spin_lock_irqsave(&sch->lock, flags);
-               /* Check at least for channel end / device end */
-               if ((sch->schib.scsw.dstat != 
-                    (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-                   (sch->schib.scsw.cstat != 0)) {
-                       ret = -EIO;
-                       continue;
-               }
-               break;
-       }
+       if (cdev->private->state != DEV_STATE_ONLINE)
+               ret = -ENODEV;
+       else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+               ret = -EBUSY;
+       else
+               /* 0x00D9C3C4 == ebcdic "RCD" */
+               ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, flags);
+
        /* Restore interrupt handler. */
        cdev->handler = handler;
        spin_unlock_irqrestore(&sch->lock, flags);
@@ -377,6 +424,7 @@ read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
                *length = ciw->count;
                *buffer = rcd_buf;
        }
+       kfree(rcd_ccw);
 
        return ret;
 }
index 780ab720085aff4e8e2459b3de8671e3213a269f..59589b9fd8f338ccb37dffca955f0c7d057da754 100644 (file)
@@ -67,7 +67,8 @@ ccw_device_path_notoper(struct ccw_device *cdev)
                      sch->schib.pmcw.pnom);
 
        sch->lpm &= ~sch->schib.pmcw.pnom;
-       dev_fsm_event(cdev, DEV_EVENT_VERIFY);
+       if (cdev->private->options.pgroup)
+               cdev->private->flags.doverify = 1;
 }
 
 /*
@@ -92,6 +93,21 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
        memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw));
 }
 
+/*
+ * Check if extended status word is valid.
+ */
+static inline int
+ccw_device_accumulate_esw_valid(struct irb *irb)
+{
+       if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
+               return 0;
+       if (irb->scsw.stctl == 
+                       (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
+           !(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
+               return 0;
+       return 1;
+}
+
 /*
  * Copy valid bits from the extended status word to device irb.
  */
@@ -101,12 +117,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
        struct irb *cdev_irb;
        struct sublog *cdev_sublog, *sublog;
 
-       /* Check if extended status word is valid. */
-       if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
-               return;
-       if (irb->scsw.stctl == 
-                       (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
-           !(irb->scsw.actl & SCSW_ACTL_SUSPENDED))
+       if (!ccw_device_accumulate_esw_valid(irb))
                return;
 
        cdev_irb = &cdev->private->irb;
@@ -169,6 +180,8 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
        cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
        /* Copy path verification required flag. */
        cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
+       if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+               cdev->private->flags.doverify = 1;
        /* Copy concurrent sense bit. */
        cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
        if (irb->esw.esw0.erw.cons)
@@ -339,6 +352,10 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
                cdev->private->irb.esw.esw0.erw.cons = 1;
                cdev->private->flags.dosense = 0;
        }
+       /* Check if path verification is required. */
+       if (ccw_device_accumulate_esw_valid(irb) &&
+           irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup) 
+               cdev->private->flags.doverify = 1;
 }
 
 /*
index d22ffaf96d2a246999170dd52882c83e7735f771..dc0d5760fb06cbeb83a8d5b06f4c5b7c5d648624 100644 (file)
@@ -55,7 +55,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.55 $"
+#define VERSION_QDIO_C "$Revision: 1.61 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -117,60 +117,6 @@ qdio_get_micros(void)
         asm volatile ("STCK %0" : "=m" (time));
         return time>>12; /* time>>12 is microseconds*/
 }
-static inline unsigned long 
-qdio_get_millis(void)
-{
-       return (unsigned long)(qdio_get_micros()>>12);
-}
-
-static __inline__ int 
-atomic_return_add (int i, atomic_t *v)
-{
-       int old, new;
-       __CS_LOOP(old, new, v, i, "ar");
-       return old;
-}
-
-static void 
-qdio_wait_nonbusy(unsigned int timeout)
-{
-        unsigned int start;
-        char dbf_text[15];
-
-       sprintf(dbf_text,"wtnb%4x",timeout);
-       QDIO_DBF_TEXT3(0,trace,dbf_text);
-
-       start=qdio_get_millis();
-       for (;;) {
-               set_task_state(current,TASK_INTERRUPTIBLE);
-               if (qdio_get_millis()-start>timeout) {
-                       goto out;
-               }
-               schedule_timeout(((start+timeout-qdio_get_millis())>>10)*HZ);
-       }
-out:
-       set_task_state(current,TASK_RUNNING);
-}
-
-static int 
-qdio_wait_for_no_use_count(atomic_t *use_count)
-{
-       unsigned long start;
-
-       QDIO_DBF_TEXT3(0,trace,"wtnousec");
-       start=qdio_get_millis();
-       for (;;) {
-               if (qdio_get_millis()-start>QDIO_NO_USE_COUNT_TIMEOUT) {
-                       QDIO_DBF_TEXT1(1,trace,"WTNOUSTO");
-                       return -ETIME;
-               }
-               if (!atomic_read(use_count)) {
-                       QDIO_DBF_TEXT3(0,trace,"wtnoused");
-                       return 0;
-               }
-               qdio_wait_nonbusy(QDIO_NO_USE_COUNT_TIME);
-       }
-}
 
 /* 
  * unfortunately, we can't just xchg the values; in do_QDIO we want to reserve
@@ -181,7 +127,7 @@ qdio_wait_for_no_use_count(atomic_t *use_count)
 static inline int 
 qdio_reserve_q(struct qdio_q *q)
 {
-       return atomic_return_add(1,&q->use_count);
+       return atomic_add_return(1,&q->use_count) - 1;
 }
 
 static inline void 
@@ -1221,21 +1167,18 @@ static void
 qdio_release_irq_memory(struct qdio_irq *irq_ptr)
 {
        int i;
-       int available;
 
        for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
                if (!irq_ptr->input_qs[i])
                        goto next;
-               available=0;
 
                if (irq_ptr->input_qs[i]->slib)
                        kfree(irq_ptr->input_qs[i]->slib);
-                       kfree(irq_ptr->input_qs[i]);
+               kfree(irq_ptr->input_qs[i]);
 
 next:
                if (!irq_ptr->output_qs[i])
                        continue;
-               available=0;
 
                if (irq_ptr->output_qs[i]->slib)
                        kfree(irq_ptr->output_qs[i]->slib);
@@ -1285,20 +1228,12 @@ qdio_set_impl_params(struct qdio_irq *irq_ptr,
 }
 
 static int
-qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
-             int no_input_qs, int no_output_qs,
-             qdio_handler_t *input_handler,
-             qdio_handler_t *output_handler,
-             unsigned long int_parm,int q_format,
-             unsigned long flags,
-             void **inbound_sbals_array,
-             void **outbound_sbals_array)
+qdio_alloc_qs(struct qdio_irq *irq_ptr,
+             int no_input_qs, int no_output_qs)
 {
+       int i;
        struct qdio_q *q;
-       int i,j,result=0;
-       char dbf_text[20]; /* see qdio_initialize */
-       void *ptr;
-       int available;
+       int result=-ENOMEM;
 
        for (i=0;i<no_input_qs;i++) {
                q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
@@ -1307,17 +1242,67 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
                        QDIO_PRINT_ERR("kmalloc of q failed!\n");
                        goto out;
                }
+
                memset(q,0,sizeof(struct qdio_q));
 
-               sprintf(dbf_text,"in-q%4x",i);
-               QDIO_DBF_TEXT0(0,setup,dbf_text);
-               QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+               q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+               if (!q->slib) {
+                       QDIO_PRINT_ERR("kmalloc of slib failed!\n");
+                       goto out;
+               }
+
+               irq_ptr->input_qs[i]=q;
+       }
+
+       for (i=0;i<no_output_qs;i++) {
+               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+
+               if (!q) {
+                       goto out;
+               }
+
+               memset(q,0,sizeof(struct qdio_q));
 
                q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
                if (!q->slib) {
                        QDIO_PRINT_ERR("kmalloc of slib failed!\n");
                        goto out;
                }
+
+               irq_ptr->output_qs[i]=q;
+       }
+
+       result=0;
+out:
+       return result;
+}
+
+static void
+qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
+                    int no_input_qs, int no_output_qs,
+            qdio_handler_t *input_handler,
+            qdio_handler_t *output_handler,
+            unsigned long int_parm,int q_format,
+            unsigned long flags,
+            void **inbound_sbals_array,
+            void **outbound_sbals_array)
+{
+       struct qdio_q *q;
+       int i,j;
+       char dbf_text[20]; /* see qdio_initialize */
+       void *ptr;
+       int available;
+
+       sprintf(dbf_text,"qfqs%4x",cdev->private->irq);
+       QDIO_DBF_TEXT0(0,setup,dbf_text);
+       for (i=0;i<no_input_qs;i++) {
+               q=irq_ptr->input_qs[i];
+
+               memset(q,0,((char*)&q->slib)-((char*)q));
+               sprintf(dbf_text,"in-q%4x",i);
+               QDIO_DBF_TEXT0(0,setup,dbf_text);
+               QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+
                memset(q->slib,0,PAGE_SIZE);
                q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2);
 
@@ -1328,7 +1313,6 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
 
                 q->queue_type=q_format;
                q->int_parm=int_parm;
-               irq_ptr->input_qs[i]=q;
                q->irq=irq_ptr->irq;
                q->irq_ptr = irq_ptr;
                q->cdev = cdev;
@@ -1380,22 +1364,13 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
        }
 
        for (i=0;i<no_output_qs;i++) {
-               q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
-
-               if (!q) {
-                       goto out;
-               }
-               memset(q,0,sizeof(struct qdio_q));
+               q=irq_ptr->output_qs[i];
+               memset(q,0,((char*)&q->slib)-((char*)q));
 
                sprintf(dbf_text,"outq%4x",i);
                QDIO_DBF_TEXT0(0,setup,dbf_text);
                QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
 
-               q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
-               if (!q->slib) {
-                       QDIO_PRINT_ERR("kmalloc of slib failed!\n");
-                       goto out;
-               }
                memset(q->slib,0,PAGE_SIZE);
                q->sl=(struct sl*)(((char*)q->slib)+PAGE_SIZE/2);
 
@@ -1406,7 +1381,6 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
 
                 q->queue_type=q_format;
                q->int_parm=int_parm;
-               irq_ptr->output_qs[i]=q;
                q->is_input_q=0;
                q->irq=irq_ptr->irq;
                q->cdev = cdev;
@@ -1446,10 +1420,6 @@ qdio_alloc_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
 /*                     q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/
                }
        }
-
-       result=1;
-out:
-       return result;
 }
 
 static void
@@ -1645,7 +1615,6 @@ qdio_timeout_handler(struct ccw_device *cdev)
        }
        ccw_device_set_timeout(cdev, 0);
        wake_up(&cdev->private->wait_q);
-
 }
 
 static void
@@ -1703,7 +1672,6 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 
        switch (irq_ptr->state) {
        case QDIO_IRQ_STATE_INACTIVE:
-               /* FIXME: defer this past interrupt time */
                qdio_establish_handle_irq(cdev, cstat, dstat);
                break;
 
@@ -2128,8 +2096,12 @@ qdio_shutdown(struct ccw_device *cdev, int how)
        for (i=0;i<irq_ptr->no_input_qs;i++) {
                qdio_unmark_q(irq_ptr->input_qs[i]);
                tasklet_kill(&irq_ptr->input_qs[i]->tasklet);
-               if (qdio_wait_for_no_use_count(&irq_ptr->input_qs[i]->
-                                              use_count))
+               wait_event_interruptible_timeout(cdev->private->wait_q,
+                                                !atomic_read(&irq_ptr->
+                                                             input_qs[i]->
+                                                             use_count),
+                                                QDIO_NO_USE_COUNT_TIMEOUT*HZ);
+               if (atomic_read(&irq_ptr->input_qs[i]->use_count))
                        /*
                         * FIXME:
                         * nobody cares about such retval,
@@ -2142,8 +2114,12 @@ qdio_shutdown(struct ccw_device *cdev, int how)
 
        for (i=0;i<irq_ptr->no_output_qs;i++) {
                tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
-               if (qdio_wait_for_no_use_count(&irq_ptr->output_qs[i]->
-                                              use_count))
+               wait_event_interruptible_timeout(cdev->private->wait_q,
+                                                !atomic_read(&irq_ptr->
+                                                             output_qs[i]->
+                                                             use_count),
+                                                QDIO_NO_USE_COUNT_TIMEOUT*HZ);
+               if (atomic_read(&irq_ptr->output_qs[i]->use_count))
                        /*
                         * FIXME:
                         * nobody cares about such retval,
@@ -2176,16 +2152,7 @@ qdio_shutdown(struct ccw_device *cdev, int how)
        wait_event(cdev->private->wait_q,
                   irq_ptr->state == QDIO_IRQ_STATE_INACTIVE ||
                   irq_ptr->state == QDIO_IRQ_STATE_ERR);
-       /* Ignore errors. */
-       qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
-out:
-       up(&irq_ptr->setting_up_sema);
-       return result;
-}
 
-static inline void
-qdio_cleanup_finish(struct ccw_device *cdev, struct qdio_irq *irq_ptr)
-{
        if (irq_ptr->is_thinint_irq) {
                qdio_put_indicator((__u32*)irq_ptr->dev_st_chg_ind);
                tiqdio_set_subchannel_ind(irq_ptr,1); 
@@ -2196,8 +2163,12 @@ qdio_cleanup_finish(struct ccw_device *cdev, struct qdio_irq *irq_ptr)
        if ((void*)cdev->handler == (void*)qdio_handler)
                cdev->handler=irq_ptr->original_int_handler;
 
-       qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
-
+       /* Ignore errors. */
+       qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
+       ccw_device_set_timeout(cdev, 0);
+out:
+       up(&irq_ptr->setting_up_sema);
+       return result;
 }
 
 int
@@ -2216,10 +2187,6 @@ qdio_free(struct ccw_device *cdev)
        QDIO_DBF_TEXT1(0,trace,dbf_text);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
 
-       if (cdev->private->state != DEV_STATE_ONLINE)
-               return -EINVAL;
-
-       qdio_cleanup_finish(cdev, irq_ptr);
        cdev->private->qdio_data = 0;
 
        up(&irq_ptr->setting_up_sema);
@@ -2234,9 +2201,6 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data)
 {
        char dbf_text[20]; /* if a printf would print out more than 8 chars */
 
-       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
-       QDIO_DBF_TEXT0(0,setup,dbf_text);
-       QDIO_DBF_TEXT0(0,trace,dbf_text);
        sprintf(dbf_text,"qfmt:%x",init_data->q_format);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,setup,init_data->adapter_name);
@@ -2409,6 +2373,8 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat)
        struct qdio_irq *irq_ptr;
        char dbf_text[15];
 
+       irq_ptr = cdev->private->qdio_data;
+
        sprintf(dbf_text,"qehi%4x",cdev->private->irq);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2418,28 +2384,6 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat)
                return;
        }
 
-       irq_ptr = cdev->private->qdio_data;
-
-       if (MACHINE_IS_VM)
-               irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq);
-       else
-                irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY
-                        | CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
-
-       sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac);
-       QDIO_DBF_TEXT2(0,setup,dbf_text);
-
-       sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac);
-       QDIO_DBF_TEXT2(0,setup,dbf_text);
-
-       irq_ptr->hydra_gives_outbound_pcis=
-               irq_ptr->qib.ac&QIB_AC_OUTBOUND_PCI_SUPPORTED;
-       irq_ptr->sync_done_on_outb_pcis=
-               irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS;
-
-       qdio_initialize_set_siga_flags_input(irq_ptr);
-       qdio_initialize_set_siga_flags_output(irq_ptr);
-
        qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
        ccw_device_set_timeout(cdev, 0);
 }
@@ -2456,7 +2400,7 @@ qdio_initialize(struct qdio_initialize *init_data)
 
        rc = qdio_allocate(init_data);
        if (rc == 0) {
-               rc = qdio_establish(init_data->cdev);
+               rc = qdio_establish(init_data);
                if (rc != 0)
                        qdio_free(init_data->cdev);
        }
@@ -2468,13 +2412,12 @@ qdio_initialize(struct qdio_initialize *init_data)
 int
 qdio_allocate(struct qdio_initialize *init_data)
 {
-       int i;
        struct qdio_irq *irq_ptr;
-       struct ciw *ciw;
-       int result;
-       int is_iqdio;
        char dbf_text[15];
 
+       sprintf(dbf_text,"qalc%4x",init_data->cdev->private->irq);
+       QDIO_DBF_TEXT0(0,setup,dbf_text);
+       QDIO_DBF_TEXT0(0,trace,dbf_text);
        if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
             (init_data->no_output_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
             ((init_data->no_input_qs) && (!init_data->input_handler)) ||
@@ -2501,7 +2444,8 @@ qdio_allocate(struct qdio_initialize *init_data)
        }
 
        memset(irq_ptr,0,sizeof(struct qdio_irq));
-        /* wipes qib.ac, required by ar7063 */
+
+       init_MUTEX(&irq_ptr->setting_up_sema);
 
        irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
        if (!(irq_ptr->qdr)) {
@@ -2510,10 +2454,38 @@ qdio_allocate(struct qdio_initialize *init_data)
                QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
                return -ENOMEM;
                }
-       memset(irq_ptr->qdr,0,sizeof(struct qdr));
        QDIO_DBF_TEXT0(0,setup,"qdr:");
        QDIO_DBF_HEX0(0,setup,&irq_ptr->qdr,sizeof(void*));
 
+       if (qdio_alloc_qs(irq_ptr,
+                                 init_data->no_input_qs,
+                         init_data->no_output_qs)) {
+               qdio_release_irq_memory(irq_ptr);
+               return -ENOMEM;
+       }
+
+       init_data->cdev->private->qdio_data = irq_ptr;
+
+       qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+
+       return 0;
+}
+
+int qdio_fill_irq(struct qdio_initialize *init_data)
+{
+       int i;
+       char dbf_text[15];
+       struct ciw *ciw;
+       int is_iqdio;
+       struct qdio_irq *irq_ptr;
+
+       irq_ptr = init_data->cdev->private->qdio_data;
+
+       memset(irq_ptr,0,((char*)&irq_ptr->qdr)-((char*)irq_ptr));
+
+        /* wipes qib.ac, required by ar7063 */
+       memset(irq_ptr->qdr,0,sizeof(struct qdr));
+
        irq_ptr->int_parm=init_data->int_parm;
 
        irq_ptr->irq = init_data->cdev->private->irq;
@@ -2548,19 +2520,14 @@ qdio_allocate(struct qdio_initialize *init_data)
        irq_ptr->aqueue.cmd=DEFAULT_ACTIVATE_QS_CMD;
        irq_ptr->aqueue.count=DEFAULT_ACTIVATE_QS_COUNT;
 
-       if (!qdio_alloc_qs(irq_ptr, init_data->cdev,
-                          init_data->no_input_qs,
-                          init_data->no_output_qs,
-                          init_data->input_handler,
-                          init_data->output_handler,init_data->int_parm,
-                          init_data->q_format,init_data->flags,
-                          init_data->input_sbal_addr_array,
-                          init_data->output_sbal_addr_array)) {
-               qdio_release_irq_memory(irq_ptr);
-               return -ENOMEM;
-       }
-
-       qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+       qdio_fill_qs(irq_ptr, init_data->cdev,
+                    init_data->no_input_qs,
+                    init_data->no_output_qs,
+                    init_data->input_handler,
+                    init_data->output_handler,init_data->int_parm,
+                    init_data->q_format,init_data->flags,
+                    init_data->input_sbal_addr_array,
+                    init_data->output_sbal_addr_array);
 
        if (!try_module_get(THIS_MODULE)) {
                QDIO_PRINT_CRIT("try_module_get() failed!\n");
@@ -2568,10 +2535,6 @@ qdio_allocate(struct qdio_initialize *init_data)
                return -EINVAL;
        }
 
-       init_MUTEX_LOCKED(&irq_ptr->setting_up_sema);
-
-       init_data->cdev->private->qdio_data = irq_ptr;
-
        qdio_fill_thresholds(irq_ptr,init_data->no_input_qs,
                             init_data->no_output_qs,
                             init_data->min_input_threshold,
@@ -2636,31 +2599,21 @@ qdio_allocate(struct qdio_initialize *init_data)
        irq_ptr->original_int_handler = init_data->cdev->handler;
        init_data->cdev->handler = qdio_handler;
 
-       /* the thinint CHSC stuff */
-       if (irq_ptr->is_thinint_irq) {
-
-               result = tiqdio_set_subchannel_ind(irq_ptr,0);
-               if (result) {
-                       up(&irq_ptr->setting_up_sema);
-                       qdio_cleanup(init_data->cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
-                       return result;
-               }
-               tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
-       }
-
        up(&irq_ptr->setting_up_sema);
 
        return 0;
 }
 
 int
-qdio_establish(struct ccw_device *cdev)
+qdio_establish(struct qdio_initialize *init_data)
 {
        struct qdio_irq *irq_ptr;
        unsigned long saveflags;
        int result, result2;
+       struct ccw_device *cdev;
        char dbf_text[20];
 
+       cdev=init_data->cdev;
        irq_ptr = cdev->private->qdio_data;
        if (!irq_ptr)
                return -EINVAL;
@@ -2670,6 +2623,20 @@ qdio_establish(struct ccw_device *cdev)
        
        down(&irq_ptr->setting_up_sema);
 
+       qdio_fill_irq(init_data);
+
+       /* the thinint CHSC stuff */
+       if (irq_ptr->is_thinint_irq) {
+
+               result = tiqdio_set_subchannel_ind(irq_ptr,0);
+               if (result) {
+                       up(&irq_ptr->setting_up_sema);
+                       qdio_cleanup(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
+                       return result;
+               }
+               tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
+       }
+
        sprintf(dbf_text,"qest%4x",cdev->private->irq);
        QDIO_DBF_TEXT0(0,setup,dbf_text);
        QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2724,6 +2691,26 @@ qdio_establish(struct ccw_device *cdev)
                result = -EIO;
        }
 
+       if (MACHINE_IS_VM)
+               irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq);
+       else
+                irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY
+                        | CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
+
+       sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac);
+       QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+       sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac);
+       QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+       irq_ptr->hydra_gives_outbound_pcis=
+               irq_ptr->qib.ac&QIB_AC_OUTBOUND_PCI_SUPPORTED;
+       irq_ptr->sync_done_on_outb_pcis=
+               irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS;
+
+       qdio_initialize_set_siga_flags_input(irq_ptr);
+       qdio_initialize_set_siga_flags_output(irq_ptr);
+
        up(&irq_ptr->setting_up_sema);
 
        return result;
@@ -2806,10 +2793,23 @@ qdio_activate(struct ccw_device *cdev, int flags)
                }
        }
 
-       qdio_wait_nonbusy(QDIO_ACTIVATE_TIMEOUT);
-
-       qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
+       wait_event_interruptible_timeout(cdev->private->wait_q,
+                                        ((irq_ptr->state ==
+                                         QDIO_IRQ_STATE_STOPPED) ||
+                                         (irq_ptr->state ==
+                                          QDIO_IRQ_STATE_ERR)),
+                                        (QDIO_ACTIVATE_TIMEOUT>>10)*HZ);
 
+       switch (irq_ptr->state) {
+       case QDIO_IRQ_STATE_STOPPED:
+       case QDIO_IRQ_STATE_ERR:
+               qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
+               result = -EIO;
+               break;
+       default:
+               qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ACTIVE);
+               result = 0;
+       }
  out:
        up(&irq_ptr->setting_up_sema);
 
@@ -2855,7 +2855,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
        int used_elements;
 
         /* This is the inbound handling of queues */
-       used_elements=atomic_return_add(count, &q->number_of_buffers_used);
+       used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
        
        qdio_do_qdio_fill_input(q,qidx,count,buffers);
        
@@ -2897,7 +2897,7 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
 
        qdio_do_qdio_fill_output(q,qidx,count,buffers);
 
-       used_elements=atomic_return_add(count, &q->number_of_buffers_used);
+       used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
 
        if (callflags&QDIO_FLAG_DONT_SIGA) {
 #ifdef QDIO_PERFORMANCE_STATS
index 37c957a98cf3763fc25045610a156b9d8aa83aa9..75ad5e09252b08363f0648775a96db1a480e9d36 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.18 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.20 $"
 
 //#define QDIO_DBF_LIKE_HELL
 
@@ -56,7 +56,6 @@
 #define QDIO_STATS_CLASSES 2
 #define QDIO_STATS_COUNT_NEEDED 2*/
 
-#define QDIO_NO_USE_COUNT_TIME 10
 #define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
                                          exiting without having use_count
                                          of the queue to 0 */
@@ -577,9 +576,6 @@ struct qdio_q {
        volatile struct qdio_q *list_next;
        volatile struct qdio_q *list_prev;
 
-       struct slib *slib; /* a page is allocated under this pointer,
-                             sl points into this page, offset PAGE_SIZE/2
-                             (after slib) */
        struct sl *sl;
        volatile struct sbal *sbal[QDIO_MAX_BUFFERS_PER_Q];
 
@@ -605,6 +601,11 @@ struct qdio_q {
                __u64 last_transfer_time;
        } timing;
         unsigned int queue_type;
+
+       /* leave this member at the end. won't be cleared in qdio_fill_qs */
+       struct slib *slib; /* a page is allocated under this pointer,
+                             sl points into this page, offset PAGE_SIZE/2
+                             (after slib) */
 } __attribute__ ((aligned(256)));
 
 struct qdio_irq {
@@ -619,20 +620,14 @@ struct qdio_irq {
        unsigned int sync_done_on_outb_pcis;
 
        enum qdio_irq_states state;
-       struct semaphore setting_up_sema;
 
        unsigned int no_input_qs;
        unsigned int no_output_qs;
 
        unsigned char qdioac;
 
-       struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
-       struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
-
        struct ccw1 ccw;
 
-       struct qdr *qdr;
-
        struct ciw equeue;
        struct ciw aqueue;
 
@@ -641,5 +636,10 @@ struct qdio_irq {
        void (*original_int_handler) (struct ccw_device *,
                                      unsigned long, struct irb *);
 
+       /* leave these four members together at the end. won't be cleared in qdio_fill_irq */
+       struct qdr *qdr;
+       struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
+       struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
+       struct semaphore setting_up_sema;
 };
 #endif
index ed2cecfd4708a7bfa798d1e42f908eb5d5ca967a..85c1afda6714ee39e22fa58a6bfbc0e9460ab313 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cu3088.c,v 1.26 2003/01/17 13:46:13 cohuck Exp $
+ * $Id: cu3088.c,v 1.30 2003/08/28 11:14:11 cohuck Exp $
  *
  * CTC / LCS ccw_device driver
  *
@@ -56,7 +56,6 @@ static struct ccw_device_id cu3088_ids[] = {
 static struct ccw_driver cu3088_driver;
 
 struct device cu3088_root_dev = {
-       .name   = "CU3088 Devices",
        .bus_id = "cu3088",
 };
 
@@ -64,7 +63,7 @@ static ssize_t
 group_write(struct device_driver *drv, const char *buf, size_t count)
 {
        const char *start, *end;
-       char bus_ids[2][BUS_ID_SIZE+1], *argv[2];
+       char bus_ids[2][BUS_ID_SIZE], *argv[2];
        int i;
        int ret;
        struct ccwgroup_driver *cdrv;
@@ -79,7 +78,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
 
                if (!(end = strchr(start, delim[i])))
                        return count;
-               len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start)+1;
+               len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
                strlcpy (bus_ids[i], start, len);
                argv[i] = bus_ids[i];
                start = end + 1;
index dc7e569ed3144465124c79eeb849b5f4ec65e52b..5e8eee3ed6b01803f66abf15f11e258054a96b9b 100644 (file)
@@ -76,7 +76,7 @@ typedef void qdio_handler_t(struct ccw_device *,unsigned int,unsigned int,
 #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
 #define QDIO_FLAG_CLEANUP_USING_HALT 0x02
 
-struct qdio_initialize{
+struct qdio_initialize {
        struct ccw_device *cdev;
        unsigned char q_format;
        unsigned char adapter_name[8];
@@ -99,9 +99,10 @@ struct qdio_initialize{
        void **input_sbal_addr_array; /* addr of n*128 void ptrs */
        void **output_sbal_addr_array; /* addr of n*128 void ptrs */
 };
+
 extern int qdio_initialize(struct qdio_initialize *init_data);
 extern int qdio_allocate(struct qdio_initialize *init_data);
-extern int qdio_establish(struct ccw_device *);
+extern int qdio_establish(struct qdio_initialize *init_data);
 
 extern int qdio_activate(struct ccw_device *,int flags);