- S/390: Update to IBM Codedrop 2004/04/15
authorHannes Reinecke <hare@suse.de>
Wed, 14 Apr 2004 08:14:36 +0000 (08:14 +0000)
committerHannes Reinecke <hare@suse.de>
Wed, 14 Apr 2004 08:14:36 +0000 (08:14 +0000)
- S/390: Removed obsolete patches
- Rediffed patches.suse/lkcd-kernel-changes-linux263.patch,
  patches.fixes/anon-vma to apply again.

suse-commit: 2f226c13a087422afd510277f49323c62eee03e8

59 files changed:
Documentation/s390/s390dbf.txt
arch/s390/Makefile
arch/s390/boot/Makefile
arch/s390/boot/kerntypes.c [new file with mode: 0644]
arch/s390/defconfig
arch/s390/kernel/time.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_cmb.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dcssblk.c
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_class.c
drivers/s390/char/tape_core.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio.c
drivers/s390/crypto/z90common.h
drivers/s390/crypto/z90hardware.c
drivers/s390/crypto/z90main.c
drivers/s390/net/Kconfig
drivers/s390/net/Makefile
drivers/s390/net/ctctty.c
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth.c [deleted file]
drivers/s390/net/qeth.h
drivers/s390/net/qeth_fs.h [new file with mode: 0644]
drivers/s390/net/qeth_main.c [new file with mode: 0644]
drivers/s390/net/qeth_mpc.c
drivers/s390/net/qeth_mpc.h
drivers/s390/net/qeth_proc.c [new file with mode: 0644]
drivers/s390/net/qeth_sys.c [new file with mode: 0644]
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_driver.c
include/asm-s390/cache.h
include/asm-s390/pgalloc.h
include/asm-s390/qeth.h [new file with mode: 0644]
include/asm-s390/spinlock.h
include/linux/netdevice.h
include/linux/rcupdate.h
kernel/rcupdate.c
mm/slab.c
net/ipv6/ndisc.c

index e704836..95bc081 100644 (file)
@@ -66,9 +66,9 @@ a view can be inspected simply by reading the corresponding proc file.
 All debug logs have an an actual debug level (range from 0 to 6).
 The default level is 3. Event and Exception functions have a 'level'
 parameter. Only debug entries with a level that is lower or equal
-than the actual level are written to the log. This means that high 
-priority log entries should have a low level value whereas low priority
-entries should have a high one. 
+than the actual level are written to the log. This means, when
+writing events, high priority log entries should have a low level 
+value whereas low priority entries should have a high one. 
 The actual debug level can be changed with the help of the proc-filesystem 
 through writing a number string "x" to the 'level' proc file which is
 provided for every debug log. Debugging can be switched off completely
index 9525ee2..7ab9d39 100644 (file)
@@ -52,12 +52,12 @@ drivers-$(CONFIG_MATHEMU) += arch/$(ARCH)/math-emu/
 
 boot           := arch/$(ARCH)/boot
 
-all: image
+all: image kerntypes.o
 
 install: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $@
 
-image: vmlinux
+image kerntypes.o: vmlinux
        $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 archclean:
index 6ead7ff..cedbdd4 100644 (file)
@@ -8,7 +8,7 @@ COMPILE_VERSION := __linux_compile_version_id__`hostname |  \
 
 EXTRA_CFLAGS  := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I.
 
-targets := image
+targets := image kerntypes.o
 
 $(obj)/image: vmlinux FORCE
        $(call if_changed,objcopy)
diff --git a/arch/s390/boot/kerntypes.c b/arch/s390/boot/kerntypes.c
new file mode 100644 (file)
index 0000000..f0b1541
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * kerntypes.c
+ *
+ * Dummy module that includes headers for all kernel types of interest.
+ * The kernel type information is used by the lcrash utility when
+ * analyzing system crash dumps or the live system. Using the type
+ * information for the running system, rather than kernel header files,
+ * makes for a more flexible and robust analysis tool.
+ *
+ * This source code is released under the GNU GPL.
+ */
+
+/* generate version for this file */
+typedef char *COMPILE_VERSION;
+
+/* General linux types */
+
+#include <linux/autoconf.h>
+#include <linux/compile.h>
+#include <linux/config.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/lowcore.h>
+#include <asm/debug.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+#include <asm/qdio.h>
+
+/* channel subsystem driver */
+#include "drivers/s390/cio/cio.h"
+#include "drivers/s390/cio/chsc.h"
+#include "drivers/s390/cio/css.h"
+#include "drivers/s390/cio/device.h"
+#include "drivers/s390/cio/qdio.h"
+
+/* dasd device driver */
+#include "drivers/s390/block/dasd_int.h"
+#include "drivers/s390/block/dasd_diag.h"
+#include "drivers/s390/block/dasd_eckd.h"
+#include "drivers/s390/block/dasd_fba.h"
+
+/* networking drivers */
+#include "drivers/s390/net/fsm.h"
+#include "drivers/s390/net/iucv.h"
+#include "drivers/s390/net/lcs.h"
+
+/* zfcp device driver */
+#include "drivers/s390/scsi/zfcp_def.h"
+#include "drivers/s390/scsi/zfcp_fsf.h"
+
+/* include sched.c for types: 
+ *    - struct prio_array 
+ *    - struct runqueue
+ */
+#include "kernel/sched.c"
index 23d7d2c..95ca211 100644 (file)
@@ -80,6 +80,7 @@ CONFIG_PFAULT=y
 # CONFIG_SHARED_KERNEL is not set
 # CONFIG_CMM is not set
 # CONFIG_VIRT_TIMER is not set
+# CONFIG_NO_IDLE_HZ is not set
 # CONFIG_PCMCIA is not set
 
 #
index f0042ae..8865e66 100644 (file)
@@ -266,6 +266,7 @@ void stop_hz_timer(void)
 }
 #endif
 
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
index d0ab034..fd9e6ea 100644 (file)
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.136 $
+ * $Revision: 1.137.2.1 $
  */
 
 #include <linux/config.h>
index c6b26e7..b494c82 100644 (file)
@@ -5,7 +5,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
  *
- * $Revision: 1.28 $
+ * $Revision: 1.29.2.1 $
  */
 
 #include <linux/timer.h>
index 8139ffd..10f1ea4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.6 $)
+ * linux/drivers/s390/block/dasd_cmb.c ($Revision: 1.7.2.1 $)
  *
  * Linux on zSeries Channel Measurement Facility support
  *  (dasd device driver interface)
index f9596f8..35b8f37 100644 (file)
@@ -4,7 +4,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.32 $
+ * $Revision: 1.33 $
  */
 
 #include <linux/config.h>
@@ -205,7 +205,7 @@ dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
                return dasd_era_none;
        
        cdev = device->cdev;
-       switch (cdev->id.dev_model) {
+       switch (cdev->id.dev_type) {
        case 0x3370:
                return dasd_3370_erp_examine(cqr, irb);
        case 0x9336:
index 44b6e73..a4e9b93 100644 (file)
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.46 $
+ * $Revision: 1.47.2.1 $
  */
 
 #include <linux/config.h>
index 5b6544b..8a30b52 100644 (file)
@@ -548,10 +548,10 @@ dcssblk_remove_store(struct device *dev, const char *buf, size_t count)
        dev_info->gd->queue = NULL;
        put_disk(dev_info->gd);
        device_unregister(&dev_info->dev);
-       put_device(&dev_info->dev);
        segment_unload(dev_info->segment_name);
        PRINT_DEBUG("Segment %s unloaded successfully\n",
                        dev_info->segment_name);
+       put_device(&dev_info->dev);
        rc = count;
 out_buf:
        kfree(local_buf);
index 16d2c43..e738c4d 100644 (file)
@@ -113,6 +113,7 @@ tape_34xx_work_handler(void *data)
        switch(p->op) {
                case TO_MSEN:
                        tape_34xx_medium_sense(p->device);
+                       break;
                default:
                        DBF_EVENT(3, "T34XX: internal error: unknown work\n");
        }
@@ -1342,7 +1343,7 @@ tape_34xx_init (void)
 {
        int rc;
 
-       DBF_EVENT(3, "34xx init: $Revision: 1.19 $\n");
+       DBF_EVENT(3, "34xx init: $Revision: 1.20 $\n");
        /* Register driver for 3480/3490 tapes. */
        rc = ccw_driver_register(&tape_34xx_driver);
        if (rc)
@@ -1361,7 +1362,7 @@ tape_34xx_exit(void)
 MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
 MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
 MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
-                  "device driver ($Revision: 1.19 $)");
+                  "device driver ($Revision: 1.20 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_34xx_init);
index 85f1693..0f8ffd4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * (C) Copyright IBM Corp. 2004
- * tape_class.c ($Revision: 1.6 $)
+ * tape_class.c ($Revision: 1.8 $)
  *
  * Tape class device support
  *
@@ -12,7 +12,7 @@
 MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
 MODULE_DESCRIPTION(
        "(C) Copyright IBM Corp. 2004   All Rights Reserved.\n"
-       "tape_class.c ($Revision: 1.6 $)"
+       "tape_class.c ($Revision: 1.8 $)"
 );
 MODULE_LICENSE("GPL");
 
@@ -85,7 +85,7 @@ struct tape_class_device *register_tape_dev(
        return tcd;
 
 fail_with_cdev:
-       cdev_del(&tcd->char_device);
+       cdev_del(tcd->char_device);
 
 fail_with_tcd:
        kfree(tcd);
index 503f3f1..286330d 100644 (file)
@@ -377,6 +377,16 @@ out:
        return rc;
 }
 
+static inline void
+tape_cleanup_device(struct tape_device *device)
+{
+       tapeblock_cleanup_device(device);
+       tapechar_cleanup_device(device);
+       device->discipline->cleanup_device(device);
+       tape_remove_minor(device);
+       tape_med_state_set(device, MS_UNKNOWN);
+}
+
 /*
  * Set device offline.
  *
@@ -399,12 +409,13 @@ tape_generic_offline(struct tape_device *device)
        switch (device->tape_state) {
                case TS_INIT:
                case TS_NOT_OPER:
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
                        break;
                case TS_UNUSED:
-                       tapeblock_cleanup_device(device);
-                       tapechar_cleanup_device(device);
-                       device->discipline->cleanup_device(device);
-                       tape_remove_minor(device);
+                       tape_state_set(device, TS_INIT);
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       tape_cleanup_device(device);
+                       break;
                default:
                        DBF_EVENT(3, "(%08x): Set offline failed "
                                "- drive in use.\n",
@@ -415,9 +426,6 @@ tape_generic_offline(struct tape_device *device)
                        spin_unlock_irq(get_ccwdev_lock(device->cdev));
                        return -EBUSY;
        }
-       spin_unlock_irq(get_ccwdev_lock(device->cdev));
-
-       tape_med_state_set(device, MS_UNKNOWN);
 
        DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id);
        return 0;
@@ -543,26 +551,12 @@ tape_generic_probe(struct ccw_device *cdev)
        return 0;
 }
 
-/*
- * Driverfs tape remove function.
- *
- * This function is called whenever the common I/O layer detects the device
- * gone. This can happen at any time and we cannot refuse.
- */
-void
-tape_generic_remove(struct ccw_device *cdev)
+static inline void
+__tape_discard_requests(struct tape_device *device)
 {
-       struct tape_device *    device;
        struct tape_request *   request;
        struct list_head *      l, *n;
 
-       device = cdev->dev.driver_data;
-       DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
-
-       /*
-        * No more requests may be processed. So just post them as i/o errors.
-        */
-       spin_lock_irq(get_ccwdev_lock(device->cdev));
        list_for_each_safe(l, n, &device->req_queue) {
                request = list_entry(l, struct tape_request, list);
                if (request->status == TAPE_REQUEST_IN_IO)
@@ -575,28 +569,66 @@ tape_generic_remove(struct ccw_device *cdev)
                if (request->callback != NULL)
                        request->callback(request, request->callback_data);
        }
+}
+
+/*
+ * Driverfs tape remove function.
+ *
+ * This function is called whenever the common I/O layer detects the device
+ * gone. This can happen at any time and we cannot refuse.
+ */
+void
+tape_generic_remove(struct ccw_device *cdev)
+{
+       struct tape_device *    device;
+
+       device = cdev->dev.driver_data;
+       if (!device) {
+               PRINT_ERR("No device pointer in tape_generic_remove!\n");
+               return;
+       }
+       DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
 
-       if (device->tape_state != TS_UNUSED && device->tape_state != TS_INIT) {
-               DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
-                       device->cdev_id);
-               PRINT_WARN("(%s): Drive in use vanished - expect trouble!\n",
-                       device->cdev->dev.bus_id);
-               PRINT_WARN("State was %i\n", device->tape_state);
-               device->tape_state = TS_NOT_OPER;
-               tapeblock_cleanup_device(device);
-               tapechar_cleanup_device(device);
-               device->discipline->cleanup_device(device);
-               tape_remove_minor(device);
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       switch (device->tape_state) {
+               case TS_INIT:
+                       tape_state_set(device, TS_NOT_OPER);
+               case TS_NOT_OPER:
+                       /*
+                        * Nothing to do.
+                        */
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       break;
+               case TS_UNUSED:
+                       /*
+                        * Need only to release the device.
+                        */
+                       tape_state_set(device, TS_NOT_OPER);
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       tape_cleanup_device(device);
+                       break;
+               default:
+                       /*
+                        * There may be requests on the queue. We will not get
+                        * an interrupt for a request that was running. So we
+                        * just post them all as I/O errors.
+                        */
+                       DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
+                               device->cdev_id);
+                       PRINT_WARN("(%s): Drive in use vanished - "
+                               "expect trouble!\n",
+                               device->cdev->dev.bus_id);
+                       PRINT_WARN("State was %i\n", device->tape_state);
+                       tape_state_set(device, TS_NOT_OPER);
+                       __tape_discard_requests(device);
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       tape_cleanup_device(device);
        }
-       device->tape_state = TS_NOT_OPER;
-       tape_med_state_set(device, MS_UNKNOWN);
-       spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
        if (cdev->dev.driver_data != NULL) {
                sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
                cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
        }
-
 }
 
 /*
@@ -1149,7 +1181,7 @@ tape_init (void)
 #ifdef DBF_LIKE_HELL
        debug_set_level(tape_dbf_area, 6);
 #endif
-       DBF_EVENT(3, "tape init: ($Revision: 1.48 $)\n");
+       DBF_EVENT(3, "tape init: ($Revision: 1.49.2.1 $)\n");
        tape_proc_init();
        tapechar_init ();
        tapeblock_init ();
@@ -1174,7 +1206,7 @@ tape_exit(void)
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
              "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
 MODULE_DESCRIPTION("Linux on zSeries channel attached "
-                  "tape device driver ($Revision: 1.48 $)");
+                  "tape device driver ($Revision: 1.49.2.1 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_init);
index af5c16c..6d0179f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.25 $
+ *   $Revision: 1.27 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
@@ -397,9 +397,35 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
        return driver_register(&cdriver->driver);
 }
 
+static inline struct device *
+__get_next_ccwgroup_device(struct device_driver *drv)
+{
+       struct device *dev, *d;
+
+       down_read(&drv->bus->subsys.rwsem);
+       dev = NULL;
+       list_for_each_entry(d, &drv->devices, driver_list) {
+               dev = get_device(d);
+               if (dev)
+                       break;
+       }
+       up_read(&drv->bus->subsys.rwsem);
+       return dev;
+}
+
 void
 ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
 {
+       struct device *dev;
+
+       /* We don't want ccwgroup devices to live longer than their driver. */
+       get_driver(&cdriver->driver);
+       while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) {
+               __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+               device_unregister(dev);
+               put_device(dev);
+       };
+       put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
 
@@ -416,8 +442,11 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 
        if (cdev->dev.driver_data) {
                gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
-               if (get_device(&gdev->dev))
-                       return gdev;
+               if (get_device(&gdev->dev)) {
+                       if (!list_empty(&gdev->dev.node))
+                               return gdev;
+                       put_device(&gdev->dev);
+               }
                return NULL;
        }
        return NULL;
index 9f55986..35c467f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.105 $
+ *   $Revision: 1.107 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
@@ -819,8 +819,10 @@ s390_vary_chpid( __u8 chpid, int on)
                struct schib schib;
 
                sch = get_subchannel_by_schid(irq);
-               if (sch)
+               if (sch) {
+                       put_device(&sch->dev);
                        continue;
+               }
                if (stsch(irq, &schib))
                        /* We're through */
                        break;
index cffeda6..e9eacd6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.117 $
+ *   $Revision: 1.117.2.1 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
index 45aa6a0..4103050 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.69 $
+ *   $Revision: 1.72 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
@@ -163,11 +163,6 @@ get_subchannel_by_schid(int irq)
                                              struct device, bus_list));
                if (!dev)
                        continue;
-               /* Skip channel paths. */
-               if (dev->release != &css_subchannel_release) {
-                       put_device(dev);
-                       continue;
-               }
                sch = to_subchannel(dev);
                if (sch->irq == irq)
                        break;
@@ -206,10 +201,16 @@ css_evaluate_subchannel(int irq, int slow)
 
        sch = get_subchannel_by_schid(irq);
        disc = sch ? device_is_disconnected(sch) : 0;
-       if (disc && slow)
+       if (disc && slow) {
+               if (sch)
+                       put_device(&sch->dev);
                return 0; /* Already processed. */
-       if (!disc && !slow)
+       }
+       if (!disc && !slow) {
+               if (sch)
+                       put_device(&sch->dev);
                return -EAGAIN; /* Will be done on the slow path. */
+       }
        event = css_get_subchannel_status(sch, irq);
        switch (event) {
        case CIO_GONE:
index 17c7785..4c9b825 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.110 $
+ *   $Revision: 1.113 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
@@ -120,6 +120,7 @@ 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 *);
 
 struct css_driver io_subchannel_driver = {
        .subchannel_type = SUBCHANNEL_TYPE_IO,
@@ -128,6 +129,7 @@ struct css_driver io_subchannel_driver = {
                .bus  = &css_bus_type,
                .probe = &io_subchannel_probe,
                .remove = &io_subchannel_remove,
+               .shutdown = &io_subchannel_shutdown,
        },
        .irq = io_subchannel_irq,
        .notify = io_subchannel_notify,
@@ -766,6 +768,37 @@ io_subchannel_ioterm(struct device *dev)
                              ERR_PTR(-EIO));
 }
 
+static void
+io_subchannel_shutdown(struct device *dev)
+{
+       struct subchannel *sch;
+       struct ccw_device *cdev;
+       int ret;
+
+       sch = to_subchannel(dev);
+       cdev = dev->driver_data;
+
+       if (cio_is_console(sch->irq))
+               return;
+       if (!sch->schib.pmcw.ena)
+               /* Nothing to do. */
+               return;
+       ret = cio_disable_subchannel(sch);
+       if (ret != -EBUSY)
+               /* Subchannel is disabled, we're done. */
+               return;
+       cdev->private->state = DEV_STATE_QUIESCE;
+       if (cdev->handler)
+               cdev->handler(cdev, cdev->private->intparm,
+                             ERR_PTR(-EIO));
+       ret = ccw_device_cancel_halt_clear(cdev);
+       if (ret == -EBUSY) {
+               ccw_device_set_timeout(cdev, HZ/10);
+               wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
+       }
+       cio_disable_subchannel(sch);
+}
+
 #ifdef CONFIG_CCW_CONSOLE
 static struct ccw_device console_cdev;
 static struct ccw_device_private console_private;
index 29e24ba..c8ff5eb 100644 (file)
@@ -18,6 +18,7 @@ enum dev_state {
        DEV_STATE_CLEAR_VERIFY,
        DEV_STATE_TIMEOUT_KILL,
        DEV_STATE_WAIT4IO,
+       DEV_STATE_QUIESCE,
        /* special states for devices gone not operational */
        DEV_STATE_DISCONNECTED,
        DEV_STATE_DISCONNECTED_SENSE_ID,
@@ -68,6 +69,8 @@ extern struct workqueue_struct *ccw_device_work;
 
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
+int ccw_device_cancel_halt_clear(struct ccw_device *);
+
 int ccw_device_register(struct ccw_device *);
 void ccw_device_do_unreg_rereg(void *);
 
index e4d781e..eac048a 100644 (file)
@@ -101,7 +101,7 @@ ccw_device_set_timeout(struct ccw_device *cdev, int expires)
  * -EBUSY if an interrupt is expected (either from halt/clear or from a
  * status pending).
  */
-static int
+int
 ccw_device_cancel_halt_clear(struct ccw_device *cdev)
 {
        struct subchannel *sch;
@@ -438,10 +438,13 @@ ccw_device_nopath_notify(void *data)
        ret = (sch->driver && sch->driver->notify) ?
                sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0;
        if (!ret) {
-               /* Driver doesn't want to keep device. */
-               device_unregister(&sch->dev);
-               sch->schib.pmcw.intparm = 0;
-               cio_modify(sch);
+               if (get_device(&sch->dev)) {
+                       /* Driver doesn't want to keep device. */
+                       device_unregister(&sch->dev);
+                       sch->schib.pmcw.intparm = 0;
+                       cio_modify(sch);
+                       put_device(&sch->dev);
+               }
        } else {
                ccw_device_set_timeout(cdev, 0);
                cdev->private->state = DEV_STATE_DISCONNECTED;
@@ -710,9 +713,17 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                cdev->private->state = DEV_STATE_TIMEOUT_KILL;
                return;
        }
-       if (ret == -ENODEV)
-               dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-       else if (cdev->handler)
+       if (ret == -ENODEV) {
+               struct subchannel *sch;
+
+               sch = to_subchannel(cdev->dev.parent);
+               if (!sch->lpm) {
+                       PREPARE_WORK(&cdev->private->kick_work,
+                                    ccw_device_nopath_notify, (void *)cdev);
+                       queue_work(ccw_device_work, &cdev->private->kick_work);
+               } else
+                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+       } else if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
                              ERR_PTR(-ETIMEDOUT));
 }
@@ -808,8 +819,8 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                        PREPARE_WORK(&cdev->private->kick_work,
                                     ccw_device_nopath_notify, (void *)cdev);
                        queue_work(ccw_device_work, &cdev->private->kick_work);
-               }
-               dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+               } else
+                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
                return;
        }
        //FIXME: Can we get here?
@@ -868,6 +879,7 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        int ret;
        struct subchannel *sch;
 
+       sch = to_subchannel(cdev->dev.parent);
        ccw_device_set_timeout(cdev, 0);
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
@@ -876,16 +888,17 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
                return;
        }
        if (ret == -ENODEV) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_nopath_notify, (void *)cdev);
-               queue_work(ccw_device_work, &cdev->private->kick_work);
-               dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+               if (!sch->lpm) {
+                       PREPARE_WORK(&cdev->private->kick_work,
+                                    ccw_device_nopath_notify, (void *)cdev);
+                       queue_work(ccw_device_work, &cdev->private->kick_work);
+               } else
+                       dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
                return;
        }
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
                              ERR_PTR(-ETIMEDOUT));
-       sch = to_subchannel(cdev->dev.parent);
        if (!sch->lpm) {
                PREPARE_WORK(&cdev->private->kick_work,
                             ccw_device_nopath_notify, (void *)cdev);
@@ -1005,6 +1018,37 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
 }
 
 
+static void
+ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
+{
+       ccw_device_set_timeout(cdev, 0);
+       if (dev_event == DEV_EVENT_NOTOPER)
+               cdev->private->state = DEV_STATE_NOT_OPER;
+       else
+               cdev->private->state = DEV_STATE_OFFLINE;
+       wake_up(&cdev->private->wait_q);
+}
+
+static void
+ccw_device_quiesce_timeout(struct ccw_device *cdev, enum dev_event dev_event)
+{
+       int ret;
+
+       ret = ccw_device_cancel_halt_clear(cdev);
+       switch (ret) {
+       case 0:
+               cdev->private->state = DEV_STATE_OFFLINE;
+               wake_up(&cdev->private->wait_q);
+               break;
+       case -ENODEV:
+               cdev->private->state = DEV_STATE_NOT_OPER;
+               wake_up(&cdev->private->wait_q);
+               break;
+       default:
+               ccw_device_set_timeout(cdev, HZ/10);
+       }
+}
+
 /*
  * No operation action. This is used e.g. to ignore a timeout event in
  * state offline.
@@ -1102,6 +1146,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
                [DEV_EVENT_TIMEOUT]     ccw_device_wait4io_timeout,
                [DEV_EVENT_VERIFY]      ccw_device_wait4io_verify,
        },
+       [DEV_STATE_QUIESCE] {
+               [DEV_EVENT_NOTOPER]     ccw_device_quiesce_done,
+               [DEV_EVENT_INTERRUPT]   ccw_device_quiesce_done,
+               [DEV_EVENT_TIMEOUT]     ccw_device_quiesce_timeout,
+               [DEV_EVENT_VERIFY]      ccw_device_nop,
+       },
        /* special states for devices gone not operational */
        [DEV_STATE_DISCONNECTED] {
                [DEV_EVENT_NOTOPER]     ccw_device_nop,
index 84dc9bb..04ea39f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.34 $
+ *   $Revision: 1.45.2.1 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
index d4e8818..3188cde 100644 (file)
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.78 $"
+#define VERSION_QDIO_C "$Revision: 1.79 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -392,6 +392,11 @@ qdio_unmark_q(struct qdio_q *q)
        if ((q->is_thinint_q)&&(q->is_input_q)) {
                /* iQDIO */
                spin_lock_irqsave(&ttiq_list_lock,flags);
+               /* in case cleanup has done this already and simultanously
+                * qdio_unmark_q is called from the interrupt handler, we've
+                * got to check this in this specific case again */
+               if ((!q->list_prev)||(!q->list_next))
+                       goto out;
                if (q->list_next==q) {
                        /* q was the only interesting q */
                        tiq_list=NULL;
@@ -404,6 +409,7 @@ qdio_unmark_q(struct qdio_q *q)
                        q->list_next=NULL;
                        q->list_prev=NULL;
                }
+out:
                spin_unlock_irqrestore(&ttiq_list_lock,flags);
        }
 }
index 7893b2a..65e9f52 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
 #ifndef _Z90COMMON_
 #define _Z90COMMON_
-#define VERSION_Z90COMMON_H "$Revision: 1.6 $"
+
+#define VERSION_Z90COMMON_H "$Revision: 1.8 $"
+
+
 #define RESPBUFFSIZE 256
 #define PCI_FUNC_KEY_DECRYPT 0x5044
 #define PCI_FUNC_KEY_ENCRYPT 0x504B
+
 enum devstat {
        DEV_GONE,               
        DEV_ONLINE,             
@@ -41,6 +46,7 @@ enum devstat {
        DEV_SEN_EXCEPTION,      
        DEV_REC_EXCEPTION       
 };
+
 enum hdstat {
        HD_NOT_THERE,           
        HD_BUSY,                
@@ -49,9 +55,11 @@ enum hdstat {
        HD_ONLINE,              
        HD_TSQ_EXCEPTION        
 };
+
 #define Z90C_AMBIGUOUS_DOMAIN  2
 #define Z90C_INCORRECT_DOMAIN  3
 #define ENOTINIT               4
+
 #define SEN_BUSY        7      
 #define SEN_USER_ERROR  8      
 #define SEN_QUEUE_FULL 11      
@@ -59,6 +67,7 @@ enum hdstat {
 #define SEN_PAD_ERROR  17      
 #define SEN_RETRY      18      
 #define SEN_RELEASED   24      
+
 #define REC_EMPTY       4      
 #define REC_BUSY        6      
 #define REC_OPERAND_INV         8      
@@ -72,22 +81,28 @@ enum hdstat {
 #define REC_BAD_MESSAGE 16     
 #define REC_INVALID_PAD 17     
 #define REC_RELEASED   28      
+
 #define WRONG_DEVICE_TYPE 20   
+
 #define REC_FATAL_ERROR 32     
 #define SEN_FATAL_ERROR 33     
 #define TSQ_FATAL_ERROR 34
 #define RSQ_FATAL_ERROR 35
+
 #define PCICA  0
 #define PCICC  1
 #define PCIXCC 2
 #define NILDEV -1
 #define ANYDEV -1
+
 enum hdevice_type {
        PCICC_HW  = 3,
        PCICA_HW  = 4,
        PCIXCC_HW = 5,
-       OTHER_HW  = 6   
+       OTHER_HW  = 6,  
+       OTHER2_HW = 7   
 };
+
 #ifndef DEV_NAME
 #define DEV_NAME       "z90crypt"
 #endif
@@ -99,12 +114,16 @@ enum hdevice_type {
        printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
 #define PRINTKC(fmt, args...) \
        printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+
 #ifdef Z90CRYPT_DEBUG
 #define PDEBUG(fmt, args...) \
        printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
 #else
 #define PDEBUG(fmt, args...) do {} while (0)
 #endif
-#define UMIN(a,b) ((a) > (b) ? (a) : (b))
+
+#define UMIN(a,b) ((a) < (b) ? (a) : (b))
 #define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
+
+
 #endif
index 41dd09f..5b52c95 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
 #include <asm/uaccess.h>       
 #include <linux/compiler.h>
 #include <linux/delay.h>       
+#include <linux/init.h>
 #include <linux/module.h>
 #include "z90crypt.h"
 #include "z90common.h"
-#define VERSION_Z90HARDWARE_C "$Revision: 1.13 $"
-static const char version[] __attribute_used__ =
-       "z90crypt.o: z90hardware.o ("
-       "z90hardware.c " VERSION_Z90HARDWARE_C "/"
-       "z90common.h "   VERSION_Z90COMMON_H   "/"
-       "z90crypt.h "    VERSION_Z90CRYPT_H    ")";
+
+#define VERSION_Z90HARDWARE_C "$Revision: 1.19 $"
+
+char z90chardware_version[] __initdata =
+       "z90hardware.o (" VERSION_Z90HARDWARE_C "/"
+                         VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
+
 struct cca_token_hdr {
        unsigned char  token_identifier;
        unsigned char  version;
        unsigned short token_length;
        unsigned char  reserved[4];
 };
+
 #define CCA_TKN_HDR_ID_EXT 0x1E
+
 struct cca_private_ext_ME_sec {
        unsigned char  section_identifier;
        unsigned char  version;
@@ -58,7 +63,9 @@ struct cca_private_ext_ME_sec {
        unsigned char  exponent[128];
        unsigned char  modulus[128];
 };
+
 #define CCA_PVT_USAGE_ALL 0x80
+
 struct cca_public_sec {
        unsigned char  section_identifier;
        unsigned char  version;
@@ -69,15 +76,18 @@ struct cca_public_sec {
        unsigned short modulus_byte_len;    
        unsigned char  exponent[3];
 };
+
 struct cca_private_ext_ME {
        struct cca_token_hdr          pvtMEHdr;
        struct cca_private_ext_ME_sec pvtMESec;
        struct cca_public_sec         pubMESec;
 };
+
 struct cca_public_key {
        struct cca_token_hdr  pubHdr;
        struct cca_public_sec pubSec;
 };
+
 struct cca_pvt_ext_CRT_sec {
        unsigned char  section_identifier;
        unsigned char  version;
@@ -99,21 +109,26 @@ struct cca_pvt_ext_CRT_sec {
        unsigned char  reserved4[52];
        unsigned char  confounder[8];
 };
+
 #define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
 #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
+
 struct cca_private_ext_CRT {
        struct cca_token_hdr       pvtCrtHdr;
        struct cca_pvt_ext_CRT_sec pvtCrtSec;
        struct cca_public_sec      pubCrtSec;
 };
+
 struct ap_status_word {
        unsigned char q_stat_flags;
        unsigned char response_code;
        unsigned char reserved[2];
 };
+
 #define AP_Q_STATUS_EMPTY              0x80
 #define AP_Q_STATUS_REPLIES_WAITING    0x40
 #define AP_Q_STATUS_ARRAY_FULL         0x20
+
 #define AP_RESPONSE_NORMAL             0x00
 #define AP_RESPONSE_Q_NOT_AVAIL                0x01
 #define AP_RESPONSE_RESET_IN_PROGRESS  0x02
@@ -125,9 +140,11 @@ struct ap_status_word {
 #define AP_RESPONSE_INDEX_TOO_BIG      0x11
 #define AP_RESPONSE_NO_FIRST_PART      0x13
 #define AP_RESPONSE_MESSAGE_TOO_BIG    0x15
+
 #define AP_MAX_CDX_BITL                4
 #define AP_RQID_RESERVED_BITL  4
 #define SKIP_BITL              (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL)
+
 struct type4_hdr {
        unsigned char  reserved1;
        unsigned char  msg_type_code;   
@@ -136,28 +153,34 @@ struct type4_hdr {
        unsigned char  msg_fmt;
        unsigned short reserved2;
 };
+
 #define TYPE4_TYPE_CODE 0x04
 #define TYPE4_REQU_CODE 0x40
+
 #define TYPE4_SME_LEN 0x0188
 #define TYPE4_LME_LEN 0x0308
 #define TYPE4_SCR_LEN 0x01E0
 #define TYPE4_LCR_LEN 0x03A0
+
 #define TYPE4_SME_FMT 0x00
 #define TYPE4_LME_FMT 0x10
 #define TYPE4_SCR_FMT 0x40
 #define TYPE4_LCR_FMT 0x50
+
 struct type4_sme {
        struct type4_hdr header;
        unsigned char    message[128];
        unsigned char    exponent[128];
        unsigned char    modulus[128];
 };
+
 struct type4_lme {
        struct type4_hdr header;
        unsigned char    message[256];
        unsigned char    exponent[256];
        unsigned char    modulus[256];
 };
+
 struct type4_scr {
        struct type4_hdr header;
        unsigned char    message[128];
@@ -167,6 +190,7 @@ struct type4_scr {
        unsigned char    q[64];
        unsigned char    u[72];
 };
+
 struct type4_lcr {
        struct type4_hdr header;
        unsigned char    message[256];
@@ -176,19 +200,23 @@ struct type4_lcr {
        unsigned char    q[128];
        unsigned char    u[136];
 };
+
 union type4_msg {
        struct type4_sme sme;
        struct type4_lme lme;
        struct type4_scr scr;
        struct type4_lcr lcr;
 };
+
 struct type84_hdr {
        unsigned char  reserved1;
        unsigned char  code;
        unsigned short len;
        unsigned char  reserved2[4];
 };
+
 #define TYPE84_RSP_CODE 0x84
+
 struct type6_hdr {
        unsigned char reserved1;        
        unsigned char type;             
@@ -202,12 +230,6 @@ struct type6_hdr {
        unsigned int  offset3;          
        unsigned int  offset4;          
        unsigned char agent_id[16];     
-                                       
-                                       
-                                       
-                                       
-                                       
-                                       
        unsigned char rqid[2];          
        unsigned char reserved5[2];     
        unsigned char function_code[2]; 
@@ -221,6 +243,7 @@ struct type6_hdr {
        unsigned int  FromCardLen3;     
        unsigned int  FromCardLen4;     
 };
+
 struct CPRB {
        unsigned char cprb_len[2];      
        unsigned char cprb_ver_id;      
@@ -232,19 +255,14 @@ struct CPRB {
        unsigned char checkpoint_flag;  
        unsigned char resv2;            
        unsigned char req_parml[2];     
-                                       
        unsigned char req_parmp[4];     
        unsigned char req_datal[4];     
-                                       
        unsigned char req_datap[4];     
-                                       
        unsigned char rpl_parml[2];     
-                                       
        unsigned char pad_001[2];       
        unsigned char rpl_parmp[4];     
        unsigned char rpl_datal[4];     
        unsigned char rpl_datap[4];     
-                                       
        unsigned char ccp_rscode[2];    
        unsigned char ccp_rtcode[2];    
        unsigned char repd_parml[2];    
@@ -259,6 +277,7 @@ struct CPRB {
        unsigned char svr_namel[2];     
        unsigned char svr_name[8];      
 };
+
 struct CPRBX {
        unsigned short cprb_len;        
        unsigned char  cprb_ver_id;     
@@ -291,19 +310,23 @@ struct CPRBX {
        unsigned char  pad_003[12];     
        unsigned char  pad_004[36];     
 };
+
 struct type6_msg {
        struct type6_hdr header;
        struct CPRB      CPRB;
 };
+
 union request_msg {
        union  type4_msg t4msg;
        struct type6_msg t6msg;
 };
+
 struct request_msg_ext {
        int               q_nr;
        unsigned char     *psmid;
        union request_msg reqMsg;
 };
+
 struct type82_hdr {
        unsigned char reserved1;        
        unsigned char type;             
@@ -311,7 +334,9 @@ struct type82_hdr {
        unsigned char reply_code;       
        unsigned char reserved3[3];     
 };
+
 #define TYPE82_RSP_CODE 0x82
+
 #define REPLY_ERROR_MACHINE_FAILURE  0x10
 #define REPLY_ERROR_PREEMPT_FAILURE  0x12
 #define REPLY_ERROR_CHECKPT_FAILURE  0x14
@@ -331,6 +356,7 @@ struct type82_hdr {
 #define REPLY_ERROR_TRANSPORT_FAIL   0x90
 #define REPLY_ERROR_PACKET_TRUNCATED 0xA0
 #define REPLY_ERROR_ZERO_BUFFER_LEN  0xB0
+
 struct type86_hdr {
        unsigned char reserved1;        
        unsigned char type;             
@@ -339,8 +365,10 @@ struct type86_hdr {
        unsigned char reply_code;       
        unsigned char reserved3[3];     
 };
+
 #define TYPE86_RSP_CODE 0x86
 #define TYPE86_FMT2    0x02
+
 struct type86_fmt2_msg {
        struct type86_hdr hdr;
        unsigned char     reserved[4];  
@@ -354,6 +382,7 @@ struct type86_fmt2_msg {
        unsigned int      ount4;        
        unsigned int      offset4;      
 };
+
 static struct type6_hdr static_type6_hdr = {
        0x00,
        0x06,
@@ -381,6 +410,7 @@ static struct type6_hdr static_type6_hdr = {
        0x00000000,
        0x00000000
 };
+
 static struct type6_hdr static_type6_hdrX = {
        0x00,
        0x06,
@@ -408,6 +438,7 @@ static struct type6_hdr static_type6_hdrX = {
        0x00000000,
        0x00000000
 };
+
 static struct CPRB static_cprb = {
        {0x70,0x00},
        0x41,
@@ -443,31 +474,37 @@ static struct CPRB static_cprb = {
        {0x08,0x00},
        {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20}
 };
+
 struct function_and_rules_block {
        unsigned char function_code[2];
        unsigned char ulen[2];
        unsigned char only_rule[8];
 };
+
 static struct function_and_rules_block static_pkd_function_and_rules = {
        {0x50,0x44},                       
        {0x0A,0x00},                       
        {'P','K','C','S','-','1','.','2'}
 };
+
 static struct function_and_rules_block static_pke_function_and_rules = {
        {0x50,0x4B},                       
        {0x0A,0x00},                       
        {'P','K','C','S','-','1','.','2'}
 };
+
 struct T6_keyBlock_hdr {
        unsigned char blen[2];
        unsigned char ulen[2];
        unsigned char flags[2];
 };
+
 static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = {
        {0x89,0x01},       
        {0x87,0x01},       
        {0x00}
 };
+
 static struct CPRBX static_cprbx = {
        0x00DC,
        0x02,
@@ -508,26 +545,25 @@ static struct CPRBX static_cprbx = {
         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
+
 static struct function_and_rules_block static_pkd_function_and_rulesX = {
        {0x50,0x44},    
        {0x00,0x0A},    
        {'P','K','C','S','-','1','.','2'}
 };
+
 static struct function_and_rules_block static_pke_function_and_rulesX = {
        {0x50,0x4B},    
        {0x00,0x0A},    
        {'Z','E','R','O','-','P','A','D'}
 };
+
 struct T6_keyBlock_hdrX {
        unsigned short blen;
        unsigned short ulen;
        unsigned char flags[2];
 };
-static struct T6_keyBlock_hdrX static_T6_keyBlock_hdrX = {
-       0x0189, 
-       0x0187, 
-       {0x00}
-};
+
 static unsigned char static_pad[256] = {
 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
@@ -546,6 +582,7 @@ static unsigned char static_pad[256] = {
 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
 };
+
 static struct cca_private_ext_ME static_pvt_me_key = {
        {
                0x1E,
@@ -553,6 +590,7 @@ static struct cca_private_ext_ME static_pvt_me_key = {
                0x0183,
                {0x00,0x00,0x00,0x00}
        },
+
        {
                0x02,
                0x00,
@@ -607,6 +645,7 @@ static struct cca_private_ext_ME static_pvt_me_key = {
                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
        },
+
        {
                0x04,
                0x00,
@@ -618,6 +657,7 @@ static struct cca_private_ext_ME static_pvt_me_key = {
                {0x01,0x00,0x01}
        }
 };
+
 static struct cca_public_key static_public_key = {
        {
                0x1E,
@@ -625,6 +665,7 @@ static struct cca_public_key static_public_key = {
                0x0000,                 
                {0x00,0x00,0x00,0x00}
        },
+
        {
                0x04,
                0x00,
@@ -636,10 +677,15 @@ static struct cca_public_key static_public_key = {
                {0x01,0x00,0x01}
        }
 };
+
 #define FIXED_TYPE6_ME_LEN 0x0000025F
+
 #define FIXED_TYPE6_ME_EN_LEN 0x000000F0
+
 #define FIXED_TYPE6_ME_LENX 0x000002CB
+
 #define FIXED_TYPE6_ME_EN_LENX 0x0000015C
+
 static struct cca_public_sec static_cca_pub_sec = {
        0x04,
        0x00,
@@ -650,23 +696,32 @@ static struct cca_public_sec static_cca_pub_sec = {
        0x0000,
        {0x01,0x00,0x01}
 };
+
 #define FIXED_TYPE6_CR_LEN 0x00000177
+
 #define FIXED_TYPE6_CR_LENX 0x000001E3
+
 #ifndef MAX_RESPONSE_SIZE
 #define MAX_RESPONSE_SIZE 0x00000710
+
 #define MAX_RESPONSEX_SIZE 0x0000077C
 #endif
+
 #define RESPONSE_CPRB_SIZE  0x000006B8 
 #define RESPONSE_CPRBX_SIZE 0x00000724 
+
 #define CALLER_HEADER 12       
+
 static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
 static inline int
 testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
 {
        int ccode;
+
        asm volatile
 #ifdef __s390x__
-       ("      lgr     0,%4            \n"     
+       ("      llgfr   0,%4            \n"     
         "      slgr    1,1             \n"     
         "      lgr     2,1             \n"     
         "0:    .long   0xb2af0000      \n"     
@@ -684,11 +739,7 @@ testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
         ".section .fixup,\"ax\"        \n"
         "3:                            \n"     
         "      lhi     %0,%h5          \n"
-        "      bras    1,4f            \n"
-        "      .long   2b              \n"
-        "4:                            \n"
-        "      l       1,0(1)          \n"
-        "      br      1               \n"
+        "      jg      2b              \n"
         ".previous                     \n"
         ".section __ex_table,\"a\"     \n"
         "      .align  8               \n"
@@ -697,7 +748,7 @@ testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
         ".previous"
         :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
         :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
-        :"cc","0","1","2");
+        :"cc","0","1","2","memory");
 #else
        ("      lr      0,%4            \n"     
         "      slr     1,1             \n"     
@@ -728,17 +779,19 @@ testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
         ".previous"
         :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
         :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
-        :"cc","0","1","2");
+        :"cc","0","1","2","memory");
 #endif
        return ccode;
 }
+
 static inline int
 resetq(int q_nr, struct ap_status_word *stat_p)
 {
        int ccode;
+
        asm volatile
 #ifdef __s390x__
-       ("      lgr     0,%2            \n"     
+       ("      llgfr   0,%2            \n"     
         "      lghi    1,1             \n"     
         "      sll     1,24            \n"     
         "      or      0,1             \n"     
@@ -754,11 +807,7 @@ resetq(int q_nr, struct ap_status_word *stat_p)
         ".section .fixup,\"ax\"        \n"
         "3:                            \n"     
         "      lhi     %0,%h3          \n"
-        "      bras    1,4f            \n"
-        "      .long   2b              \n"
-        "4:                            \n"
-        "      l       1,0(1)          \n"
-        "      br      1               \n"
+        "      jg      2b              \n"
         ".previous                     \n"
         ".section __ex_table,\"a\"     \n"
         "      .align  8               \n"
@@ -767,7 +816,7 @@ resetq(int q_nr, struct ap_status_word *stat_p)
         ".previous"
         :"=d" (ccode),"=d" (*stat_p)
         :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
-        :"cc","0","1","2");
+        :"cc","0","1","2","memory");
 #else
        ("      lr      0,%2            \n"     
         "      lhi     1,1             \n"     
@@ -796,18 +845,20 @@ resetq(int q_nr, struct ap_status_word *stat_p)
         ".previous"
         :"=d" (ccode),"=d" (*stat_p)
         :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
-        :"cc","0","1","2");
+        :"cc","0","1","2","memory");
 #endif
        return ccode;
 }
+
 static inline int
 sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
 {
        int ccode;
+
        asm volatile
 #ifdef __s390x__
        ("      lgr     6,%3            \n"     
-        "      lgr     7,%2            \n"     
+        "      llgfr   7,%2            \n"     
         "      llgt    0,0(6)          \n"     
         "      lghi    1,64            \n"     
         "      sll     1,24            \n"     
@@ -828,11 +879,7 @@ sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
         ".section .fixup,\"ax\"        \n"
         "3:                            \n"     
         "      lhi     %0,%h4          \n"
-        "      bras    1,4f            \n"
-        "      .long   2b              \n"
-        "4:                            \n"
-        "      l       1,0(1)          \n"
-        "      br      1               \n"
+        "      jg      2b              \n"
         ".previous                     \n"
         ".section __ex_table,\"a\"     \n"
         "      .align  8               \n"
@@ -841,7 +888,7 @@ sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
         ".previous"
         :"=d" (ccode),"=d" (*stat)
         :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
-        :"cc","0","1","2","3","6","7");
+        :"cc","0","1","2","3","6","7","memory");
 #else
        ("      lr      6,%3            \n"     
         "      lr      7,%2            \n"     
@@ -876,21 +923,23 @@ sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
         ".previous"
         :"=d" (ccode),"=d" (*stat)
         :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
-        :"cc","0","1","2","3","6","7");
+        :"cc","0","1","2","3","6","7","memory");
 #endif
        return ccode;
 }
+
 static inline int
 rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
     struct ap_status_word *st)
 {
        int ccode;
+
        asm volatile
 #ifdef __s390x__
-       ("      lgr     0,%2            \n"     
+       ("      llgfr   0,%2            \n"     
         "      lgr     3,%4            \n"     
         "      lgr     6,%3            \n"     
-        "      lgr     7,%5            \n"     
+        "      llgfr   7,%5            \n"     
         "      lghi    1,128           \n"     
         "      sll     1,24            \n"     
         "      or      0,1             \n"     
@@ -912,11 +961,7 @@ rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
         ".section .fixup,\"ax\"        \n"
         "3:                            \n"     
         "      lhi   %0,%h6            \n"
-        "      bras  1,4f              \n"
-        "      .long 2b                \n"
-        "4:                            \n"
-        "      l     1,0(1)            \n"
-        "      br    1                 \n"
+        "      jg    2b                \n"
         ".previous                     \n"
         ".section __ex_table,\"a\"     \n"
         "   .align     8               \n"
@@ -967,12 +1012,14 @@ rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
 #endif
        return ccode;
 }
+
 static inline void
 itoLe2(int *i_p, unsigned char *lechars)
 {
        *lechars       = *((unsigned char *) i_p + sizeof(int) - 1);
        *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2);
 }
+
 static inline void
 le2toI(unsigned char *lechars, int *i_p)
 {
@@ -982,11 +1029,13 @@ le2toI(unsigned char *lechars, int *i_p)
        *(ic_p + 2) = *(lechars + 1);
        *(ic_p + 3) = *(lechars);
 }
+
 static inline int
 is_empty(unsigned char *ptr, int len)
 {
        return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len);
 }
+
 enum hdstat
 query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
 {
@@ -995,6 +1044,7 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
        struct ap_status_word stat_word;
        enum hdstat stat;
        int break_out;
+
        q_nr = (deviceNr << SKIP_BITL) + cdx;
        stat = HD_BUSY;
        ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
@@ -1013,6 +1063,7 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
                        *q_depth = t_depth + 1;
                        switch (t_dev_type) {
                        case OTHER_HW:
+                       case OTHER2_HW:
                                stat = HD_NOT_THERE;
                                *dev_type = NILDEV;
                                break;
@@ -1085,13 +1136,14 @@ query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
                }
                if (break_out)
                        break;
-               
+
                udelay(5);
-               
+
                ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
        }
        return stat;
 }
+
 enum devstat
 reset_device(int deviceNr, int cdx, int resetNr)
 {
@@ -1099,11 +1151,13 @@ reset_device(int deviceNr, int cdx, int resetNr)
        struct ap_status_word stat_word;
        enum devstat stat;
        int break_out;
+
        q_nr = (deviceNr << SKIP_BITL) + cdx;
        stat = DEV_GONE;
        ccode = resetq(q_nr, &stat_word);
        if (ccode > 3)
                return DEV_RSQ_EXCEPTION;
+
        break_out = 0;
        for (i = 0; i < resetNr; i++) {
                switch (ccode) {
@@ -1145,6 +1199,7 @@ reset_device(int deviceNr, int cdx, int resetNr)
                if (break_out == 1)
                        break;
                udelay(5);
+
                ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word);
                if (ccode > 3) {
                        stat = DEV_TSQ_EXCEPTION;
@@ -1152,11 +1207,14 @@ reset_device(int deviceNr, int cdx, int resetNr)
                }
        }
        PDEBUG("Number of testq's needed for reset: %d\n", i);
+
        if (i >= resetNr) {
          stat = DEV_GONE;
        }
+
        return stat;
 }
+
 #ifdef DEBUG_HYDRA_MSGS
 static inline void
 print_buffer(unsigned char *buffer, int bufflen)
@@ -1172,30 +1230,34 @@ print_buffer(unsigned char *buffer, int bufflen)
        }
 }
 #endif
+
 enum devstat
 send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
 {
        struct ap_status_word stat_word;
        enum devstat stat;
        int ccode;
+
        ((struct request_msg_ext *) msg_ext)->q_nr =
                (dev_nr << SKIP_BITL) + cdx;
        PDEBUG("msg_len passed to sen: %d\n", msg_len);
        PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
               msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
        stat = DEV_GONE;
+
 #ifdef DEBUG_HYDRA_MSGS
        PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X "
               "%02X%02X%02X%02X\n",
               msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
               msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
               msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
-       
        print_buffer(msg_ext+12, msg_len);
 #endif
+
        ccode = sen(msg_len, msg_ext, &stat_word);
        if (ccode > 3)
                return DEV_SEN_EXCEPTION;
+
        PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n",
               ccode, stat_word.q_stat_flags, stat_word.response_code,
               stat_word.reserved[0], stat_word.reserved[1]);
@@ -1222,8 +1284,10 @@ send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
        default:
                stat = DEV_GONE;
        }
+
        return stat;
 }
+
 enum devstat
 receive_from_AP(int dev_nr, int cdx, int resplen,
                unsigned char *resp, unsigned char *psmid)
@@ -1231,14 +1295,18 @@ receive_from_AP(int dev_nr, int cdx, int resplen,
        int ccode;
        struct ap_status_word stat_word;
        enum devstat stat;
+
        memset(resp, 0x00, 8);
+
        ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid,
                    &stat_word);
        if (ccode > 3)
                return DEV_REC_EXCEPTION;
+
        PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n",
               ccode, stat_word.q_stat_flags, stat_word.response_code,
               stat_word.reserved[0], stat_word.reserved[1]);
+
        stat = DEV_GONE;
        switch (ccode) {
        case 0:
@@ -1270,28 +1338,37 @@ receive_from_AP(int dev_nr, int cdx, int resplen,
        default:
                break;
        }
+
        return stat;
 }
+
 static inline int
 pad_msg(unsigned char *buffer, int  totalLength, int msgLength)
 {
        int pad_len;
+
        for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++)
                if (buffer[pad_len] != 0x00)
                        break;
        pad_len -= 3; 
        if (pad_len < 8)
                return SEN_PAD_ERROR;
+
        buffer[0] = 0x00;
        buffer[1] = 0x02;
+
        memcpy(buffer+2, static_pad, pad_len);
+
        buffer[pad_len + 2] = 0x00;
+
        return 0;
 }
+
 static inline int
 is_common_public_key(unsigned char *key, int len)
 {
        int i;
+
        for (i = 0; i < len; i++)
                if (key[i])
                        break;
@@ -1300,8 +1377,10 @@ is_common_public_key(unsigned char *key, int len)
        if (((len == 1) && (key[0] == 3)) ||
            ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1)))
                return 1;
+
        return 0;
 }
+
 static int
 ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
                           union type4_msg *z90cMsg_p)
@@ -1309,14 +1388,20 @@ ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
        int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
        unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
        union type4_msg *tmp_type4_msg;
+
        mod_len = icaMex_p->inputdatalength;
+
        msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) +
                    CALLER_HEADER;
+
        memset(z90cMsg_p, 0, msg_size);
+
        tmp_type4_msg = (union type4_msg *)
                ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
        tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE;
        tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE;
+
        if (mod_len <= 128) {
                tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT;
                tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN;
@@ -1336,6 +1421,7 @@ ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
                inp_tgt = tmp_type4_msg->lme.message;
                inp_tgt_len = sizeof(tmp_type4_msg->lme.message);
        }
+
        mod_tgt += (mod_tgt_len - mod_len);
        if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
                return SEN_RELEASED;
@@ -1351,9 +1437,12 @@ ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
                return SEN_RELEASED;
        if (is_empty(inp_tgt, mod_len))
                return SEN_USER_ERROR;
+
        *z90cMsg_l_p = msg_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
 ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
                           int *z90cMsg_l_p, union type4_msg *z90cMsg_p)
@@ -1362,14 +1451,19 @@ ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
            dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len;
        unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt;
        union type4_msg *tmp_type4_msg;
+
        mod_len = icaMsg_p->inputdatalength;
        short_len = mod_len / 2;
        long_len = mod_len / 2 + 8;
+
        tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) +
                    CALLER_HEADER;
+
        memset(z90cMsg_p, 0, tmp_size);
+
        tmp_type4_msg = (union type4_msg *)
                ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
        tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE;
        tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE;
        if (mod_len <= 128) {
@@ -1403,6 +1497,7 @@ ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
                inp_tgt = tmp_type4_msg->lcr.message;
                inp_tgt_len = sizeof(tmp_type4_msg->lcr.message);
        }
+
        p_tgt += (p_tgt_len - long_len);
        if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len))
                return SEN_RELEASED;
@@ -1433,9 +1528,12 @@ ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
                return SEN_RELEASED;
        if (is_empty(inp_tgt, mod_len))
                return SEN_USER_ERROR;
+
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
 ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
                              int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
@@ -1445,43 +1543,45 @@ ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        struct type6_hdr *tp6Hdr_p;
        struct CPRB *cprb_p;
        struct cca_private_ext_ME *key_p;
+
        mod_len = icaMsg_p->inputdatalength;
        tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
        total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
        parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
        tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
        memset(z90cMsg_p, 0, tmp_size);
-       
+
        temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
        memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
        tp6Hdr_p = (struct type6_hdr *)temp;
        tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
        tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
-       
+
        temp += sizeof(struct type6_hdr);
        memcpy(temp, &static_cprb, sizeof(struct CPRB));
        cprb_p = (struct CPRB *) temp;
        cprb_p->usage_domain[0]= (unsigned char)cdx;
        itoLe2(&parmBlock_l, cprb_p->req_parml);
        itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
-       
+
        temp += sizeof(struct CPRB);
        memcpy(temp, &static_pkd_function_and_rules,
               sizeof(struct function_and_rules_block));
-       
+
        temp += sizeof(struct function_and_rules_block);
        vud_len = 2 + icaMsg_p->inputdatalength;
        itoLe2(&vud_len, temp); 
-       
+
        temp += 2;
        if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
                return SEN_RELEASED;
        if (is_empty(temp, mod_len))
                return SEN_USER_ERROR;
-       
+
        temp += mod_len;
        memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr));
-       
+
        temp += sizeof(struct T6_keyBlock_hdr);
        memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME));
        key_p = (struct cca_private_ext_ME *)temp;
@@ -1491,21 +1591,26 @@ ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
                return SEN_RELEASED;
        if (is_empty(temp, mod_len))
                return SEN_USER_ERROR;
+
        if (is_common_public_key(temp, mod_len)) {
                PRINTK("Common public key used for modex decrypt\n");
                return SEN_NOT_AVAIL;
        }
+
        temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
               - mod_len;
        if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len) != 0)
                return SEN_RELEASED;
        if (is_empty(temp, mod_len))
                return SEN_USER_ERROR;
-       
+
        key_p->pubMESec.modulus_bit_len = 8 * mod_len;
+
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
 ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
                              int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
@@ -1517,27 +1622,32 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        struct CPRB *cprb_p;
        struct cca_public_key *key_p;
        struct T6_keyBlock_hdr *keyb_p;
+
        mod_len = icaMsg_p->inputdatalength;
        if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
                return SEN_RELEASED;
        if (is_empty(temp_exp, mod_len))
                return SEN_USER_ERROR;
+
        exp_p = temp_exp;
        for (i = 0; i < mod_len; i++)
                if (exp_p[i])
                        break;
        if (i >= mod_len)
                return SEN_USER_ERROR;
+
        exp_len = mod_len - i;
        exp_p += i;
+
        PDEBUG("exp_len after computation: %08x\n", exp_len);
        tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len;
        total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
        parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
        tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
        vud_len = 2 + mod_len;
        memset(z90cMsg_p, 0, tmp_size);
-       
+
        temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
        memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
        tp6Hdr_p = (struct type6_hdr *)temp;
@@ -1545,24 +1655,20 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
        memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
               sizeof(static_PKE_function_code));
-       
        temp += sizeof(struct type6_hdr);
        memcpy(temp, &static_cprb, sizeof(struct CPRB));
        cprb_p = (struct CPRB *) temp;
        cprb_p->usage_domain[0]= (unsigned char)cdx;
        itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
-       
        temp += sizeof(struct CPRB);
        memcpy(temp, &static_pke_function_and_rules,
                 sizeof(struct function_and_rules_block));
-       
        temp += sizeof(struct function_and_rules_block);
        temp += 2;
        if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
                return SEN_RELEASED;
        if (is_empty(temp, mod_len))
                return SEN_USER_ERROR;
-       
        if (temp[0] != 0x00 || temp[1] != 0x02)
                return SEN_NOT_AVAIL;
        for (i = 2; i < mod_len; i++)
@@ -1573,14 +1679,11 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        pad_len = i + 1;
        vud_len = mod_len - pad_len;
        memmove(temp, temp+pad_len, vud_len);
-       
        temp -= 2;
        vud_len += 2;
        itoLe2(&vud_len, temp);
-       
        temp += (vud_len);
        keyb_p = (struct T6_keyBlock_hdr *)temp;
-       
        temp += sizeof(struct T6_keyBlock_hdr);
        memcpy(temp, &static_public_key, sizeof(static_public_key));
        key_p = (struct cca_public_key *)temp;
@@ -1604,8 +1707,10 @@ ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        parmBlock_l -= pad_len;
        itoLe2(&parmBlock_l, cprb_p->req_parml);
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
 ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
@@ -1618,6 +1723,7 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        struct cca_token_hdr *keyHdr_p;
        struct cca_pvt_ext_CRT_sec *pvtSec_p;
        struct cca_public_sec *pubSec_p;
+
        mod_len = icaMsg_p->inputdatalength;
        short_len = mod_len / 2;
        long_len = 8 + short_len;
@@ -1629,14 +1735,13 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
        vud_len = 2 + mod_len;     
        tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
        memset(z90cMsg_p, 0, tmp_size);
-       
        tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
        memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr));
        tp6Hdr_p = (struct type6_hdr *)tgt_p;
        tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
        tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
-       
        tgt_p += sizeof(struct type6_hdr);
        cprb_p = (struct CPRB *) tgt_p;
        memcpy(tgt_p, &static_cprb, sizeof(struct CPRB));
@@ -1644,39 +1749,32 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        itoLe2(&parmBlock_l, cprb_p->req_parml);
        memcpy(cprb_p->rpl_parml, cprb_p->req_parml,
               sizeof(cprb_p->req_parml));
-       
        tgt_p += sizeof(struct CPRB);
        memcpy(tgt_p, &static_pkd_function_and_rules,
               sizeof(struct function_and_rules_block));
-       
        tgt_p += sizeof(struct function_and_rules_block);
        itoLe2(&vud_len, tgt_p);
-       
        tgt_p += 2;
        if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
                return SEN_RELEASED;
        if (is_empty(tgt_p, mod_len))
                return SEN_USER_ERROR;
-       
        tgt_p += mod_len;
        tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
                sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
        itoLe2(&tmp_l, tgt_p);
-       
        temp = tgt_p + 2;
        tmp_l -= 2;
        itoLe2(&tmp_l, temp);
-       
        tgt_p += sizeof(struct T6_keyBlock_hdr);
        keyHdr_p = (struct cca_token_hdr *)tgt_p;
        keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
        tmp_l -= 4;
        keyHdr_p->token_length = tmp_l;
-       
        tgt_p += sizeof(struct cca_token_hdr);
        pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
        pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
-       pvtSec_p->section_length = 
+       pvtSec_p->section_length =
                sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
        pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
        pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
@@ -1687,7 +1785,6 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        pvtSec_p->u_len = long_len;
        pvtSec_p->mod_len = mod_len;
        pvtSec_p->pad_len = pad_len;
-       
        tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
        if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
                return SEN_RELEASED;
@@ -1716,89 +1813,18 @@ ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        tgt_p += long_len;
        tgt_p += pad_len;
        memset(tgt_p, 0xFF, mod_len);
-       
        tgt_p += mod_len;
        memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
        pubSec_p = (struct cca_public_sec *) tgt_p;
        pubSec_p->modulus_bit_len = 8 * mod_len;
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
-ICAMEX_msg_to_type6MEX_de_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
-                              int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
-{
-       int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
-       unsigned char *tgt_p, *temp;
-       struct type6_hdr *tp6Hdr_p;
-       struct CPRBX *cprbx_p;
-       struct cca_private_ext_ME *key_p;
-       mod_len = icaMsg_p->inputdatalength;
-       tmp_size = FIXED_TYPE6_ME_LENX + mod_len;
-       total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
-       parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
-       tmp_size += CALLER_HEADER;
-       vud_len = 2 + mod_len;
-       memset(z90cMsg_p, 0, tmp_size);
-       
-       tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
-       memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
-       tp6Hdr_p = (struct type6_hdr *)tgt_p;
-       tp6Hdr_p->ToCardLen1 = total_CPRB_len;
-       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
-       
-       tgt_p += sizeof(struct type6_hdr);
-       memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
-       cprbx_p = (struct CPRBX *) tgt_p;
-       cprbx_p->domain = (unsigned short)cdx;
-       cprbx_p->req_parml = parmBlock_l;
-       cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
-       
-       tgt_p += sizeof(struct CPRBX);
-       memcpy(tgt_p, &static_pkd_function_and_rulesX,
-              sizeof(struct function_and_rules_block));
-       
-       tgt_p += sizeof(struct function_and_rules_block);
-       *((short *)tgt_p) = (short) vud_len;
-       
-       tgt_p += 2;
-       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
-               return SEN_RELEASED;
-       if (is_empty(tgt_p, mod_len))
-               return SEN_USER_ERROR;
-       
-       tgt_p += mod_len;
-       memcpy(tgt_p, &static_T6_keyBlock_hdrX,
-              sizeof(struct T6_keyBlock_hdrX));
-       
-       tgt_p += sizeof(struct T6_keyBlock_hdrX);
-       memcpy(tgt_p, &static_pvt_me_key,
-              sizeof(struct cca_private_ext_ME));
-       key_p = (struct cca_private_ext_ME *)tgt_p;
-       temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent) -
-              mod_len;
-       if (copy_from_user(temp, icaMsg_p->b_key, mod_len))
-               return SEN_RELEASED;
-       if (is_empty(temp, mod_len))
-               return SEN_USER_ERROR;
-       
-       if (is_common_public_key(temp, mod_len)) {
-               PRINTK("Common public key used for modex decrypt\n");
-               return SEN_NOT_AVAIL;
-       }
-       temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus) -
-              mod_len;
-       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
-               return SEN_RELEASED;
-       if (is_empty(temp, mod_len))
-               return SEN_USER_ERROR;
-       key_p->pubMESec.modulus_bit_len = 8 * mod_len;
-       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-       return 0;
-}
-static int
-ICAMEX_msg_to_type6MEX_en_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
-                              int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
 {
        int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
        int key_len, i;
@@ -1807,6 +1833,7 @@ ICAMEX_msg_to_type6MEX_en_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        struct CPRBX *cprbx_p;
        struct cca_public_key *key_p;
        struct T6_keyBlock_hdrX *keyb_p;
+
        mod_len = icaMsg_p->inputdatalength;
        if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
                return SEN_RELEASED;
@@ -1827,7 +1854,6 @@ ICAMEX_msg_to_type6MEX_en_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        tmp_size = tmp_size + CALLER_HEADER;
        vud_len = 2 + mod_len;
        memset(z90cMsg_p, 0, tmp_size);
-       
        tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
        memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
        tp6Hdr_p = (struct type6_hdr *)tgt_p;
@@ -1835,30 +1861,25 @@ ICAMEX_msg_to_type6MEX_en_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
        memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
               sizeof(static_PKE_function_code));
-       
        tgt_p += sizeof(struct type6_hdr);
        memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
        cprbx_p = (struct CPRBX *) tgt_p;
        cprbx_p->domain = (unsigned short)cdx;
        cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
-       
        tgt_p += sizeof(struct CPRBX);
        memcpy(tgt_p, &static_pke_function_and_rulesX,
               sizeof(struct function_and_rules_block));
-       
        tgt_p += sizeof(struct function_and_rules_block);
-       
+
        tgt_p += 2;
        if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
              return SEN_RELEASED;
        if (is_empty(tgt_p, mod_len))
              return SEN_USER_ERROR;
-       
        tgt_p -= 2;
        *((short *)tgt_p) = (short) vud_len;
        tgt_p += vud_len;
        keyb_p = (struct T6_keyBlock_hdrX *)tgt_p;
-       
        tgt_p += sizeof(struct T6_keyBlock_hdrX);
        memcpy(tgt_p, &static_public_key, sizeof(static_public_key));
        key_p = (struct cca_public_key *)tgt_p;
@@ -1881,8 +1902,10 @@ ICAMEX_msg_to_type6MEX_en_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
        keyb_p->blen = (unsigned short)key_len;
        cprbx_p->req_parml = parmBlock_l;
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 static int
 ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
                            int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
@@ -1895,6 +1918,7 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        struct cca_token_hdr *keyHdr_p;
        struct cca_pvt_ext_CRT_sec *pvtSec_p;
        struct cca_public_sec *pubSec_p;
+
        mod_len = icaMsg_p->inputdatalength;
        short_len = mod_len / 2;
        long_len = 8 + short_len;
@@ -1907,33 +1931,27 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        vud_len = 2 + mod_len;
        tmp_size = tmp_size + CALLER_HEADER;
        memset(z90cMsg_p, 0, tmp_size);
-       
        tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
        memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
        tp6Hdr_p = (struct type6_hdr *)tgt_p;
        tp6Hdr_p->ToCardLen1 = total_CPRB_len;
        tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
-       
        tgt_p += sizeof(struct type6_hdr);
        cprbx_p = (struct CPRBX *) tgt_p;
        memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
        cprbx_p->domain = (unsigned short)cdx;
        cprbx_p->req_parml = parmBlock_l;
        cprbx_p->rpl_msgbl = parmBlock_l;
-       
        tgt_p += sizeof(struct CPRBX);
        memcpy(tgt_p, &static_pkd_function_and_rulesX,
               sizeof(struct function_and_rules_block));
-       
        tgt_p += sizeof(struct function_and_rules_block);
        *((short *)tgt_p) = (short) vud_len;
-       
        tgt_p += 2;
        if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
                return SEN_RELEASED;
        if (is_empty(tgt_p, mod_len))
                return SEN_USER_ERROR;
-       
        tgt_p += mod_len;
        tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
                sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
@@ -1941,13 +1959,11 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        temp = tgt_p + 2;
        tmp_l -= 2;
        *((short *)temp) = (short) tmp_l;
-       
        tgt_p += sizeof(struct T6_keyBlock_hdr);
        keyHdr_p = (struct cca_token_hdr *)tgt_p;
        keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
        tmp_l -= 4;
        keyHdr_p->token_length = tmp_l;
-       
        tgt_p += sizeof(struct cca_token_hdr);
        pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
        pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
@@ -1962,7 +1978,6 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        pvtSec_p->u_len = long_len;
        pvtSec_p->mod_len = mod_len;
        pvtSec_p->pad_len = pad_len;
-       
        tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
        if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
                return SEN_RELEASED;
@@ -1991,14 +2006,15 @@ ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
        tgt_p += long_len;
        tgt_p += pad_len;
        memset(tgt_p, 0xFF, mod_len);
-       
        tgt_p += mod_len;
        memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
        pubSec_p = (struct cca_public_sec *) tgt_p;
        pubSec_p->modulus_bit_len = 8 * mod_len;
        *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
        return 0;
 }
+
 int
 convert_request(unsigned char *buffer, int func, unsigned short function,
                int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p)
@@ -2032,19 +2048,17 @@ convert_request(unsigned char *buffer, int func, unsigned short function,
                        return ICACRT_msg_to_type6CRT_msgX(
                                (struct ica_rsa_modexpo_crt *) buffer,
                                cdx, msg_l_p, (struct type6_msg *) msg_p);
-               if (function == PCI_FUNC_KEY_ENCRYPT)
-                       return ICAMEX_msg_to_type6MEX_en_msgX(
-                               (struct ica_rsa_modexpo *) buffer,
-                               cdx, msg_l_p, (struct type6_msg *) msg_p);
                else
-                       return ICAMEX_msg_to_type6MEX_de_msgX(
+                       return ICAMEX_msg_to_type6MEX_msgX(
                                (struct ica_rsa_modexpo *) buffer,
                                cdx, msg_l_p, (struct type6_msg *) msg_p);
        }
+
        return 0;
 }
+
 int
-convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
+convert_response(unsigned char *response, unsigned char *buffer,
                 int *respbufflen_p, unsigned char *resp_buff)
 {
        struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
@@ -2055,6 +2069,7 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
        unsigned char *src_p, *tgt_p;
        struct CPRB *cprb_p;
        struct CPRBX *cprbx_p;
+
        src_p = 0;
        reply_code = 0;
        service_rc = 0;
@@ -2092,8 +2107,11 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
                        le2toI(cprb_p->ccp_rtcode, &service_rc);
                        if (service_rc != 0) {
                                le2toI(cprb_p->ccp_rscode, &service_rs);
-                               PDEBUG("service rc/rc: %d/%d\n",
-                                      service_rc, service_rs);
+                               if ((service_rc == 8) && (service_rs == 66))
+                                       PDEBUG("8/66 on PCICC\n");
+                               else
+                                       PRINTK("service rc/rs: %d/%d\n",
+                                              service_rc, service_rs);
                                rv = 8;
                        }
                        src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
@@ -2105,8 +2123,11 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
                        service_rc = (int)cprbx_p->ccp_rtcode;
                        if (service_rc != 0) {
                                service_rs = (int) cprbx_p->ccp_rscode;
-                               PRINTK("service rc:%d; service rs:%d\n",
-                                      service_rc, service_rs);
+                               if ((service_rc == 8) && (service_rs == 66))
+                                       PDEBUG("8/66 on PCIXCC\n");
+                               else
+                                       PRINTK("service rc/rs: %d/%d\n",
+                                              service_rc, service_rs);
                                rv = 8;
                        }
                        src_p = (unsigned char *)
@@ -2120,8 +2141,7 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
        default:
                break;
        }
-       
-       
+
        if (rv == 8)
                return 8;
        if (rv == 4)
@@ -2137,18 +2157,18 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
                default:
                        return 12;
                }
-       
+
        if (service_rc != 0)
                return REC_OPERAND_INV;
+
        if ((src_l > icaMsg_p->outputdatalength) ||
            (src_l > RESPBUFFSIZE) ||
            (src_l <= 0))
                return REC_OPERAND_SIZE;
+
        PDEBUG("Length returned = %d\n", src_l);
-       
        tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
        memcpy(tgt_p, src_p, src_l);
-       
        if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
                memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
                rv = pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l);
@@ -2158,5 +2178,7 @@ convert_response(unsigned char *response, int dev_type, unsigned char *buffer,
        *respbufflen_p = icaMsg_p->outputdatalength;
        if (*respbufflen_p == 0)
                PRINTK("Zero *respbufflen_p\n");
+
        return rv;
 }
+
index 9bbc8e8..0190e27 100644 (file)
  */
 
 #include <asm/uaccess.h>       // copy_(from|to)_user
+#include <linux/compat.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>       // mdelay
+#include <linux/init.h>
 #include <linux/interrupt.h>   // for tasklets
+#include <linux/ioctl32.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/proc_fs.h>
+#include <linux/syscalls.h>
 #include <linux/version.h>
 #include "z90crypt.h"
 #include "z90common.h"
 #  error "This kernel is too recent: not supported by this file"
 #endif
 
-#define VERSION_Z90MAIN_C "$Revision: 1.15 $"
+#define VERSION_Z90MAIN_C "$Revision: 1.31 $"
 
-static const char version[] __attribute_used__ =
-       "z90crypt.o: z90main.o ("
-       "z90main.c "   VERSION_Z90MAIN_C   "/"
-       "z90common.h " VERSION_Z90COMMON_H "/"
-       "z90crypt.h "  VERSION_Z90CRYPT_H  ")";
+static char z90cmain_version[] __initdata =
+       "z90main.o (" VERSION_Z90MAIN_C "/"
+                      VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
+
+extern char z90chardware_version[];
 
 /**
  * Defaults that may be modified.
@@ -142,7 +146,7 @@ static const char version[] __attribute_used__ =
 #define STAT_FAILED    0x40 // bit 6: this bit is set if the request failed
                             //        before being sent to the hardware.
 #define STAT_WRITTEN   0x30 // bits 5-4: work to be done, not sent to device
-#define STAT_QUEUED    0x20 // bits 5-4: work has been sent to a device
+//                     0x20 // UNUSED state
 #define STAT_READPEND  0x10 // bits 5-4: work done, we're returning data now
 #define STAT_NOWORK    0x00 // bits off: no work on any queue
 #define STAT_RDWRMASK  0x30 // mask for bits 5-4
@@ -311,8 +315,7 @@ enum devstat send_to_AP(int, int, int, unsigned char *);
 enum devstat receive_from_AP(int, int, int, unsigned char *, unsigned char *);
 int convert_request(unsigned char *, int, short, int, int, int *,
                    unsigned char *);
-int convert_response(unsigned char *, int, unsigned char *, int *,
-                    unsigned char *);
+int convert_response(unsigned char *, unsigned char *, int *, unsigned char *);
 
 /**
  * Low level function prototypes
@@ -329,7 +332,7 @@ static int probe_device_type(struct device *);
 /**
  * proc fs definitions
  */
-struct proc_dir_entry *z90crypt_entry;
+static struct proc_dir_entry *z90crypt_entry;
 
 /**
  * data structures
@@ -424,7 +427,7 @@ static struct timer_list cleanup_timer;
 static atomic_t total_open;
 static atomic_t z90crypt_step;
 
-struct file_operations z90crypt_fops = {
+static struct file_operations z90crypt_fops = {
        .owner   = THIS_MODULE,
        .read    = z90crypt_read,
        .write   = z90crypt_write,
@@ -434,7 +437,7 @@ struct file_operations z90crypt_fops = {
 };
 
 #ifndef Z90CRYPT_USE_HOTPLUG
-struct miscdevice z90crypt_misc_device = {
+static struct miscdevice z90crypt_misc_device = {
        .minor      = Z90CRYPT_MINOR,
        .name       = DEV_NAME,
        .fops       = &z90crypt_fops,
@@ -453,6 +456,150 @@ MODULE_LICENSE("GPL");
 module_param(domain, int, 0);
 MODULE_PARM_DESC(domain, "domain index for device");
 
+#ifdef CONFIG_COMPAT
+/**
+ * ioctl32 conversion routines
+ */
+struct ica_rsa_modexpo_32 { // For 32-bit callers
+       compat_uptr_t   inputdata;
+       unsigned int    inputdatalength;
+       compat_uptr_t   outputdata;
+       unsigned int    outputdatalength;
+       compat_uptr_t   b_key;
+       compat_uptr_t   n_modulus;
+};
+
+static int
+trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg,
+               struct file *file)
+{
+       struct ica_rsa_modexpo_32 *mex32u = compat_ptr(arg);
+       struct ica_rsa_modexpo_32  mex32k;
+       struct ica_rsa_modexpo    *mex64;
+       int ret = 0;
+       unsigned int i;
+
+       if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
+               return -EFAULT;
+       mex64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo));
+       if (!access_ok(VERIFY_WRITE, mex64, sizeof(struct ica_rsa_modexpo)))
+               return -EFAULT;
+       if (copy_from_user(&mex32k, mex32u, sizeof(struct ica_rsa_modexpo_32)))
+               return -EFAULT;
+       if (__put_user(compat_ptr(mex32k.inputdata), &mex64->inputdata)   ||
+           __put_user(mex32k.inputdatalength, &mex64->inputdatalength)   ||
+           __put_user(compat_ptr(mex32k.outputdata), &mex64->outputdata) ||
+           __put_user(mex32k.outputdatalength, &mex64->outputdatalength) ||
+           __put_user(compat_ptr(mex32k.b_key), &mex64->b_key)           ||
+           __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
+               return -EFAULT;
+       ret = sys_ioctl(fd, cmd, (unsigned long)mex64);
+       if (!ret)
+               if (__get_user(i, &mex64->outputdatalength) ||
+                   __put_user(i, &mex32u->outputdatalength))
+                       ret = -EFAULT;
+       return ret;
+}
+
+struct ica_rsa_modexpo_crt_32 { // For 32-bit callers
+       compat_uptr_t   inputdata;
+       unsigned int    inputdatalength;
+       compat_uptr_t   outputdata;
+       unsigned int    outputdatalength;
+       compat_uptr_t   bp_key;
+       compat_uptr_t   bq_key;
+       compat_uptr_t   np_prime;
+       compat_uptr_t   nq_prime;
+       compat_uptr_t   u_mult_inv;
+};
+
+static int
+trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg,
+                   struct file *file)
+{
+       struct ica_rsa_modexpo_crt_32 *crt32u = compat_ptr(arg);
+       struct ica_rsa_modexpo_crt_32  crt32k;
+       struct ica_rsa_modexpo_crt    *crt64;
+       int ret = 0;
+       unsigned int i;
+
+       if (!access_ok(VERIFY_WRITE, crt32u,
+                      sizeof(struct ica_rsa_modexpo_crt_32)))
+               return -EFAULT;
+       crt64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo_crt));
+       if (!access_ok(VERIFY_WRITE, crt64, sizeof(struct ica_rsa_modexpo_crt)))
+               return -EFAULT;
+       if (copy_from_user(&crt32k, crt32u,
+                          sizeof(struct ica_rsa_modexpo_crt_32)))
+               return -EFAULT;
+       if (__put_user(compat_ptr(crt32k.inputdata), &crt64->inputdata)   ||
+           __put_user(crt32k.inputdatalength, &crt64->inputdatalength)   ||
+           __put_user(compat_ptr(crt32k.outputdata), &crt64->outputdata) ||
+           __put_user(crt32k.outputdatalength, &crt64->outputdatalength) ||
+           __put_user(compat_ptr(crt32k.bp_key), &crt64->bp_key)         ||
+           __put_user(compat_ptr(crt32k.bq_key), &crt64->bq_key)         ||
+           __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime)     ||
+           __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime)     ||
+           __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
+               ret = -EFAULT;
+       if (!ret)
+               ret = sys_ioctl(fd, cmd, (unsigned long)crt64);
+       if (!ret)
+               if (__get_user(i, &crt64->outputdatalength) ||
+                   __put_user(i, &crt32u->outputdatalength))
+                       ret = -EFAULT;
+       return ret;
+}
+
+static int compatible_ioctls[] = {
+       ICAZ90STATUS, Z90QUIESCE, Z90STAT_TOTALCOUNT, Z90STAT_PCICACOUNT,
+       Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_REQUESTQ_COUNT,
+       Z90STAT_PENDINGQ_COUNT, Z90STAT_TOTALOPEN_COUNT, Z90STAT_DOMAIN_INDEX,
+       Z90STAT_STATUS_MASK, Z90STAT_QDEPTH_MASK, Z90STAT_PERDEV_REQCNT,
+};
+
+static void z90_unregister_ioctl32s(void)
+{
+       int i;
+
+       unregister_ioctl32_conversion(ICARSAMODEXPO);
+       unregister_ioctl32_conversion(ICARSACRT);
+
+       for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++)
+               unregister_ioctl32_conversion(compatible_ioctls[i]);
+}
+
+static int z90_register_ioctl32s(void)
+{
+       int result, i;
+
+       result = register_ioctl32_conversion(ICARSAMODEXPO, trans_modexpo32);
+       if (result)
+               return result;
+       result = register_ioctl32_conversion(ICARSACRT, trans_modexpo_crt32);
+       if (result)
+               return result;
+
+       for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) {
+               result = register_ioctl32_conversion(compatible_ioctls[i],NULL);
+               if (result) {
+                       z90_unregister_ioctl32s();
+                       return result;
+               }
+       }
+       return result;
+}
+#else // !CONFIG_COMPAT
+static inline void z90_unregister_ioctl32s(void)
+{
+}
+
+static inline int z90_register_ioctl32s(void)
+{
+       return 0;
+}
+#endif
+
 /**
  * The module initialization code.
  */
@@ -499,6 +646,8 @@ z90crypt_init_module(void)
                PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
                        z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
                        __DATE__, __TIME__);
+               PRINTKN("%s\n", z90cmain_version);
+               PRINTKN("%s\n", z90chardware_version);
                PDEBUG("create_z90crypt (domain index %d) successful.\n",
                       domain);
        } else
@@ -557,9 +706,14 @@ z90crypt_init_module(void)
        reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
        add_timer(&reader_timer);
 
+       if ((result = z90_register_ioctl32s()))
+               goto init_module_cleanup;
+
        return 0; // success
 
 init_module_cleanup:
+       z90_unregister_ioctl32s();
+
 #ifndef Z90CRYPT_USE_HOTPLUG
        if ((nresult = misc_deregister(&z90crypt_misc_device)))
                PRINTK("misc_deregister failed with %d.\n", nresult);
@@ -585,6 +739,8 @@ z90crypt_cleanup_module(void)
 
        PDEBUG("PID %d\n", PID());
 
+       z90_unregister_ioctl32s();
+
        remove_proc_entry("driver/z90crypt", 0);
 
 #ifndef Z90CRYPT_USE_HOTPLUG
@@ -608,6 +764,8 @@ z90crypt_cleanup_module(void)
        del_timer(&cleanup_timer);
 
        destroy_z90crypt();
+
+       PRINTKN("Unloaded.\n");
 }
 
 /**
@@ -642,8 +800,10 @@ z90crypt_open(struct inode *inode, struct file *filp)
                return -EQUIESCE;
 
        private_data_p = kmalloc(sizeof(struct priv_data), GFP_KERNEL);
-       if (!private_data_p)
+       if (!private_data_p) {
+               PRINTK("Memory allocate failed\n");
                return -ENOMEM;
+       }
 
        memset((void *)private_data_p, 0, sizeof(struct priv_data));
        private_data_p->status = STAT_OPEN;
@@ -713,8 +873,10 @@ z90crypt_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
        if (count == 0)
                return 0;
        temp_buff = kmalloc(RESPBUFFSIZE, GFP_KERNEL);
-       if (!temp_buff)
+       if (!temp_buff) {
+               PRINTK("Memory allocate failed\n");
                return -ENOMEM;
+       }
        get_random_bytes(temp_buff, count);
 
        if (copy_to_user(buf, temp_buff, count) != 0) {
@@ -974,29 +1136,27 @@ select_device(int *dev_type_p, int *device_nr_p)
 }
 
 static inline int
-send_to_crypto_device(unsigned char *psmid, int func, int buff_len,
-                     unsigned char *buff_ptr, int devType,
-                     int *devNr_p, unsigned char *reqBuff)
+send_to_crypto_device(struct work_element *we_p)
 {
        struct caller *caller_p;
        struct device *device_p;
        int dev_nr;
 
-       if (!reqBuff)
+       if (!we_p->requestptr)
                return SEN_FATAL_ERROR;
-       caller_p = (struct caller *)reqBuff;
-       dev_nr = *devNr_p;
-       if (select_device(&devType, &dev_nr) == -1) {
+       caller_p = (struct caller *)we_p->requestptr;
+       dev_nr = we_p->devindex;
+       if (select_device(&we_p->devtype, &dev_nr) == -1) {
                if (z90crypt.hdware_info->hdware_mask.st_count != 0)
                        return SEN_RETRY;
                else
                        return SEN_NOT_AVAIL;
        }
-       *devNr_p = dev_nr;
+       we_p->devindex = dev_nr;
        device_p = z90crypt.device_p[dev_nr];
        if (!device_p)
                return SEN_NOT_AVAIL;
-       if (device_p->dev_type != devType)
+       if (device_p->dev_type != we_p->devtype)
                return SEN_RETRY;
        if (device_p->dev_caller_count >= device_p->dev_q_depth)
                return SEN_QUEUE_FULL;
@@ -1048,9 +1208,7 @@ z90crypt_send(struct work_element *we_p, const char *buf)
        }
        we_p->devindex = -1; // Reset device number
        spin_lock_irq(&queuespinlock);
-       rv = send_to_crypto_device(we_p->caller_id, we_p->funccode,
-                                  we_p->buff_size, we_p->buffer, we_p->devtype,
-                                  &we_p->devindex, we_p->requestptr);
+       rv = send_to_crypto_device(we_p);
        switch (rv) {
        case 0:
                we_p->requestsent = jiffies;
@@ -1196,27 +1354,34 @@ is_PKCS12_padded(unsigned char *buffer, int length)
  * function is PCI_FUNC_KEY_ENCRYPT or PCI_FUNC_KEY_DECRYPT
  */
 static inline int
-build_caller(char *psmid, int func, short function, int buff_len,
-            char *buff_ptr, int dev_type, struct caller *caller_p)
+build_caller(struct work_element *we_p, short function)
 {
        int rv;
+       struct caller *caller_p = (struct caller *)we_p->requestptr;
 
-       if ((dev_type != PCICC) && (dev_type != PCICA) && (dev_type != PCIXCC))
+       if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
+           (we_p->devtype != PCIXCC))
                return SEN_NOT_AVAIL;
 
-       memcpy(caller_p->caller_id, psmid, sizeof(caller_p->caller_id));
+       memcpy(caller_p->caller_id, we_p->caller_id,
+              sizeof(caller_p->caller_id));
        caller_p->caller_dev_dep_req_p = caller_p->caller_dev_dep_req;
        caller_p->caller_dev_dep_req_l = MAX_RESPONSE_SIZE;
-       caller_p->caller_buf_p = buff_ptr;
+       caller_p->caller_buf_p = we_p->buffer;
        INIT_LIST_HEAD(&(caller_p->caller_liste));
 
-       rv = convert_request(buff_ptr, func, function, z90crypt.cdx, dev_type,
+       rv = convert_request(we_p->buffer, we_p->funccode, function,
+                            z90crypt.cdx, we_p->devtype,
                             &caller_p->caller_dev_dep_req_l,
                             caller_p->caller_dev_dep_req_p);
-       if (rv)
-               PRINTK("Error from convert_request: %d\n", rv);
+       if (rv) {
+               if (rv == SEN_NOT_AVAIL)
+                       PDEBUG("request can't be processed on hdwr avail\n");
+               else
+                       PRINTK("Error from convert_request: %d\n", rv);
+       }
        else
-               memcpy(&(caller_p->caller_dev_dep_req_p[4]), psmid, 8);
+               memcpy(&(caller_p->caller_dev_dep_req_p[4]), we_p->caller_id,8);
        return rv;
 }
 
@@ -1235,9 +1400,7 @@ unbuild_caller(struct device *device_p, struct caller *caller_p)
 }
 
 static inline int
-get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
-                         unsigned char *buff_ptr, int *dev_type_p,
-                         unsigned char *caller_p)
+get_crypto_request_buffer(struct work_element *we_p)
 {
        struct ica_rsa_modexpo *mex_p;
        struct ica_rsa_modexpo_crt *crt_p;
@@ -1245,39 +1408,29 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
        short function;
        int rv;
 
-       mex_p = (struct ica_rsa_modexpo *) buff_ptr;
-       crt_p = (struct ica_rsa_modexpo_crt *) buff_ptr;
+       mex_p = (struct ica_rsa_modexpo *) we_p->buffer;
+       crt_p = (struct ica_rsa_modexpo_crt *) we_p->buffer;
 
-       PDEBUG("device type input = %d\n", *dev_type_p);
+       PDEBUG("device type input = %d\n", we_p->devtype);
 
        if (z90crypt.terminating)
                return REC_NO_RESPONSE;
-
-       temp_buffer = kmalloc(256, GFP_KERNEL);
-       if (!temp_buffer) {
-               PRINTK("kmalloc for temp_buffer failed!\n");
-               return SEN_NOT_AVAIL;
-       }
-       if (memcmp(psmid, NULL_psmid, 8) == 0) {
+       if (memcmp(we_p->caller_id, NULL_psmid, 8) == 0) {
                PRINTK("psmid zeroes\n");
-               kfree(temp_buffer);
                return SEN_FATAL_ERROR;
        }
-       if (!buff_ptr) {
+       if (!we_p->buffer) {
                PRINTK("buffer pointer NULL\n");
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
-       if (!caller_p) {
+       if (!we_p->requestptr) {
                PRINTK("caller pointer NULL\n");
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
 
-       if ((*dev_type_p != PCICA) && (*dev_type_p != PCICC) &&
-           (*dev_type_p != PCIXCC) && (*dev_type_p != ANYDEV)) {
+       if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
+           (we_p->devtype != PCIXCC) && (we_p->devtype != ANYDEV)) {
                PRINTK("invalid device type\n");
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
 
@@ -1285,21 +1438,18 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
            (mex_p->inputdatalength > MAX_MOD_SIZE)) {
                PRINTK("inputdatalength[%d] is not valid\n",
                       mex_p->inputdatalength);
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
 
        if (mex_p->outputdatalength < mex_p->inputdatalength) {
                PRINTK("outputdatalength[%d] < inputdatalength[%d]\n",
                       mex_p->outputdatalength, mex_p->inputdatalength);
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
 
        if (!mex_p->inputdata || !mex_p->outputdata) {
                PRINTK("inputdata[%p] or outputdata[%p] is NULL\n",
                       mex_p->outputdata, mex_p->inputdata);
-               kfree(temp_buffer);
                return SEN_USER_ERROR;
        }
 
@@ -1311,7 +1461,7 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
        mex_p->outputdatalength = mex_p->inputdatalength;
 
        rv = 0;
-       switch (func) {
+       switch (we_p->funccode) {
        case ICARSAMODEXPO:
                if (!mex_p->b_key || !mex_p->n_modulus)
                        rv = SEN_USER_ERROR;
@@ -1336,28 +1486,24 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
                }
                break;
        default:
-               PRINTK("bad func = %d\n", func);
+               PRINTK("bad func = %d\n", we_p->funccode);
                rv = SEN_USER_ERROR;
                break;
        }
-       if (rv != 0) {
-               kfree(temp_buffer);
+       if (rv != 0)
                return rv;
-       }
 
-       if (select_device_type(dev_type_p) < 0) {
-               kfree(temp_buffer);
+       if (select_device_type(&we_p->devtype) < 0)
                return SEN_NOT_AVAIL;
-       }
 
+       temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
+                     sizeof(struct caller);
        if (copy_from_user(temp_buffer, mex_p->inputdata,
-                          mex_p->inputdatalength) != 0) {
-               kfree(temp_buffer);
+                          mex_p->inputdatalength) != 0)
                return SEN_RELEASED;
-       }
 
        function = PCI_FUNC_KEY_ENCRYPT;
-       switch (*dev_type_p) {
+       switch (we_p->devtype) {
        /* PCICA does everything with a simple RSA mod-expo operation */
        case PCICA:
                function = PCI_FUNC_KEY_ENCRYPT;
@@ -1368,11 +1514,9 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
         */
        case PCIXCC:
                /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
-               if (mex_p->inputdatalength < MIN_MOD_SIZE) {
-                       kfree(temp_buffer);
+               if (mex_p->inputdatalength < MIN_MOD_SIZE)
                        return SEN_NOT_AVAIL;
-               }
-               if (func == ICARSAMODEXPO)
+               if (we_p->funccode == ICARSAMODEXPO)
                        function = PCI_FUNC_KEY_ENCRYPT;
                else
                        function = PCI_FUNC_KEY_DECRYPT;
@@ -1383,20 +1527,17 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
        case PCICC:
                /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
                if (mex_p->inputdatalength < MIN_MOD_SIZE) {
-                       kfree(temp_buffer);
                        return SEN_NOT_AVAIL;
                }
                /* Anythings over MAX_PCICC_MOD_SIZE MUST go to a PCICA */
                if (mex_p->inputdatalength > MAX_PCICC_MOD_SIZE) {
-                       kfree(temp_buffer);
                        return SEN_NOT_AVAIL;
                }
                /* PCICC cannot handle input that is is PKCS#1.1 padded */
                if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
-                       kfree(temp_buffer);
                        return SEN_NOT_AVAIL;
                }
-               if (func == ICARSAMODEXPO) {
+               if (we_p->funccode == ICARSAMODEXPO) {
                        if (is_PKCS12_padded(temp_buffer,
                                             mex_p->inputdatalength))
                                function = PCI_FUNC_KEY_ENCRYPT;
@@ -1408,10 +1549,8 @@ get_crypto_request_buffer(unsigned char *psmid, int func, int buff_len,
                break;
        }
        PDEBUG("function: %04x\n", function);
-       rv = build_caller(psmid, func, function, buff_len, buff_ptr,
-                         *dev_type_p, (struct caller *)caller_p);
+       rv = build_caller(we_p, function);
        PDEBUG("rv from build_caller = %d\n", rv);
-       kfree(temp_buffer);
        return rv;
 }
 
@@ -1435,9 +1574,7 @@ z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
        we_p->funccode = funccode;
        we_p->devtype = -1;
        we_p->audit[0] |= FP_BUFFREQ;
-       rv = get_crypto_request_buffer(we_p->caller_id, we_p->funccode,
-                                      we_p->buff_size, we_p->buffer,
-                                      &we_p->devtype, we_p->requestptr);
+       rv = get_crypto_request_buffer(we_p);
        switch (rv) {
        case 0:
                we_p->audit[0] |= FP_BUFFGOT;
@@ -1455,6 +1592,8 @@ z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
                rv = -ENODEV;
                break;
        case SEN_NOT_AVAIL:
+               rv = -EGETBUFF;
+               break;
        default:
                PRINTK("rv = %d\n", rv);
                rv = -EGETBUFF;
@@ -1496,16 +1635,14 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
             unsigned int cmd, unsigned long arg)
 {
        struct work_element *we_p;
-       int keep_work_element;
        int rv;
 
-       if ((rv = allocate_work_element(&we_p, private_data_p, pid)))
-               return rv;
-       if ((rv = z90crypt_prepare(we_p, cmd, (const char *)arg))) {
-               PDEBUG("PID %d: rv = %d from z90crypt_prepare\n",
-                      pid, rv);
+       if ((rv = allocate_work_element(&we_p, private_data_p, pid))) {
+               PDEBUG("PID %d: allocate_work_element returned ENOMEM\n", pid);
                return rv;
        }
+       if ((rv = z90crypt_prepare(we_p, cmd, (const char *)arg)))
+               PDEBUG("PID %d: rv = %d from z90crypt_prepare\n", pid, rv);
        if (!rv)
                if ((rv = z90crypt_send(we_p, (const char *)arg)))
                        PDEBUG("PID %d: rv %d from z90crypt_send.\n", pid, rv);
@@ -1518,7 +1655,6 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
        if (!rv)
                rv = z90crypt_process_results(we_p, (char *)arg);
 
-       keep_work_element = 0;
        if ((we_p->status[0] & STAT_FAILED)) {
                switch (rv) {
                /**
@@ -1544,9 +1680,6 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
                        case STAT_WRITTEN:
                                purge_work_element(we_p);
                                break;
-                       case STAT_QUEUED:
-                               keep_work_element = 1;
-                               break;
                        case STAT_READPEND:
                        case STAT_NOWORK:
                        default:
@@ -1558,8 +1691,7 @@ z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
                        break;
                }
        }
-       if (!keep_work_element)
-               free_page((long)we_p);
+       free_page((long)we_p);
        return rv;
 }
 
@@ -1577,6 +1709,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
        unsigned int *reqcnt;
        struct ica_z90_status *pstat;
        int ret, i, loopLim, tempstat;
+       static int deprecated_msg_count = 0;
 
        PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
        PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
@@ -1612,55 +1745,55 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                if (ret == -ERESTARTSYS)
                        ret = -ENODEV;
                break;
-               
+
        case Z90STAT_TOTALCOUNT:
                tempstat = get_status_totalcount();
                if (copy_to_user((int *)arg, &tempstat,sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_PCICACOUNT:
                tempstat = get_status_PCICAcount();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_PCICCCOUNT:
                tempstat = get_status_PCICCcount();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_PCIXCCCOUNT:
                tempstat = get_status_PCIXCCcount();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_REQUESTQ_COUNT:
                tempstat = get_status_requestq_count();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_PENDINGQ_COUNT:
                tempstat = get_status_pendingq_count();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_TOTALOPEN_COUNT:
                tempstat = get_status_totalopen_count();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_DOMAIN_INDEX:
                tempstat = get_status_domain_index();
                if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
                        ret = -EFAULT;
                break;
-               
+
        case Z90STAT_STATUS_MASK:
                status = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
                if (!status) {
@@ -1673,7 +1806,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                        ret = -EFAULT;
                kfree(status);
                break;
-               
+
        case Z90STAT_QDEPTH_MASK:
                qdepth = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
                if (!qdepth) {
@@ -1686,7 +1819,7 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                        ret = -EFAULT;
                kfree(qdepth);
                break;
-               
+
        case Z90STAT_PERDEV_REQCNT:
                reqcnt = kmalloc(sizeof(int) * Z90CRYPT_NUM_APS, GFP_KERNEL);
                if (!reqcnt) {
@@ -1700,18 +1833,24 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                        ret = -EFAULT;
                kfree(reqcnt);
                break;
-               
+
                /* THIS IS DEPRECATED.  USE THE NEW STATUS CALLS */
        case ICAZ90STATUS:
-               PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
-               
+               if (deprecated_msg_count < 100) {
+                       PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
+                       deprecated_msg_count++;
+                       if (deprecated_msg_count == 100)
+                               PRINTK("No longer issuing messages related to "
+                                      "deprecated call to ICAZ90STATUS.\n");
+               }
+
                pstat = kmalloc(sizeof(struct ica_z90_status), GFP_KERNEL);
                if (!pstat) {
                        PRINTK("kmalloc for pstat failed!\n");
                        ret = -ENOMEM;
                        break;
                }
-               
+
                pstat->totalcount        = get_status_totalcount();
                pstat->leedslitecount    = get_status_PCICAcount();
                pstat->leeds2count       = get_status_PCICCcount();
@@ -1721,13 +1860,13 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                pstat->cryptoDomain      = get_status_domain_index();
                get_status_status_mask(pstat->status);
                get_status_qdepth_mask(pstat->qdepth);
-               
+
                if (copy_to_user((struct ica_z90_status *) arg, pstat,
                                 sizeof(struct ica_z90_status)) != 0)
                        ret = -EFAULT;
                kfree(pstat);
                break;
-               
+
        case Z90QUIESCE:
                if (current->euid != 0) {
                        PRINTK("QUIESCE fails: euid %d\n",
@@ -1738,14 +1877,14 @@ z90crypt_ioctl(struct inode *inode, struct file *filp,
                        quiesce_z90crypt = 1;
                }
                break;
-               
+
        default:
                /* user passed an invalid IOCTL number */
                PDEBUG("cmd 0x%08X contains invalid ioctl code\n", cmd);
                ret = -ENOTTY;
                break;
        }
-       
+
        return ret;
 }
 
@@ -2130,10 +2269,12 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                        rv = REC_NO_RESPONSE;
                        break;
                }
-               if (dev_ptr->dev_caller_count <= 0)
-                       rv = REC_USER_GONE;
                if (rv)
                        break;
+               if (dev_ptr->dev_caller_count <= 0) {
+                       rv = REC_USER_GONE;
+                       break;
+               }
 
                list_for_each_safe(ptr, tptr, &dev_ptr->dev_caller_list) {
                        caller_p = list_entry(ptr, struct caller, caller_liste);
@@ -2154,7 +2295,7 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                }
 
                PDEBUG("caller_p after successful receive: %p\n", caller_p);
-               rv = convert_response(dev_ptr->dev_resp_p, dev_ptr->dev_type,
+               rv = convert_response(dev_ptr->dev_resp_p,
                                      caller_p->caller_buf_p, buff_len_p, buff);
                switch (rv) {
                case REC_OPERAND_INV:
@@ -2189,7 +2330,7 @@ receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
                remove_device(dev_ptr);
                break;
        }
-       
+
        if (caller_p)
                unbuild_caller(dev_ptr, caller_p);
 
@@ -2210,13 +2351,7 @@ helper_send_work(int index)
        rq_p->audit[1] |= FP_REMREQUEST;
        if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
                rq_p->devindex = SHRT2LONG(index);
-               rv = send_to_crypto_device(rq_p->caller_id,
-                                          rq_p->funccode,
-                                          rq_p->buff_size,
-                                          rq_p->buffer,
-                                          rq_p->devtype,
-                                          &rq_p->devindex,
-                                          rq_p->requestptr);
+               rv = send_to_crypto_device(rq_p);
                if (rv == 0) {
                        rq_p->requestsent = jiffies;
                        rq_p->audit[0] |= FP_SENT;
@@ -2333,18 +2468,18 @@ helper_receive_rc(int index, int *rc_p, int *workavail_p)
        case REC_EVEN_MOD:
        case REC_INVALID_PAD:
                return 1;
-               
+
        case REC_BUSY:
        case REC_NO_WORK:
        case REC_EMPTY:
        case REC_RETRY_DEV:
        case REC_FATAL_ERROR:
                break;
-               
+
        case REC_NO_RESPONSE:
                *workavail_p = 0;
                break;
-               
+
        default:
                PRINTK("rc %d, device %d\n", *rc_p, SHRT2LONG(index));
                *rc_p = REC_NO_RESPONSE;
@@ -2433,7 +2568,7 @@ z90crypt_schedule_config_task(unsigned int expiration)
                PRINTK("Timer pending while modifying config timer\n");
 }
 
-static void 
+static void
 z90crypt_config_task(unsigned long ptr)
 {
        int rc;
@@ -2604,9 +2739,9 @@ helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
        q_depth = dev_type = k = 0;
        for (i = 0; i < z90crypt.max_count; i++) {
                hd_stat = HD_NOT_THERE;
-               for (j = 0; j < 15; cdx_array[j++] = -1);
+               for (j = 0; j <= 15; cdx_array[j++] = -1);
                k = 0;
-               for (j = 0; j < 15; j++) {
+               for (j = 0; j <= 15; j++) {
                        hd_stat = query_online(i, j, MAX_RESET,
                                               &q_depth, &dev_type);
                        if (hd_stat == HD_TSQ_EXCEPTION) {
@@ -2854,6 +2989,8 @@ create_crypto_device(int index)
                if (dev_ptr->dev_type == NILDEV) {
                        rv = probe_device_type(dev_ptr);
                        if (rv) {
+                               PRINTK("rv = %d from probe_device_type %d\n",
+                                      rv, index);
                                kfree(dev_ptr->dev_resp_p);
                                kfree(dev_ptr);
                                return rv;
@@ -2977,26 +3114,16 @@ static int
 probe_device_type(struct device *devPtr)
 {
        int rv, dv, i, index, length;
-       unsigned char psmid[8], *dyn_testmsg;
-
-       dyn_testmsg = kmalloc(384, GFP_KERNEL);
-       if (!dyn_testmsg) {
-               PRINTK("kmalloc for dyn_testmsg failed in probe_device_type\n");
-               /**
-                * Strange to return 0, but it will work. Since we didn't
-                * update the device type, the next time around, we will
-                * reprobe and hopefully have enough memory.
-                */
-               return 0;
-       }
+       unsigned char psmid[8];
+       static unsigned char loc_testmsg[384];
 
        index = devPtr->dev_self_x;
        rv = 0;
        do {
-               memcpy(dyn_testmsg, static_testmsg, sizeof(static_testmsg));
+               memcpy(loc_testmsg, static_testmsg, sizeof(static_testmsg));
                length = sizeof(static_testmsg) - 24;
                /* the -24 allows for the header */
-               dv = send_to_AP(index, z90crypt.cdx, length, dyn_testmsg);
+               dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
                if (dv) {
                        PDEBUG("dv returned by send during probe: %d\n", dv);
                        if (dv == DEV_SEN_EXCEPTION) {
@@ -3024,8 +3151,10 @@ probe_device_type(struct device *devPtr)
                                break;
                        case DEV_QUEUE_FULL:
                                rv = SEN_QUEUE_FULL;
-                                       break;
+                               break;
                        default:
+                               PRINTK("unknown dv=%d for dev %d\n", dv, index);
+                               rv = SEN_NOT_AVAIL;
                                break;
                        }
                }
@@ -3069,16 +3198,14 @@ probe_device_type(struct device *devPtr)
                if (rv)
                        break;
                rv = (devPtr->dev_resp_p[0] == 0x00) &&
-                    (devPtr->dev_resp_p[0] == 0x86);
-               if (rv) {
+                    (devPtr->dev_resp_p[1] == 0x86);
+               if (rv)
                        devPtr->dev_type = PCICC;
-                       break;
-               }
-               devPtr->dev_type = PCICA;
+               else
+                       devPtr->dev_type = PCICA;
                rv = 0;
        } while (0);
        /* In a general error case, the card is not marked online */
-       kfree(dyn_testmsg);
        return rv;
 }
 
index ab38a06..7899560 100644 (file)
@@ -63,7 +63,7 @@ config QETH
          <http://www10.software.ibm.com/developerworks/opensource/linux390>
 
          To compile this driver as a module, choose M here: the
-         module will be called qeth.
+         module will be called qeth.ko.
 
 
 comment "Gigabit Ethernet default settings"
index e2fbc36..8befcd6 100644 (file)
@@ -9,6 +9,6 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
 obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
 obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
 obj-$(CONFIG_LCS) += lcs.o cu3088.o
-qeth_mod-objs := qeth.o qeth_mpc.o
-obj-$(CONFIG_QETH) += qeth_mod.o
-
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o
+qeth-$(CONFIG_PROC_FS) += qeth_proc.o
+obj-$(CONFIG_QETH) += qeth.o
index e9d81d4..1120f79 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.16 2004/02/05 12:39:55 felfert Exp $
+ * $Id: ctctty.c,v 1.17 2004/03/31 17:06:34 ptiedem Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -1232,7 +1232,7 @@ ctc_tty_cleanup(void) {
        ctc_tty_shuttingdown = 1;
        spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
        tty_unregister_driver(driver->ctc_tty_device);
-       kfree(driver);
        put_tty_driver(driver->ctc_tty_device);
+       kfree(driver);
        driver = NULL;
 }
index dc23d1d..26514ac 100644 (file)
@@ -11,7 +11,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.72 $         $Date: 2004/03/22 09:34:27 $
+ *    $Revision: 1.74 $         $Date: 2004/04/05 00:01:04 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -58,7 +58,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.72 $"
+#define VERSION_LCS_C  "$Revision: 1.74 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 static char debug_buffer[255];
@@ -206,6 +206,9 @@ lcs_alloc_card(void)
                return NULL;
        }
 
+#ifdef CONFIG_IP_MULTICAST
+       INIT_LIST_HEAD(&card->ipm_list);
+#endif
        LCS_DBF_HEX(2, setup, &card, sizeof(void*));
        return card;
 }
@@ -1967,7 +1970,8 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
        if (ccwgdev->state == CCWGROUP_ONLINE) {
                lcs_shutdown_device(ccwgdev);
        }
-       unregister_netdev(card->dev);
+       if (card->dev)
+               unregister_netdev(card->dev);
        sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);
        lcs_cleanup_card(card);
        lcs_free_card(card);
index fbad9a6..fb30461 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.47 2004/03/22 07:41:42 braunu Exp $
+ * $Id: netiucv.c,v 1.48 2004/04/01 13:42:09 braunu Exp $
  *
  * IUCV network driver
  *
@@ -30,7 +30,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.47 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.48 $
  *
  */
 \f
@@ -100,7 +100,6 @@ struct iucv_connection {
        int                       max_buffsize;
        int                       flags;
        fsm_timer                 timer;
-       int                       retry;
        fsm_instance              *fsm;
        struct net_device         *netdev;
        struct connection_profile prof;
@@ -169,8 +168,6 @@ static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
        return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy);
 }
 
-#define SET_DEVICE_START(device, value)
-
 static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 static __u8 iucvMagic[16] = {
        0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
@@ -217,7 +214,6 @@ enum dev_states {
        DEV_STATE_STARTWAIT,
        DEV_STATE_STOPWAIT,
        DEV_STATE_RUNNING,
-       DEV_STATE_STARTRETRY,
        /**
         * MUST be always the last element!!
         */
@@ -229,7 +225,6 @@ static const char *dev_state_names[] = {
        "StartWait",
        "StopWait",
        "Running",
-       "StartRetry",
 };
 
 /**
@@ -599,7 +594,6 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
 
        pr_debug("%s() called\n", __FUNCTION__);
 
-       fsm_deltimer(&conn->timer);
        if (conn && conn->netdev && conn->netdev->priv)
                privptr = (struct netiucv_priv *)conn->netdev->priv;
        conn->prof.tx_pending--;
@@ -639,8 +633,6 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
                memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
                       NETIUCV_HDRLEN);
 
-               fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
-                            CONN_EVENT_TIMER, conn);
                conn->prof.send_stamp = xtime;
                rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0,
                               conn->tx_buff->data, conn->tx_buff->len);
@@ -650,7 +642,6 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
                if (conn->prof.tx_pending > conn->prof.tx_max_pending)
                        conn->prof.tx_max_pending = conn->prof.tx_pending;
                if (rc != 0) {
-                       fsm_deltimer(&conn->timer);
                        conn->prof.tx_pending--;
                        fsm_newstate(fi, CONN_STATE_IDLE);
                        if (privptr)
@@ -721,6 +712,7 @@ conn_action_connack(fsm_instance *fi, int event, void *arg)
 
        pr_debug("%s() called\n", __FUNCTION__);
 
+       fsm_deltimer(&conn->timer);
        fsm_newstate(fi, CONN_STATE_IDLE);
        conn->pathid = eib->ippathid;
        netdev->tx_queue_len = eib->ipmsglim;
@@ -728,35 +720,35 @@ conn_action_connack(fsm_instance *fi, int event, void *arg)
 }
 
 static void
+conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
+{
+       struct iucv_connection *conn = (struct iucv_connection *)arg;
+       __u8 udata[16];
+
+       pr_debug("%s() called\n", __FUNCTION__);
+
+       fsm_deltimer(&conn->timer);
+       iucv_sever(conn->pathid, udata);
+       fsm_newstate(fi, CONN_STATE_STARTWAIT);
+}
+
+static void
 conn_action_connsever(fsm_instance *fi, int event, void *arg)
 {
        struct iucv_event *ev = (struct iucv_event *)arg;
        struct iucv_connection *conn = ev->conn;
-       // iucv_ConnectionSevered *eib = (iucv_ConnectionSevered *)ev->data;
        struct net_device *netdev = conn->netdev;
        struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv;
-       int state = fsm_getstate(fi);
+       __u8 udata[16];
 
        pr_debug("%s() called\n", __FUNCTION__);
 
-       switch (state) {
-               case CONN_STATE_SETUPWAIT:
-                       printk(KERN_INFO "%s: Remote dropped connection\n",
-                              netdev->name);
-                       fsm_newstate(fi, CONN_STATE_STOPPED);
-                       fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
-                       break;
-               case CONN_STATE_IDLE:
-               case CONN_STATE_TX:
-                       printk(KERN_INFO "%s: Remote dropped connection\n",
-                              netdev->name);
-                       if (conn->handle)
-                               iucv_unregister_program(conn->handle);
-                       conn->handle = 0;
-                       fsm_newstate(fi, CONN_STATE_STOPPED);
-                       fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
-                       break;
-       }
+       fsm_deltimer(&conn->timer);
+       iucv_sever(conn->pathid, udata);
+       printk(KERN_INFO "%s: Remote dropped connection\n",
+              netdev->name);
+       fsm_newstate(fi, CONN_STATE_STARTWAIT);
+       fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
 }
 
 static void
@@ -798,6 +790,8 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
        switch (rc) {
                case 0:
                        conn->netdev->tx_queue_len = msglimit;
+                       fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
+                               CONN_EVENT_TIMER, conn);
                        return;
                case 11:
                        printk(KERN_NOTICE
@@ -864,6 +858,7 @@ conn_action_stop(fsm_instance *fi, int event, void *arg)
 
        pr_debug("%s() called\n", __FUNCTION__);
 
+       fsm_deltimer(&conn->timer);
        fsm_newstate(fi, CONN_STATE_STOPPED);
        netiucv_purge_skb_queue(&conn->collect_queue);
        if (conn->handle)
@@ -888,7 +883,6 @@ conn_action_inval(fsm_instance *fi, int event, void *arg)
 static const fsm_node conn_fsm[] = {
        { CONN_STATE_INVALID,   CONN_EVENT_START,    conn_action_inval      },
        { CONN_STATE_STOPPED,   CONN_EVENT_START,    conn_action_start      },
-       { CONN_STATE_STARTWAIT, CONN_EVENT_START,    conn_action_start      },
 
        { CONN_STATE_STOPPED,   CONN_EVENT_STOP,     conn_action_stop       },
        { CONN_STATE_STARTWAIT, CONN_EVENT_STOP,     conn_action_stop       },
@@ -905,6 +899,7 @@ static const fsm_node conn_fsm[] = {
        { CONN_STATE_TX,        CONN_EVENT_CONN_REQ, conn_action_connreject },
 
        { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_ACK, conn_action_connack    },
+       { CONN_STATE_SETUPWAIT, CONN_EVENT_TIMER,    conn_action_conntimsev },
 
        { CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REJ, conn_action_connsever  },
        { CONN_STATE_IDLE,      CONN_EVENT_CONN_REJ, conn_action_connsever  },
@@ -940,7 +935,6 @@ dev_action_start(fsm_instance *fi, int event, void *arg)
 
        pr_debug("%s() called\n", __FUNCTION__);
 
-       fsm_deltimer(&privptr->timer);
        ev.conn = privptr->conn;
        fsm_newstate(fi, DEV_STATE_STARTWAIT);
        fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
@@ -964,7 +958,6 @@ dev_action_stop(fsm_instance *fi, int event, void *arg)
 
        ev.conn = privptr->conn;
 
-       fsm_deltimer(&privptr->timer);
        fsm_newstate(fi, DEV_STATE_STOPWAIT);
        fsm_event(privptr->conn->fsm, CONN_EVENT_STOP, &ev);
 }
@@ -981,13 +974,10 @@ static void
 dev_action_connup(fsm_instance *fi, int event, void *arg)
 {
        struct net_device   *dev = (struct net_device *)arg;
-       struct netiucv_priv *privptr = dev->priv;
 
        pr_debug("%s() called\n", __FUNCTION__);
 
        switch (fsm_getstate(fi)) {
-               case DEV_STATE_STARTRETRY:
-                       fsm_deltimer(&privptr->timer);
                case DEV_STATE_STARTWAIT:
                        fsm_newstate(fi, DEV_STATE_RUNNING);
                        printk(KERN_INFO
@@ -1013,22 +1003,11 @@ dev_action_connup(fsm_instance *fi, int event, void *arg)
 static void
 dev_action_conndown(fsm_instance *fi, int event, void *arg)
 {
-       struct net_device   *dev = (struct net_device *)arg;
-       struct netiucv_priv *privptr = dev->priv;
-       struct iucv_event   ev;
-
        pr_debug("%s() called\n", __FUNCTION__);
 
        switch (fsm_getstate(fi)) {
                case DEV_STATE_RUNNING:
                        fsm_newstate(fi, DEV_STATE_STARTWAIT);
-                       ev.conn = privptr->conn;
-                       fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev);
-                       break;
-               case DEV_STATE_STARTWAIT:
-                       fsm_addtimer(&privptr->timer, NETIUCV_TIMEOUT_5SEC,
-                                    DEV_EVENT_TIMER, dev);
-                       fsm_newstate(fi, DEV_STATE_STARTRETRY);
                        break;
                case DEV_STATE_STOPWAIT:
                        fsm_newstate(fi, DEV_STATE_STOPPED);
@@ -1044,11 +1023,6 @@ static const fsm_node dev_fsm[] = {
 
        { DEV_STATE_STARTWAIT,  DEV_EVENT_STOP,    dev_action_stop     },
        { DEV_STATE_STARTWAIT,  DEV_EVENT_CONUP,   dev_action_connup   },
-       { DEV_STATE_STARTWAIT,  DEV_EVENT_CONDOWN, dev_action_conndown },
-
-       { DEV_STATE_STARTRETRY, DEV_EVENT_TIMER,   dev_action_start    },
-       { DEV_STATE_STARTRETRY, DEV_EVENT_CONUP,   dev_action_connup   },
-       { DEV_STATE_STARTRETRY, DEV_EVENT_STOP,    dev_action_stop     },
 
        { DEV_STATE_RUNNING,    DEV_EVENT_STOP,    dev_action_stop     },
        { DEV_STATE_RUNNING,    DEV_EVENT_CONDOWN, dev_action_conndown },
@@ -1119,10 +1093,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
                header.next = 0;
                memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header,  NETIUCV_HDRLEN);
 
-               conn->retry = 0;
                fsm_newstate(conn->fsm, CONN_STATE_TX);
-               fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
-                            CONN_EVENT_TIMER, conn);
                conn->prof.send_stamp = xtime;
                
                rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */,
@@ -1135,7 +1106,6 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
                        conn->prof.tx_max_pending = conn->prof.tx_pending;
                if (rc != 0) {
                        struct netiucv_priv *privptr;
-                       fsm_deltimer(&conn->timer);
                        fsm_newstate(conn->fsm, CONN_STATE_IDLE);
                        conn->prof.tx_pending--;
                        privptr = (struct netiucv_priv *)conn->netdev->priv;
@@ -1178,7 +1148,6 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
  */
 static int
 netiucv_open(struct net_device *dev) {
-       SET_DEVICE_START(dev, 1);
        fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START, dev);
        return 0;
 }
@@ -1193,7 +1162,6 @@ netiucv_open(struct net_device *dev) {
  */
 static int
 netiucv_close(struct net_device *dev) {
-       SET_DEVICE_START(dev, 0);
        fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev);
        return 0;
 }
@@ -1912,7 +1880,7 @@ static struct device_driver netiucv_driver = {
 static void
 netiucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.47 $";
+       char vbuf[] = "$Revision: 1.48 $";
        char *version = vbuf;
 
        if ((version = strchr(version, ':'))) {
diff --git a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c
deleted file mode 100644 (file)
index ebef0a9..0000000
+++ /dev/null
@@ -1,10872 +0,0 @@
-/*
- *
- * linux/drivers/s390/net/qeth.c ($Revision: 1.177 $)
- *
- * Linux on zSeries OSA Express and HiperSockets support
- *
- * Copyright 2000,2003 IBM Corporation
- *
- * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
- *            Cornelia Huck <cohuck@de.ibm.com> (2.5 integration,
- *                                               numerous bugfixes)
- *            Frank Pavlic <pavlic@de.ibm.com>  (query/purge ARP, SNMP, fixes)
- *            Andreas Herrmann <aherrman@de.ibm.com> (bugfixes)
- *            Thomas Spatzier <tspat@de.ibm.com> (bugfixes)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * The driver supports in general all QDIO driven network devices on the
- * Hydra card.
- *
- * For all devices, three channels must be available to the driver. One
- * channel is the read channel, one is the write channel and the third
- * one is the channel used to control QDIO.
- *
- * There are several stages from the channel recognition to the running
- * network device:
- * - The channels are scanned and ordered due to the parameters (see
- *   MODULE_PARM_DESC)
- * - The card is hardsetup: this means, that the communication channels
- *   are prepared
- * - The card is softsetup: this means, that commands are issued
- *   to activate the network parameters
- * - After that, data can flow through the card (transported by QDIO)
- *
- *IPA Takeover:
- * /proc/qeth_ipa_takeover provides the possibility to add and remove
- * certain ranges of IP addresses to the driver. As soon as these
- * addresses have to be set by the driver, the driver uses the OSA
- * Address Takeover mechanism.
- * reading out of the proc-file displays the registered addresses;
- * writing into it changes the information. Only one command at one
- * time must be written into the file. Subsequent commands are ignored.
- * The following commands are available:
- * inv4
- * inv6
- * add4 <ADDR>/<mask bits>[:<interface>]
- * add6 <ADDR>/<mask bits>[:<interface>]
- * del4 <ADDR>/<mask bits>[:<interface>]
- * del6 <ADDR>/<mask bits>[:<interface>]
- * inv4 and inv6 toggle the IPA takeover behaviour for all interfaces:
- * when inv4 was input once, all addresses specified with add4 are not
- * set using the takeover mechanism, but all other IPv4 addresses are set so.
- *
- * add# adds an address range, del# deletes an address range. # corresponds
- * to the IP version (4 or 6).
- * <ADDR> is a 8 or 32byte hexadecimal view of the IP address.
- * <mask bits> specifies the number of bits which are set in the network mask.
- * <interface> is optional and specifies the interface name to which the
- * address range is bound.
- * E. g.
- *   add4 C0a80100/24
- * activates all addresses in the 192.168.10 subnet for address takeover.
- * Note, that the address is not taken over before an according ifconfig
- * is executed.
- *
- *VIPA:
- * add_vipa4 <ADDR>:<interface>
- * add_vipa6 <ADDR>:<interface>
- * del_vipa4 <ADDR>:<interface>
- * del_vipa6 <ADDR>:<interface>
- *
- * the specified address is set/unset as VIPA on the specified interface.
- * use the src_vipa package to exploit this out of arbitrary applications.
- *
- *Proxy ARP:
- *
- * add_rxip4 <ADDR>:<interface>
- * add_rxip6 <ADDR>:<interface>
- * del_rxip4 <ADDR>:<interface>
- * del_rxip6 <ADDR>:<interface>
- *
- * the specified address is set/unset as "do not fail a gratuitous ARP"
- * on the specified interface. this can be used to act as a proxy ARP.
- */
-
-static void volatile
-qeth_eyecatcher(void)
-{
-       return;
-}
-
-#undef DEBUG
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/ebcdic.h>
-#include <linux/ctype.h>
-#include <asm/semaphore.h>
-#include <asm/timex.h>
-#include <linux/if.h>
-#include <linux/if_arp.h>
-#include <linux/ip.h>
-#include <linux/inetdevice.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/tcp.h>
-#include <linux/icmp.h>
-#include <linux/skbuff.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif /* CONFIG_PROC_FS */
-#include <net/route.h>
-#include <net/arp.h>
-#include <linux/in.h>
-#include <linux/igmp.h>
-#include <net/ip.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
-#include <net/ipv6.h>
-#include <linux/in6.h>
-#include <net/if_inet6.h>
-#include <net/addrconf.h>
-#include <linux/if_tr.h>
-#include <linux/trdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/reboot.h>
-
-#include <linux/if_vlan.h>
-
-#include <asm/ccwdev.h>
-#include <asm/ccwgroup.h>
-#include <asm/debug.h>
-
-#include "qeth_mpc.h"
-#include "qeth.h"
-
-/****************** MODULE PARAMETER VARIABLES ********************/
-static int qeth_sparebufs = 0;
-module_param(qeth_sparebufs, int, 0);
-MODULE_PARM_DESC(qeth_sparebufs, "the number of pre-allocated spare buffers "
-                "reserved for low memory situations");
-
-/****************** MODULE STUFF **********************************/
-#define VERSION_QETH_C "$Revision: 1.177 $"
-static const char *version = "qeth S/390 OSA-Express driver ("
-    VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H
-    QETH_VERSION_IPV6 QETH_VERSION_VLAN ")";
-
-MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
-MODULE_DESCRIPTION("Linux on zSeries OSA Express and HiperSockets support\n" \
-                  "Copyright 2000,2003 IBM Corporation\n");
-MODULE_LICENSE("GPL");
-
-/******************** HERE WE GO ***********************************/
-
-#define PROCFILE_SLEEP_SEM_MAX_VALUE 0
-#define PROCFILE_IOCTL_SEM_MAX_VALUE 3
-static struct semaphore qeth_procfile_ioctl_lock;
-static struct semaphore qeth_procfile_ioctl_sem;
-static struct qeth_card *firstcard = NULL;
-
-static struct sparebufs sparebufs[MAX_SPARE_BUFFERS];
-static int sparebuffer_count;
-
-static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
-
-static spinlock_t setup_lock = SPIN_LOCK_UNLOCKED;
-static rwlock_t list_lock = RW_LOCK_UNLOCKED;
-
-static debug_info_t *qeth_dbf_setup = NULL;
-static debug_info_t *qeth_dbf_data = NULL;
-static debug_info_t *qeth_dbf_misc = NULL;
-static debug_info_t *qeth_dbf_control = NULL;
-static debug_info_t *qeth_dbf_trace = NULL;
-static debug_info_t *qeth_dbf_sense = NULL;
-static debug_info_t *qeth_dbf_qerr = NULL;
-
-static int proc_file_registration;
-#ifdef QETH_PERFORMANCE_STATS
-static int proc_perf_file_registration;
-#define NOW qeth_get_micros()
-#endif /* QETH_PERFORMANCE_STATS */
-static int proc_ipato_file_registration;
-
-static int ipato_inv4 = 0, ipato_inv6 = 0;
-static struct ipato_entry *ipato_entries = NULL;
-static spinlock_t ipato_list_lock = SPIN_LOCK_UNLOCKED;
-
-struct tempinfo{
-       char *data;
-       int len;
-};
-
-/* thought I could get along without forward declarations...
- * just lazyness here */
-static int qeth_reinit_thread(void *);
-static inline void qeth_schedule_recovery(struct qeth_card *card);
-
-static inline int
-QETH_IP_VERSION(struct sk_buff *skb)
-{
-       switch (skb->protocol) {
-       case ETH_P_IPV6:
-               return 6;
-       case ETH_P_IP:
-               return 4;
-       default:
-               return 0;
-       }
-}
-
-/* not a macro, as one of the arguments is atomic_read */
-static inline int
-qeth_min(int a, int b)
-{
-       if (a < b)
-               return a;
-       else
-               return b;
-}
-
-static inline unsigned int
-qeth_get_millis(void)
-{
-       return (int) (get_clock() >> 22);   /* time>>12 is microseconds, we
-                                              divide it by 1024 */
-}
-
-#ifdef QETH_PERFORMANCE_STATS
-static inline unsigned int
-qeth_get_micros(void)
-{
-       return (int) (get_clock() >> 12);
-}
-#endif /* QETH_PERFORMANCE_STATS */
-
-static void
-qeth_delay_millis(unsigned long msecs)
-{
-       unsigned int start;
-
-       start = qeth_get_millis();
-       while (qeth_get_millis() - start < msecs) ;
-}
-
-static void
-qeth_wait_nonbusy(unsigned int timeout)
-{
-       unsigned int start;
-       char dbf_text[15];
-
-       sprintf(dbf_text, "wtnb%4x", timeout);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       start = qeth_get_millis();
-       for (;;) {
-               set_task_state(current, TASK_INTERRUPTIBLE);
-               if (qeth_get_millis() - start > timeout) {
-                       goto out;
-               }
-               schedule_timeout(((start + timeout -
-                                  qeth_get_millis()) >> 10) * HZ);
-       }
-out:
-       set_task_state(current, TASK_RUNNING);
-}
-
-static void
-qeth_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev)
-{
-       if (dev->type == ARPHRD_IEEE802_TR)
-               ip_tr_mc_map(ipm, mac);
-       else
-               ip_eth_mc_map(ipm, mac);
-}
-
-#define atomic_swap(a,b) xchg((int*)a.counter,b)
-
-static int inline
-my_spin_lock_nonbusy(struct qeth_card *card, spinlock_t * lock)
-{
-       for (;;) {
-               if (card) {
-                       if (atomic_read(&card->shutdown_phase))
-                               return -1;
-               }
-               if (spin_trylock(lock))
-                       return 0;
-               qeth_wait_nonbusy(QETH_IDLE_WAIT_TIME);
-       }
-}
-
-static int inline
-my_down_trylock_nonbusy(struct qeth_card *card, struct semaphore  *sema)
-{
-       for (;;) {
-               if (card) {
-                       if (atomic_read(&card->shutdown_phase))
-                               return -1;
-               }
-               if (down_trylock(sema))
-                       return 0;
-               qeth_wait_nonbusy(QETH_IDLE_WAIT_TIME);
-       }
-}
-
-
-#ifdef CONFIG_ARCH_S390X
-#define QETH_GET_ADDR(x) ((__u32)(unsigned long)x)
-#else /* CONFIG_ARCH_S390X */
-#define QETH_GET_ADDR(x) ((__u32)x)
-#endif /* CONFIG_ARCH_S390X */
-
-static int
-qeth_does_card_exist(struct qeth_card *card)
-{
-       struct qeth_card *c = firstcard;
-       int rc = 0;
-
-       read_lock(&list_lock);
-       while (c) {
-               if (c == card) {
-                       rc = 1;
-                       break;
-               }
-               c = c->next;
-       }
-       read_unlock(&list_lock);
-       return rc;
-}
-
-static int
-qeth_getxdigit(char c)
-{
-       if ((c >= '0') && (c <= '9'))
-               return c - '0';
-       if ((c >= 'a') && (c <= 'f'))
-               return c + 10 - 'a';
-       if ((c >= 'A') && (c <= 'F'))
-               return c + 10 - 'A';
-       return -1;
-}
-
-static struct qeth_card *
-qeth_get_card_by_name(char *name)
-{
-       struct qeth_card *card;
-
-       read_lock(&list_lock);
-       card = firstcard;
-       while (card) {
-               if (!strncmp(name, card->dev_name, DEV_NAME_LEN))
-                       break;
-               card = card->next;
-       }
-       read_unlock(&list_lock);
-
-       return card;
-}
-
-static void
-qeth_convert_addr_to_text(int version, __u8 * addr, char *text)
-{
-       if (version == 4) {
-               sprintf(text, "%02x%02x%02x%02x",
-                       addr[0], addr[1], addr[2], addr[3]);
-       } else {
-               sprintf(text, "%02x%02x%02x%02x%02x%02x%02x%02x"
-                       "%02x%02x%02x%02x%02x%02x%02x%02x",
-                       addr[0], addr[1], addr[2], addr[3],
-                       addr[4], addr[5], addr[6], addr[7],
-                       addr[8], addr[9], addr[10], addr[11],
-                       addr[12], addr[13], addr[14], addr[15]);
-       }
-}
-
-static int
-qeth_convert_text_to_addr(int version, char *text, __u8 * addr)
-{
-       int olen = (version == 4) ? 4 : 16;
-
-       while (olen--) {
-               if ((!isxdigit(*text)) || (!isxdigit(*(text + 1))))
-                       return -EINVAL;
-               *addr =
-                   (qeth_getxdigit(*text) << 4) + qeth_getxdigit(*(text + 1));
-               addr++;
-               text += 2;
-       }
-       return 0;
-}
-
-static void
-qeth_add_ipato_entry(int version, __u8 * addr, int mask_bits, char *dev_name)
-{
-       struct ipato_entry *entry, *e;
-       int len = (version == 4) ? 4 : 16;
-
-       entry =
-           (struct ipato_entry *) kmalloc(sizeof (struct ipato_entry),
-                                          GFP_KERNEL);
-       if (!entry) {
-               PRINT_ERR("not enough memory for ipato allocation\n");
-               return;
-       }
-       entry->version = version;
-       memcpy(entry->addr, addr, len);
-       if (dev_name) {
-               strncpy(entry->dev_name, dev_name, DEV_NAME_LEN);
-               if (qeth_get_card_by_name(dev_name)->options.ena_ipat !=
-                   ENABLE_TAKEOVER)
-                       PRINT_WARN("IP takeover is not enabled on %s! "
-                                  "Ignoring line\n", dev_name);
-       } else
-               memset(entry->dev_name, 0, DEV_NAME_LEN);
-       entry->mask_bits = mask_bits;
-       entry->next = NULL;
-
-       spin_lock(&ipato_list_lock);
-       if (ipato_entries) {
-               e = ipato_entries;
-               while (e) {
-                       if ((e->version == version) &&
-                           (e->mask_bits == mask_bits) &&
-                           (((dev_name) && !strncmp(e->dev_name, dev_name,
-                                                    DEV_NAME_LEN)) ||
-                            (!dev_name)) && (!memcmp(e->addr, addr, len))) {
-                               PRINT_INFO("ipato to be added does already "
-                                          "exist\n");
-                               kfree(entry);
-                               goto out;
-                       }
-                       if (e->next)
-                               e = e->next;
-                       else
-                               break;
-               }
-               e->next = entry;
-       } else
-               ipato_entries = entry;
-      out:
-       spin_unlock(&ipato_list_lock);
-}
-
-static void
-qeth_del_ipato_entry(int version, __u8 * addr, int mask_bits, char *dev_name)
-{
-       struct ipato_entry *e, *e_before;
-       int len = (version == 4) ? 4 : 16;
-       int found = 0;
-
-       spin_lock(&ipato_list_lock);
-       e = ipato_entries;
-       if ((e->version == version) &&
-           (e->mask_bits == mask_bits) && (!memcmp(e->addr, addr, len))) {
-               ipato_entries = e->next;
-               kfree(e);
-       } else
-               while (e) {
-                       e_before = e;
-                       e = e->next;
-                       if (!e)
-                               break;
-                       if ((e->version == version) &&
-                           (e->mask_bits == mask_bits) &&
-                           (((dev_name) && !strncmp(e->dev_name, dev_name,
-                                                    DEV_NAME_LEN)) ||
-                            (!dev_name)) && (!memcmp(e->addr, addr, len))) {
-                               e_before->next = e->next;
-                               kfree(e);
-                               found = 1;
-                               break;
-                       }
-               }
-       if (!found)
-               PRINT_INFO("ipato to be deleted does not exist\n");
-       spin_unlock(&ipato_list_lock);
-}
-
-static void
-qeth_convert_addr_to_bits(__u8 * addr, char *bits, int len)
-{
-       int i, j;
-       __u8 octet;
-
-       for (i = 0; i < len; i++) {
-               octet = addr[i];
-               for (j = 7; j >= 0; j--) {
-                       bits[i * 8 + j] = (octet & 1) ? 1 : 0;
-                       octet >>= 1;
-               }
-       }
-}
-
-static int
-qeth_is_ipa_covered_by_ipato_entries(int version, __u8 * addr,
-                                    struct qeth_card *card)
-{
-       char *memarea, *addr_bits, *entry_bits;
-       int len = (version == 4) ? 4 : 16;
-       int invert = (version == 4) ? ipato_inv4 : ipato_inv6;
-       int result = 0;
-       struct ipato_entry *e;
-
-       if (card->options.ena_ipat != ENABLE_TAKEOVER) {
-               return 0;
-       }
-
-       memarea = kmalloc(256, GFP_KERNEL);
-       if (!memarea) {
-               PRINT_ERR("not enough memory to check out whether to "
-                         "use ipato\n");
-               return 0;
-       }
-       addr_bits = memarea;
-       entry_bits = memarea + 128;
-       qeth_convert_addr_to_bits(addr, addr_bits, len);
-       e = ipato_entries;
-       while (e) {
-               qeth_convert_addr_to_bits(e->addr, entry_bits, len);
-               if ((!memcmp(addr_bits, entry_bits,
-                            __min(len * 8, e->mask_bits))) &&
-                   ((e->dev_name[0] &&
-                     (!strncmp(e->dev_name, card->dev_name, DEV_NAME_LEN))) ||
-                    (!e->dev_name[0]))) {
-                       result = 1;
-                       break;
-               }
-               e = e->next;
-       }
-
-       kfree(memarea);
-       if (invert)
-               return !result;
-       else
-               return result;
-}
-
-static void
-qeth_set_dev_flag_running(struct qeth_card *card)
-{
-       if (card) {
-               card->dev->flags |= IFF_RUNNING;
-       }
-}
-
-static void
-qeth_set_dev_flag_norunning(struct qeth_card *card)
-{
-       if (card) {
-               card->dev->flags &= ~IFF_RUNNING;
-       }
-}
-
-static void
-qeth_restore_dev_flag_state(struct qeth_card *card)
-{
-       if (card) {
-               if (card->saved_dev_flags & IFF_RUNNING)
-                       card->dev->flags |= IFF_RUNNING;
-               else
-                       card->dev->flags &= ~IFF_RUNNING;
-       }
-}
-
-static void
-qeth_save_dev_flag_state(struct qeth_card *card)
-{
-       if (card) {
-               card->saved_dev_flags = card->dev->flags & IFF_RUNNING;
-       }
-}
-
-static int
-qeth_open(struct net_device *dev)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_CARD2(0, trace, "open", card);
-       QETH_DBF_CARD2(0, setup, "open", card);
-
-       qeth_save_dev_flag_state(card);
-
-       netif_start_queue(dev);
-       atomic_set(&((struct qeth_card *) dev->priv)->is_open, 1);
-
-       return 0;
-}
-
-static int
-qeth_set_config(struct net_device *dev, struct ifmap *map)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *)dev->priv;
-       QETH_DBF_CARD3(0, trace, "nscf", card);
-
-       return -EOPNOTSUPP;
-}
-
-static int
-qeth_is_multicast_skb_at_all(struct sk_buff *skb, int version)
-{
-       int i;
-       struct qeth_card *card;
-
-       i = RTN_UNSPEC;
-       card = (struct qeth_card *)skb->dev->priv;
-       if (skb->dst && skb->dst->neighbour) {
-               i = skb->dst->neighbour->type;
-               return ((i == RTN_BROADCAST) ||
-                       (i == RTN_MULTICAST) || (i == RTN_ANYCAST)) ? i : 0;
-       }
-       /* ok, we've to try it somehow else */
-       if (version == 4) {
-               return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
-       } else if (version == 6) {
-               return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
-       }
-       if (!memcmp(skb->nh.raw, skb->dev->broadcast, 6)) {
-               i = RTN_BROADCAST;
-       } else {
-               __u16 hdr_mac;
-
-               hdr_mac = *((__u16*)skb->nh.raw);
-               /* tr multicast? */
-               switch (card->link_type) {
-               case QETH_MPC_LINK_TYPE_HSTR:
-               case QETH_MPC_LINK_TYPE_LANE_TR:
-                       if ((hdr_mac == QETH_TR_MAC_NC) ||
-                           (hdr_mac == QETH_TR_MAC_C))
-                               i = RTN_MULTICAST;
-                       break;
-               /* eth or so multicast? */
-                default:
-                       if ((hdr_mac == QETH_ETH_MAC_V4) ||
-                           (hdr_mac == QETH_ETH_MAC_V6))
-                               i = RTN_MULTICAST;
-               }
-        }
-       return ((i == RTN_BROADCAST)||
-               (i == RTN_MULTICAST)||
-               (i == RTN_ANYCAST)) ? i : 0;
-}
-
-static int
-qeth_get_prioqueue(struct qeth_card *card, struct sk_buff *skb,
-                  int multicast, int version)
-{
-       if (!version && (card->type == QETH_CARD_TYPE_OSAE))
-               return QETH_DEFAULT_QUEUE;
-       switch (card->no_queues) {
-       case 1:
-               return 0;
-       case 4:
-               if (card->is_multicast_different) {
-                       if (multicast) {
-                               return card->is_multicast_different &
-                                   (card->no_queues - 1);
-                       } else {
-                               return 0;
-                       }
-               }
-               if (card->options.do_prio_queueing) {
-                       if (version == 4) {
-                               if (card->options.do_prio_queueing ==
-                                   PRIO_QUEUEING_TOS) {
-                                       if (skb->nh.iph->tos &
-                                           IP_TOS_NOTIMPORTANT) {
-                                               return 3;
-                                       }
-                                       if (skb->nh.iph->tos & IP_TOS_LOWDELAY) {
-                                               return 0;
-                                       }
-                                       if (skb->nh.iph->tos &
-                                           IP_TOS_HIGHTHROUGHPUT) {
-                                               return 1;
-                                       }
-                                       if (skb->nh.iph->tos &
-                                           IP_TOS_HIGHRELIABILITY) {
-                                               return 2;
-                                       }
-                                       return QETH_DEFAULT_QUEUE;
-                               }
-                               if (card->options.do_prio_queueing ==
-                                   PRIO_QUEUEING_PREC) {
-                                       return 3 - (skb->nh.iph->tos >> 6);
-                               }
-                       } else if (version == 6) {
-                               /********************
-                                ********************
-                                *TODO: IPv6!!!
-                                ********************/
-                       }
-                       return card->options.default_queue;
-               } else
-                       return card->options.default_queue;
-       default:
-               return 0;
-       }
-}
-
-static void
-qeth_wakeup(struct qeth_card *card)
-{
-       QETH_DBF_CARD5(0, trace, "wkup", card);
-
-       atomic_set(&card->data_has_arrived, 1);
-       wake_up(&card->wait_q);
-}
-
-static int
-qeth_check_idx_response(unsigned char *buffer)
-{
-       if (!buffer)
-               return 0;
-       if ((buffer[2] & 0xc0) == 0xc0) {
-               return -EIO;
-       }
-       return 0;
-}
-
-static int
-qeth_get_cards_problem(struct ccw_device *cdev, unsigned char *buffer,
-                      int dstat, int cstat, int rqparam,
-                      char *irb, char *sense)
-{
-       char dbf_text[15];
-       int problem = 0;
-       struct qeth_card *card;
-
-       card = CARD_FROM_CDEV(cdev);
-
-       if (atomic_read(&card->shutdown_phase))
-               return 0;
-       if (dstat & DEV_STAT_UNIT_CHECK) {
-               if (sense[SENSE_RESETTING_EVENT_BYTE] &
-                   SENSE_RESETTING_EVENT_FLAG) {
-                       QETH_DBF_CARD1(0, trace, "REVN", card);
-                       problem = PROBLEM_RESETTING_EVENT_INDICATOR;
-                       goto out;
-               }
-               if (sense[SENSE_COMMAND_REJECT_BYTE] &
-                   SENSE_COMMAND_REJECT_FLAG) {
-                       QETH_DBF_CARD1(0, trace, "CREJ", card);
-                       problem = PROBLEM_COMMAND_REJECT;
-                       goto out;
-               }
-               if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) {
-                       QETH_DBF_CARD1(0, trace, "AFFE", card);
-                       problem = PROBLEM_AFFE;
-                       goto out;
-               }
-               if ((!sense[0]) && (!sense[1]) && (!sense[2]) && (!sense[3])) {
-                       QETH_DBF_CARD1(0, trace, "ZSNS", card);
-                       problem = PROBLEM_ZERO_SENSE_DATA;
-                       goto out;
-               }
-               QETH_DBF_CARD1(0, trace, "GCHK", card);
-               problem = PROBLEM_GENERAL_CHECK;
-               goto out;
-       }
-       if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
-                    SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
-                    SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
-               QETH_DBF_TEXT1(0, trace, "GCHK");
-               QETH_DBF_TEXT1(0, trace, cdev->dev.bus_id);
-               QETH_DBF_HEX1(0, misc, irb, __max(QETH_DBF_MISC_LEN, 64));
-               PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x, "
-                          "rqparam=x%x\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-               HEXDUMP16(WARN, "irb: ", irb);
-               HEXDUMP16(WARN, "irb: ", ((char *) irb) + 32);
-               problem = PROBLEM_GENERAL_CHECK;
-               goto out;
-       }
-       if (qeth_check_idx_response(buffer)) {
-               PRINT_WARN("received an IDX TERMINATE on device %s "
-                          "with cause code 0x%02x%s\n",
-                          CARD_BUS_ID(card), buffer[4],
-                          (buffer[4] ==
-                           0x22) ? " -- try another portname" : "");
-               QETH_DBF_CARD1(0, trace, "RTRM", card);
-               problem = PROBLEM_RECEIVED_IDX_TERMINATE;
-               goto out;
-       }
-       if (IS_IPA(buffer) && !IS_IPA_REPLY(buffer)) {
-               if (*(PDU_ENCAPSULATION(buffer)) == IPA_CMD_STOPLAN) {
-                       atomic_set(&card->is_startlaned, 0);
-                       /* we don't do a  netif_stop_queue(card->dev);
-                          we better discard all packets --
-                          the outage could take longer */
-                       PRINT_WARN("Link failure on %s (CHPID 0x%X) -- "
-                                  "there is a network problem or someone "
-                                  "pulled the cable or disabled the port."
-                                  "Discarding outgoing packets.\n",
-                                  card->dev_name, card->chpid);
-                       QETH_DBF_CARD1(0, trace, "CBOT", card);
-                       qeth_set_dev_flag_norunning(card);
-                       problem = 0;
-                       goto out;
-               }
-               if (*(PDU_ENCAPSULATION(buffer)) == IPA_CMD_STARTLAN) {
-                       if (!atomic_read(&card->is_startlaned)) {
-                               atomic_set(&card->is_startlaned, 1);
-                               problem = PROBLEM_CARD_HAS_STARTLANED;
-                       }
-                       goto out;
-               }
-               if (*(PDU_ENCAPSULATION(buffer)) == IPA_CMD_REGISTER_LOCAL_ADDR)
-                       QETH_DBF_CARD3(0, trace, "irla", card);
-               if (*(PDU_ENCAPSULATION(buffer)) == 
-                   IPA_CMD_UNREGISTER_LOCAL_ADDR)
-                       QETH_DBF_CARD3(0, trace, "irla", card);
-               PRINT_WARN("probably a problem on %s: received data is IPA, "
-                          "but not a reply: command=0x%x\n", card->dev_name,
-                          *(PDU_ENCAPSULATION(buffer) + 1));
-               QETH_DBF_CARD1(0, trace, "INRP", card);
-               goto out;
-       }
-       /* no probs */
-out:
-       if (problem) {
-               QETH_DBF_CARD3(0, trace, "gcpr", card);
-               sprintf(dbf_text, "%2x%2x%4x", dstat, cstat, problem);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               sprintf(dbf_text, "%8x", rqparam);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               if (buffer)
-                       QETH_DBF_HEX3(0, trace, &buffer, sizeof (void *));
-               QETH_DBF_HEX3(0, trace, &irb, sizeof (void *));
-               QETH_DBF_HEX3(0, trace, &sense, sizeof (void *));
-       }
-       atomic_set(&card->problem, problem);
-       return problem;
-}
-
-static void
-qeth_issue_next_read(struct qeth_card *card)
-{
-       int result, result2;
-       char dbf_text[15];
-
-       QETH_DBF_CARD5(0, trace, "isnr", card);
-
-       /* set up next read ccw */
-       memcpy(&card->dma_stuff->read_ccw, READ_CCW, sizeof (struct ccw1));
-       card->dma_stuff->read_ccw.count = QETH_BUFSIZE;
-       /* recbuf is not yet used by read channel program */
-       card->dma_stuff->read_ccw.cda = QETH_GET_ADDR(card->dma_stuff->recbuf);
-
-       /* 
-        * we don't spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)),flags), as
-        * we are only called in the interrupt handler
-        */
-       result = ccw_device_start(CARD_RDEV(card), &card->dma_stuff->read_ccw,
-                                 MPC_SETUP_STATE, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 =
-                   ccw_device_start(CARD_RDEV(card), &card->dma_stuff->read_ccw,
-                                    MPC_SETUP_STATE, 0, 0);
-               PRINT_WARN("read handler on device %s, read: ccw_device_start "
-                          "returned %i, next try returns %i\n",
-                          CARD_BUS_ID(card), result, result2);
-               QETH_DBF_CARD1(0, trace, "IsNR", card);
-               sprintf(dbf_text, "%04x%04x", (__s16) result, (__s16) result2);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-       }
-}
-
-static int
-qeth_is_to_recover(struct qeth_card *card, int problem)
-{
-       switch (problem) {
-       case PROBLEM_CARD_HAS_STARTLANED:
-               return 1;
-       case PROBLEM_RECEIVED_IDX_TERMINATE:
-               if (atomic_read(&card->in_recovery)) {
-                       return 1;
-               } else {
-                       qeth_set_dev_flag_norunning(card);
-                       return 0;
-               }
-       case PROBLEM_ACTIVATE_CHECK_CONDITION:
-               return 1;
-       case PROBLEM_RESETTING_EVENT_INDICATOR:
-               return 1;
-       case PROBLEM_COMMAND_REJECT:
-               return 0;
-       case PROBLEM_ZERO_SENSE_DATA:
-               return 0;
-       case PROBLEM_GENERAL_CHECK:
-               return 1;
-       case PROBLEM_BAD_SIGA_RESULT:
-               return 1;
-       case PROBLEM_USER_TRIGGERED_RECOVERY:
-               return 1;
-       case PROBLEM_AFFE:
-               return 1;
-       case PROBLEM_MACHINE_CHECK:
-               return 1;
-       case PROBLEM_TX_TIMEOUT:
-               return 1;
-       }
-       return 0;
-}
-
-static int
-qeth_get_spare_buf(void)
-{
-       int i = 0;
-       char dbf_text[15];
-
-       while (i < sparebuffer_count) {
-               if (!atomic_compare_and_swap(SPAREBUF_FREE, SPAREBUF_USED,
-                                            &sparebufs[i].status)) {
-                       sprintf(dbf_text, "gtspb%3x", i);
-                       QETH_DBF_TEXT4(0, trace, dbf_text);
-                       return i;
-               }
-               i++;
-       }
-       QETH_DBF_TEXT3(0, trace, "nospbuf");
-
-       return -1;
-}
-
-static void
-qeth_put_spare_buf(int no)
-{
-       char dbf_text[15];
-
-       sprintf(dbf_text, "ptspb%3x", no);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       atomic_set(&sparebufs[no].status, SPAREBUF_FREE);
-}
-
-static inline void
-qeth_put_buffer_pool_entry(struct qeth_card *card, int entry_no)
-{
-       if (entry_no & SPAREBUF_MASK)
-               qeth_put_spare_buf(entry_no & (~SPAREBUF_MASK));
-       else
-               card->inbound_buffer_pool_entry_used[entry_no] = BUFFER_UNUSED;
-}
-
-static inline int
-qeth_get_empty_buffer_pool_entry(struct qeth_card *card)
-{
-       int i;
-       int max_buffers = card->options.inbound_buffer_count;
-
-       for (i = 0; i < max_buffers; i++) {
-               if (xchg((int *) &card->inbound_buffer_pool_entry_used[i],
-                        BUFFER_USED) == BUFFER_UNUSED)
-                       return i;
-       }
-       return -1;
-}
-
-static inline void
-qeth_clear_input_buffer(struct qeth_card *card, int bufno)
-{
-       struct qdio_buffer *buffer;
-       int i;
-       int elements, el_m_1;
-       char dbf_text[15];
-
-       QETH_DBF_CARD6(0, trace, "clib", card);
-       sprintf(dbf_text, "bufno%3x", bufno);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-
-       buffer = &card->inbound_qdio_buffers[bufno];
-       elements = BUFFER_MAX_ELEMENTS;
-       el_m_1 = elements - 1;
-
-       for (i = 0; i < elements; i++) {
-               if (i == el_m_1)
-                       buffer->element[i].flags = SBAL_FLAGS_LAST_ENTRY;
-               else
-                       buffer->element[i].flags = 0;
-
-               buffer->element[i].length = PAGE_SIZE;
-               buffer->element[i].addr = INBOUND_BUFFER_POS(card, bufno, i);
-       }
-}
-
-static void
-qeth_queue_input_buffer(struct qeth_card *card, int bufno,
-                       unsigned int under_int)
-{
-       int count = 0, start = 0, stop = 0, pos;
-       int result;
-       int cnt1, cnt2 = 0;
-       int wrapped = 0;
-       int i;
-       int requeue_counter;
-       char dbf_text[15];
-       int no;
-
-       QETH_DBF_CARD5(0, trace, "qibf", card);
-       sprintf(dbf_text, "%4x%4x", under_int, bufno);
-       QETH_DBF_TEXT5(0, trace, dbf_text);
-       atomic_inc(&card->requeue_counter);
-       if (atomic_read(&card->requeue_counter) <= QETH_REQUEUE_THRESHOLD)
-               return;
-
-       if (!spin_trylock(&card->requeue_input_lock)) {
-               QETH_DBF_CARD5(0, trace, "qibl", card);
-               return;
-       }
-       requeue_counter = atomic_read(&card->requeue_counter);
-       pos = atomic_read(&card->requeue_position);
-       
-       start = pos;
-       /* 
-        * omit the situation with 128 simultaneously
-        * enqueued buffers, as then we can't benefit from PCI
-        * avoidance anymore -- therefore we let count not grow as
-        * big as requeue_counter
-        */
-       while ((!atomic_read(&card->inbound_buffer_refcnt[pos])) &&
-              (count < requeue_counter - 1)) {
-               no = qeth_get_empty_buffer_pool_entry(card);
-               if (no == -1) {
-                       if (count)
-                               break;
-                       no = qeth_get_spare_buf();
-                       if (no == -1) {
-                               PRINT_ERR("%s: no more input buffers "
-                                         "available! Inbound traffic could "
-                                         "be lost! Try increasing the bufcnt "
-                                         "parameter\n",
-                                         card->dev_name);
-                               QETH_DBF_CARD2(1, trace, "QINB", card);
-                               goto out;
-                       }
-                       card->inbound_buffer_entry_no[pos] =
-                               no | SPAREBUF_MASK;
-               }
-               card->inbound_buffer_entry_no[pos] = no;
-               atomic_set(&card->inbound_buffer_refcnt[pos], 1);
-               count++;
-               if (pos >= QDIO_MAX_BUFFERS_PER_Q - 1) {
-                       pos = 0;
-                       wrapped = 1;
-               } else
-                       pos++;
-       }
-       /* stop points to the position after the last element */
-       stop = pos;
-
-       QETH_DBF_CARD3(0, trace, "qibi", card);
-       sprintf(dbf_text, "%4x", requeue_counter);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x%4x", start, stop);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-       
-       if (wrapped) {
-               cnt1 = QDIO_MAX_BUFFERS_PER_Q - start;
-               cnt2 = stop;
-       } else {
-               cnt1 = count;
-               /* cnt2 is already set to 0 */
-       }
-       
-       atomic_sub(count, &card->requeue_counter);
-       /* 
-        * this is the only place where card->requeue_position is
-        * written to, so that's ok (as it is in a lock)
-        */
-       atomic_set(&card->requeue_position,
-                  (atomic_read(&card->requeue_position) + count)
-                  & (QDIO_MAX_BUFFERS_PER_Q - 1));
-       
-       if (cnt1) {
-               for (i = start; i < start + cnt1; i++) {
-                       qeth_clear_input_buffer(card, i);
-               }
-               result = do_QDIO(CARD_DDEV(card),
-                                QDIO_FLAG_SYNC_INPUT | under_int,
-                                0, start, cnt1, NULL);
-               if (result) {
-                       PRINT_WARN("qeth_queue_input_buffer's "
-                                  "do_QDIO returnd %i (device %s)\n",
-                                  result, CARD_DDEV_ID(card));
-                       QETH_DBF_CARD1(0, trace, "QIDQ", card);
-                       sprintf(dbf_text, "%4x%4x", result, requeue_counter);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", start, cnt1);
-                       QETH_DBF_TEXT1(1, trace, dbf_text);
-               }
-       }
-       if (cnt2) {
-               for (i = 0; i < cnt2; i++) {
-                       qeth_clear_input_buffer(card, i);
-               }
-               result = do_QDIO(CARD_DDEV(card),
-                                QDIO_FLAG_SYNC_INPUT | under_int, 0,
-                                0, cnt2, NULL);
-               if (result) {
-                       PRINT_WARN("qeth_queue_input_buffer's "
-                                  "do_QDIO returnd %i (device %s)\n",
-                                  result, CARD_DDEV_ID(card));
-                       QETH_DBF_CARD1(0, trace, "QIDQ", card);
-                       sprintf(dbf_text, "%4x%4x", result, requeue_counter);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", 0, cnt2);
-                       QETH_DBF_TEXT1(1, trace, dbf_text);
-               }
-       }
-out:
-       spin_unlock(&card->requeue_input_lock);
-
-}
-
-static inline struct sk_buff *
-qeth_get_skb(unsigned int len)
-{
-       struct sk_buff *skb;
-
-#ifdef QETH_VLAN
-       skb = dev_alloc_skb(len + VLAN_HLEN);
-       if (skb)
-               skb_reserve(skb, VLAN_HLEN);
-#else /* QETH_VLAN */
-       skb = dev_alloc_skb(len);
-#endif /* QETH_VLAN */
-       return skb;
-}
-
-static inline struct sk_buff *
-qeth_get_next_skb(struct qeth_card *card,
-                 int *element_ptr, int *pos_in_el_ptr,
-                 void **hdr_ptr, struct qdio_buffer *buffer)
-{
-       int length;
-       char *data_ptr;
-       int step, len_togo, element, pos_in_el;
-       int curr_len;
-       int max_elements;
-       struct sk_buff *skb;
-       char dbf_text[15];
-
-       max_elements = BUFFER_MAX_ELEMENTS;
-
-#define SBALE_LEN(x) ((x>=max_elements)?0:(buffer->element[x].length))
-#define SBALE_ADDR(x) (buffer->element[x].addr)
-
-       element = *element_ptr;
-
-       if (element >= max_elements) {
-               PRINT_WARN("device %s: error in interpreting buffer (data "
-                          "too long), %i elements.\n",
-                          CARD_BUS_ID(card), element);
-               QETH_DBF_CARD0(0, trace, "IEDL", card);
-               sprintf(dbf_text, "%4x%4x", *element_ptr, *pos_in_el_ptr);
-               QETH_DBF_TEXT0(1, trace, dbf_text);
-               QETH_DBF_HEX0(0, misc, buffer, QETH_DBF_MISC_LEN);
-               QETH_DBF_HEX0(0, misc, buffer + QETH_DBF_MISC_LEN,
-                             QETH_DBF_MISC_LEN);
-               return NULL;
-       }
-
-       pos_in_el = *pos_in_el_ptr;
-
-       curr_len = SBALE_LEN(element);
-       if (curr_len > PAGE_SIZE) {
-               PRINT_WARN("device %s: bad element length in element %i: "
-                          "0x%x\n", CARD_BUS_ID(card), element, curr_len);
-               QETH_DBF_CARD0(0, trace, "BELN", card);
-               sprintf(dbf_text, "%4x", curr_len);
-               QETH_DBF_TEXT0(0, trace, dbf_text);
-               sprintf(dbf_text, "%4x%4x", *element_ptr, *pos_in_el_ptr);
-               QETH_DBF_TEXT0(1, trace, dbf_text);
-               QETH_DBF_HEX0(0, misc, buffer, QETH_DBF_MISC_LEN);
-               QETH_DBF_HEX0(0, misc, buffer + QETH_DBF_MISC_LEN,
-                             QETH_DBF_MISC_LEN);
-               return NULL;
-       }
-       /* header fits in current element? */
-       if (curr_len < pos_in_el + QETH_HEADER_SIZE) {
-               if (!pos_in_el) {
-                       QETH_DBF_CARD6(0, trace, "gnmh", card);
-                       return NULL;    /* no more data in buffer */
-               }
-               /* set hdr to next element */
-               element++;
-               pos_in_el = 0;
-               curr_len = SBALE_LEN(element);
-               /* does it fit in there? */
-               if (curr_len < QETH_HEADER_SIZE) {
-                       QETH_DBF_CARD6(0, trace, "gdnf", card);
-                       return NULL;
-               }
-       }
-
-       *hdr_ptr = SBALE_ADDR(element) + pos_in_el;
-
-       length = *(__u16 *) ((char *) (*hdr_ptr) + QETH_HEADER_LEN_POS);
-
-       QETH_DBF_CARD6(0, trace, "gdHd", card);
-       QETH_DBF_HEX6(0, trace, hdr_ptr, sizeof (void *));
-
-       pos_in_el += QETH_HEADER_SIZE;
-       if (curr_len <= pos_in_el) {
-               /* switch to next element for data */
-               pos_in_el = 0;
-               element++;
-               curr_len = SBALE_LEN(element);
-               if (!curr_len) {
-                       PRINT_WARN("device %s: inb. buffer with more headers "
-                                  "than data areas (%i elements).\n",
-                                  CARD_BUS_ID(card), element);
-                       QETH_DBF_CARD0(0, trace, "IEMH", card);
-                       sprintf(dbf_text, "%2x%2x%4x", element, *element_ptr,
-                               *pos_in_el_ptr);
-                       QETH_DBF_TEXT0(1, trace, dbf_text);
-                       QETH_DBF_HEX0(0, misc, buffer, QETH_DBF_MISC_LEN);
-                       QETH_DBF_HEX0(0, misc, buffer + QETH_DBF_MISC_LEN,
-                                     QETH_DBF_MISC_LEN);
-                       return NULL;
-               }
-       }
-
-       data_ptr = SBALE_ADDR(element) + pos_in_el;
-
-       if (card->options.fake_ll == FAKE_LL) {
-               skb = qeth_get_skb(length + QETH_FAKE_LL_LEN);
-               if (!skb)
-                       goto nomem;
-               skb_pull(skb, QETH_FAKE_LL_LEN);
-       } else {
-               skb = qeth_get_skb(length);
-               if (!skb)
-                       goto nomem;
-       }
-
-       QETH_DBF_HEX6(0, trace, &data_ptr, sizeof (void *));
-       QETH_DBF_HEX6(0, trace, &skb, sizeof (void *));
-
-       len_togo = length;
-       while (1) {
-               step = qeth_min(len_togo, curr_len - pos_in_el);
-               if (!step) {
-                       PRINT_WARN("device %s: unexpected end of buffer, "
-                                  "length of element %i is 0. Discarding "
-                                  "packet.\n",
-                                  CARD_BUS_ID(card), element);
-                       QETH_DBF_CARD0(0, trace, "IEUE", card);
-                       sprintf(dbf_text, "%2x%2x%4x", element, *element_ptr,
-                               *pos_in_el_ptr);
-                       QETH_DBF_TEXT0(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", len_togo, step);
-                       QETH_DBF_TEXT0(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", curr_len, pos_in_el);
-                       QETH_DBF_TEXT0(1, trace, dbf_text);
-                       QETH_DBF_HEX0(0, misc, buffer, QETH_DBF_MISC_LEN);
-                       QETH_DBF_HEX0(0, misc, buffer + QETH_DBF_MISC_LEN,
-                                     QETH_DBF_MISC_LEN);
-                       dev_kfree_skb_irq(skb);
-                       return NULL;
-               }
-               memcpy(skb_put(skb, step), data_ptr, step);
-               len_togo -= step;
-               if (len_togo) {
-                       pos_in_el = 0;
-                       element++;
-                       curr_len = SBALE_LEN(element);
-                       data_ptr = SBALE_ADDR(element);
-               } else {
-#ifdef QETH_INBOUND_PACKING_1_PACKET_PER_SBALE
-                       element++;
-                       /* we don't need to calculate curr_len */
-                       pos_in_el = 0;
-#else /* QETH_INBOUND_PACKING_1_PACKET_PER_SBALE */
-                       pos_in_el += step;
-#endif /* QETH_INBOUND_PACKING_1_PACKET_PER_SBALE */
-                       break;
-               }
-       }
-
-       sprintf(dbf_text, "%4x%4x", element, pos_in_el);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-
-       *element_ptr = element;
-       *pos_in_el_ptr = pos_in_el;
-
-       return skb;
-
-nomem:
-       if (net_ratelimit()) {
-               PRINT_WARN("no memory for packet from %s\n", card->dev_name);
-       }
-       QETH_DBF_CARD0(0, trace, "NOMM", card);
-       return NULL;
-}
-
-static inline void
-__qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
-                          void *hdr_ptr)
-{
-       skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
-       switch (skb->pkt_type) {
-       case PACKET_MULTICAST:
-               switch (skb->protocol) {
-#ifdef QETH_IPV6
-               case __constant_htons(ETH_P_IPV6):
-                       ndisc_mc_map((struct in6_addr *)
-                                    skb->data + QETH_FAKE_LL_V6_ADDR_POS,
-                                    skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
-                                    card->dev, 0);
-                               break;
-#endif /* QETH_IPV6 */
-               case __constant_htons(ETH_P_IP):
-                       qeth_get_mac_for_ipm(*(__u32*)
-                                            skb->data + QETH_FAKE_LL_V4_ADDR_POS,
-                                            skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
-                                            card->dev);
-                       break;
-               default:
-                       memcpy(skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
-                              card->dev->dev_addr, QETH_FAKE_LL_ADDR_LEN);
-               }
-               break;
-       case PACKET_BROADCAST:
-               memset(skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
-                      0xff, QETH_FAKE_LL_ADDR_LEN);
-               break;
-       default:
-               memcpy(skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
-                      card->dev->dev_addr, QETH_FAKE_LL_ADDR_LEN);
-       }
-
-       if (*(__u8 *) (hdr_ptr + 11) & QETH_EXT_HEADER_SRC_MAC_ADDRESS) {
-               memcpy(skb->mac.raw + QETH_FAKE_LL_SRC_MAC_POS,
-                      hdr_ptr + QETH_FAKE_LL_SRC_MAC_POS_IN_QDIO_HDR,
-                      QETH_FAKE_LL_ADDR_LEN);
-       } else {
-               /* clear source MAC for security reasons */
-               memset(skb->mac.raw + QETH_FAKE_LL_SRC_MAC_POS,
-                      0, QETH_FAKE_LL_ADDR_LEN);
-       }
-       memcpy(skb->mac.raw + QETH_FAKE_LL_PROT_POS,
-              &skb->protocol, QETH_FAKE_LL_PROT_LEN);
-
-}
-
-static inline void
-__qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
-                       void *hdr_ptr)
-{
-#ifdef QETH_VLAN
-       __u16 *vlan_tag;
-
-       if (*(__u8 *) (hdr_ptr + 11) & QETH_EXT_HEADER_VLAN_FRAME) {
-
-               vlan_tag = (__u16 *) skb_push(skb, VLAN_HLEN);
-               /*
-                 if (*(__u8*)(hdr_ptr+11) & 
-                 QETH_EXT_HEADER_INCLUDE_VLAN_TAG) {
-                 *vlan_tag = *(__u16*)(hdr_ptr+28);
-                 *(vlan_tag+1)= *(__u16*)(hdr_ptr+30);
-                 } else {
-               */
-               *vlan_tag = *(__u16 *) (hdr_ptr + 12);
-               *(vlan_tag + 1) = skb->protocol;
-               /*
-                 }
-               */
-               skb->protocol = __constant_htons(ETH_P_8021Q);
-       }
-#endif
-}
-
-static inline void
-__qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, void *hdr_ptr)
-{
-       char dbf_text[15];
-       int version;
-       unsigned short cast_type;
-       
-       version = ((*(__u16 *) (hdr_ptr)) & (QETH_HEADER_IPV6)) ? 6 : 4;
-       skb->protocol = htons((version == 4) ? ETH_P_IP : 
-                             (version == 6) ? ETH_P_IPV6 : ETH_P_ALL);
-       cast_type = (*(__u16 *) (hdr_ptr)) & (QETH_CAST_FLAGS);
-       switch (cast_type) {
-       case QETH_CAST_UNICAST:
-               skb->pkt_type = PACKET_HOST;
-               break;
-       case QETH_CAST_MULTICAST:
-               skb->pkt_type = PACKET_MULTICAST;
-               break;
-       case QETH_CAST_BROADCAST:
-               skb->pkt_type = PACKET_BROADCAST;
-               break;
-       case QETH_CAST_ANYCAST:
-       case QETH_CAST_NOCAST:
-               QETH_DBF_CARD2(0, trace, "ribf", card);
-               sprintf(dbf_text, "castan%2x", cast_type);
-               QETH_DBF_TEXT2(1, trace, dbf_text);
-               skb->pkt_type = PACKET_HOST;
-               break;
-       default:
-               PRINT_WARN("adapter is using an unknown casting value "
-                          "of 0x%x. Using unicasting instead.\n",
-                          cast_type);
-               skb->pkt_type = PACKET_HOST;
-               QETH_DBF_CARD2(0, trace, "ribf", card);
-               sprintf(dbf_text, "castun%2x", cast_type);
-               QETH_DBF_TEXT2(1, trace, dbf_text);
-       }
-
-       if (card->options.fake_ll == FAKE_LL)
-               __qeth_rebuild_skb_fake_ll(card, skb, hdr_ptr);
-       else
-               skb->mac.raw = skb->data;
-
-       skb->ip_summed = card->options.checksum_type;
-       if (card->options.checksum_type == HW_CHECKSUMMING) {
-               /* do we have a checksummed packet? */
-
-               /* 
-                * we only check for TCP/UDP checksums when the pseudo
-                * header was also checked successfully -- for the
-                * rest of the packets, it's not clear, whether the
-                * upper layer csum is alright. And they shouldn't
-                * occur too often anyway in real life 
-                */
-
-               if ((*(__u8*)(hdr_ptr+11) & (QETH_EXT_HEADER_CSUM_HDR_REQ |
-                                            QETH_EXT_HEADER_CSUM_TRANSP_REQ)) ==
-                   (QETH_EXT_HEADER_CSUM_HDR_REQ |
-                    QETH_EXT_HEADER_CSUM_TRANSP_REQ)) {
-#if 0
-                       /* csum does not need to be set inbound anyway */
-                       
-                       /* 
-                        * vlan is not an issue here, it's still in
-                        * the QDIO header, not pushed in the skb yet
-                        */
-                       int ip_len = (skb->data[0] & 0x0f) << 2;
-
-                       if (*(__u8 *) (hdr_ptr + 11) &
-                           QETH_EXT_HEADER_CSUM_TRANSP_FRAME_TYPE) {
-                               /* get the UDP checksum */
-                               skb->csum = *(__u16 *)
-                                       (&skb->data[ip_len + 
-                                                   QETH_UDP_CSUM_OFFSET]);
-                       } else {
-                               /* get the TCP checksum */
-                               skb->csum = *(__u16 *)
-                                       (&skb->data[ip_len +
-                                                   QETH_TCP_CSUM_OFFSET]);
-                       }
-#endif /* 0 */
-                       skb->ip_summed=CHECKSUM_UNNECESSARY;
-               } else {
-                       /* make the stack check it */
-                       skb->ip_summed = SW_CHECKSUMMING;
-               }
-       } else
-               skb->ip_summed=card->options.checksum_type;
-
-       __qeth_rebuild_skb_vlan(card, skb, hdr_ptr);
-}
-
-static void
-qeth_read_in_buffer(struct qeth_card *card, int buffer_no)
-{
-       struct sk_buff *skb;
-       void *hdr_ptr;
-       int element = 0, pos_in_el = 0;
-       struct qdio_buffer *buffer;
-       int i;
-       int max_elements;
-       char dbf_text[15];
-       struct net_device *dev;
-
-       dev = card->dev;
-       max_elements = BUFFER_MAX_ELEMENTS;
-
-       buffer = &card->inbound_qdio_buffers[buffer_no];
-
-       /* inform about errors */
-       if (buffer->element[15].flags & 0xff) {
-               PRINT_WARN("on device %s: incoming SBALF 15 on buffer "
-                          "0x%x are 0x%x\n",
-                          CARD_BUS_ID(card), buffer_no,
-                          buffer->element[15].flags & 0xff);
-               sprintf(dbf_text, "SF%s%2x%2x",
-                       CARD_BUS_ID(card), buffer_no,
-                       buffer->element[15].flags & 0xff);
-               QETH_DBF_HEX1(1, trace, dbf_text, QETH_DBF_TRACE_LEN);
-       }
-
-       for (i = 0; i < max_elements - 1; i++) {
-               if (buffer->element[i].flags & SBAL_FLAGS_LAST_ENTRY) {
-                       buffer->element[i + 1].length = 0;
-                       break;
-               }
-       }
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.bufs_rec++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       sprintf(dbf_text, "ribX%s", CARD_BUS_ID(card));
-       dbf_text[3] = buffer_no;
-       QETH_DBF_HEX6(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-
-       while ((skb = qeth_get_next_skb(card, &element, &pos_in_el,
-                                       &hdr_ptr, buffer))) {
-
-#ifdef QETH_PERFORMANCE_STATS
-               card->perf_stats.skbs_rec++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-               if (skb) {
-                       skb->dev = dev;
-
-#ifdef QETH_IPV6
-                       if ((*(__u16 *) (hdr_ptr)) & (QETH_HEADER_PASSTHRU))
-                               skb->protocol = card->type_trans(skb, dev);
-                       else
-#endif /* QETH_IPV6 */
-                               __qeth_rebuild_skb(card, skb, hdr_ptr);
-
-#ifdef QETH_PERFORMANCE_STATS
-                       card->perf_stats.inbound_time +=
-                           NOW - card->perf_stats.inbound_start_time;
-                       card->perf_stats.inbound_cnt++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-                       QETH_DBF_CARD6(0, trace, "rxpk", card);
-
-                       netif_rx(skb);
-                       dev->last_rx = jiffies;
-                       card->stats->rx_packets++;
-                       card->stats->rx_bytes += skb->len;
-               } else {
-                       PRINT_WARN("%s: dropped packet, no buffers "
-                                  "available.\n", card->dev_name);
-                       QETH_DBF_CARD2(1, trace, "DROP", card);
-                       card->stats->rx_dropped++;
-               }
-       }
-       atomic_set(&card->inbound_buffer_refcnt[buffer_no], 0);
-       qeth_put_buffer_pool_entry(card,
-                                  card->inbound_buffer_entry_no[buffer_no]);
-}
-
-static inline void
-__qeth_fill_header_add_vlan(struct qeth_hdr *hdr, struct sk_buff *skb,
-                           int version)
-{
-#ifdef QETH_VLAN
-       struct qeth_card *card;
-
-       /* 
-        * before we're going to overwrite this location with next hop ip.
-        * v6 uses passthrough, v4 sets the tag in the QDIO header.
-        */
-       card = (struct qeth_card *) skb->dev->priv;
-       if ((card->vlangrp != NULL) && vlan_tx_tag_present(skb)) {
-               hdr->ext_flags = (version == 4) ? QETH_EXT_HEADER_VLAN_FRAME :
-                       QETH_EXT_HEADER_INCLUDE_VLAN_TAG;
-               hdr->vlan_id = vlan_tx_tag_get(skb);
-       }
-#endif
-}
-
-static inline __u8
-__qeth_get_flags_v4(int multicast)
-{
-       if (multicast == RTN_MULTICAST)
-               return QETH_CAST_MULTICAST;
-       if (multicast == RTN_BROADCAST)
-               return QETH_CAST_BROADCAST;
-       return QETH_CAST_UNICAST;
-}
-
-static inline __u8
-__qeth_get_flags_v6(int multicast)
-{
-       if (multicast == RTN_MULTICAST)
-               return QETH_CAST_MULTICAST |
-                       QETH_HEADER_PASSTHRU | QETH_HEADER_IPV6;
-       if (multicast == RTN_ANYCAST)
-               return QETH_CAST_ANYCAST |
-                       QETH_HEADER_PASSTHRU | QETH_HEADER_IPV6;
-       if (multicast == RTN_BROADCAST)
-               return QETH_CAST_BROADCAST |
-                       QETH_HEADER_PASSTHRU | QETH_HEADER_IPV6;
-       return QETH_CAST_UNICAST |
-#ifdef QETH_IPV6
-               QETH_HEADER_PASSTHRU |
-#endif /* QETH_IPV6 */
-               QETH_HEADER_IPV6;
-}
-
-static inline void
-qeth_fill_header(struct qeth_hdr *hdr, struct sk_buff *skb,
-                int version, int multicast)
-{
-       char dbf_text[15];
-
-       hdr->id = 1;
-       hdr->ext_flags = 0;
-
-       __qeth_fill_header_add_vlan(hdr, skb, version);
-
-       hdr->length = skb->len - QETH_HEADER_SIZE;      /* as skb->len includes
-                                                          the header now */
-
-       /* yes, I know this is doubled code, but a small little bit
-          faster maybe */
-       if (version == 4) {     /* IPv4 */
-               hdr->flags = __qeth_get_flags_v4(multicast);
-               *((__u32 *) (&hdr->dest_addr[0])) = 0;
-               *((__u32 *) (&hdr->dest_addr[4])) = 0;
-               *((__u32 *) (&hdr->dest_addr[8])) = 0;
-               if ((skb->dst) && (skb->dst->neighbour)) {
-                       *((__u32 *) (&hdr->dest_addr[12])) =
-                           *((__u32 *) skb->dst->neighbour->primary_key);
-               } else {
-                       /* fill in destination address used in ip header */
-                       *((__u32 *) (&hdr->dest_addr[12])) = skb->nh.iph->daddr;
-               }
-       } else if (version == 6) {      /* IPv6 or passthru */
-               hdr->flags = __qeth_get_flags_v6(multicast);
-               if ((skb->dst) && (skb->dst->neighbour)) {
-                       memcpy(hdr->dest_addr,
-                              skb->dst->neighbour->primary_key, 16);
-               } else {
-                       /* fill in destination address used in ip header */
-                       memcpy(hdr->dest_addr, &skb->nh.ipv6h->daddr, 16);
-               }
-       } else {                /* passthrough */
-               if (!memcmp(skb->data + QETH_HEADER_SIZE,
-                           skb->dev->broadcast, 6)) {   /* broadcast? */
-                       hdr->flags = QETH_CAST_BROADCAST | QETH_HEADER_PASSTHRU;
-               } else {
-                       hdr->flags = (multicast == RTN_MULTICAST) ?
-                               QETH_CAST_MULTICAST | QETH_HEADER_PASSTHRU :
-                               QETH_CAST_UNICAST | QETH_HEADER_PASSTHRU;
-               }
-       }
-       sprintf(dbf_text, "filhdr%2x", version);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-       sprintf(dbf_text, "%2x", multicast);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-       QETH_DBF_HEX6(0, trace, &skb, sizeof (void *));
-       QETH_DBF_HEX6(0, trace, &skb->data, sizeof (void *));
-       QETH_DBF_HEX6(0, misc, hdr, __max(QETH_HEADER_SIZE, QETH_DBF_MISC_LEN));
-       QETH_DBF_HEX6(0, data, skb->data,
-                     __max(QETH_DBF_DATA_LEN, QETH_DBF_DATA_LEN));
-}
-
-static inline int
-qeth_fill_buffer(struct qdio_buffer *buffer, char *dataptr,
-                int length, int element)
-{
-       int length_here;
-       int first_lap = 1;
-       char dbf_text[15];
-       int first_element = element;
-
-       while (length > 0) {
-               /* length_here is the remaining amount of data in this page */
-               length_here =
-                   PAGE_SIZE - ((unsigned long) dataptr & (PAGE_SIZE - 1));
-               if (length < length_here)
-                       length_here = length;
-
-               buffer->element[element].addr = dataptr;
-               buffer->element[element].length = length_here;
-               length -= length_here;
-               if (!length) {
-                       if (first_lap) {
-                               buffer->element[element].flags = 0;
-                       } else {
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_LAST_FRAG;
-                       }
-               } else {
-                       if (first_lap) {
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_FIRST_FRAG;
-                       } else {
-                               buffer->element[element].flags =
-                                   SBAL_FLAGS_MIDDLE_FRAG;
-                       }
-               }
-               dataptr = dataptr + length_here;
-               element++;
-               if (element > QDIO_MAX_ELEMENTS_PER_BUFFER) {
-                       PRINT_ERR("qeth_fill_buffer: IP packet too big!\n");
-                       QETH_DBF_TEXT1(0, trace, "IPpktobg");
-                       QETH_DBF_HEX1(1, trace, &dataptr, sizeof (void *));
-                       buffer->element[first_element].length = 0;
-                       break;
-               }
-               first_lap = 0;
-       }
-       sprintf(dbf_text, "filbuf%2x", element);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-       QETH_DBF_HEX3(0, misc, buffer, QETH_DBF_MISC_LEN);
-       QETH_DBF_HEX3(0, misc, buffer + QETH_DBF_MISC_LEN, QETH_DBF_MISC_LEN);
-
-       return element;
-}
-
-static inline void
-qeth_flush_packed_packets(struct qeth_card *card, int queue, int under_int)
-{
-       struct qdio_buffer *buffer;
-       int result;
-       int position;
-       int position_for_do_qdio;
-       char dbf_text[15];
-       int last_pci;
-
-       position = card->outbound_first_free_buffer[queue];
-       /* can happen, when in the time between deciding to pack and sending
-          the next packet the lower mark was reached: */
-       if (!card->outbound_ringbuffer[queue]->ringbuf_element[position].
-           next_element_to_fill)
-               return;
-
-       buffer = &card->outbound_ringbuffer[queue]->buffer[position];
-       buffer->element[card->outbound_ringbuffer[queue]->
-                       ringbuf_element[position].
-                       next_element_to_fill - 1].flags |=
-           SBAL_FLAGS_LAST_ENTRY;
-
-       card->dev->trans_start = jiffies;
-
-#ifdef QETH_PERFORMANCE_STATS
-       if (card->outbound_buffer_send_state[queue][position] ==
-           SEND_STATE_DONT_PACK) {
-               card->perf_stats.bufs_sent_dont_pack++;
-       } else if (card->outbound_buffer_send_state[queue][position] ==
-                  SEND_STATE_PACK) {
-               card->perf_stats.bufs_sent_pack++;
-       }
-       card->perf_stats.bufs_sent++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       position_for_do_qdio = position;
-
-       position = (position + 1) & (QDIO_MAX_BUFFERS_PER_Q - 1);
-       card->outbound_first_free_buffer[queue] = position;
-
-       card->outbound_bytes_in_buffer[queue] = 0;
-       /* we can override that, as we have at most 127 buffers enqueued */
-       card->outbound_ringbuffer[queue]->ringbuf_element[position].
-           next_element_to_fill = 0;
-
-       atomic_inc(&card->outbound_used_buffers[queue]);
-
-       QETH_DBF_CARD5(0, trace, "flsp", card);
-       sprintf(dbf_text, "%4x%2x%2x", position_for_do_qdio, under_int, queue);
-       QETH_DBF_TEXT5(0, trace, dbf_text);
-       QETH_DBF_HEX5(0, misc, buffer, QETH_DBF_MISC_LEN);
-       QETH_DBF_HEX5(0, misc, buffer + QETH_DBF_MISC_LEN, QETH_DBF_MISC_LEN);
-
-       /* 
-        * we always set the outbound pci flag, don't care, whether the
-        * adapter honors it or not
-        */
-       switch (card->send_state[queue]) {
-       case SEND_STATE_DONT_PACK:
-               if (atomic_read(&card->outbound_used_buffers[queue])
-                   < HIGH_WATERMARK_PACK - WATERMARK_FUZZ)
-                       break;
-               /* set the PCI bit */
-               card->outbound_ringbuffer[queue]->
-                   buffer[position_for_do_qdio].element[0].flags |= 0x40;
-               atomic_set(&card->last_pci_pos[queue], position_for_do_qdio);
-               break;
-       case SEND_STATE_PACK:
-               last_pci = atomic_read(&card->last_pci_pos[queue]);
-               if (position_for_do_qdio < last_pci)
-                       last_pci -= QDIO_MAX_BUFFERS_PER_Q;
-               /* so:
-                * last_pci is the position of the last pci we've set
-                * position_for_do_qdio is the position we will send out now
-                * outbound_used_buffers is the number of buffers used (means
-                *   all buffers hydra has, inclusive position_for_do_qdio)
-                *
-                * we have to request a pci, if we have got the buffer of the
-                * last_pci position back.
-                *
-                * position_for_do_qdio-outbound_used_buffers is the newest
-                *   buffer that we got back from hydra
-                *
-                * if this is greater or equal than the last_pci position,
-                * we should request a pci, as no pci request is
-                * outstanding anymore
-                */
-               if (position_for_do_qdio -
-                   atomic_read(&card->outbound_used_buffers[queue]) >=
-                   last_pci) {
-                       /* set the PCI bit */
-                       card->outbound_ringbuffer[queue]->
-                           buffer[position_for_do_qdio].
-                           element[0].flags |= 0x40;
-                       atomic_set(&card->last_pci_pos[queue],
-                                  position_for_do_qdio);
-               }
-       }
-
-       /* 
-        * this has to be at the end, otherwise a buffer could be flushed
-        * twice (see comment in qeth_do_send_packet)
-        */
-       result = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_OUTPUT | under_int, queue,
-                        position_for_do_qdio, 1, NULL);
-
-       if (result) {
-               PRINT_WARN("Outbound do_QDIO returned %i "
-                          "(device %s)\n", result, CARD_DDEV_ID(card));
-               QETH_DBF_CARD5(0, trace, "FLSP", card);
-               sprintf(dbf_text, "odoQ%4x", result);
-               QETH_DBF_TEXT5(0, trace, dbf_text);
-               sprintf(dbf_text, "%4x%2x%2x", position_for_do_qdio,
-                       under_int, queue);
-               QETH_DBF_TEXT5(0, trace, dbf_text);
-               QETH_DBF_HEX5(0, misc, buffer, QETH_DBF_MISC_LEN);
-               QETH_DBF_HEX5(0, misc, buffer + QETH_DBF_MISC_LEN,
-                             QETH_DBF_MISC_LEN);
-       }
-}
-
-#define ERROR_NONE 0
-#define ERROR_RETRY 1
-#define ERROR_LINK_FAILURE 2
-#define ERROR_KICK_THAT_PUPPY 3
-static inline int
-qeth_determine_send_error(int cc, int qdio_error, int sbalf15)
-{
-       char dbf_text[15];
-
-       switch (cc & 3) {
-       case 0:
-               if (qdio_error)
-                       return ERROR_LINK_FAILURE;
-               return ERROR_NONE;
-       case 2:
-               if (cc & QDIO_SIGA_ERROR_B_BIT_SET) {
-                       QETH_DBF_TEXT3(0, trace, "sigacc2b");
-                       return ERROR_KICK_THAT_PUPPY;
-               }
-               if (qeth_sbalf15_in_retrieable_range(sbalf15))
-                       return ERROR_RETRY;
-               return ERROR_LINK_FAILURE;
-               /* look at qdio_error and sbalf 15 */
-       case 1:
-               PRINT_WARN("siga returned cc 1! cc=0x%x, "
-                          "qdio_error=0x%x, sbalf15=0x%x\n",
-                          cc, qdio_error, sbalf15);
-
-               QETH_DBF_TEXT3(0, trace, "siga-cc1");
-               QETH_DBF_TEXT2(0, qerr, "siga-cc1");
-               sprintf(dbf_text, "%1x%2x%2x", cc, qdio_error, sbalf15);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               QETH_DBF_TEXT2(0, qerr, dbf_text);
-               return ERROR_LINK_FAILURE;
-       case 3:
-               QETH_DBF_TEXT3(0, trace, "siga-cc3");
-               return ERROR_KICK_THAT_PUPPY;
-       }
-       return ERROR_LINK_FAILURE;      /* should never happen */
-}
-
-static inline void
-qeth_free_buffer(struct qeth_card *card, int queue, int bufno,
-                int qdio_error, int siga_error)
-{
-       struct sk_buff *skb;
-       int error;
-       int retries;
-       int sbalf15;
-       char dbf_text[15];
-       struct qdio_buffer *buffer;
-
-       switch (card->outbound_buffer_send_state[queue][bufno]) {
-       case SEND_STATE_DONT_PACK:      /* fallthrough */
-       case SEND_STATE_PACK:
-               QETH_DBF_CARD5(0, trace, "frbf", card);
-               sprintf(dbf_text, "%2x%2x%4x", queue, bufno,
-                       card->outbound_buffer_send_state[queue][bufno]);
-               QETH_DBF_TEXT5(0, trace, dbf_text);
-
-               buffer = &card->outbound_ringbuffer[queue]->buffer[bufno];
-               sbalf15 = buffer->element[15].flags & 0xff;
-               error =
-                   qeth_determine_send_error(siga_error, qdio_error, sbalf15);
-               if (error == ERROR_KICK_THAT_PUPPY) {
-                       sprintf(dbf_text, "KP%s%2x",
-                               CARD_BUS_ID(card), queue);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       QETH_DBF_TEXT2(0, qerr, dbf_text);
-                       QETH_DBF_TEXT2(1, setup, dbf_text);
-                       sprintf(dbf_text, "%2x%2x%2x%2x", bufno,
-                               siga_error, qdio_error, sbalf15);
-                       QETH_DBF_TEXT2(1, trace, dbf_text);
-                       QETH_DBF_TEXT2(1, qerr, dbf_text);
-                       PRINT_ERR("Outbound queue x%x on device %s (%s); "
-                                 "errs: siga: x%x, qdio: x%x, flags15: "
-                                 "x%x. The device will be taken down.\n",
-                                 queue, CARD_BUS_ID(card), card->dev_name,
-                                 siga_error, qdio_error, sbalf15);
-                       netif_stop_queue(card->dev);
-                       qeth_set_dev_flag_norunning(card);
-                       atomic_set(&card->problem, PROBLEM_BAD_SIGA_RESULT);
-                       qeth_schedule_recovery(card);
-               } else if (error == ERROR_RETRY) {
-                       /* analyze, how many retries we did so far */
-                       retries = card->send_retries[queue][bufno];
-
-                       sprintf(dbf_text, "Rt%s%2x",
-                               CARD_BUS_ID(card), queue);
-                       QETH_DBF_TEXT4(0, trace, dbf_text);
-                       sprintf(dbf_text, "b%2x:%2x%2x", bufno,
-                               sbalf15, retries);
-                       QETH_DBF_TEXT4(0, trace, dbf_text);
-
-                       if (++retries > SEND_RETRIES_ALLOWED) {
-                               error = ERROR_LINK_FAILURE;
-                               QETH_DBF_TEXT4(1, trace, "ndegelnd");
-                       }
-                       /* else error stays RETRY for the switch statemnet */
-               } else if (error == ERROR_LINK_FAILURE) {
-                       /* we don't want to log failures resulting from
-                        * too many retries */
-                       QETH_DBF_CARD3(1, trace, "Fail", card);
-                       QETH_DBF_HEX3(0, misc, buffer, QETH_DBF_MISC_LEN);
-                       QETH_DBF_HEX3(0, misc, buffer + QETH_DBF_MISC_LEN,
-                                     QETH_DBF_MISC_LEN);
-               }
-
-               while ((skb = skb_dequeue(&card->outbound_ringbuffer[queue]->
-                                         ringbuf_element[bufno].skb_list))) {
-                       switch (error) {
-                       case ERROR_NONE:
-                               atomic_dec(&skb->users);
-                               dev_kfree_skb_irq(skb);
-                               break;
-                       case ERROR_RETRY:
-                               QETH_DBF_TEXT3(0, qerr, "RETRY!!!");
-                               QETH_DBF_TEXT4(0, trace, "RETRY!!!");
-                               atomic_dec(&skb->users);
-                               /* retry packet async (quickly) ... */
-                               atomic_dec(&skb->users);
-                               dev_kfree_skb_irq(skb);
-                               break;
-                       case ERROR_LINK_FAILURE:
-                       case ERROR_KICK_THAT_PUPPY:
-                               QETH_DBF_TEXT4(0, trace, "endeglnd");
-                               atomic_dec(&skb->users);
-                               dev_kfree_skb_irq(skb);
-                               break;
-                       }
-               }
-               break;
-       default:
-               PRINT_WARN("oops... wrong send_state on %s. "
-                          "shouldn't happen "
-                          "(line %i). q=%i, bufno=x%x, state=%i\n",
-                          card->dev_name, __LINE__, queue, bufno,
-                          card->outbound_buffer_send_state[queue][bufno]);
-               QETH_DBF_CARD0(1, trace, "UPSf", card);
-               QETH_DBF_CARD0(1, qerr, "UPSf", card);
-               sprintf(dbf_text, "%2x%2x%4x", queue, bufno,
-                       card->outbound_buffer_send_state[queue][bufno]);
-               QETH_DBF_TEXT0(1, trace, dbf_text);
-               QETH_DBF_TEXT0(1, qerr, dbf_text);
-       }
-       card->outbound_buffer_send_state[queue][bufno] = SEND_STATE_INACTIVE;
-       card->send_retries[queue][bufno] = 0;
-}
-
-static inline void
-qeth_free_all_skbs(struct qeth_card *card)
-{
-       int q, b;
-
-       for (q = 0; q < card->no_queues; q++)
-               for (b = 0; b < QDIO_MAX_BUFFERS_PER_Q; b++)
-                       if (card->outbound_buffer_send_state[q][b] !=
-                           SEND_STATE_INACTIVE)
-                               qeth_free_buffer(card, q, b, 0, 0);
-}
-
-static inline void
-qeth_flush_buffer(struct qeth_card *card, int queue, int under_int)
-{
-       char dbf_text[15];
-       QETH_DBF_CARD5(0, trace, "flsb", card);
-       sprintf(dbf_text, "%2x%2x%2x", queue, under_int,
-               card->outbound_buffer_send_state[queue]
-               [card->outbound_first_free_buffer[queue]]);
-       QETH_DBF_TEXT5(0, trace, dbf_text);
-
-       switch (card->outbound_buffer_send_state[queue]
-               [card->outbound_first_free_buffer[queue]]) {
-       case SEND_STATE_DONT_PACK:
-               break;
-       case SEND_STATE_PACK:
-               qeth_flush_packed_packets(card, queue, under_int);
-               break;
-       default:
-               break;
-       }
-}
-
-#ifdef QETH_VLAN
-static inline void
-qeth_insert_ipv6_vlan_tag(struct sk_buff *__skb)
-{
-
-       /* Move the mac addresses to the beginning of the new header.
-        * We are using three memcpys instead of one memmove to save cycles.
-        */
-#define TMP_CPYSIZE 4
-       __u16 *tag;
-       tag = (__u16 *) skb_push(__skb, VLAN_HLEN);
-       memcpy(__skb->data, __skb->data + TMP_CPYSIZE, TMP_CPYSIZE);
-       memcpy(__skb->data + TMP_CPYSIZE,
-              __skb->data + (2 * TMP_CPYSIZE), TMP_CPYSIZE);
-       memcpy(__skb->data + (2 * TMP_CPYSIZE),
-              __skb->data + (3 * TMP_CPYSIZE), TMP_CPYSIZE);
-       tag = (__u16 *) (__skb->data + (3 * TMP_CPYSIZE));
-
-       /*first two bytes  = ETH_P_8021Q (0x8100)
-        *second two bytes = VLANID
-        */
-
-       *tag = __constant_htons(ETH_P_8021Q);
-       *(tag + 1) = vlan_tx_tag_get(__skb);
-       *(tag + 1) = htons(*(tag + 1));
-#undef TMP_CPYSIZE
-}
-#endif
-
-static inline void
-__qeth_add_vlan_tag(struct qeth_card *card, struct sk_buff *skb, int version)
-{
-#ifdef QETH_VLAN
-       if ((card->vlangrp != NULL) &&
-           vlan_tx_tag_present(skb) && (version == 6)) {
-               qeth_insert_ipv6_vlan_tag(skb);
-       }
-#endif
-}
-
-static inline void
-qeth_send_packet_fast(struct qeth_card *card, struct sk_buff *skb,
-                     struct net_device *dev,
-                     int queue, int version, int multicast)
-{
-       struct qeth_ringbuffer_element *mybuffer;
-       int position;
-       struct qeth_hdr *hdr;
-       char *dataptr;
-       char dbf_text[15];
-       struct sk_buff *nskb;
-
-       position = card->outbound_first_free_buffer[queue];
-
-       card->outbound_buffer_send_state[queue][position] =
-           SEND_STATE_DONT_PACK;
-
-       mybuffer = &card->outbound_ringbuffer[queue]->ringbuf_element[position];
-       if (skb_headroom(skb) < QETH_HEADER_SIZE) {
-               if ((version) && (!card->realloc_message)) {
-                       card->realloc_message = 1;
-                       PRINT_WARN("%s: not enough headroom in skb. "
-                                  "Increasing the "
-                                  "add_hhlen parameter by %i may help.\n",
-                                  card->dev_name,
-                                  QETH_HEADER_SIZE - skb_headroom(skb));
-               }
-               PRINT_STUPID("%s: not enough headroom in skb (missing: %i)\n",
-                            card->dev_name,
-                            QETH_HEADER_SIZE - skb_headroom(skb));
-               QETH_DBF_CARD3(0, trace, "NHRf", card);
-               sprintf(dbf_text, "%2x%2x%2x%2x", skb_headroom(skb),
-                       version, multicast, queue);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               QETH_DBF_HEX3(0, trace, &skb->head, sizeof (void *));
-               QETH_DBF_HEX3(0, trace, &skb->data, sizeof (void *));
-               nskb = skb_realloc_headroom(skb, QETH_HEADER_SIZE);
-               if (!nskb) {
-                       PRINT_WARN("%s: could not realloc headroom\n",
-                                  card->dev_name);
-                       QETH_DBF_CARD2(0, trace, "CNRf", card);
-                       dev_kfree_skb_irq(skb);
-                       return;
-               }
-               dev_kfree_skb_irq(skb);
-               skb = nskb;
-       }
-       __qeth_add_vlan_tag(card, skb, version);
-       hdr = (struct qeth_hdr *) (skb_push(skb, QETH_HEADER_SIZE));
-       /* 
-        * sanity check, the Linux memory allocation scheme should
-        * never present us cases like this one (the 32bytes header plus
-        * the first 40 bytes of the paket cross a 4k boundary)
-        */
-       dataptr = (char *) hdr;
-       if ((((unsigned long) dataptr) & (~(PAGE_SIZE - 1))) !=
-           (((unsigned long) dataptr + QETH_HEADER_SIZE +
-             QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
-               PRINT_ERR("%s: packet misaligned -- the first %i bytes "
-                         "are not in the same page. Discarding packet!\n",
-                         card->dev_name,
-                         QETH_HEADER_SIZE + QETH_IP_HEADER_SIZE);
-               PRINT_ERR("head=%p, data=%p\n", skb->head, skb->data);
-               QETH_DBF_CARD1(0, trace, "PMAf", card);
-               sprintf(dbf_text, "%2x%2x%2x%2x", skb_headroom(skb),
-                       version, multicast, queue);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_HEX1(0, trace, &skb->head, sizeof (void *));
-               QETH_DBF_HEX1(1, trace, &skb->data, sizeof (void *));
-               dev_kfree_skb_irq(skb);
-               return;
-       }
-
-       atomic_inc(&skb->users);
-       skb_queue_tail(&mybuffer->skb_list, skb);
-       qeth_fill_header(hdr, skb, version, multicast);
-       /* we need to write to next_element_to_fill as
-          qeth_flush_packed_packets checks it */
-       card->outbound_ringbuffer[queue]->ringbuf_element[position].
-           next_element_to_fill =
-           qeth_fill_buffer(&card->outbound_ringbuffer[queue]->
-                            buffer[position], (char *) hdr, skb->len, 0);
-
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.skbs_sent_dont_pack++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       qeth_flush_packed_packets(card, queue, 0);
-}
-
-/* no checks, if all elements are used, as then we would not be here (at most
-   127 buffers are enqueued) */
-static inline void
-qeth_send_packet_packed(struct qeth_card *card, struct sk_buff *skb,
-                       struct net_device *dev,
-                       int queue, int version, int multicast)
-{
-       struct qeth_ringbuffer_element *mybuffer;
-       int elements_needed;
-       int element_to_fill;
-       int buffer_no;
-       int length;
-       char *dataptr;
-       struct qeth_hdr *hdr;
-       char dbf_text[15];
-       struct sk_buff *nskb;
-
-       /* sanity check, dev->hard_header_len should prevent this */
-       if (skb_headroom(skb) < QETH_HEADER_SIZE) {
-               if ((version) && (!card->realloc_message)) {
-                       card->realloc_message = 1;
-                       PRINT_WARN("%s: not enough headroom in skb. "
-                                  "Try increasing the "
-                                  "add_hhlen parameter by %i.\n",
-                                  card->dev_name,
-                                  QETH_HEADER_SIZE - skb_headroom(skb));
-               }
-               PRINT_STUPID("%s: not enough headroom in skb (missing: %i)\n",
-                            card->dev_name,
-                            QETH_HEADER_SIZE - skb_headroom(skb));
-               QETH_DBF_CARD3(0, trace, "NHRp", card);
-               sprintf(dbf_text, "%2x%2x%2x%2x", skb_headroom(skb),
-                       version, multicast, queue);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               QETH_DBF_HEX3(0, trace, &skb->head, sizeof (void *));
-               QETH_DBF_HEX3(0, trace, &skb->data, sizeof (void *));
-               nskb = skb_realloc_headroom(skb, QETH_HEADER_SIZE);
-               if (!nskb) {
-                       PRINT_WARN("%s: could not realloc headroom\n",
-                                  card->dev_name);
-                       QETH_DBF_CARD2(0, trace, "CNRp", card);
-                       dev_kfree_skb_irq(skb);
-                       return;
-               }
-               dev_kfree_skb_irq(skb);
-               skb = nskb;
-       }
-       __qeth_add_vlan_tag(card, skb, version);
-       hdr = (struct qeth_hdr *) (skb_push(skb, QETH_HEADER_SIZE));
-
-       length = skb->len;
-
-       /* 
-        * sanity check, the Linux memory allocation scheme should
-        * never present us cases like this one (the 32bytes header plus
-        * the first 40 bytes of the paket cross a 4k boundary)
-        */
-       dataptr = (char *) hdr;
-       if ((((unsigned long) dataptr) & (~(PAGE_SIZE - 1))) !=
-           (((unsigned long) dataptr + QETH_HEADER_SIZE +
-             QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
-               PRINT_ERR("%s: packet misaligned -- the first %i bytes "
-                         "are not in the same page. Discarding packet!\n",
-                         card->dev_name,
-                         QETH_HEADER_SIZE + QETH_IP_HEADER_SIZE);
-               QETH_DBF_CARD1(0, trace, "PMAp", card);
-               sprintf(dbf_text, "%2x%2x%2x%2x", skb_headroom(skb),
-                       version, multicast, queue);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_HEX1(0, trace, &skb->head, sizeof (void *));
-               QETH_DBF_HEX1(1, trace, &skb->data, sizeof (void *));
-               dev_kfree_skb_irq(skb);
-               return;
-       }
-
-       buffer_no = card->outbound_first_free_buffer[queue];
-
-       element_to_fill = card->outbound_ringbuffer[queue]->
-           ringbuf_element[buffer_no].next_element_to_fill;
-
-       elements_needed = 1 + (((((unsigned long) dataptr) & (PAGE_SIZE - 1)) +
-                               length) >> PAGE_SHIFT);
-       if ((elements_needed > (QDIO_MAX_ELEMENTS_PER_BUFFER - element_to_fill))
-           ||
-           ((elements_needed ==
-             (QDIO_MAX_ELEMENTS_PER_BUFFER - element_to_fill))
-            && ((element_to_fill >> PAGE_SHIFT) ==
-                card->outbound_bytes_in_buffer[queue]))) {
-               qeth_flush_packed_packets(card, queue, 0);
-               element_to_fill = 0;
-               card->outbound_bytes_in_buffer[queue] = 0;
-               buffer_no = (buffer_no + 1) & (QDIO_MAX_BUFFERS_PER_Q - 1);
-       }
-
-       if (!element_to_fill)
-               card->outbound_buffer_send_state[queue][buffer_no]
-                   = SEND_STATE_PACK;
-
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.skbs_sent_pack++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       mybuffer =
-           &card->outbound_ringbuffer[queue]->ringbuf_element[buffer_no];
-       atomic_inc(&skb->users);
-       skb_queue_tail(&mybuffer->skb_list, skb);
-       qeth_fill_header(hdr, skb, version, multicast);
-       card->outbound_bytes_in_buffer[queue] += length + QETH_HEADER_SIZE;
-       card->outbound_ringbuffer[queue]->ringbuf_element[buffer_no].
-           next_element_to_fill =
-           qeth_fill_buffer(&card->outbound_ringbuffer[queue]->
-                            buffer[buffer_no],
-                            dataptr, length, element_to_fill);
-}
-
-static void
-qeth_alloc_spare_bufs(void)
-{
-       int i;
-       int dont_alloc_more = 0;
-       char dbf_text[15];
-
-       sparebuffer_count = 0;
-       for (i = 0; i < qeth_sparebufs; i++) {
-               if (!dont_alloc_more) {
-                       sparebufs[i].buf = (char *)
-                           kmalloc(DEFAULT_BUFFER_SIZE, GFP_KERNEL);
-                       if (sparebufs[i].buf)
-                               sparebuffer_count++;
-                       else
-                               dont_alloc_more = 1;
-               }
-               atomic_set(&sparebufs[i].status, (dont_alloc_more) ?
-                          SPAREBUF_UNAVAIL : SPAREBUF_FREE);
-       }
-       sprintf(dbf_text, "alspb%3x", sparebuffer_count);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       PRINT_INFO("allocated %i spare buffers\n", sparebuffer_count);
-}
-
-static void
-qeth_free_all_spare_bufs(void)
-{
-       int i;
-
-       QETH_DBF_TEXT2(0, trace, "frealspb");
-
-       for (i = 0; i < qeth_sparebufs; i++)
-               if (atomic_read(&sparebufs[i].status) != SPAREBUF_UNAVAIL) {
-                       kfree(sparebufs[i].buf);
-                       atomic_set(&sparebufs[i].status, SPAREBUF_UNAVAIL);
-               }
-}
-
-static inline void
-__qeth_dump_packet_info(struct qeth_card *card, int version, int multicast,
-                       int queue)
-{
-       char dbf_text[15];
-
-       QETH_DBF_CARD6(0, trace, "dsp:", card);
-       sprintf(dbf_text, "%c %c%4x",
-               (version == 4) ? '4' : ((version == 6) ? '6' : '0'),
-               (multicast) ? 'm' : '_', queue);
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x%4x",
-               card->outbound_first_free_buffer[queue],
-               atomic_read(&card->outbound_used_buffers[queue]));
-       QETH_DBF_TEXT6(0, trace, dbf_text);
-       if (qeth_sbal_packing_on_card(card->type)) {
-               switch (card->send_state[queue]) {
-               case SEND_STATE_DONT_PACK:
-                       QETH_DBF_TEXT6(0, trace, "usngfast");
-                       break;
-               case SEND_STATE_PACK:
-                       QETH_DBF_TEXT6(0, trace, "usngpack");
-                       break;
-               }
-       } else {
-               QETH_DBF_TEXT6(0, trace, "usngfast");
-       }
-}
-
-static inline void
-__qeth_switch_state_if_needed(struct qeth_card *card, int queue)
-{
-       if (atomic_read(&card->outbound_used_buffers[queue])
-           >= HIGH_WATERMARK_PACK) {
-               card->send_state[queue] = SEND_STATE_PACK;
-               QETH_DBF_CARD3(0, trace, "stchup", card);
-#ifdef QETH_PERFORMANCE_STATS
-               card->perf_stats.sc_dp_p++;
-#endif /* QETH_PERFORMANCE_STATS */
-       }
-}
-
-static inline int
-qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
-                   struct net_device *dev)
-{
-       int queue, result = 0;
-       int multicast, version;
-
-       version = QETH_IP_VERSION(skb);
-       multicast = qeth_is_multicast_skb_at_all(skb, version);
-       queue = qeth_get_prioqueue(card, skb, multicast, version);
-
-       __qeth_dump_packet_info(card, version, multicast, queue);
-
-       if (atomic_read(&card->outbound_used_buffers[queue])
-           >= QDIO_MAX_BUFFERS_PER_Q - 1) {
-               QETH_DBF_CARD2(1, trace, "cdbs", card);
-               netif_stop_queue(dev);
-               return -EBUSY;
-       }
-
-       /* 
-        * we are not called under int, so we just spin
-        * happens around once a second under heavy traffic. takes a little
-        * bit less than 10usec in avg. on a z900
-        */
-       if (atomic_compare_and_swap(QETH_LOCK_UNLOCKED, QETH_LOCK_NORMAL,
-                                   &card->outbound_ringbuffer_lock[queue])) {
-               QETH_DBF_CARD2(0, trace, "SPIN", card);
-               while (atomic_compare_and_swap
-                      (QETH_LOCK_UNLOCKED, QETH_LOCK_NORMAL,
-                       &card->outbound_ringbuffer_lock[queue])) ;
-               QETH_DBF_CARD2(0, trace, "spin", card);
-       }
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.skbs_sent++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       if (qeth_sbal_packing_on_card(card->type)) {
-               switch (card->send_state[queue]) {
-               case SEND_STATE_DONT_PACK:
-                       qeth_send_packet_fast(card, skb, dev, queue,
-                                             version, multicast);
-                       __qeth_switch_state_if_needed(card, queue);
-                       break;
-               case SEND_STATE_PACK:
-                       qeth_send_packet_packed(card, skb, dev, queue,
-                                               version, multicast);
-                       break;
-               default:
-                       result = -EBUSY;
-                       QETH_DBF_CARD0(1, trace, "UPSs", card);
-                       PRINT_ALL("oops... shouldn't happen (line %i:%i).\n",
-                                 __LINE__, card->send_state[queue]);
-               }
-       } else {
-               qeth_send_packet_fast(card, skb, dev, queue,
-                                     version, multicast);
-       }
-
-       /* ATOMIC: (NORMAL->UNLOCKED, FLUSH->NORMAL) */
-       while (atomic_dec_return(&card->outbound_ringbuffer_lock[queue])) {
-               qeth_flush_buffer(card, queue, 0);
-               card->send_state[queue] = SEND_STATE_DONT_PACK;
-       }
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.outbound_time +=
-           NOW - card->perf_stats.outbound_start_time;
-       card->perf_stats.outbound_cnt++;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       card->stats->tx_packets++;
-       card->stats->tx_bytes += skb->len;
-
-       return result;
-}
-
-static int
-qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct qeth_card *card;
-       int result;
-
-       card = (struct qeth_card *) (dev->priv);
-
-       if (skb == NULL)
-               return 0;
-
-       QETH_DBF_HEX4(0, data, skb->data, __max(QETH_DBF_DATA_LEN, skb->len));
-
-       netif_stop_queue(dev);
-
-       if (!card) {
-               QETH_DBF_TEXT2(0, trace, "XMNSNOCD");
-               dev_kfree_skb_irq(skb);
-               return 0;
-       }
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.outbound_start_time = NOW;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       if (!atomic_read(&card->is_startlaned)) {
-               card->stats->tx_carrier_errors++;
-               QETH_DBF_CARD2(0, trace, "XMNS", card);
-               dev_kfree_skb_irq(skb);
-               return 0;
-       }
-
-       result = qeth_do_send_packet(card, skb, dev);
-
-       if (!result)
-               netif_wake_queue(card->dev);
-
-       return result;
-}
-
-static struct net_device_stats *
-qeth_get_stats(struct net_device *dev)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) (dev->priv);
-
-       QETH_DBF_CARD3(0, trace, "gtst", card);
-
-       return card->stats;
-}
-
-static int
-qeth_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct qeth_card *card;
-       char dbf_text[15];
-
-       card = (struct qeth_card *) (dev->priv);
-
-       QETH_DBF_CARD2(0, trace, "mtu", card);
-       sprintf(dbf_text, "%8x", new_mtu);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       if (new_mtu < 64)
-               return -EINVAL;
-       if (new_mtu > 65535)
-               return -EINVAL;
-       if ((!qeth_is_supported(IPA_IP_FRAGMENTATION)) &&
-           (!qeth_mtu_is_valid(card, new_mtu)))
-               return -EINVAL;
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-static void
-qeth_start_softsetup_thread(struct qeth_card *card)
-{
-       if (!atomic_read(&card->shutdown_phase)) {
-               QETH_DBF_CARD2(0, trace, "stss", card);
-               up(&card->softsetup_thread_sem);
-       }
-}
-
-static int
-qeth_sleepon(struct qeth_card *card, int timeout)
-{
-       char dbf_text[15];
-
-       QETH_DBF_CARD5(0, trace, "slpn", card);
-       sprintf(dbf_text, "%08x", timeout);
-       QETH_DBF_TEXT5(0, trace, dbf_text);
-
-       wait_event_interruptible_timeout(card->wait_q,
-                                        atomic_read(&card->data_has_arrived),
-                                        timeout * HZ);
-       if (atomic_read(&card->data_has_arrived)) {
-               atomic_set(&card->data_has_arrived, 0);
-               return 0;
-       }
-       return -ETIME;
-}
-
-static void
-qeth_wakeup_ioctl(struct qeth_card *card)
-{
-
-       QETH_DBF_CARD5(0, trace, "wkup", card);
-
-       atomic_set(&card->ioctl_data_has_arrived, 1);
-       wake_up(&card->ioctl_wait_q);
-}
-
-static int
-qeth_sleepon_ioctl(struct qeth_card *card, int timeout)
-{
-       char dbf_text[15];
-
-       QETH_DBF_CARD5(0, trace, "ioctlslpn", card);
-       sprintf(dbf_text, "%08x", timeout);
-       QETH_DBF_TEXT5(0, trace, dbf_text);
-
-       wait_event_interruptible_timeout(card->ioctl_wait_q,
-                                        atomic_read(&card->
-                                                    ioctl_data_has_arrived),
-                                        timeout * HZ);
-       if (atomic_read(&card->ioctl_data_has_arrived)) {
-               atomic_set(&card->ioctl_data_has_arrived, 0);
-               return 0;
-       }
-       return -ETIME;
-}
-
-/*SNMP IOCTL on Procfile */
-
-static void
-qeth_wakeup_procfile(void)
-{
-       QETH_DBF_TEXT5(0, trace, "procwkup");
-       /* is this if statement correct? */
-       if (atomic_read(&qeth_procfile_ioctl_sem.count) <=
-           PROCFILE_SLEEP_SEM_MAX_VALUE)
-               up(&qeth_procfile_ioctl_sem);
-}
-
-static int
-qeth_sleepon_procfile(void)
-{
-       QETH_DBF_TEXT5(0, trace, "procslp");
-       if (down_interruptible(&qeth_procfile_ioctl_sem)) {
-               return -ERESTARTSYS;
-       }
-       return 0;
-}
-
-/* SNMP END */
-
-static char *
-qeth_send_control_data(struct qeth_card *card, unsigned char *buffer,
-                      int len, unsigned long intparam)
-{
-       unsigned long flags;
-       int result, result2;
-       char dbf_text[15];
-       unsigned char *rec_buf;
-       int setip = (intparam & IPA_SETIP_FLAG) ? 1 : 0;
-
-again:
-       if (atomic_read(&card->shutdown_phase) == QETH_REMOVE_CARD_QUICK)
-               return NULL;
-       if (atomic_read(&card->escape_softsetup))
-               return NULL;
-
-       /* we lock very early to synchronize access to seqnos */
-       if (atomic_swap(&card->write_busy, 1)) {
-               qeth_wait_nonbusy(QETH_IDLE_WAIT_TIME);
-               QETH_DBF_CARD2(0, trace, "LSCD", card);
-               goto again;
-       }
-       memcpy(card->dma_stuff->sendbuf, card->send_buf, QETH_BUFSIZE);
-
-       memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(buffer),
-              &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
-       card->seqno.trans_hdr++;
-
-       memcpy(QETH_PDU_HEADER_SEQ_NO(buffer),
-              &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH);
-       card->seqno.pdu_hdr++;
-       memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(buffer),
-              &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
-
-       /* there is noone doing this except sleep and this function */
-       atomic_set(&card->data_has_arrived, 0);
-
-       memcpy(&card->dma_stuff->write_ccw, WRITE_CCW, sizeof (struct ccw1));
-       card->dma_stuff->write_ccw.count = len;
-       card->dma_stuff->write_ccw.cda =
-           QETH_GET_ADDR(card->dma_stuff->sendbuf);
-
-       QETH_DBF_CARD2(0, trace, "scdw", card);
-       sprintf(dbf_text, "%8x", len);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       QETH_DBF_HEX4(0, trace, &intparam, QETH_DBF_TRACE_LEN);
-       QETH_DBF_HEX2(0, control, buffer, QETH_DBF_CONTROL_LEN);
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_WDEV(card)), flags);
-       result = ccw_device_start(CARD_WDEV(card), &card->dma_stuff->write_ccw,
-                                 intparam, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 = ccw_device_start(CARD_WDEV(card),
-                                          &card->dma_stuff->write_ccw,
-                                          intparam, 0, 0);
-               if (result2 != -ENODEV)
-                       PRINT_WARN("qeth_send_control_data: do_IO "
-                                  "returned %i, next try returns %i\n",
-                                  result, result2);
-               result = result2;
-       }
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_WDEV(card)), flags);
-
-       if (result) {
-               QETH_DBF_TEXT2(0, trace, "scd:doio");
-               sprintf(dbf_text, "%4x", (__s16) result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               /* re-enable qeth_send_control_data again */
-               atomic_set(&card->write_busy,0);
-               return NULL;
-       }
-
-       if (intparam == IPA_IOCTL_STATE) {
-               if (qeth_sleepon_ioctl(card, QETH_IPA_TIMEOUT)) {
-                       QETH_DBF_TEXT2(0, trace, "scd:ioctime");
-                       /* re-enable qeth_send_control_data again */
-                       atomic_set(&card->write_busy, 0);
-                       return NULL;
-               }
-               rec_buf = card->dma_stuff->recbuf;
-               QETH_DBF_CARD2(0, trace, "scro", card);
-       } else {
-               if (qeth_sleepon(card, (setip) ? QETH_IPA_TIMEOUT :
-                                QETH_MPC_TIMEOUT)) {
-                       QETH_DBF_TEXT2(0, trace, "scd:time");
-                       /* re-enable qeth_send_control_data again */
-                       atomic_set(&card->write_busy, 0);
-                       return NULL;
-               }
-               rec_buf = card->ipa_buf;
-               QETH_DBF_CARD2(0, trace, "scri", card);
-       }
-       QETH_DBF_HEX2(0, control, rec_buf, QETH_DBF_CONTROL_LEN);
-
-       memcpy(&card->seqno.pdu_hdr_ack,
-              QETH_PDU_HEADER_SEQ_NO(rec_buf), QETH_SEQ_NO_LENGTH);
-
-       return rec_buf;
-}
-
-static int
-qeth_send_ipa_cmd(struct qeth_card *card, struct ipa_cmd *cmd, int update_cmd,
-                 int ipatype)
-{
-       unsigned char *buffer;
-       struct ipa_cmd *reply;
-       int ipa_cmd;
-       int result;
-
-       /* don't muck around with ipv6 if there's no use to do so */
-       if ((cmd->prot_version == 6) && (!qeth_is_supported(IPA_IPv6)))
-               return 0;
-
-       ipa_cmd = cmd->command;
-
-       memcpy(card->send_buf, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
-
-       memcpy(QETH_IPA_CMD_DEST_ADDR(card->send_buf),
-              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
-
-       memcpy(card->send_buf + IPA_PDU_HEADER_SIZE,
-              cmd, sizeof (struct ipa_cmd));
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       IPA_PDU_HEADER_SIZE +
-                                       sizeof (struct ipa_cmd), ipatype);
-
-       if (!buffer) {
-               if (atomic_read(&card->escape_softsetup))
-                       return 0;
-               else
-                       return -1;
-       }
-       reply = (struct ipa_cmd *) PDU_ENCAPSULATION(buffer);
-       if ((update_cmd) && (reply))
-               memcpy(cmd, reply, sizeof (struct ipa_cmd));
-       result = reply->return_code;
-
-       /* some special sausages: */
-       if ((ipa_cmd == IPA_CMD_SETASSPARMS) && (result == 0)) {
-               result = reply->data.setassparms.return_code;
-               if ((reply->data.setassparms.assist_no==IPA_INBOUND_CHECKSUM) &&
-                   (reply->data.setassparms.command_code == IPA_CMD_ASS_START))
-                       card->csum_enable_mask =
-                               reply->data.setassparms.data.flags_32bit;
-       }
-       if ((ipa_cmd == IPA_CMD_SETADAPTERPARMS) && (result == 0)) {
-               result = reply->data.setadapterparms.return_code;
-       }
-
-       return result;
-}
-
-static void
-qeth_fill_ipa_cmd(struct qeth_card *card, struct ipa_cmd *cmd,
-                 __u8 command, int ip_vers)
-{
-       memset(cmd, 0, sizeof (struct ipa_cmd));
-       cmd->command = command;
-       cmd->initiator = INITIATOR_HOST;
-       cmd->seq_no = card->seqno.ipa++;
-       cmd->adapter_type = qeth_get_adapter_type_for_ipa(card->link_type);
-       cmd->rel_adapter_no = (__u8) card->options.portno;
-       cmd->prim_version_no = 1;
-       cmd->param_count = 1;
-       cmd->prot_version = ip_vers;
-       cmd->ipa_supported = 0;
-       cmd->ipa_enabled = 0;
-}
-
-static int
-qeth_send_startstoplan(struct qeth_card *card, __u8 ipacmd, __u16 ip_vers)
-{
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, ipacmd, 0);
-       cmd.param_count = 0;
-       cmd.prot_version = ip_vers;
-       cmd.ipa_supported = 0;
-       cmd.ipa_enabled = 0;
-
-       result = qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE);
-       return result;
-}
-
-static int
-qeth_send_startlan(struct qeth_card *card, __u16 ip_vers)
-{
-       int result;
-       char dbf_text[15];
-
-       QETH_DBF_CARD4(0, trace, "stln", card);
-
-       result = qeth_send_startstoplan(card, IPA_CMD_STARTLAN, ip_vers);
-       if (!result)
-               atomic_set(&card->is_startlaned, 1);
-
-       if (result) {
-               QETH_DBF_CARD2(0, trace, "STRTLNFL", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-
-       return result;
-}
-
-static int
-qeth_send_stoplan(struct qeth_card *card)
-{
-#ifdef QETH_SEND_STOPLAN_ON_SHUTDOWN
-       int result;
-       char dbf_text[15];
-
-       atomic_set(&card->is_startlaned, 0);
-
-       QETH_DBF_CARD4(0, trace, "spln", card);
-
-       result = qeth_send_startstoplan(card, IPA_CMD_STOPLAN, 4);
-
-       if (result) {
-               QETH_DBF_CARD2(0, trace, "STPLNFLD", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-
-       return result;
-#else /* QETH_SEND_STOPLAN_ON_SHUTDOWN */
-       return 0;
-#endif /* QETH_SEND_STOPLAN_ON_SHUTDOWN */
-}
-
-static int
-qeth_send_qipassist(struct qeth_card *card, short ip_vers)
-{
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_QIPASSIST, ip_vers);
-
-       result = qeth_send_ipa_cmd(card, &cmd, 1, IPA_CMD_STATE);
-
-       if (!result) {
-               if (ip_vers == 4) {
-                       card->ipa_supported = cmd.ipa_supported;
-                       card->ipa_enabled = cmd.ipa_enabled;
-               } else {
-                       card->ipa6_supported = cmd.ipa_supported;
-                       card->ipa6_enabled = cmd.ipa_enabled;
-               }
-       }
-
-       return result;
-}
-
-/* QUERY ARP FUNCTIONS */
-
-static int
-qeth_send_ipa_arpcmd(struct qeth_card *card, struct arp_cmd *cmd,
-                    int update_cmd, int ipatype, __u32 req_size)
-{
-       unsigned char *buffer;
-       int ipa_cmd;
-       int result;
-       __u16 s1, s2;
-
-       /* don't muck around with ipv6 if there's no use to do so */
-       if ((cmd->prot_version == 6) && (!qeth_is_supported(IPA_IPv6)))
-               return 0;
-       result = 0;
-       ipa_cmd = cmd->command;
-
-       memcpy(card->send_buf, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
-       memcpy(QETH_IPA_CMD_DEST_ADDR(card->send_buf),
-              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(card->send_buf + IPA_PDU_HEADER_SIZE,
-              cmd, sizeof (struct arp_cmd));
-
-       if (req_size) {
-               /* adjust sizes for big requests */
-               s1 = (__u32) IPA_PDU_HEADER_SIZE + SNMP_BASE_CMDLENGTH +
-                   req_size;
-               s2 = (__u32) SNMP_BASE_CMDLENGTH + req_size;
-               memcpy(QETH_IPA_PDU_LEN_TOTAL(card->send_buf), &s1, 2);
-               memcpy(QETH_IPA_PDU_LEN_PDU1(card->send_buf), &s2, 2);
-               memcpy(QETH_IPA_PDU_LEN_PDU2(card->send_buf), &s2, 2);
-               memcpy(QETH_IPA_PDU_LEN_PDU3(card->send_buf), &s2, 2);
-       }
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       IPA_PDU_HEADER_SIZE +
-                                       sizeof (struct arp_cmd), ipatype);
-       if (!buffer)
-               result = -ENODATA;
-       else
-               result = card->ioctl_returncode;
-       return result;
-}
-
-static int
-qeth_ioctl_handle_snmp_data(struct qeth_card *card, struct arp_cmd *reply)
-{
-       __u16 data_len;
-
-#define SNMP_HEADER_SIZE_WITH_TOKEN 36
-
-       data_len = *((__u16*)QETH_IPA_PDU_LEN_PDU1(card->dma_stuff->recbuf));
-       if (reply->data.setadapterparms.frame_seq_no == 1)
-               data_len = data_len - 
-                       (__u16)((char*)reply->data.setadapterparms.data.
-                               snmp_subcommand.snmp_data - (char*)reply); 
-       else
-               data_len = data_len - 
-                       (__u16)((char*)&reply->data.setadapterparms.data.
-                               snmp_subcommand.snmp_request - (char*)reply);
-
-       if (reply->data.setadapterparms.frame_seq_no == 1) {
-
-               if (card->ioctl_buffersize <= (SNMP_HEADER_SIZE_WITH_TOKEN +
-                                              reply->data.setadapterparms.
-                                              frames_used_total *
-                                              ARP_DATA_SIZE)) {
-
-                       card->ioctl_returncode = ARP_RETURNCODE_ERROR;
-                       reply->data.setadapterparms.data.snmp_subcommand.
-                           snmp_returncode = -ENOMEM;
-               } else {
-                       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-                       card->number_of_entries = 0;
-                       memcpy(((char *)card->ioctl_data_buffer),
-                              reply->data.setadapterparms.snmp_token,
-                              SNMP_HEADER_SIZE_WITH_TOKEN);
-                       card->ioctl_buffer_pointer = card->ioctl_data_buffer+
-                               SNMP_HEADER_SIZE_WITH_TOKEN;
-               }
-       }
-
-       if (card->ioctl_returncode != ARP_RETURNCODE_ERROR &&
-           reply->data.setadapterparms.frame_seq_no <=
-           reply->data.setadapterparms.frames_used_total) {
-
-               if (reply->data.setadapterparms.return_code ==
-                   IPA_REPLY_SUCCESS) {
-
-                       if (reply->data.setadapterparms.frame_seq_no == 1)
-                               memcpy(card->ioctl_buffer_pointer,
-                                      reply->data.setadapterparms.data.
-                                      snmp_subcommand.snmp_data, data_len);
-                       else
-                               memcpy(card->ioctl_buffer_pointer,
-                                      (char*)&reply->data.setadapterparms.
-                                      data.snmp_subcommand.snmp_request,
-                                      data_len);
-
-                       card->ioctl_buffer_pointer =
-                           card->ioctl_buffer_pointer + data_len;
-                       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-
-                       if (reply->data.setadapterparms.frame_seq_no ==
-                           reply->data.setadapterparms.frames_used_total) {
-                               card->ioctl_returncode =
-                                   ARP_RETURNCODE_LASTREPLY;
-                       }
-               } else {
-                       card->ioctl_returncode = ARP_RETURNCODE_ERROR;
-                       memset(card->ioctl_data_buffer, 0,
-                              card->ioctl_buffersize);
-                       reply->data.setadapterparms.data.snmp_subcommand.
-                           snmp_returncode =
-                           reply->data.setadapterparms.return_code;
-               }
-       }
-#undef  SNMP_HEADER_SIZE_WITH_TOKEN
-
-       return card->ioctl_returncode;
-}
-
-static int
-qeth_ioctl_handle_arp_data(struct qeth_card *card, struct arp_cmd *reply)
-{
-
-       if (reply->data.setassparms.seq_no == 1) {
-               if (card->ioctl_buffersize <=
-                   (sizeof (__u16) + sizeof (int) +
-                    reply->data.setassparms.number_of_replies *
-                    ARP_DATA_SIZE)) {
-
-                       card->ioctl_returncode = ARP_RETURNCODE_ERROR;
-
-               } else {
-                       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-                       card->number_of_entries = 0;
-                       card->ioctl_buffer_pointer =
-                           card->ioctl_data_buffer + sizeof (__u16) +
-                           sizeof (int);
-               }
-       }
-
-       if (card->ioctl_returncode != ARP_RETURNCODE_ERROR &&
-           reply->data.setassparms.seq_no <=
-           reply->data.setassparms.number_of_replies) {
-
-               if (reply->data.setassparms.return_code == IPA_REPLY_SUCCESS) {
-
-                       card->number_of_entries = card->number_of_entries +
-                           reply->data.setassparms.
-                           data.queryarp_data.number_of_entries;
-                       memcpy(card->ioctl_buffer_pointer,
-                              reply->data.setassparms.data.queryarp_data.
-                              arp_data, ARP_DATA_SIZE);
-                       card->ioctl_buffer_pointer = card->
-                           ioctl_buffer_pointer + ARP_DATA_SIZE;
-                       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-                       if (reply->data.setassparms.seq_no ==
-                           reply->data.setassparms.number_of_replies) {
-                               memcpy(card->ioctl_data_buffer,
-                                      &reply->data.setassparms.data.
-                                      queryarp_data.osa_setbitmask,
-                                      sizeof (__u16));
-                               card->ioctl_returncode =
-                                   ARP_RETURNCODE_LASTREPLY;
-                       }
-               } else {
-
-                       card->ioctl_returncode = ARP_RETURNCODE_ERROR;
-                       memset(card->ioctl_data_buffer, 0,
-                              card->ioctl_buffersize);
-               }
-       }
-       return card->ioctl_returncode;
-}
-
-static int
-qeth_look_for_arp_data(struct qeth_card *card)
-{
-       struct arp_cmd *reply;
-       int result;
-
-       reply = (struct arp_cmd *) PDU_ENCAPSULATION(card->dma_stuff->recbuf);
-
-       if ((reply->command == IPA_CMD_SETASSPARMS) &&
-           (reply->data.setassparms.assist_no == IPA_ARP_PROCESSING) &&
-           (reply->data.setassparms.command_code ==
-            IPA_CMD_ASS_ARP_FLUSH_CACHE)) {
-               result = ARP_FLUSH;
-       } else if ((reply->command == IPA_CMD_SETASSPARMS) &&
-                  (reply->data.setassparms.assist_no == IPA_ARP_PROCESSING) &&
-                  (reply->data.setassparms.command_code ==
-                   IPA_CMD_ASS_ARP_QUERY_INFO) &&
-                  (card->ioctl_returncode == ARP_RETURNCODE_SUCCESS)) {
-
-               result = qeth_ioctl_handle_arp_data(card, reply);
-
-       } else if ((reply->command == IPA_CMD_SETADAPTERPARMS) &&
-                  (reply->data.setadapterparms.command_code ==
-                   IPA_SETADP_SET_SNMP_CONTROL) &&
-                  (card->ioctl_returncode == ARP_RETURNCODE_SUCCESS)) {
-
-               result = qeth_ioctl_handle_snmp_data(card, reply);
-       } else
-               result = ARP_RETURNCODE_NOARPDATA;
-
-       return result;
-}
-
-static int
-qeth_queryarp(struct qeth_card *card, struct ifreq *req, int version,
-             __u32 assist_no, __u16 command_code, char *c_data, __u16 len)
-{
-       int data_size;
-       struct arp_cmd *cmd;
-       int result;
-
-       cmd = (struct arp_cmd *) kmalloc(sizeof (struct arp_cmd), GFP_KERNEL);
-       if (!cmd) {
-               return IPA_REPLY_FAILED;
-       }
-
-       memcpy(&data_size, c_data, sizeof (int));
-
-       qeth_fill_ipa_cmd(card, (struct ipa_cmd *) cmd, IPA_CMD_SETASSPARMS,
-                         version);
-
-       cmd->data.setassparms.assist_no = assist_no;
-       cmd->data.setassparms.length = 8 + len;
-       cmd->data.setassparms.command_code = command_code;
-       cmd->data.setassparms.return_code = 0;
-       cmd->data.setassparms.seq_no = 0;
-
-       card->ioctl_buffersize = data_size;
-       card->ioctl_data_buffer = (char *) vmalloc(data_size);
-       if (!card->ioctl_data_buffer) {
-               kfree(cmd);
-               return IPA_REPLY_FAILED;
-       }
-
-       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-
-       result = qeth_send_ipa_arpcmd(card, cmd, 1, IPA_IOCTL_STATE, 0);
-
-       if ((result == ARP_RETURNCODE_ERROR) || (result == -ENODATA)) {
-               result = IPA_REPLY_FAILED;
-       } else {
-               result = IPA_REPLY_SUCCESS;
-               memcpy(((char *) (card->ioctl_data_buffer)) + sizeof (__u16),
-                      &(card->number_of_entries), sizeof (int));
-               if (copy_to_user(req->ifr_ifru.ifru_data,
-                               card->ioctl_data_buffer, data_size))
-                               result = -EFAULT;
-       }
-       card->ioctl_buffer_pointer = NULL;
-       vfree(card->ioctl_data_buffer);
-       kfree(cmd);
-       card->number_of_entries = 0;
-       card->ioctl_buffersize = 0;
-
-       return result;
-}
-
-static int
-snmp_set_setadapterparms_command(struct qeth_card *card,
-                                struct arp_cmd *cmd, struct ifreq *req,
-                                char *data, __u16 len,
-                                __u16 command_code, int req_size)
-{
-       __u32 data_size;
-
-       memcpy(&data_size, data, sizeof (__u32));
-
-       card->ioctl_buffersize = data_size;
-       card->ioctl_data_buffer = (char *) vmalloc(data_size);
-       if (!card->ioctl_data_buffer) {
-               return -ENOMEM;
-       }
-       card->ioctl_returncode = ARP_RETURNCODE_SUCCESS;
-
-       memcpy(cmd->data.setadapterparms.snmp_token,
-              data + SNMP_REQUEST_DATA_OFFSET, req_size);
-
-       cmd->data.setadapterparms.cmdlength = SNMP_SETADP_CMDLENGTH + req_size;
-       cmd->data.setadapterparms.command_code = command_code;
-       cmd->data.setadapterparms.frames_used_total = 1;
-       cmd->data.setadapterparms.frame_seq_no = 1;
-
-       return 0;
-}
-static int
-qeth_send_snmp_control(struct qeth_card *card, struct ifreq *req,
-                      __u32 command, __u16 command_code,
-                      char *c_data, __u16 len)
-{
-       struct arp_cmd *cmd;
-       __u32 result, req_size;
-
-       cmd = (struct arp_cmd *) kmalloc(sizeof (struct arp_cmd), GFP_KERNEL);
-       if (!cmd) {
-               return IPA_REPLY_FAILED;
-       }
-
-       qeth_fill_ipa_cmd(card, (struct ipa_cmd *) cmd, command, 4);
-
-       memcpy(&req_size, ((char *) c_data) + sizeof (__u32), sizeof (__u32));
-
-       if (snmp_set_setadapterparms_command(card, cmd, req, c_data,
-                                            len, command_code, req_size)) {
-               kfree(cmd);
-               return IPA_REPLY_FAILED;
-       }
-
-       result = qeth_send_ipa_arpcmd(card, cmd, 1, IPA_IOCTL_STATE, req_size);
-
-       if (result == -ENODATA) {
-               result = IPA_REPLY_FAILED;
-               goto snmp_out;
-       }
-       if (result == ARP_RETURNCODE_ERROR) {
-               result = IPA_REPLY_FAILED;
-               if (copy_to_user(req->ifr_ifru.ifru_data + 
-                            SNMP_REQUEST_DATA_OFFSET, card->ioctl_data_buffer,
-                            card->ioctl_buffersize))
-                       result = -EFAULT;
-       } else {
-               result = IPA_REPLY_SUCCESS;
-               if (copy_to_user(req->ifr_ifru.ifru_data +
-                                SNMP_REQUEST_DATA_OFFSET, card->ioctl_data_buffer,
-                                card->ioctl_buffersize))
-                       result = -EFAULT;
-       }
-snmp_out:
-       card->number_of_entries = 0;
-       card->ioctl_buffersize = 0;
-       card->ioctl_buffer_pointer = NULL;
-       vfree(card->ioctl_data_buffer);
-       kfree(cmd);
-
-       return result;
-}
-
-static int
-qeth_send_setassparms(struct qeth_card *card, int version, __u32 assist_no,
-                     __u16 command_code, long data, __u16 len)
-{
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_SETASSPARMS, version);
-
-       cmd.data.setassparms.assist_no = assist_no;
-       cmd.data.setassparms.length = 8 + len;
-       cmd.data.setassparms.command_code = command_code;
-       cmd.data.setassparms.return_code = 0;
-       cmd.data.setassparms.seq_no = 0;
-
-       if (len <= sizeof (__u32))
-               cmd.data.setassparms.data.flags_32bit = (__u32) data;
-       else if (len > sizeof (__u32))
-               memcpy(&cmd.data.setassparms.data, (void *) data,
-                      qeth_min(len, PAGE_SIZE));
-       if (command_code != IPA_CMD_ASS_START) {
-               result = qeth_send_ipa_cmd(card, &cmd, 0,
-                                          ((assist_no == IPA_ARP_PROCESSING) &&
-                                           (command_code !=
-                                            IPA_CMD_ASS_ARP_FLUSH_CACHE)) ?
-                                          IPA_IOCTL_STATE : IPA_CMD_STATE);
-
-       } else
-               result = qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE);
-
-       return result;
-}
-
-static int
-qeth_send_setadapterparms_query(struct qeth_card *card)
-{
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_SETADAPTERPARMS,
-                         IPA_SETADAPTERPARMS_IP_VERSION);
-       cmd.data.setadapterparms.cmdlength = sizeof (struct ipa_setadp_cmd);
-       cmd.data.setadapterparms.command_code =
-           IPA_SETADP_QUERY_COMMANDS_SUPPORTED;
-       cmd.data.setadapterparms.frames_used_total = 1;
-       cmd.data.setadapterparms.frame_seq_no = 1;
-       result = qeth_send_ipa_cmd(card, &cmd, 1, IPA_CMD_STATE);
-
-       if (cmd.data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f)
-               card->link_type = cmd.data.setadapterparms.data.
-                   query_cmds_supp.lan_type;
-
-       card->adp_supported =
-           cmd.data.setadapterparms.data.query_cmds_supp.supported_cmds;
-
-       return result;
-}
-
-static int
-qeth_send_setadapterparms_mode(struct qeth_card *card, __u32 command,
-                              __u32 mode)
-{
-
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_SETADAPTERPARMS,
-                         IPA_SETADAPTERPARMS_IP_VERSION);
-       cmd.data.setadapterparms.cmdlength = sizeof (struct ipa_setadp_cmd);
-       cmd.data.setadapterparms.command_code = command;
-       cmd.data.setadapterparms.frames_used_total = 1;
-       cmd.data.setadapterparms.frame_seq_no = 1;
-       cmd.data.setadapterparms.data.mode = mode;
-       result = qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE);
-
-       return result;
-}
-
-static int
-qeth_send_setadapterparms_change_addr(struct qeth_card *card,
-                                     __u32 command,
-                                     __u32 subcmd, __u8 * mac_addr,
-                                     int addr_len)
-{
-       struct ipa_cmd cmd;
-       int result;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_SETADAPTERPARMS,
-                         IPA_SETADAPTERPARMS_IP_VERSION);
-       cmd.data.setadapterparms.cmdlength = sizeof (struct ipa_setadp_cmd);
-       cmd.data.setadapterparms.command_code = command;
-       cmd.data.setadapterparms.frames_used_total = 1;
-       cmd.data.setadapterparms.frame_seq_no = 1;
-       cmd.data.setadapterparms.data.change_addr.cmd = subcmd;
-       cmd.data.setadapterparms.data.change_addr.addr_size = addr_len;
-       memcpy(&cmd.data.setadapterparms.data.change_addr.addr,
-              mac_addr, addr_len);
-
-       result = qeth_send_ipa_cmd(card, &cmd, 1, IPA_CMD_STATE);
-
-       memcpy(mac_addr, &cmd.data.setadapterparms.data.change_addr.addr,
-              addr_len);
-
-       return result;
-}
-
-static int
-qeth_send_setassparms_simple_with_data(struct qeth_card *card,
-                                      __u32 assist_no,
-                                      __u16 command_code, long data)
-{
-       return qeth_send_setassparms(card, 4, assist_no, command_code, data, 4);
-}
-
-static int
-qeth_send_setassparms_simple_without_data(struct qeth_card *card,
-                                         __u32 assist_no, __u16 command_code)
-{
-       return qeth_send_setassparms(card, 4, assist_no, command_code, 0, 0);
-}
-
-static int
-qeth_send_setassparms_simple_without_data6(struct qeth_card *card,
-                                          __u32 assist_no, __u16 command_code)
-{
-       return qeth_send_setassparms(card, 6, assist_no, command_code, 0, 0);
-}
-
-static int
-qeth_send_setdelip(struct qeth_card *card, __u8 * ip, __u8 * netmask,
-                  int ipacmd, short ip_vers, unsigned int flags)
-{
-       struct ipa_cmd cmd;
-       int ip_len = (ip_vers == 6) ? 16 : 4;
-
-       qeth_fill_ipa_cmd(card, &cmd, ipacmd, ip_vers);
-
-       if (ip_vers == 6) {
-               memcpy(&cmd.data.setdelip6.ip, ip, ip_len);
-               memcpy(&cmd.data.setdelip6.netmask, netmask, ip_len);
-               cmd.data.setdelip6.flags = flags;
-       } else {
-               memcpy(&cmd.data.setdelip4.ip, ip, ip_len);
-               memcpy(&cmd.data.setdelip4.netmask, netmask, ip_len);
-               cmd.data.setdelip4.flags = flags;
-       }
-
-       return qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE |
-                                ((ipacmd ==
-                                  IPA_CMD_SETIP) ? IPA_SETIP_FLAG : 0));
-}
-
-static int
-qeth_send_setdelipm(struct qeth_card *card, __u8 * ip, __u8 * mac,
-                   int ipacmd, short ip_vers)
-{
-       struct ipa_cmd cmd;
-       int ip_len = (ip_vers == 6) ? 16 : 4;
-
-       qeth_fill_ipa_cmd(card, &cmd, ipacmd, ip_vers);
-       memcpy(&cmd.data.setdelipm.mac, mac, 6);
-       if (ip_vers == 6) {
-               memcpy(&cmd.data.setdelipm.ip6, ip, ip_len);
-       } else {
-               memcpy(&cmd.data.setdelipm.ip4_6, ip, ip_len);
-       }
-
-       return qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE |
-                                ((ipacmd ==
-                                  IPA_CMD_SETIPM) ? IPA_SETIP_FLAG : 0));
-}
-
-#define PRINT_SETIP_ERROR(x) \
-       if (result) \
-               PRINT_ERR("setip%c: return code 0x%x (%s)\n",x,result, \
-                         (result==0xe002)?"invalid mtu size": \
-                         (result==0xe005)?"duplicate ip address": \
-                         (result==0xe0a5)?"duplicate ip address": \
-                                 (result==0xe006)?"ip table full": \
-                         (result==0xe008)?"startlan not received": \
-                         (result==0xe009)?"setip already received": \
-                         (result==0xe00a)?"dup network ip address": \
-                         (result==0xe00b)?"mblk no free main task entry": \
-                         (result==0xe00d)?"invalid ip version": \
-                         (result==0xe00e)?"unsupported arp assist cmd": \
-                         (result==0xe00f)?"arp assist not enabled": \
-                         (result==0xe080)?"startlan disabled": \
-                         (result==0xf012)?"unicast IP address invalid": \
-                         (result==0xf013)?"multicast router limit reached": \
-                         (result==0xf014)?"stop assist not supported": \
-                         (result==0xf015)?"multicast assist not set": \
-                         (result==0xf080)?"VM: startlan disabled": \
-                         (result==-1)?"IPA communication timeout": \
-                         "unknown return code")
-
-static inline int
-qeth_send_setip(struct qeth_card *card, __u8 * ip,
-               __u8 * netmask, short ip_vers, int use_retries)
-{
-       int result;
-       int retries;
-       char dbf_text[15];
-       int takeover = 0;
-
-       retries = (use_retries) ? QETH_SETIP_RETRIES : 1;
-       if (qeth_is_ipa_covered_by_ipato_entries(ip_vers, ip, card)) {
-               QETH_DBF_CARD2(0, trace, "ipto", card);
-               if (ip_vers == 4) {
-                       *((__u32 *) (&dbf_text[0])) = *((__u32 *) ip);
-                       *((__u32 *) (&dbf_text[4])) = *((__u32 *) netmask);
-                       QETH_DBF_HEX2(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-               } else {
-                       QETH_DBF_HEX2(0, trace, ip, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, ip + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, netmask, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, netmask + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-               }
-               takeover = 1;
-       } else {
-       }
-retry:
-       result = qeth_send_setdelip(card, ip, netmask, IPA_CMD_SETIP, ip_vers,
-                                   (takeover) ? IPA_SETIP_TAKEOVER_FLAGS :
-                                   IPA_SETIP_FLAGS);
-       PRINT_SETIP_ERROR(' ');
-
-       if (result) {
-               QETH_DBF_CARD2(0, trace, "SETIPFLD", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-
-       if (((result == -1) || (result == 0xe080) ||(result==0xf080)) &&
-           (retries--)) {
-               QETH_DBF_CARD2(0, trace, "sipr", card);
-               if (ip_vers == 4) {
-                       *((__u32 *) (&dbf_text[0])) = *((__u32 *) ip);
-                       *((__u32 *) (&dbf_text[4])) = *((__u32 *) netmask);
-                       QETH_DBF_HEX2(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-               } else {
-                       QETH_DBF_HEX2(0, trace, ip, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, ip + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, netmask, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, netmask + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-               }
-               PRINT_WARN("trying again...\n");
-               goto retry;
-       }
-
-       return result;
-}
-
-static inline int
-qeth_send_delip(struct qeth_card *card, __u8 * ip,
-               __u8 * netmask, short ip_vers)
-{
-       return qeth_send_setdelip(card, ip, netmask, IPA_CMD_DELIP, ip_vers,
-                                 IPA_DELIP_FLAGS);
-}
-
-static inline int
-qeth_send_setipm(struct qeth_card *card, __u8 * ip,
-                __u8 * mac, short ip_vers, int use_retries)
-{
-       int result;
-       int retries;
-       char dbf_text[15];
-
-       retries = (use_retries) ? QETH_SETIP_RETRIES : 1;
-       if (qeth_is_ipa_covered_by_ipato_entries(ip_vers, ip, card)) {
-               QETH_DBF_CARD2(0, trace, "imto", card);
-               if (ip_vers == 4) {
-                       *((__u32 *) (&dbf_text[0])) = *((__u32 *) ip);
-                       QETH_DBF_HEX2(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-               } else {
-                       QETH_DBF_HEX2(0, trace, ip, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, ip + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-               }
-       }
-
-retry:
-       result = qeth_send_setdelipm(card, ip, mac, IPA_CMD_SETIPM, ip_vers);
-       PRINT_SETIP_ERROR('m');
-
-       if (result) {
-               QETH_DBF_CARD2(0, trace, "SETIMFLD", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-
-       if ((result == -1) && (retries--)) {
-               QETH_DBF_CARD2(0, trace, "simr", card);
-               if (ip_vers == 4) {
-                       sprintf(dbf_text, "%08x", *((__u32 *) ip));
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-               } else {
-                       QETH_DBF_HEX2(0, trace, ip, QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX2(0, trace, ip + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-               }
-               QETH_DBF_HEX2(0, trace, mac, OSA_ADDR_LEN);
-               PRINT_WARN("trying again...\n");
-               goto retry;
-       }
-
-       return result;
-}
-
-static inline int
-qeth_send_delipm(struct qeth_card *card, __u8 * ip, __u8 * mac, short ip_vers)
-{
-       return qeth_send_setdelipm(card, ip, mac, IPA_CMD_DELIPM, ip_vers);
-}
-
-static int
-qeth_add_vipa_entry(struct qeth_card *card, int version, __u8 * addr, int flag)
-{
-       struct qeth_vipa_entry *entry, *e;
-       int result = 0;
-
-       entry =
-           (struct qeth_vipa_entry *) kmalloc(sizeof (struct qeth_vipa_entry),
-                                              GFP_KERNEL);
-       if (!entry) {
-               PRINT_ERR("not enough memory for vipa handling\n");
-               return -ENOMEM;
-       }
-       entry->version = version;
-       entry->flag = flag;
-       memcpy(entry->ip, addr, 16);
-       entry->state = VIPA_2_B_ADDED;
-
-       write_lock(&card->vipa_list_lock);
-       e = card->vipa_list;
-       while (e) {
-               if (e->version != version)
-                       goto next;
-               if (memcmp(e->ip, addr, (version == 4) ? 4 : 16))
-                       goto next;
-               if (flag == IPA_SETIP_VIPA_FLAGS) {
-                       PRINT_ERR("vipa already set\n");
-               } else {
-                       PRINT_ERR("rxip already set\n");
-               }
-               kfree(entry);
-               result = -EALREADY;
-               goto out;
-       next:
-               e = e->next;
-       }
-       entry->next = card->vipa_list;
-       card->vipa_list = entry;
-out:
-       write_unlock(&card->vipa_list_lock);
-       return result;
-}
-
-static int
-qeth_del_vipa_entry(struct qeth_card *card, int version, __u8 * addr, int flag)
-{
-       struct qeth_vipa_entry *e;
-       int result = 0;
-
-       write_lock(&card->vipa_list_lock);
-       e = card->vipa_list;
-       while (e) {
-               if (e->version != version)
-                       goto next;
-               if (e->flag != flag)
-                       goto next;
-               if (memcmp(e->ip, addr, (version == 4) ? 4 : 16))
-                       goto next;
-               e->state = VIPA_2_B_REMOVED;
-               goto out;
-       next:
-               e = e->next;
-       }
-       if (flag == IPA_SETIP_VIPA_FLAGS) {
-               PRINT_ERR("vipa not found\n");
-       } else {
-               PRINT_ERR("rxip not found\n");
-       }
-       result = -ENOENT;
-out:
-       write_unlock(&card->vipa_list_lock);
-       return result;
-}
-
-static void
-qeth_set_vipas(struct qeth_card *card, int set_only)
-{
-       struct qeth_vipa_entry *e, *le = NULL, *ne;     /* ne stands for new entry,
-                                                          le is last entry */
-       char dbf_text[15];
-       int result;
-       __u8 netmask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-       };
-       struct qeth_vipa_entry *priv_add_list = NULL;
-       struct qeth_vipa_entry *priv_del_list = NULL;
-
-       write_lock(&card->vipa_list_lock);
-       e = card->vipa_list;
-       while (e) {
-               switch (e->state) {
-               case VIPA_2_B_ADDED:
-                       if (!set_only)
-                               break;
-                       if (!atomic_read(&card->is_open))
-                               break;
-                       /* we don't want to hold the lock for a long time...
-                        * so we clone the entry */
-                       ne = (struct qeth_vipa_entry *)
-                           kmalloc(sizeof (struct qeth_vipa_entry),
-                                   GFP_ATOMIC);
-                       if (ne) {
-                               ne->version = e->version;
-                               ne->flag = e->flag;
-                               memcpy(ne->ip, e->ip, 16);
-                               ne->next = priv_add_list;
-                               priv_add_list = ne;
-
-                               e->state = VIPA_ESTABLISHED;
-                       } else {
-                               PRINT_ERR("not enough for internal vipa "
-                                         "handling... trying to set "
-                                         "vipa next time.\n");
-                               qeth_start_softsetup_thread(card);
-                       }
-                       break;
-               case VIPA_2_B_REMOVED:
-                       if (set_only)
-                               break;
-                       if (le)
-                               le->next = e->next;
-                       else
-                               card->vipa_list = e->next;
-                       ne = e->next;
-                       e->next = priv_del_list;
-                       priv_del_list = e;
-                       e = ne;
-                       continue;
-               case VIPA_ESTABLISHED:
-                       if (atomic_read(&card->is_open))
-                               break;
-                       /* we don't want to hold the lock for a long time...
-                        * so we clone the entry */
-                       ne = (struct qeth_vipa_entry *)
-                           kmalloc(sizeof (struct qeth_vipa_entry),
-                                   GFP_KERNEL);
-                       if (ne) {
-                               ne->version = e->version;
-                               ne->flag = e->flag;
-                               memcpy(ne->ip, e->ip, 16);
-                               ne->next = priv_del_list;
-                               priv_del_list = ne;
-
-                               e->state = VIPA_2_B_ADDED;
-                       } else {
-                               PRINT_ERR("not enough for internal vipa "
-                                         "handling... VIPA/RXIP remains set "
-                                         "although device is stopped.\n");
-                               qeth_start_softsetup_thread(card);
-                       }
-                       break;
-               default:
-                       break;
-               }
-               le = e;
-               e = e->next;
-       }
-       write_unlock(&card->vipa_list_lock);
-
-       while (priv_add_list) {
-               result = qeth_send_setdelip(card, priv_add_list->ip, netmask,
-                                           IPA_CMD_SETIP,
-                                           priv_add_list->version,
-                                           priv_add_list->flag);
-               PRINT_SETIP_ERROR('s');
-
-               if (result) {
-                       QETH_DBF_CARD2(0, trace, "SETSVFLD", card);
-                       sprintf(dbf_text, "%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       if (priv_add_list->version == 4) {
-                               PRINT_ERR("going to leave vipa/rxip x%08x"
-                                         "unset...\n",
-                                         *((__u32 *) & priv_add_list->ip[0]));
-                               sprintf(dbf_text, "%08x",
-                                       *((__u32 *) & priv_add_list->ip[0]));
-                               QETH_DBF_TEXT2(0, trace, dbf_text);
-                       } else {
-                               PRINT_ERR("going to leave vipa/rxip "
-                                         "%08x%08x%08x%08x unset...\n",
-                                         *((__u32 *) & priv_add_list->ip[0]),
-                                         *((__u32 *) & priv_add_list->ip[4]),
-                                         *((__u32 *) & priv_add_list->ip[8]),
-                                         *((__u32 *) & priv_add_list->ip[12]));
-                               QETH_DBF_HEX2(0, trace, &priv_add_list->ip[0],
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX2(0, trace, &priv_add_list->ip[8],
-                                             QETH_DBF_TRACE_LEN);
-                       }
-               }
-               e = priv_add_list;
-               priv_add_list = priv_add_list->next;
-               kfree(e);
-       }
-
-       while (priv_del_list) {
-               result = qeth_send_setdelip(card, priv_del_list->ip, netmask,
-                                           IPA_CMD_DELIP,
-                                           priv_del_list->version,
-                                           priv_del_list->flag);
-               if (result) {
-                       QETH_DBF_CARD2(0, trace, "DELSVFLD", card);
-                       sprintf(dbf_text, "%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       if (priv_del_list->version == 4) {
-                               PRINT_ERR("could not delete vipa/rxip "
-                                         "%08x...\n",
-                                         *((__u32 *) & priv_del_list->ip[0]));
-                               sprintf(dbf_text, "%08x",
-                                       *((__u32 *) & priv_del_list->ip[0]));
-                               QETH_DBF_TEXT2(0, trace, dbf_text);
-                       } else {
-                               PRINT_ERR("could not delete vipa/rxip "
-                                         "%08x%08x%08x%08x...\n",
-                                         *((__u32 *) & priv_del_list->ip[0]),
-                                         *((__u32 *) & priv_del_list->ip[4]),
-                                         *((__u32 *) & priv_del_list->ip[8]),
-                                         *((__u32 *) & priv_del_list->ip[12]));
-                               QETH_DBF_HEX2(0, trace, &priv_del_list->ip[0],
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX2(0, trace, &priv_del_list->ip[8],
-                                             QETH_DBF_TRACE_LEN);
-                       }
-/* in case of problems, it's better if we just display a message and
- * don't requeue the entry back...
-                       write_lock(&card->vipa_list_lock);
-                       e=card->vipa_list;
-                       card->vipa_list=priv_del_list;
-                       priv_del_list=priv_del_list->next;
-                       card->vipa_list->next=e;
-                       card->vipa_list->state=VIPA_ESTABLISHED;
-                       write_unlock(&card->vipa_list_lock);
-                       continue;
-*/
-               }
-               e = priv_del_list;
-               priv_del_list = priv_del_list->next;
-               kfree(e);
-       }
-}
-
-static void
-qeth_refresh_vipa_states(struct qeth_card *card)
-{
-       struct qeth_vipa_entry *e;
-
-       write_lock(&card->vipa_list_lock);
-       e = card->vipa_list;
-       while (e) {
-               if (e->state == VIPA_ESTABLISHED)
-                       e->state = VIPA_2_B_ADDED;
-               e = e->next;
-       }
-       write_unlock(&card->vipa_list_lock);
-}
-
-static inline int
-qeth_send_setrtg(struct qeth_card *card, int routing_type, short ip_vers)
-{
-       struct ipa_cmd cmd;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_SETRTG, ip_vers);
-       /* strip off RESET_ROUTING_FLAG */
-       cmd.data.setrtg.type = (routing_type) & (ROUTER_MASK);
-
-       return qeth_send_ipa_cmd(card, &cmd, 0, IPA_CMD_STATE);
-}
-
-static int
-qeth_is_ipa_in_list(struct in_ifaddr *ip, struct in_ifaddr *list)
-{
-       while (list) {
-               if (ip->ifa_address == list->ifa_address)
-                       return 1;
-               list = list->ifa_next;
-       }
-       return 0;
-}
-
-#ifdef QETH_IPV6
-static int
-qeth_is_ipa_in_list6(struct inet6_ifaddr *ip, struct inet6_ifaddr *list)
-{
-       while (list) {
-               if (!memcmp(&ip->addr.s6_addr, &list->addr.s6_addr, 16))
-                       return 1;
-               list = list->if_next;
-       }
-       return 0;
-}
-
-static int
-qeth_add_ifa6_to_list(struct inet6_ifaddr **list, struct inet6_ifaddr *ifa)
-{
-       struct inet6_ifaddr *i;
-
-       if (*list == NULL) {
-               *list = ifa;
-       } else {
-               if (qeth_is_ipa_in_list6(ifa, *list))
-                       return -EALREADY;
-               i = *list;
-               while (i->if_next) {
-                       i = i->if_next;
-               }
-               i->if_next = ifa;
-       }
-       ifa->if_next = NULL;
-       return 0;
-}
-#endif /* QETH_IPV6 */
-
-static int
-qeth_add_ifa_to_list(struct in_ifaddr **list, struct in_ifaddr *ifa)
-{
-       struct in_ifaddr *i;
-
-       if (*list == NULL) {
-               *list = ifa;
-       } else {
-               if (qeth_is_ipa_in_list(ifa, *list))
-                       return -EALREADY;
-               i = *list;
-               while (i->ifa_next) {
-                       i = i->ifa_next;
-               }
-               i->ifa_next = ifa;
-       }
-       ifa->ifa_next = NULL;
-       return 0;
-}
-
-static void
-__qeth_setips_ipv6(struct qeth_card *card, int use_setip_retries)
-{
-#ifdef QETH_IPV6
-       int result;
-       char dbf_text[15];
-       struct inet6_ifaddr *addr6;
-       __u8 netmask[16];
-
-#define FILL_NETMASK(len) { \
-       int i,j; \
-       for (i=0;i<16;i++) { \
-               j=(len)-(i*8); \
-               netmask[i]=(__u8)(0xFF00>>j); \
-       } \
-}
-       /* here we go with IPv6 */
-       addr6 = card->ip_current_state.ip6_ifa;
-       while (addr6) {
-               if (qeth_is_ipa_in_list6(addr6, card->ip_new_state.ip6_ifa)) {
-                       addr6 = addr6->if_next;
-                       continue;
-               }
-               QETH_DBF_TEXT3(0, trace, "setipdl6");
-               QETH_DBF_HEX3(0, trace, &addr6->addr.s6_addr,
-                             QETH_DBF_TRACE_LEN);
-               QETH_DBF_HEX3(0, trace,
-                             ((char *) (&addr6->addr.s6_addr)) +
-                             QETH_DBF_TRACE_LEN, QETH_DBF_TRACE_LEN);
-               sprintf(dbf_text, "nmsk%4u", addr6->prefix_len);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               FILL_NETMASK(addr6->prefix_len);
-               result = qeth_send_delip(card,
-                                        (__u8 *) & addr6->addr.s6_addr,
-                                        (__u8 *) & netmask, 6);
-               if (result) {
-                       PRINT_ERR("was not able to delete ip "
-                                 "%04x:%04x:%04x:%04x:%04x:%04x:"
-                                 "%04x:%04x/%u on device %s "
-                                 "(result: 0x%x), "
-                                 "trying to continue\n",
-                                 addr6->addr.s6_addr16[0],
-                                 addr6->addr.s6_addr16[1],
-                                 addr6->addr.s6_addr16[2],
-                                 addr6->addr.s6_addr16[3],
-                                 addr6->addr.s6_addr16[4],
-                                 addr6->addr.s6_addr16[5],
-                                 addr6->addr.s6_addr16[6],
-                                 addr6->addr.s6_addr16[7],
-                                 addr6->prefix_len,
-                                 CARD_BUS_ID(card), result);
-                       sprintf(dbf_text, "std6%4x", result);
-                       QETH_DBF_TEXT3(0, trace, dbf_text);
-               }
-               addr6 = addr6->if_next;
-       }
-
-       addr6 = card->ip_new_state.ip6_ifa;
-       while (addr6) {
-               if (qeth_is_ipa_in_list6(addr6,
-                                         card->ip_current_state.ip6_ifa)) {
-                       addr6 = addr6->if_next;
-                       continue;
-               }
-               QETH_DBF_TEXT3(0, trace, "setipst6");
-               QETH_DBF_HEX3(0, trace, &addr6->addr.s6_addr,
-                             QETH_DBF_TRACE_LEN);
-               QETH_DBF_HEX3(0, trace,
-                             ((char *) (&addr6->addr.s6_addr)) +
-                             QETH_DBF_TRACE_LEN, QETH_DBF_TRACE_LEN);
-               sprintf(dbf_text, "nmsk%4u", addr6->prefix_len);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               FILL_NETMASK(addr6->prefix_len);
-               result = qeth_send_setip(card,
-                                        (__u8 *) & addr6->addr.s6_addr,
-                                        (__u8 *) & netmask, 6,
-                                        use_setip_retries);
-               if (!result) {
-                       addr6 = addr6->if_next;
-                       continue;
-               }
-               PRINT_ERR("was not able to set ip "
-                         "%04x:%04x:%04x:%04x:%04x:%04x:"
-                         "%04x:%04x/%u on device %s "
-                         "(result: 0x%x), trying to continue\n",
-                         addr6->addr.s6_addr16[0],
-                         addr6->addr.s6_addr16[1],
-                         addr6->addr.s6_addr16[2],
-                         addr6->addr.s6_addr16[3],
-                         addr6->addr.s6_addr16[4],
-                         addr6->addr.s6_addr16[5],
-                         addr6->addr.s6_addr16[6],
-                         addr6->addr.s6_addr16[7],
-                         addr6->prefix_len,
-                         CARD_BUS_ID(card), result);
-               sprintf(dbf_text, "sts6%4x", result);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               addr6 = addr6->if_next;
-       }
-#endif /* QETH_IPV6 */
-}
-
-static int
-qeth_setips(struct qeth_card *card, int use_setip_retries)
-{
-       struct in_ifaddr *addr;
-       int result;
-       char dbf_text[15];
-
-       QETH_DBF_CARD3(0, trace, "stip", card);
-
-       addr = card->ip_current_state.ip_ifa;
-       while (addr) {
-               if (!qeth_is_ipa_in_list(addr, card->ip_new_state.ip_ifa)) {
-                       QETH_DBF_TEXT3(0, trace, "setipdel");
-                       *((__u32 *) (&dbf_text[0])) =
-                           *((__u32 *) & addr->ifa_address);
-                       *((__u32 *) (&dbf_text[4])) =
-                           *((__u32 *) & addr->ifa_mask);
-                       QETH_DBF_HEX3(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-                       result =
-                           qeth_send_delip(card, (__u8 *) & addr->ifa_address,
-                                           (__u8 *) & addr->ifa_mask, 4);
-                       if (result) {
-                               PRINT_ERR("was not able to delete ip "
-                                         "%08x/%08x on device %s "
-                                         "(result: 0x%x), "
-                                         "trying to continue\n",
-                                         addr->ifa_address, addr->ifa_mask,
-                                         CARD_BUS_ID(card), result);
-                               sprintf(dbf_text, "stdl%4x", result);
-                               QETH_DBF_TEXT3(0, trace, dbf_text);
-                       }
-               }
-               addr = addr->ifa_next;
-       }
-
-       addr = card->ip_new_state.ip_ifa;
-       while (addr) {
-               if (qeth_is_ipa_in_list(addr, card->ip_current_state.ip_ifa)) {
-                       addr = addr->ifa_next;
-                       continue;
-               }
-               QETH_DBF_TEXT3(0, trace, "setipset");
-               *((__u32 *) (&dbf_text[0])) = *((__u32 *) & addr->ifa_address);
-               *((__u32 *) (&dbf_text[4])) = *((__u32 *) & addr->ifa_mask);
-               QETH_DBF_HEX3(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-               result = qeth_send_setip(card, (__u8 *) & addr->ifa_address,
-                                        (__u8 *) & addr->ifa_mask, 4,
-                                        use_setip_retries);
-               if (!result) {
-                       addr = addr->ifa_next;
-                       continue;
-               }
-               PRINT_ERR("was not able to set ip "
-                         "%08x/%08x on device %s, trying to continue\n",
-                         addr->ifa_address, addr->ifa_mask,
-                         CARD_BUS_ID(card));
-               sprintf(dbf_text, "stst%4x", result);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               addr = addr->ifa_next;
-       }
-
-       __qeth_setips_ipv6(card, use_setip_retries);
-
-       return 0;
-}
-
-static int
-qeth_is_ipma_in_list(struct qeth_ipm_mac *ipma, struct qeth_ipm_mac *list)
-{
-       while (list) {
-               if ((!memcmp(ipma->ip, list->ip, 16)) &&
-                   (!memcmp(ipma->mac, list->mac, 6)))
-                       return 1;
-               list = list->next;
-       }
-       return 0;
-}
-
-static void
-qeth_remove_mc_ifa_from_list(struct qeth_ipm_mac **list,
-                            struct qeth_ipm_mac *ipma)
-{
-       struct qeth_ipm_mac *i, *li = NULL;
-
-       if ((!(*list)) || (!ipma))
-               return;
-
-       if (*list == ipma) {
-               *list = ipma->next;
-       } else {
-               i = *list;
-               while (i) {
-                       if (i == ipma) {
-                               li->next = i->next;
-                       } else {
-                               li = i;
-                       }
-                       i = i->next;
-               }
-       }
-}
-
-static int
-qeth_add_mc_ifa_to_list(struct qeth_ipm_mac **list, struct qeth_ipm_mac *ipma)
-{
-       struct qeth_ipm_mac *i;
-
-       if (qeth_is_ipma_in_list(ipma, *list))
-               return -EALREADY;
-
-       if (*list == NULL) {
-               *list = ipma;
-       } else {
-               i = *list;
-               while (i->next) {
-                       i = i->next;
-               }
-               i->next = ipma;
-       }
-       ipma->next = NULL;
-       return 0;
-}
-
-static void
-__qeth_setipms_ipv6(struct qeth_card *card, int use_setipm_retries)
-{
-#ifdef QETH_IPV6
-       struct qeth_ipm_mac *addr;
-       int result;
-       char dbf_text[15];
-
-       /* here we go with IPv6 */
-       addr = card->ip_mc_current_state.ipm6_ifa;
-       while (addr) {
-               if (!qeth_is_ipma_in_list(addr,
-                                         card->ip_mc_new_state.ipm6_ifa)) {
-                       QETH_DBF_TEXT3(0, trace, "setimdl6");
-                       QETH_DBF_HEX3(0, trace, &addr->ip[0],
-                                     QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX3(0, trace,
-                                     (&addr->ip[0]) + QETH_DBF_TRACE_LEN,
-                                     QETH_DBF_TRACE_LEN);
-                       QETH_DBF_HEX3(0, trace, &addr->mac,
-                                     QETH_DBF_TRACE_LEN);
-                       result = qeth_send_delipm(card,
-                                                 (__u8 *) & addr->ip[0],
-                                                 (__u8 *) addr->mac, 6);
-                       if (result) {
-                               PRINT_ERR("was not able to delete "
-                                         "multicast ip %04x:%04x:"
-                                         "%04x:%04x:%04x:%04x:%04x:%04x/"
-                                         "%02x%02x%02x%02x%02x%02x "
-                                         "on device %s (result: 0x%x), "
-                                         "trying to continue\n",
-                                         *((__u16 *) & addr->ip[0]),
-                                         *((__u16 *) & addr->ip[2]),
-                                         *((__u16 *) & addr->ip[4]),
-                                         *((__u16 *) & addr->ip[6]),
-                                         *((__u16 *) & addr->ip[8]),
-                                         *((__u16 *) & addr->ip[10]),
-                                         *((__u16 *) & addr->ip[12]),
-                                         *((__u16 *) & addr->ip[14]),
-                                         addr->mac[0], addr->mac[1],
-                                         addr->mac[2], addr->mac[3],
-                                         addr->mac[4], addr->mac[5],
-                                         CARD_BUS_ID(card), result);
-                               sprintf(dbf_text, "smd6%4x", result);
-                               QETH_DBF_TEXT3(0, trace, dbf_text);
-                       }
-               }
-               addr = addr->next;
-       }
-
-       addr = card->ip_mc_new_state.ipm6_ifa;
-       while (addr) {
-               if (qeth_is_ipma_in_list(addr,
-                                        card->ip_mc_current_state.ipm6_ifa)) {
-                       qeth_remove_mc_ifa_from_list(
-                                       &card->ip_mc_new_state.ipm6_ifa,
-                                       addr);
-                       addr = addr->next;
-                       continue;
-               }
-               QETH_DBF_TEXT3(0, trace, "setimst6");
-               QETH_DBF_HEX3(0, trace, &addr->ip[0], QETH_DBF_TRACE_LEN);
-               QETH_DBF_HEX3(0, trace, (&addr->ip[0]) + QETH_DBF_TRACE_LEN,
-                             QETH_DBF_TRACE_LEN);
-               QETH_DBF_HEX3(0, trace, &addr->mac, QETH_DBF_TRACE_LEN);
-               result = qeth_send_setipm(card,
-                                         (__u8 *) & addr->ip[0],
-                                         (__u8 *) addr->mac, 6,
-                                         use_setipm_retries);
-               if (result) {
-                       PRINT_ERR("was not able to set "
-                                 "multicast ip %04x:%04x:"
-                                 "%04x:%04x:%04x:%04x:%04x:%04x/"
-                                 "%02x%02x%02x%02x%02x%02x "
-                                 "on device %s (result: 0x%x), "
-                                 "trying to continue\n",
-                                 *((__u16 *) & addr->ip[0]),
-                                 *((__u16 *) & addr->ip[2]),
-                                 *((__u16 *) & addr->ip[4]),
-                                 *((__u16 *) & addr->ip[6]),
-                                 *((__u16 *) & addr->ip[8]),
-                                 *((__u16 *) & addr->ip[10]),
-                                 *((__u16 *) & addr->ip[12]),
-                                 *((__u16 *) & addr->ip[14]),
-                                 addr->mac[0], addr->mac[1],
-                                 addr->mac[2], addr->mac[3],
-                                 addr->mac[4], addr->mac[5],
-                                 CARD_BUS_ID(card), result);
-                       sprintf(dbf_text, "sms6%4x", result);
-                       QETH_DBF_TEXT3(0, trace, dbf_text);
-               } else {
-                       qeth_remove_mc_ifa_from_list(
-                                       &card->ip_mc_new_state.ipm6_ifa,
-                                       addr);
-                       qeth_add_mc_ifa_to_list(
-                                       &card->ip_mc_current_state.ipm6_ifa,
-                                       addr);
-               }
-               addr = addr->next;
-       }
-#endif /* QETH_IPV6 */
-}
-
-static int
-qeth_setipms(struct qeth_card *card, int use_setipm_retries)
-{
-       struct qeth_ipm_mac *addr;
-       int result;
-       char dbf_text[15];
-
-       QETH_DBF_CARD3(0, trace, "stim", card);
-
-       if (!qeth_is_supported(IPA_MULTICASTING))
-               return 0;
-       addr = card->ip_mc_current_state.ipm_ifa;
-       while (addr) {
-               if (!qeth_is_ipma_in_list(addr,
-                                         card->ip_mc_new_state.ipm_ifa)) {
-                       QETH_DBF_TEXT3(0, trace, "setimdel");
-                       sprintf(dbf_text, "%08x", *((__u32 *) & addr->ip[0]));
-                       QETH_DBF_TEXT3(0, trace, dbf_text);
-                       *((__u32 *) (&dbf_text[0])) = *((__u32 *) & addr->mac);
-                       *((__u32 *) (&dbf_text[4])) = 
-                               *(((__u32 *) & addr->mac) + 1);
-                       QETH_DBF_HEX3(0, trace, dbf_text,
-                                     QETH_DBF_TRACE_LEN);
-                       result = qeth_send_delipm(card,
-                                                 (__u8 *) & addr->ip[0],
-                                                 (__u8 *) addr->mac, 4);
-                       if (result) {
-                               PRINT_ERR("was not able to delete "
-                                         "multicast ip %08x/"
-                                         "%02x%02x%02x%02x%02x%02x "
-                                         "on device %s "
-                                         "(result: 0x%x), "
-                                         "trying to continue\n",
-                                         *((__u32 *) & addr->ip[0]),
-                                         addr->mac[0], addr->mac[1],
-                                         addr->mac[2], addr->mac[3],
-                                         addr->mac[4], addr->mac[5],
-                                         CARD_BUS_ID(card), result);
-                               sprintf(dbf_text, "smdl%4x", result);
-                               QETH_DBF_TEXT3(0, trace, dbf_text);
-                       }
-               }
-               addr = addr->next;
-       }
-
-       addr = card->ip_mc_new_state.ipm_ifa;
-       while (addr) {
-               if (qeth_is_ipma_in_list(addr,
-                                        card->ip_mc_current_state.ipm_ifa)) {
-                       addr = addr->next;
-                       continue;
-               }
-               QETH_DBF_TEXT3(0, trace, "setimset");
-               sprintf(dbf_text, "%08x", *((__u32 *) & addr->ip[0]));
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               *((__u32 *) (&dbf_text[0])) = *((__u32 *) & addr->mac);
-               *((__u32 *) (&dbf_text[4])) = *(((__u32 *) & addr->mac) + 1);
-               QETH_DBF_HEX3(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-               result = qeth_send_setipm(card, (__u8 *) & addr->ip[0],
-                                         (__u8 *) addr->mac, 4,
-                                         use_setipm_retries);
-               if (result) {
-                       PRINT_ERR("was not able to set multicast ip %08x/"
-                                 "%02x%02x%02x%02x%02x%02x "
-                                 "on device %s (result: 0x%x), "
-                                 "trying to continue\n",
-                                 *((__u32 *) & addr->ip[0]),
-                                 addr->mac[0], addr->mac[1],
-                                 addr->mac[2], addr->mac[3],
-                                 addr->mac[4], addr->mac[5],
-                                 CARD_BUS_ID(card), result);
-                       sprintf(dbf_text, "smst%4x", result);
-                       QETH_DBF_TEXT3(0, trace, dbf_text);
-                       qeth_remove_mc_ifa_from_list
-                               (&card->ip_mc_current_state.ipm_ifa, addr);
-               }
-               addr = addr->next;
-       }
-       __qeth_setipms_ipv6(card, use_setipm_retries);
-       return 0;
-}
-
-static void
-qeth_clone_ifa(struct in_ifaddr *src, struct in_ifaddr *dest)
-{
-       memcpy(dest, src, sizeof (struct in_ifaddr));
-       dest->ifa_next = NULL;
-}
-
-#ifdef QETH_IPV6
-static void
-qeth_clone_ifa6(struct inet6_ifaddr *src, struct inet6_ifaddr *dest)
-{
-       memcpy(dest, src, sizeof (struct inet6_ifaddr));
-       dest->if_next = NULL;
-}
-#endif /* QETH_IPV6 */
-
-#define QETH_STANDARD_RETVALS \
-               ret_val=-EIO; \
-               if (result == -EFAULT) ret_val = -EFAULT; \
-                if (result==IPA_REPLY_SUCCESS) ret_val=0; \
-               if (result==IPA_REPLY_FAILED) ret_val=-EIO; \
-               if (result==IPA_REPLY_OPNOTSUPP) ret_val=-EOPNOTSUPP
-
-static int
-qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       char *data;
-       int result, i, ret_val;
-       int version = 4;
-       struct qeth_card *card;
-       char dbf_text[15];
-       char buff[100];
-
-       card = (struct qeth_card *) dev->priv;
-
-       PRINT_STUPID("CALL: qeth_do_ioctl called with cmd %i (=0x%x).\n", cmd,
-                    cmd);
-       QETH_DBF_CARD2(0, trace, "ioct", card);
-       sprintf(dbf_text, "cmd=%4x", cmd);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-       QETH_DBF_HEX2(0, trace, &rq, sizeof (void *));
-
-       if ((cmd < SIOCDEVPRIVATE) || (cmd > SIOCDEVPRIVATE + 5))
-               return -EOPNOTSUPP;
-       if (copy_from_user(buff, rq->ifr_ifru.ifru_data, sizeof (buff)))
-               return -EFAULT;
-       data = buff;
-
-       if ((!atomic_read(&card->is_registered)) ||
-           (!atomic_read(&card->is_hardsetup)))
-               return -ENODEV;
-
-       if (atomic_read(&card->shutdown_phase))
-               return -ENODEV;
-
-       spin_lock(&card->ioctl_lock);
-
-       if (atomic_read(&card->shutdown_phase)) {
-               ret_val = -ENODEV;
-               goto out;
-       }
-       if ((!atomic_read(&card->is_registered)) ||
-           (!atomic_read(&card->is_hardsetup))) {
-               ret_val = -ENODEV;
-               goto out;
-       }
-
-       switch (cmd) {
-       case SIOCDEVPRIVATE + 0:
-               if (!capable(CAP_NET_ADMIN)) {
-                       ret_val = -EPERM;
-                       break;
-               }
-               result =
-                   qeth_send_setassparms(card, version, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
-                                         rq->ifr_ifru.ifru_ivalue, 4);
-               QETH_STANDARD_RETVALS;
-               if (result == 3)
-                       ret_val = -EINVAL;
-               break;
-       case SIOCDEVPRIVATE + 1:
-               if (!capable(CAP_NET_ADMIN)) {
-                       ret_val = -EPERM;
-                       break;
-               }
-               result = qeth_queryarp(card, rq, version, IPA_ARP_PROCESSING,
-                                      IPA_CMD_ASS_ARP_QUERY_INFO, data, 4);
-
-               QETH_STANDARD_RETVALS;
-               break;
-       case SIOCDEVPRIVATE + 2:
-               if (!capable(CAP_NET_ADMIN)) {
-                       ret_val = -EPERM;
-                       break;
-               }
-               for (i = 12; i < 24; i++)
-                       if (data[i])
-                               version = 6;
-               result =
-                   qeth_send_setassparms(card, version, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_ADD_ENTRY,
-                                         (long) data, 56);
-               QETH_STANDARD_RETVALS;
-               break;
-       case SIOCDEVPRIVATE + 3:
-               if (!capable(CAP_NET_ADMIN)) {
-                       ret_val = -EPERM;
-                       break;
-               }
-               for (i = 4; i < 12; i++)
-                       if (data[i])
-                               version = 6;
-               result =
-                   qeth_send_setassparms(card, version, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_REMOVE_ENTRY,
-                                         (long) data, 16);
-               QETH_STANDARD_RETVALS;
-               break;
-       case SIOCDEVPRIVATE + 4:
-               if (!capable(CAP_NET_ADMIN)) {
-                       ret_val = -EPERM;
-                       break;
-               }
-               result =
-                   qeth_send_setassparms(card, version, IPA_ARP_PROCESSING,
-                                         IPA_CMD_ASS_ARP_FLUSH_CACHE, 0, 0);
-               QETH_STANDARD_RETVALS;
-               break;
-       case SIOCDEVPRIVATE + 5:
-
-               result =
-                   qeth_send_snmp_control(card, rq, IPA_CMD_SETADAPTERPARMS,
-                                          IPA_SETADP_SET_SNMP_CONTROL, data,
-                                          4);
-               QETH_STANDARD_RETVALS;
-               break;
-
-       default:
-               ret_val = -EOPNOTSUPP;
-               goto out;
-       }
-out:
-       spin_unlock(&card->ioctl_lock);
-
-       sprintf(dbf_text, "ret=%4x", ret_val);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       return ret_val;
-}
-
-static void
-qeth_clear_ifamc_list(struct qeth_ipm_mac **ifa_list)
-{
-       struct qeth_ipm_mac *ifa;
-       while (*ifa_list) {
-               ifa = *ifa_list;
-               *ifa_list = ifa->next;
-               kfree(ifa);
-       }
-}
-
-#ifdef QETH_IPV6
-static void
-qeth_clear_ifa6_list(struct inet6_ifaddr **ifa_list)
-{
-       struct inet6_ifaddr *ifa;
-       while (*ifa_list) {
-               ifa = *ifa_list;
-               *ifa_list = ifa->if_next;
-               kfree(ifa);
-       }
-}
-
-static inline void
-__qeth_append_vlan_ipas_v6(struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       char dbf_text[15];
-       struct vlan_group *card_group;
-       int i;
-       int remove;
-       struct inet6_ifaddr *ifa, *ifanew;
-
-       /*
-        * append all known VLAN IP Addresses corresponding to the real device
-        * card->dev->ifindex
-        */
-       QETH_DBF_TEXT4(0, trace, "to-vip6s");
-       if ((!qeth_is_supported(IPA_FULL_VLAN)) || (!atomic_read(&card->is_open)))
-               return;
-
-       card_group = (struct vlan_group *) card->vlangrp;
-       
-       if (!card_group)
-               return;
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-               if (!card_group->vlan_devices[i] ||
-                   !(card_group->vlan_devices[i]->flags & IFF_UP) ||
-                   !(struct inet6_dev *) card_group->vlan_devices[i]->ip6_ptr)
-                       continue;
-               ifa = ((struct inet6_dev *)
-                      card_group->vlan_devices[i]->ip6_ptr)->addr_list;
-               
-               while (ifa) {
-                       ifanew = kmalloc(sizeof(struct inet6_ifaddr),
-                                        GFP_KERNEL);
-                       if (!ifanew) {
-                               PRINT_WARN("No memory for IP address "
-                                          "handling. Some of the IPs "
-                                          "will not be set on %s.\n",
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPNMEM");
-                       } else {
-                               qeth_clone_ifa6(ifa, ifanew);
-                               remove = qeth_add_ifa6_to_list
-                                       (&card->ip_new_state.ip6_ifa, ifanew);
-                               QETH_DBF_HEX4(0, trace,
-                                             &ifanew->addr.s6_addr,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace,
-                                             &ifanew->addr.s6_addr +
-                                             QETH_DBF_TRACE_LEN,
-                                             QETH_DBF_TRACE_LEN);
-                               sprintf(dbf_text, "pref%4u", ifanew->prefix_len);
-                               QETH_DBF_TEXT4(0, trace, dbf_text);
-                               if (remove) {
-                                       kfree(ifanew);
-                                       QETH_DBF_TEXT4(0, trace, "alrdv6rm");
-                               }
-                       }
-                       ifa = ifa->if_next;
-               }
-       }
-#endif
-}
-
-static inline void
-__qeth_append_vlan_ipas_v6_mc(struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       struct vlan_group *card_group;
-       int i;
-       int remove;
-       struct inet6_dev *in6_vdev;
-       char buf[MAX_ADDR_LEN];
-       struct qeth_ipm_mac *ipmanew;
-       struct ifmcaddr6 *im6;
-       
-       QETH_DBF_TEXT4(0, trace, "tovipm6s");
-       if (!qeth_is_supported(IPA_FULL_VLAN) || !atomic_read(&card->is_open))
-               return;
-
-       card_group = (struct vlan_group *) card->vlangrp;
-       if (!card_group)
-               return;
-
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-               if (!card_group->vlan_devices[i] ||
-                   !(card_group->vlan_devices[i]->flags & IFF_UP))
-                       continue;
-               
-               in6_vdev = in6_dev_get(card_group->vlan_devices[i]);
-               if (!in6_vdev) {
-                       QETH_DBF_CARD2(0, trace, "id26", card);
-                       continue;
-               }
-
-               read_lock(&in6_vdev->lock);
-               for (im6 = in6_vdev->mc_list; im6; im6 = im6->next) {
-                       ndisc_mc_map(&im6->mca_addr, buf,
-                                    card_group->vlan_devices[i], 0);
-                       ipmanew = (struct qeth_ipm_mac *)
-                               kmalloc(sizeof(struct qeth_ipm_mac), GFP_KERNEL);
-                       if (!ipmanew) {
-                               PRINT_WARN("No memory for IPM address "
-                                          "handling. Multicast IP "
-                                          "%04x:%04x:%04x:%04x:%04x:"
-                                          "%04x:%04x:%04x"
-                                          "will not be set on %s.\n",
-                                          im6->mca_addr.s6_addr16[0],
-                                          im6->mca_addr.s6_addr16[1],
-                                          im6->mca_addr.s6_addr16[2],
-                                          im6->mca_addr.s6_addr16[3],
-                                          im6->mca_addr.s6_addr16[4],
-                                          im6->mca_addr.s6_addr16[5],
-                                          im6->mca_addr.s6_addr16[6],
-                                          im6->mca_addr.s6_addr16[7],
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPMNMM");
-                       } else {
-                               memset(ipmanew, 0, sizeof(struct qeth_ipm_mac));
-                               memcpy(ipmanew->mac, buf,OSA_ADDR_LEN);
-                               memcpy(ipmanew->ip, im6->mca_addr.s6_addr, 16);
-                               ipmanew->next = NULL;
-                               remove = qeth_add_mc_ifa_to_list
-                                       (&card->ip_mc_new_state.ipm6_ifa,
-                                                ipmanew);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->ip,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->ip +
-                                             QETH_DBF_TRACE_LEN,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->mac,
-                                             QETH_DBF_TRACE_LEN);
-                               
-                               if (remove) {
-                                       QETH_DBF_TEXT4(0, trace, "mlrdv6rm");
-                                       kfree(ipmanew);
-                               }
-                       }
-               }
-               read_unlock(&in6_vdev->lock);
-               in6_dev_put(in6_vdev);
-       }
-#endif
-}
-
-static struct inet6_dev *
-__qeth_get_mc_lock_v6(struct qeth_card *card)
-{
-       struct inet6_dev *in6_dev;
-
-       in6_dev = in6_dev_get(card->dev);
-
-       if (!in6_dev) {
-               QETH_DBF_CARD2(0, trace, "id16", card);
-               return ERR_PTR(-ENODEV);
-       }
-       read_lock(&in6_dev->lock);
-       return in6_dev;
-}
-
-static void
-__qeth_takeover_ip_ipms6_mc(struct qeth_card *card, struct inet6_dev *in6_dev)
-{
-       int remove;
-       struct qeth_ipm_mac *ipmanew;
-       struct ifmcaddr6 *im6;
-       char buf[MAX_ADDR_LEN];
-
-       QETH_DBF_TEXT4(0, trace, "to-ipm6s");
-       if (atomic_read(&card->is_open))
-               for (im6 = in6_dev->mc_list; im6; im6 = im6->next) {
-                       ndisc_mc_map(&im6->mca_addr, buf, card->dev, 0);
-                       ipmanew =
-                           (struct qeth_ipm_mac *)
-                           kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
-                       if (!ipmanew) {
-                               PRINT_WARN("No memory for IPM address "
-                                          "handling. Multicast IP "
-                                          "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-                                          "will not be set on %s.\n",
-                                          im6->mca_addr.s6_addr16[0],
-                                          im6->mca_addr.s6_addr16[1],
-                                          im6->mca_addr.s6_addr16[2],
-                                          im6->mca_addr.s6_addr16[3],
-                                          im6->mca_addr.s6_addr16[4],
-                                          im6->mca_addr.s6_addr16[5],
-                                          im6->mca_addr.s6_addr16[6],
-                                          im6->mca_addr.s6_addr16[7],
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPMNMM");
-                       } else {
-                               memset(ipmanew, 0,
-                                      sizeof (struct qeth_ipm_mac));
-                               memcpy(ipmanew->mac, buf, OSA_ADDR_LEN);
-                               memcpy(ipmanew->ip, im6->mca_addr.s6_addr, 16);
-                               ipmanew->next = NULL;
-                               remove =
-                                   qeth_add_mc_ifa_to_list(&card->
-                                                           ip_mc_new_state.
-                                                           ipm6_ifa, ipmanew);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->ip,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace,
-                                             &ipmanew->ip + QETH_DBF_TRACE_LEN,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->mac,
-                                             QETH_DBF_TRACE_LEN);
-                               if (remove) {
-                                       QETH_DBF_TEXT4(0, trace, "mlrdy6rm");
-                                       kfree(ipmanew);
-                               }
-                       }
-               }
-       __qeth_append_vlan_ipas_v6_mc(card);
-
-       read_unlock(&in6_dev->lock);
-       in6_dev_put(in6_dev);
-}
-#endif /* QETH_IPV6 */
-
-static void
-qeth_takeover_ip_ipms6(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       struct inet6_ifaddr *ifa, *ifanew;
-       char dbf_text[15];
-       int remove;
-       struct inet6_dev *in6_dev;
-
-       QETH_DBF_CARD3(0, trace, "tip6", card);
-       /* unicast */
-       /* clear ip_current_state */
-       qeth_clear_ifa6_list(&card->ip_current_state.ip6_ifa);
-       /* take it over */
-       card->ip_current_state.ip6_ifa = card->ip_new_state.ip6_ifa;
-       card->ip_new_state.ip6_ifa = NULL;
-
-       in6_dev = __qeth_get_mc_lock_v6(card);
-       if (PTR_ERR(in6_dev) == -ENODEV)
-               return;
-       /* get new one, we try to have the same order as ifa_list in device
-          structure, for what reason ever */
-       QETH_DBF_TEXT4(0, trace, "to-ip6s");
-       if ((atomic_read(&card->is_open)) && (card->dev->ip6_ptr) &&
-           (((struct inet6_dev *) card->dev->ip6_ptr)->addr_list)) {
-               ifa = ((struct inet6_dev *) card->dev->ip6_ptr)->addr_list;
-
-               while (ifa) {
-                       ifanew =
-                           kmalloc(sizeof (struct inet6_ifaddr), GFP_ATOMIC);
-                       if (!ifanew) {
-                               PRINT_WARN("No memory for IP address "
-                                          "handling. Some of the IPs "
-                                          "will not be set on %s.\n",
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPNMEM");
-                       } else {
-                               qeth_clone_ifa6(ifa, ifanew);
-                               remove =
-                                   qeth_add_ifa6_to_list(&card->ip_new_state.
-                                                         ip6_ifa, ifanew);
-                               QETH_DBF_HEX4(0, trace, &ifanew->addr.s6_addr,
-                                             QETH_DBF_TRACE_LEN);
-                               QETH_DBF_HEX4(0, trace,
-                                             &ifanew->addr.s6_addr +
-                                             QETH_DBF_TRACE_LEN,
-                                             QETH_DBF_TRACE_LEN);
-                               sprintf(dbf_text, "pref%4u",
-                                       ifanew->prefix_len);
-                               QETH_DBF_TEXT4(0, trace, dbf_text);
-                               if (remove) {
-                                       kfree(ifanew);
-                                       QETH_DBF_TEXT4(0, trace, "alrdy6rm");
-                               }
-                       }
-                       ifa = ifa->if_next;
-               }
-       }
-
-       __qeth_append_vlan_ipas_v6(card);
-       
-       __qeth_takeover_ip_ipms6_mc(card, in6_dev);
-#endif /* QETH_IPV6 */
-}
-
-static void
-qeth_clear_ifa4_list(struct in_ifaddr **ifa_list)
-{
-       struct in_ifaddr *ifa;
-       while (*ifa_list) {
-               ifa = *ifa_list;
-               *ifa_list = ifa->ifa_next;
-               kfree(ifa);
-       }
-}
-
-static inline void
-__qeth_append_vlan_ipas_v4(struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       struct in_ifaddr *ifa, *ifanew;
-       char dbf_text[15];
-       struct vlan_group *card_group;
-       int i;
-       int remove;
-       struct in_device *vin4_dev;
-
-       /*
-        * append all known VLAN IP Addresses corresponding to the real device
-        * card->dev->ifindex
-        */
-       QETH_DBF_TEXT4(0, trace, "to-vips");
-       if (!qeth_is_supported(IPA_FULL_VLAN) || !atomic_read(&card->is_open))
-               return;
-
-       card_group = (struct vlan_group *) card->vlangrp;
-       if (!card_group)
-               return;
-
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-               vin4_dev = in_dev_get(card->dev);
-               if (!vin4_dev) {
-                       QETH_DBF_TEXT2(0, trace, "nodvhol2");
-                       QETH_DBF_TEXT2(0, trace, card->dev_name);
-                       continue;
-               }
-               read_lock(&vin4_dev->lock);
-
-               if ((card_group->vlan_devices[i]) &&
-                   (card_group->vlan_devices[i]->flags & IFF_UP)) {
-                       ifa = ((struct in_device *)
-                              card_group->vlan_devices[i]->ip_ptr)->ifa_list;
-                       while (ifa) {
-                               ifanew = kmalloc(sizeof(struct in_ifaddr),
-                                                GFP_KERNEL);
-                               if (!ifanew) {
-                                       PRINT_WARN("No memory for IP address "
-                                                  "handling. Some of the IPs "
-                                                  "will not be set on %s.\n",
-                                                  card->dev_name);
-                                       QETH_DBF_TEXT2(0, trace, "TOIPNMEM");
-                               } else {
-                                       qeth_clone_ifa(ifa, ifanew);
-                                       remove = qeth_add_ifa_to_list
-                                               (&card->ip_new_state.ip_ifa,
-                                                ifanew);
-                                       *((__u32*) (&dbf_text[0])) =
-                                               *((__u32*) &ifanew->ifa_address);
-                                       *((__u32*) (&dbf_text[4])) =
-                                               *((__u32*) &ifanew->ifa_mask);
-                                       QETH_DBF_TEXT4(0, trace, dbf_text);
-                                       if (remove) {
-                                               kfree(ifanew);
-                                               QETH_DBF_TEXT4(0, trace,
-                                                              "alrdv4rm");
-                                       }
-                               }
-                               ifa = ifa->ifa_next;
-                       }
-               }               
-
-               read_unlock(&vin4_dev->lock);
-               in_dev_put(vin4_dev);
-       }
-#endif /* QETH_VLAN */
-
-}
-
-static inline void
-__qeth_append_vlan_ipas_v4_mc(struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       char dbf_text[15];
-       int i;
-       int remove;
-       struct vlan_group *card_group;
-       struct in_device *vin4_dev;
-       struct qeth_ipm_mac *ipmanew;
-       struct ip_mc_list *im4;
-       char buf[MAX_ADDR_LEN];
-       __u32 maddr;
-       
-       QETH_DBF_TEXT4(0, trace, "to-vipms");
-       if (!qeth_is_supported(IPA_FULL_VLAN) || !atomic_read(&card->is_open))
-               return;
-
-       card_group = (struct vlan_group *) card->vlangrp;
-       if (!card_group)
-               return;
-
-       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-               if (!card_group->vlan_devices[i] ||
-                   !(card_group->vlan_devices[i]->flags & IFF_UP))
-                       continue;
-
-               vin4_dev = in_dev_get(card_group->vlan_devices[i]);
-               if (!vin4_dev) {
-                       QETH_DBF_TEXT2(0, trace, "novdhol3");
-                       QETH_DBF_TEXT2(0, trace, card->dev_name);
-                       QETH_DBF_TEXT2(0, trace,
-                                      card_group->vlan_devices[i]->name);
-                       continue;
-               }
-               read_lock(&vin4_dev->lock);
-               for (im4 = vin4_dev->mc_list; im4; im4 = im4->next) {
-                       qeth_get_mac_for_ipm(im4->multiaddr, buf, vin4_dev->dev);
-                       ipmanew = (struct qeth_ipm_mac *)
-                               kmalloc(sizeof(struct qeth_ipm_mac), GFP_KERNEL);
-                       if (!ipmanew) {
-                               PRINT_WARN("No memory for IPM address "
-                                          "handling. Multicast VLAN IP %08x"
-                                          "will not be set on %s.\n",
-                                          (__u32) im4->multiaddr,
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPMNMM");
-                       } else {
-                               memset(ipmanew, 0, sizeof(struct qeth_ipm_mac));
-                               memcpy(ipmanew->mac, buf, OSA_ADDR_LEN);
-                               maddr = im4->multiaddr;
-                               memcpy(&(ipmanew->ip[0]), &maddr, 4);
-                               memset(&(ipmanew->ip[4]), 0xff, 12);
-                               ipmanew->next = NULL;
-                               remove = qeth_add_mc_ifa_to_list
-                                       (&card->ip_mc_new_state.ipm_ifa,
-                                        ipmanew);
-                               sprintf(dbf_text, "%08x",
-                                       *((__u32 *) &ipmanew->ip));
-                               QETH_DBF_TEXT4(0, trace, dbf_text);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->mac,
-                                             QETH_DBF_TRACE_LEN);
-                               if (remove) {
-                                       QETH_DBF_TEXT4(0, trace, "mlrdv4rm");
-                                       kfree(ipmanew);
-                               }
-                       }
-               }
-               read_unlock(&vin4_dev->lock);
-               in_dev_put(vin4_dev);
-       }
-#endif /* QETH_VLAN */
-
-}
-
-static struct in_device *
-__qeth_get_mc_lock(struct qeth_card *card)
-{
-       struct in_device *in4_dev;
-
-       /* multicast */
-       /* clear ip_mc_current_state */
-       qeth_clear_ifamc_list(&card->ip_mc_current_state.ipm_ifa);
-       /* take it over */
-       card->ip_mc_current_state.ipm_ifa = card->ip_mc_new_state.ipm_ifa;
-       /* get new one, we try to have the same order as ifa_list in device
-          structure, for what reason ever */
-       card->ip_mc_new_state.ipm_ifa = NULL;
-
-       in4_dev = in_dev_get(card->dev);
-       if (!in4_dev) {
-               QETH_DBF_TEXT2(0, trace, "nodvhol1");
-               QETH_DBF_TEXT2(0, trace, card->dev_name);
-               return ERR_PTR(-ENODEV);
-       }
-       read_lock(&in4_dev->lock);
-       return in4_dev;
-}
-
-static void
-__qeth_takeover_ip_ipms_mc(struct qeth_card *card, struct in_device *in4_dev)
-{
-       char dbf_text[15];
-       int remove;
-       struct qeth_ipm_mac *ipmanew;
-       struct ip_mc_list *im4;
-       char buf[MAX_ADDR_LEN];
-       __u32 maddr;
-
-       QETH_DBF_TEXT4(0, trace, "to-ipms");
-       if (atomic_read(&card->is_open))
-               for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
-                       qeth_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
-                       ipmanew =
-                           (struct qeth_ipm_mac *)
-                           kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
-                       if (!ipmanew) {
-                               PRINT_WARN("No memory for IPM address "
-                                          "handling. Multicast IP %08x"
-                                          "will not be set on %s.\n",
-                                          (__u32) im4->multiaddr,
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPMNMM");
-                       } else {
-                               memset(ipmanew, 0,
-                                      sizeof (struct qeth_ipm_mac));
-                               memcpy(ipmanew->mac, buf, OSA_ADDR_LEN);
-                               maddr = im4->multiaddr;
-                               memcpy(&(ipmanew->ip[0]), &maddr, 4);
-                               memset(&(ipmanew->ip[4]), 0xff, 12);
-                               ipmanew->next = NULL;
-                               remove =
-                                   qeth_add_mc_ifa_to_list(&card->
-                                                           ip_mc_new_state.
-                                                           ipm_ifa, ipmanew);
-                               sprintf(dbf_text, "%08x",
-                                       *((__u32 *) & ipmanew->ip));
-                               QETH_DBF_TEXT4(0, trace, dbf_text);
-                               QETH_DBF_HEX4(0, trace, &ipmanew->mac,
-                                             QETH_DBF_TRACE_LEN);
-                               if (remove) {
-                                       QETH_DBF_TEXT4(0, trace, "mlrdy4rm");
-                                       kfree(ipmanew);
-                               }
-                       }
-               }
-       __qeth_append_vlan_ipas_v4(card);
-
-       read_unlock(&in4_dev->lock);
-       in_dev_put(in4_dev);
-
-}
-
-static void
-qeth_takeover_ip_ipms(struct qeth_card *card)
-{
-       struct in_ifaddr *ifa, *ifanew;
-       char dbf_text[15];
-       int remove;
-       struct in_device *in4_dev;
-
-       QETH_DBF_CARD3(0, trace, "tips", card);
-       /* unicast */
-       /* clear ip_current_state */
-       qeth_clear_ifa4_list(&card->ip_current_state.ip_ifa);
-       /* take it over */
-       card->ip_current_state.ip_ifa = card->ip_new_state.ip_ifa;
-       card->ip_new_state.ip_ifa = NULL;
-
-       in4_dev = __qeth_get_mc_lock(card);
-       if (PTR_ERR(in4_dev) == -ENODEV)
-               return;
-
-       /* get new one, we try to have the same order as ifa_list in device
-          structure, for what reason ever */
-       QETH_DBF_TEXT4(0, trace, "to-ips");
-       if ((atomic_read(&card->is_open)) && (card->dev->ip_ptr) &&
-           (((struct in_device *) card->dev->ip_ptr)->ifa_list)) {
-               ifa = ((struct in_device *) card->dev->ip_ptr)->ifa_list;
-
-               while (ifa) {
-                       ifanew = kmalloc(sizeof (struct in_ifaddr), GFP_ATOMIC);
-                       if (!ifanew) {
-                               PRINT_WARN("No memory for IP address "
-                                          "handling. Some of the IPs "
-                                          "will not be set on %s.\n",
-                                          card->dev_name);
-                               QETH_DBF_TEXT2(0, trace, "TOIPNMEM");
-                       } else {
-                               qeth_clone_ifa(ifa, ifanew);
-                               remove =
-                                   qeth_add_ifa_to_list(&card->ip_new_state.
-                                                        ip_ifa, ifanew);
-                               *((__u32 *) (&dbf_text[0])) =
-                                   *((__u32 *) & ifanew->ifa_address);
-                               *((__u32 *) (&dbf_text[4])) =
-                                   *((__u32 *) & ifanew->ifa_mask);
-                               QETH_DBF_TEXT4(0, trace, dbf_text);
-                               if (remove) {
-                                       kfree(ifanew);
-                                       QETH_DBF_TEXT4(0, trace, "alrdy4rm");
-                               }
-                       }
-
-                       ifa = ifa->ifa_next;
-               }
-       }
-       __qeth_append_vlan_ipas_v4(card);
-
-       __qeth_takeover_ip_ipms_mc(card, in4_dev);
-}
-
-static void
-qeth_get_unique_id(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       struct ipa_cmd cmd;
-       int result;
-       char dbf_text[15];
-
-       if (!qeth_is_supported(IPA_IPv6)) {
-               card->unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
-                   UNIQUE_ID_NOT_BY_CARD;
-               return;
-       }
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_CREATE_ADDR, 6);
-
-       *((__u16 *) & cmd.data.create_destroy_addr.unique_id[6]) =
-           card->unique_id;
-
-       result = qeth_send_ipa_cmd(card, &cmd, 1, IPA_CMD_STATE);
-
-       if (result) {
-               card->unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
-                   UNIQUE_ID_NOT_BY_CARD;
-               PRINT_WARN("couldn't get a unique id from the card on device "
-                          "%s (result=x%x), using default id. ipv6 "
-                          "autoconfig on other lpars may lead to duplicate "
-                          "ip addresses. please use manually "
-                          "configured ones.\n",
-                          CARD_BUS_ID(card), result);
-               QETH_DBF_CARD2(0, trace, "unid fld", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       } else {
-               card->unique_id =
-                   *((__u16 *) & cmd.data.create_destroy_addr.unique_id[6]);
-               QETH_DBF_CARD2(0, setup, "uniqueid", card);
-               sprintf(dbf_text, "%4x", card->unique_id);
-               QETH_DBF_TEXT2(0, setup, dbf_text);
-       }
-#else /* QETH_IPV6 */
-       card->unique_id =
-           UNIQUE_ID_IF_CREATE_ADDR_FAILED | UNIQUE_ID_NOT_BY_CARD;
-#endif /* QETH_IPV6 */
-}
-
-static void
-qeth_put_unique_id(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       struct ipa_cmd cmd;
-       int result;
-       char dbf_text[15];
-
-       /* is also true, if ipv6 is not supported on the card */
-       if ((card->unique_id & UNIQUE_ID_NOT_BY_CARD) == UNIQUE_ID_NOT_BY_CARD)
-               return;
-
-       qeth_fill_ipa_cmd(card, &cmd, IPA_CMD_DESTROY_ADDR, 6);
-       *((__u16 *) & cmd.data.create_destroy_addr.unique_id[6]) =
-           card->unique_id;
-       memcpy(&cmd.data.create_destroy_addr.unique_id[0], card->dev->dev_addr,
-              OSA_ADDR_LEN);
-
-       result = qeth_send_ipa_cmd(card, &cmd, 1, IPA_CMD_STATE);
-
-       if (result) {
-               QETH_DBF_CARD2(0, trace, "unibkfld", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-#else /* QETH_IPV6 */
-       card->unique_id =
-           UNIQUE_ID_IF_CREATE_ADDR_FAILED | UNIQUE_ID_NOT_BY_CARD;
-#endif /* QETH_IPV6 */
-}
-
-static inline void
-__qeth_setparms_hstr(struct qeth_card *card)
-{
-       char dbf_text[15];
-       int result;
-
-       if ((card->link_type != QETH_MPC_LINK_TYPE_HSTR) &&
-           (card->link_type != QETH_MPC_LINK_TYPE_LANE_TR))
-               return;
-
-       QETH_DBF_CARD3(0, trace, "hstr", card);
-       
-       if (qeth_is_adp_supported(IPA_SETADP_SET_BROADCAST_MODE)) {
-               result = qeth_send_setadapterparms_mode
-                       (card, IPA_SETADP_SET_BROADCAST_MODE,
-                        card->options.broadcast_mode);
-               if (result) {
-                       PRINT_WARN("couldn't set broadcast mode on "
-                                  "device %s: x%x\n",
-                                  CARD_BUS_ID(card), result);
-                       QETH_DBF_CARD1(0, trace, "STBRDCST", card);
-                       sprintf(dbf_text, "%4x", result);
-                       QETH_DBF_TEXT1(1, trace, dbf_text);
-               }
-       } else if (card->options.broadcast_mode) {
-               PRINT_WARN("set adapter parameters not available "
-                          "to set broadcast mode, using ALLRINGS "
-                          "on device %s:\n", CARD_BUS_ID(card));
-               QETH_DBF_CARD1(0, trace, "NOBC", card);
-       }
-       
-       if (qeth_is_adp_supported(IPA_SETADP_SET_BROADCAST_MODE)) {
-               result = qeth_send_setadapterparms_mode
-                       (card, IPA_SETADP_ALTER_MAC_ADDRESS,
-                        card->options.macaddr_mode);
-               if (result) {
-                       PRINT_WARN("couldn't set macaddr mode on "
-                                  "device %s: x%x\n", CARD_BUS_ID(card),
-                                  result);
-                       QETH_DBF_CARD1(0, trace, "STMACMOD", card);
-                       sprintf(dbf_text, "%4x", result);
-                       QETH_DBF_TEXT1(1, trace, dbf_text);
-               }
-       } else if (card->options.macaddr_mode) {
-               PRINT_WARN("set adapter parameters not available "
-                          "to set macaddr mode, using NONCANONICAL "
-                          "on device %s:\n", CARD_BUS_ID(card));
-               QETH_DBF_CARD1(0, trace, "NOMA", card);
-       }
-}
-
-static void
-qeth_do_setadapterparms_stuff(struct qeth_card *card)
-{
-       int result;
-       char dbf_text[15];
-
-       if (!qeth_is_supported(IPA_SETADAPTERPARMS)) {
-               return;
-       }
-
-       QETH_DBF_CARD4(0, trace, "stap", card);
-
-       result = qeth_send_setadapterparms_query(card);
-
-       if (result) {
-               PRINT_WARN("couldn't set adapter parameters on device %s: "
-                          "x%x\n", CARD_BUS_ID(card), result);
-               QETH_DBF_CARD1(0, trace, "SETADPFL", card);
-               sprintf(dbf_text, "%4x", result);
-               QETH_DBF_TEXT1(1, trace, dbf_text);
-               return;
-       }
-
-       sprintf(dbf_text, "spap%4x", card->adp_supported);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       if (qeth_is_adp_supported(IPA_SETADP_ALTER_MAC_ADDRESS)) {
-               QETH_DBF_CARD3(0, trace, "rdmc", card);
-               QETH_DBF_CARD2(0, setup, "rdmc", card);
-
-               result = qeth_send_setadapterparms_change_addr(card,
-                                                              IPA_SETADP_ALTER_MAC_ADDRESS,
-                                                              CHANGE_ADDR_READ_MAC,
-                                                              card->dev->
-                                                              dev_addr,
-                                                              OSA_ADDR_LEN);
-               if (result) {
-                       PRINT_WARN("couldn't get MAC address on "
-                                  "device %s: x%x\n",
-                                  CARD_BUS_ID(card), result);
-                       QETH_DBF_CARD1(0, trace, "NOMACADD", card);
-                       sprintf(dbf_text, "%4x", result);
-                       QETH_DBF_TEXT1(1, trace, dbf_text);
-               } else {
-                       QETH_DBF_HEX2(0, setup, card->dev->dev_addr,
-                                     __max(OSA_ADDR_LEN, QETH_DBF_SETUP_LEN));
-                       QETH_DBF_HEX3(0, trace, card->dev->dev_addr,
-                                     __max(OSA_ADDR_LEN, QETH_DBF_TRACE_LEN));
-               }
-       }
-       __qeth_setparms_hstr(card);
-}
-
-static inline void
-__qeth_start_vlan_assist(struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       char dbf_text[15];
-       int result;
-
-       if (!qeth_is_supported(IPA_FULL_VLAN)) {
-               PRINT_WARN("VLAN not supported on %s\n",
-                          card->dev_name);
-               QETH_DBF_TEXT2(0, trace, "vlnotsup");
-               return;
-       }
-       result = qeth_send_setassparms_simple_without_data(card,
-                                                          IPA_VLAN_PRIO,
-                                                          IPA_CMD_ASS_START);
-       QETH_DBF_TEXT2(0, trace, "enavlan");
-       if (result) {
-               PRINT_WARN("Could not start vlan "
-                          "assist on %s: 0x%x, continuing\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "VLAN%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               return;
-       }
-       card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif /* QETH_VLAN */
-}
-
-static inline void
-__qeth_start_mc_assist(struct qeth_card *card)
-{
-       char dbf_text[15];
-       int result;
-
-       if (!qeth_is_supported(IPA_MULTICASTING)) {
-               PRINT_WARN("multicasting not supported on %s\n",
-                          card->dev_name);
-               QETH_DBF_TEXT2(0, trace, "mcnotsup");
-               return;
-       }
-       result = qeth_send_setassparms_simple_without_data(card,
-                                                          IPA_MULTICASTING,
-                                                          IPA_CMD_ASS_START);
-       QETH_DBF_TEXT2(0, trace, "enamcass");
-       if (result) {
-               PRINT_WARN("Could not start multicast "
-                          "assist on %s: 0x%x, continuing\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "MCAS%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               return;
-       }
-       card->dev->flags |= IFF_MULTICAST;
-}
-
-static int
-__qeth_softsetup_enable_ipv6(struct qeth_card *card, int do_a_startlan6)
-{
-       int result;
-       char dbf_text[15];
-
-       if (do_a_startlan6) {
-               QETH_DBF_TEXT2(0, trace, "startln6");
-               netif_stop_queue(card->dev);
-               result = qeth_send_startlan(card, 6);
-               if (result) {
-                       sprintf(dbf_text, "stl6%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       atomic_set(&card->is_softsetup, 0);
-                       /* do not return an error */
-                       if ((result == 0xe080) || (result == 0xf080))
-                               result = 0;
-                       return result;
-               }
-       }
-       netif_wake_queue(card->dev);
-
-       QETH_DBF_TEXT2(0, trace, "qipassi6");
-       result = qeth_send_qipassist(card, 6);
-       if (result) {
-               PRINT_WARN("couldn't send QIPASSIST6 on %s: 0x%x\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "QIP6%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->is_softsetup, 0);
-               return result;
-       }
-               
-       sprintf(dbf_text, "%4x%4x", card->ipa6_supported, card->ipa6_enabled);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       QETH_DBF_TEXT2(0, trace, "enaipv46");
-       result = qeth_send_setassparms_simple_with_data(card, IPA_IPv6,
-                                                       IPA_CMD_ASS_START, 3);
-       if (result) {
-               PRINT_WARN("Could not enable IPv4&6 assist "
-                          "on %s: 0x%x, continuing\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "I46A%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               /* go on */
-       }
-
-       QETH_DBF_TEXT2(0, trace, "enaipv6");
-       result = qeth_send_setassparms_simple_without_data6(card, IPA_IPv6,
-                                                           IPA_CMD_ASS_START);
-       if (result) {
-               PRINT_WARN("Could not start IPv6 assist "
-                          "on %s: 0x%x, continuing\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "I6AS%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               /* go on */
-       }
-
-       QETH_DBF_TEXT2(0, trace, "enapstr6");
-       result = qeth_send_setassparms_simple_without_data6(card, IPA_PASSTHRU,
-                                                           IPA_CMD_ASS_START);
-       if (result) {
-               PRINT_WARN("Could not enable passthrough "
-                          "on %s: 0x%x, continuing\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "PSTR%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               /* go on */
-       }
-       return 0;
-}
-
-static int
-__qeth_softsetup_start_assists(struct qeth_card *card)
-{
-       int result;
-       char dbf_text[15];
-       int do_a_startlan6 = 0;
-
-       if (atomic_read(&card->is_softsetup))
-               return 0;
-
-       atomic_set(&card->enable_routing_attempts4, QETH_ROUTING_ATTEMPTS);
-#ifdef QETH_IPV6
-       atomic_set(&card->enable_routing_attempts6, QETH_ROUTING_ATTEMPTS);
-#endif /* QETH_IPV6 */
-       if ((!atomic_read(&card->is_startlaned)) &&
-           (atomic_read(&card->startlan_attempts))) {
-               atomic_dec(&card->startlan_attempts);
-               QETH_DBF_TEXT2(0, trace, "startlan");
-               netif_stop_queue(card->dev);
-               result = qeth_send_startlan(card, 4);
-               if (result) {
-                       PRINT_WARN("couldn't send STARTLAN on %s "
-                                  "(CHPID 0x%X): 0x%x (%s)\n",
-                                  card->dev_name, card->chpid, result,
-                                  (result == 0xe080) ?
-                                  "startlan disabled (link "
-                                  "failure -- please check the "
-                                  "network, plug in the cable or "
-                                  "enable the OSA port" :
-                                  (result==0xf080) ?
-                                  "startlan disabled (VM: LAN " \
-                                  "is offline for functions " \
-                                  "requiring LAN access.":
-                                  "unknown return code");
-                       sprintf(dbf_text, "stln%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       atomic_set(&card->is_softsetup, 0);
-                       atomic_set(&card->is_startlaned, 0);
-                       /* do not return an error */
-                       if ((result == 0xe080) || (result == 0xf080)) {
-                               result = 0;
-                       }
-                       return result;
-               }
-               do_a_startlan6 = 1;
-       }
-       netif_wake_queue(card->dev);
-       
-       qeth_do_setadapterparms_stuff(card);
-       
-       if (!qeth_is_supported(IPA_ARP_PROCESSING)) {
-               PRINT_WARN("oops... ARP processing not supported "
-                          "on %s!\n", card->dev_name);
-               QETH_DBF_TEXT1(0, trace, "NOarpPRC");
-       } else {
-               QETH_DBF_TEXT2(0, trace, "enaARPpr");
-               result = qeth_send_setassparms_simple_without_data
-                       (card, IPA_ARP_PROCESSING, IPA_CMD_ASS_START);
-               if (result) {
-                       PRINT_WARN("Could not start ARP processing "
-                                  "assist on %s: 0x%x\n",
-                                  card->dev_name, result);
-                       sprintf(dbf_text, "ARPp%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       atomic_set(&card->is_softsetup, 0);
-                       return result;
-               }
-       }
-       
-       if (qeth_is_supported(IPA_IP_FRAGMENTATION)) {
-               PRINT_INFO("IP fragmentation supported on "
-                          "%s... :-)\n", card->dev_name);
-               /* start it */
-               QETH_DBF_TEXT2(0, trace, "enaipfrg");
-               result = qeth_send_setassparms_simple_without_data
-                       (card, IPA_IP_FRAGMENTATION, IPA_CMD_ASS_START);
-               if (result) {
-                       PRINT_WARN("Could not start IP fragmenting "
-                                  "assist on %s: 0x%x, continuing\n",
-                                  card->dev_name, result);
-                       sprintf(dbf_text, "IFRG%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       /* go on */
-               }
-       }
-       if (card->options.fake_ll == FAKE_LL) {
-               if (qeth_is_supported(IPA_SOURCE_MAC_AVAIL)) {
-                       /* start it */
-                       QETH_DBF_TEXT2(0, trace, "enainsrc");
-                       result = qeth_send_setassparms_simple_without_data
-                               (card, IPA_SOURCE_MAC_AVAIL, IPA_CMD_ASS_START);
-                       if (result) {
-                               PRINT_WARN
-                                       ("Could not start inbound source "
-                                        "assist on %s: 0x%x, continuing\n",
-                                        card->dev_name, result);
-                               sprintf(dbf_text, "INSR%4x", result);
-                               QETH_DBF_TEXT2(0, trace, dbf_text);
-                               /* go on */
-                       }
-               } else {
-                       PRINT_INFO("Inbound source addresses not "
-                                  "supported on %s\n", card->dev_name);
-               }
-       }
-       __qeth_start_vlan_assist(card);
-       __qeth_start_mc_assist(card);
-       
-       if (!qeth_is_supported(IPA_IPv6)) {
-               QETH_DBF_TEXT2(0, trace, "ipv6ntsp");
-               PRINT_WARN("IPv6 not supported on %s\n", card->dev_name);
-       } else {
-               result = __qeth_softsetup_enable_ipv6(card, do_a_startlan6);
-               if (result != 0)
-                       return result;
-       }
-       
-       card->broadcast_capable = 0;
-       if (!qeth_is_supported(IPA_FILTERING)) {
-               QETH_DBF_TEXT2(0, trace, "filtntsp");
-               PRINT_WARN("Broadcasting not supported on %s\n",
-                          card->dev_name);
-       } else {
-               QETH_DBF_TEXT2(0, trace, "enafiltr");
-               result = qeth_send_setassparms_simple_without_data
-                       (card, IPA_FILTERING, IPA_CMD_ASS_START);
-               if (result) {
-                       PRINT_WARN("Could not enable broadcast "
-                                  "filtering on %s: "
-                                  "0x%x, continuing\n",
-                                  card->dev_name, result);
-                       sprintf(dbf_text, "FLT1%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       goto go_on_filt;
-               }
-               result = qeth_send_setassparms_simple_with_data
-                       (card, IPA_FILTERING, IPA_CMD_ASS_CONFIGURE, 1);
-               if (result) {
-                       PRINT_WARN("Could not set up broadcast "
-                                  "filtering on %s: "
-                                  "0x%x, continuing\n",
-                                  card->dev_name, result);
-                       sprintf(dbf_text, "FLT2%4x", result);
-                       QETH_DBF_TEXT2(0, trace, dbf_text);
-                       goto go_on_filt;
-               }
-               card->dev->flags |= IFF_BROADCAST;
-               card->broadcast_capable = 1;
-       }
-go_on_filt:
-       if (card->options.checksum_type == HW_CHECKSUMMING) {
-               if (!qeth_is_supported(IPA_INBOUND_CHECKSUM)) {
-                       PRINT_WARN("Inbound HW checksumming not "
-                                  "supported on %s, continuing "
-                                  "using inbound sw checksumming\n",
-                                  card->dev_name);
-                       QETH_DBF_TEXT2(0, trace, "ibckntsp");
-                       card->options.checksum_type = SW_CHECKSUMMING;
-               } else {
-                       QETH_DBF_TEXT2(0, trace, "ibcksupp");
-                       result = qeth_send_setassparms_simple_without_data
-                               (card, IPA_INBOUND_CHECKSUM,
-                                IPA_CMD_ASS_START);
-                       if (result) {
-                               PRINT_WARN("Could not start inbound "
-                                          "checksumming on %s: 0x%x, "
-                                          "continuing using "
-                                          "inbound sw checksumming\n",
-                                          card->dev_name, result);
-                               sprintf(dbf_text, "SIBC%4x", result);
-                               QETH_DBF_TEXT2(0, trace, dbf_text);
-                               card->options.checksum_type = SW_CHECKSUMMING;
-                               goto go_on_checksum;
-                       }
-                       result=qeth_send_setassparms_simple_with_data
-                               (card,IPA_INBOUND_CHECKSUM,
-                                IPA_CMD_ASS_ENABLE, card->csum_enable_mask);
-                       if (result) {
-                               PRINT_WARN("Could not enable inbound " \
-                                          "checksumming on %s: 0x%x, " \
-                                          "continuing using " \
-                                          "inbound sw checksumming\n",
-                                          card->dev_name,result);
-                               sprintf(dbf_text,"EIBC%4x",result);
-                               QETH_DBF_TEXT2(0,trace,dbf_text);
-                               card->options.checksum_type = SW_CHECKSUMMING;
-                               goto go_on_checksum;
-
-                       }
-               }
-       }
-go_on_checksum:        
-       atomic_set(&card->is_softsetup, 1);
-       return 0;
-}
-
-static inline void
-__qeth_softsetup_routingv4(struct qeth_card *card)
-{
-       int result;
-       char dbf_text[15];
-
-       if (!atomic_read(&card->enable_routing_attempts4))
-               return;
-
-       if (!card->options.routing_type4) {
-               atomic_set(&card->enable_routing_attempts4, 0);
-               atomic_set(&card->rt4fld, 0);
-               return;
-       }
-
-       sprintf(dbf_text, "strtg4%2x", card->options.routing_type4);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-       result = qeth_send_setrtg(card, card->options.routing_type4, 4);
-       if (!result) {  /* routing set correctly */
-               atomic_set(&card->enable_routing_attempts4, 0);
-               atomic_set(&card->rt4fld, 0);
-               return;
-       }
-       if (atomic_dec_return(&card->enable_routing_attempts4)) {
-               PRINT_WARN("couldn't set up v4 routing type "
-                          "on %s: 0x%x (%s).\nWill try "
-                          "next time again.\n",
-                          card->dev_name, result,
-                          ((result == 0xe010) || (result == 0xe008)) ?
-                          "primary already defined"
-                          : ((result == 0xe011) || (result == 0xe009)) ?
-                          "secondary already defined"
-                          : (result == 0xe012) ? "invalid indicator" :
-                          "unknown return code");
-               sprintf(dbf_text, "sRT4%4x", result);
-               atomic_set(&card->rt4fld, 1);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       } else {
-               PRINT_WARN("couldn't set up v4 routing type "
-                          "on %s: 0x%x (%s).\nTrying to "
-                          "continue without routing.\n",
-                          card->dev_name, result,
-                          ((result == 0xe010) || (result == 0xe008)) ?
-                          "primary already defined"
-                          : ((result == 0xe011) || (result == 0xe009)) ?
-                          "secondary already defined"
-                          : (result == 0xe012) ? "invalid indicator" :
-                          "unknown return code");
-               sprintf(dbf_text, "SRT4%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->rt4fld, 1);
-       }
-}
-
-static void
-__qeth_softsetup_routingv6(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       int result;
-       char dbf_text[15];
-
-       if (!atomic_read(&card->enable_routing_attempts6))
-               return;
-
-       if (!card->options.routing_type6 ||
-           ((card->type == QETH_CARD_TYPE_OSAE) &&
-           ((card->options.routing_type6&ROUTER_MASK) == MULTICAST_ROUTER) &&
-           !qeth_is_supported6(IPA_OSA_MC_ROUTER_AVAIL))) {
-               atomic_set(&card->enable_routing_attempts6, 0);
-               atomic_set(&card->rt6fld, 0);
-               return;
-       }
-       sprintf(dbf_text, "strtg6%2x", card->options.routing_type6);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-       result = qeth_send_setrtg(card, card->options.routing_type6, 6);
-       if (!result) {  /* routing set correctly */
-               atomic_set(&card->enable_routing_attempts6, 0);
-               atomic_set(&card->rt6fld, 0);
-               return;
-       }
-       if (atomic_dec_return(&card->enable_routing_attempts6)) {
-               PRINT_WARN("couldn't set up v6 routing type "
-                          "on %s: 0x%x (%s).\nWill try "
-                          "next time again.\n",
-                          card->dev_name, result,
-                          ((result == 0xe010) || (result == 0xe008)) ?
-                          "primary already defined"
-                          : ((result == 0xe011) || (result == 0xe009)) ?
-                          "secondary already defined"
-                          : (result == 0xe012) ? "invalid indicator" :
-                          "unknown return code");
-               sprintf(dbf_text, "sRT6%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->rt6fld, 1);
-       } else {
-               PRINT_WARN("couldn't set up v6 routing type "
-                          "on %s: 0x%x (%s).\nTrying to "
-                          "continue without routing.\n",
-                          card->dev_name, result,
-                          ((result == 0xe010) || (result == 0xe008)) ?
-                          "primary already defined"
-                          : ((result == 0xe011) || (result == 0xe009)) ?
-                          "secondary already defined"
-                          : (result == 0xe012) ? "invalid indicator" :
-                          "unknown return code");
-               sprintf(dbf_text, "SRT6%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->rt6fld, 1);
-       }
-#endif /* QETH_IPV6 */
-}
-
-static int
-qeth_softsetup_card(struct qeth_card *card, int wait_for_lock)
-{
-       int result;
-       char dbf_text[15];
-       int use_setip_retries = 1;
-
-       if (wait_for_lock == QETH_WAIT_FOR_LOCK) {
-               down(&card->softsetup_sema);
-       } else if (wait_for_lock == QETH_DONT_WAIT_FOR_LOCK) {
-               if (!down_trylock(&card->softsetup_sema)) {
-                       return -EAGAIN;
-               }
-       } else if (wait_for_lock == QETH_LOCK_ALREADY_HELD) {
-               use_setip_retries = 0;  /* we are in recovery and don't want
-                                          to repeat setting ips on and on */
-       } else {
-               return -EINVAL;
-       }
-
-       qeth_save_dev_flag_state(card);
-
-       QETH_DBF_CARD1(0, trace, wait_for_lock?"sscw":"sscn", card);
-
-       result = __qeth_softsetup_start_assists(card);
-       if (result)
-               goto out;
-
-       __qeth_softsetup_routingv4(card);
-       __qeth_softsetup_routingv6(card);
-
-       QETH_DBF_TEXT2(0, trace, "delvipa");
-       qeth_set_vipas(card, 0);
-       QETH_DBF_TEXT2(0, trace, "toip/ms");
-       qeth_takeover_ip_ipms(card);
-       qeth_takeover_ip_ipms6(card);
-       QETH_DBF_TEXT2(0, trace, "setvipa");
-       qeth_set_vipas(card, 1);
-
-       result = qeth_setips(card, use_setip_retries);
-       if (result) {           /* by now, qeth_setips does not return errors */
-               PRINT_WARN("couldn't set up IPs on %s: 0x%x\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "SSIP%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->is_softsetup, 0);
-               goto out;
-       }
-       result = qeth_setipms(card, use_setip_retries);
-       if (result) {           /* by now, qeth_setipms does not return errors */
-               PRINT_WARN("couldn't set up multicast IPs on %s: 0x%x\n",
-                          card->dev_name, result);
-               sprintf(dbf_text, "ssim%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               atomic_set(&card->is_softsetup, 0);
-               goto out;
-       }
-out:
-       if (!result) {
-               netif_wake_queue(card->dev);
-       }
-       if (wait_for_lock != QETH_LOCK_ALREADY_HELD)
-               up(&card->softsetup_sema);
-       return result;
-}
-
-static int
-qeth_softsetup_thread(void *param)
-{
-       char name[15];
-       struct qeth_card *card = (struct qeth_card *) param;
-
-       /* set a nice name ... */
-       sprintf(name, "qethsoftd%s", CARD_BUS_ID(card));
-       daemonize(name);
-
-       QETH_DBF_CARD2(0, trace, "ssth", card);
-
-       atomic_set(&card->softsetup_thread_is_running, 1);
-       for (;;) {
-               if (atomic_read(&card->shutdown_phase))
-                       goto out;
-               down_interruptible(&card->softsetup_thread_sem);
-               QETH_DBF_CARD2(0, trace, "ssst", card);
-               if (atomic_read(&card->shutdown_phase))
-                       goto out;
-               while (qeth_softsetup_card(card, QETH_DONT_WAIT_FOR_LOCK)
-                      == -EAGAIN) {
-                       if (atomic_read(&card->shutdown_phase))
-                               goto out;
-                       qeth_wait_nonbusy(QETH_IDLE_WAIT_TIME);
-               }
-               QETH_DBF_CARD2(0, trace, "sssd", card);
-               netif_wake_queue(card->dev);
-       }
-out:
-       atomic_set(&card->softsetup_thread_is_running, 0);
-
-       QETH_DBF_CARD2(0, trace, "lsst", card);
-
-       return 0;
-}
-
-static void
-qeth_softsetup_thread_starter(void *data)
-{
-       struct qeth_card *card = (struct qeth_card *) data;
-
-       QETH_DBF_CARD4(0, trace, "ssts", card);
-       sema_init(&card->softsetup_thread_sem, 0);
-       kernel_thread(qeth_softsetup_thread, card, SIGCHLD);
-}
-
-static void
-qeth_start_reinit_thread(struct qeth_card *card)
-{
-       /* we allow max 2 reinit threads, one could be just about to
-        * finish and the next would be waiting. another waiting
-        * reinit_thread is not necessary. */
-       if (atomic_read(&card->reinit_counter) < 2) {
-               atomic_inc(&card->reinit_counter);
-               if (atomic_read(&card->shutdown_phase)) {
-                       atomic_dec(&card->reinit_counter);
-                       return;
-               }
-               QETH_DBF_CARD2(0, trace, "stri", card);
-               PRINT_STUPID("starting reinit-thread\n");
-               kernel_thread(qeth_reinit_thread, card, SIGCHLD);
-       }
-}
-
-static void
-qeth_recover(void *data)
-{
-       struct qeth_card *card;
-       int i;
-       char dbf_text[15];
-
-       card = (struct qeth_card *) data;
-
-       QETH_DBF_CARD2(0, trace, "recv", card);
-
-       if (atomic_compare_and_swap(0, 1, &card->in_recovery))
-               return;
-
-       i = atomic_read(&card->problem);
-
-       sprintf(dbf_text, "PROB%4x", i);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       if (i != PROBLEM_TX_TIMEOUT)
-               PRINT_WARN("recovery was scheduled on device %s (%s) with "
-                          "problem 0x%x\n",
-                          CARD_BUS_ID(card), card->dev_name, i);
-       switch (i) {
-       case PROBLEM_RECEIVED_IDX_TERMINATE:
-               if (atomic_read(&card->in_recovery))
-                       atomic_set(&card->break_out, QETH_BREAKOUT_AGAIN);
-               break;
-       case PROBLEM_CARD_HAS_STARTLANED:
-               PRINT_WARN("You are lucky! Somebody either fixed the "
-                          "network problem, plugged the cable back in "
-                          "or enabled the OSA port on %s (CHPID 0x%X). "
-                          "The link has come up.\n",
-                          card->dev_name, card->chpid);
-               sprintf(dbf_text, "CBIN%4x", i);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               atomic_set(&card->is_softsetup, 0);
-               qeth_set_dev_flag_running(card);
-               atomic_set(&card->enable_routing_attempts4,
-                          QETH_ROUTING_ATTEMPTS);
-               qeth_clear_ifa4_list(&card->ip_new_state.ip_ifa);
-#ifdef QETH_IPV6
-               atomic_set(&card->enable_routing_attempts6,
-                          QETH_ROUTING_ATTEMPTS);
-               qeth_clear_ifa6_list(&card->ip_new_state.ip6_ifa);
-#endif /* QETH_IPV6 */
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm_ifa);
-#ifdef QETH_IPV6
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm6_ifa);
-#endif /* QETH_IPV6 */
-               qeth_refresh_vipa_states(card);
-               qeth_start_softsetup_thread(card);
-               atomic_set(&card->in_recovery, 0);
-               break;
-       case PROBLEM_RESETTING_EVENT_INDICATOR:
-               /* we do nothing here */
-               break;
-       case PROBLEM_ACTIVATE_CHECK_CONDITION:
-       case PROBLEM_GENERAL_CHECK:
-       case PROBLEM_USER_TRIGGERED_RECOVERY:
-       case PROBLEM_AFFE:
-       case PROBLEM_MACHINE_CHECK:
-       case PROBLEM_BAD_SIGA_RESULT:
-       case PROBLEM_TX_TIMEOUT:
-               qeth_start_reinit_thread(card);
-               break;
-       }
-}
-
-static inline void
-qeth_schedule_recovery(struct qeth_card *card)
-{
-       if (card) {
-               INIT_WORK(&card->tqueue, qeth_recover, card);
-               schedule_work(&card->tqueue);
-       } else {
-               QETH_DBF_TEXT2(1, trace, "scdnocrd");
-               PRINT_WARN("recovery requested to be scheduled "
-                          "with no card!\n");
-       }
-}
-
-static void
-qeth_qdio_input_handler(struct ccw_device *cdev, unsigned int status,
-                       unsigned int qdio_error, unsigned int siga_error,
-                       unsigned int queue,
-                       int first_element, int count, unsigned long card_ptr)
-{
-       struct net_device *dev;
-       struct qeth_card *card;
-       int problem;
-       int sbalf15;
-       char dbf_text[15];
-
-       sprintf(dbf_text, "qibhn%s", cdev->dev.bus_id);
-       QETH_DBF_HEX6(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-
-       card = (struct qeth_card *) card_ptr;
-
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.inbound_start_time = NOW;
-#endif /* QETH_PERFORMANCE_STATS */
-       dev = card->dev;
-
-       if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
-               if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION) {
-                       problem = PROBLEM_ACTIVATE_CHECK_CONDITION;
-                       atomic_set(&card->problem, problem);
-                       QETH_DBF_TEXT1(0, trace, "IHACTQCK");
-                       sprintf(dbf_text, "%4x%4x", first_element, count);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", queue, status);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       QETH_DBF_CARD1(1, trace, "qscd", card);
-                       qeth_schedule_recovery(card);
-                       return;
-               }
-               sbalf15 = (card->inbound_qdio_buffers[(first_element + count - 1)
-                                                     & QDIO_MAX_BUFFERS_PER_Q].
-                          element[15].flags) && 0xff;
-               PRINT_STUPID("inbound qdio transfer error on device %s. "
-                            "qdio_error=0x%x (more than one: %c), "
-                            "siga_error=0x%x (more than one: %c), "
-                            "sbalf15=x%x, bufno=x%x\n", cdev->dev.bus_id,
-                            qdio_error,
-                            (status & QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR) ?
-                            'y' : 'n', siga_error,
-                            (status & QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR) ?
-                            'y' : 'n', sbalf15, first_element);
-               QETH_DBF_CARD1(0, trace, "IQTI", card);
-               QETH_DBF_CARD1(0, qerr, "IQTI", card);
-               sprintf(dbf_text, "%4x%4x", first_element, count);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               sprintf(dbf_text, "%2x%4x%2x", queue, status, sbalf15);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               sprintf(dbf_text, "%4x%4x", qdio_error, siga_error);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               /* we inform about error more detailed in
-                * qeth_read_in_buffer() */
-       }
-
-       for (;;) {
-               qeth_read_in_buffer(card, first_element);
-               qeth_queue_input_buffer(card, first_element,
-                                       QDIO_FLAG_UNDER_INTERRUPT);
-               count--;
-               if (count)
-                       first_element = (first_element + 1) &
-                           (QDIO_MAX_BUFFERS_PER_Q - 1);
-               else
-                       break;
-       }
-}
-
-static void
-__qeth_try_to_flush_packets(struct qeth_card *card, int last_pci_hit,
-                           unsigned int queue)
-{
-       int switch_state;
-
-       switch_state = (atomic_read(&card->outbound_used_buffers[queue]) <=
-                       LOW_WATERMARK_PACK);
-       /* first_element is the last buffer that we got back from hydra */
-       if (!switch_state && !last_pci_hit)
-               return;
-       QETH_DBF_CARD3(0, trace, "stchcw", card);
-       if (atomic_swap(&card->outbound_ringbuffer_lock[queue], QETH_LOCK_FLUSH)
-           == QETH_LOCK_UNLOCKED) {
-               /* 
-                * we stop the queue as we try to not run onto the 
-                * outbound_ringbuffer_lock -- this will not prevent it totally,
-                * but reduce it. in high traffic situations, it saves around
-                * 20us per second, hopefully this is amortized by calling 
-                * netif_...
-                */
-               netif_stop_queue(card->dev);
-               qeth_flush_packed_packets(card, queue,
-                                         QDIO_FLAG_UNDER_INTERRUPT);
-               /* 
-                * only switch state to non-packing, if the amount of used
-                * buffers decreased
-                */
-               if (switch_state)
-                       card->send_state[queue] = SEND_STATE_DONT_PACK;
-               netif_wake_queue(card->dev);
-               atomic_set(&card->outbound_ringbuffer_lock[queue],
-                          QETH_LOCK_UNLOCKED);
-       }
-       /* 
-        * if the lock was UNLOCKED, we flush ourselves, otherwise this is done
-        * in do_send_packet when the lock is released
-        */
-#ifdef QETH_PERFORMANCE_STATS
-       card->perf_stats.sc_p_dp++;
-#endif /* QETH_PERFORMANCE_STATS */
-}
-
-static void
-qeth_qdio_output_handler(struct ccw_device *cdev,
-                        unsigned int status,
-                        unsigned int qdio_error,
-                        unsigned int siga_error,
-                        unsigned int queue,
-                        int first_element, int count, unsigned long card_ptr)
-{
-       struct qeth_card *card;
-       int mycnt, problem, buffers_used;
-       int sbalf15;
-       char dbf_text[15];
-       int last_pci_hit = 0;
-       int last_pci;
-
-       sprintf(dbf_text, "qouthn%s", cdev->dev.bus_id);
-       QETH_DBF_HEX6(0, trace, dbf_text, QETH_DBF_TRACE_LEN);
-
-       mycnt = count;
-       card = (struct qeth_card *) card_ptr;
-
-       if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
-               if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION) {
-                       problem = PROBLEM_ACTIVATE_CHECK_CONDITION;
-                       atomic_set(&card->problem, problem);
-                       QETH_DBF_TEXT1(0, trace, "OHACTQCK");
-                       sprintf(dbf_text, "%4x%4x", first_element, count);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       sprintf(dbf_text, "%4x%4x", queue, status);
-                       QETH_DBF_TEXT1(0, trace, dbf_text);
-                       QETH_DBF_CARD1(1, trace, "qscd", card);
-                       qeth_schedule_recovery(card);
-                       goto out;
-               }
-               sbalf15 = (card->outbound_ringbuffer[queue]->
-                          buffer[(first_element + count - 1) & QDIO_MAX_BUFFERS_PER_Q].
-                          element[15].flags) & 0xff;
-               PRINT_STUPID("outbound qdio transfer error on device %s, "
-                            "queue=%i. qdio_error=0x%x (more than one: %c),"
-                            " siga_error=0x%x (more than one: %c), "
-                            "sbalf15=x%x, bufno=x%x\n",
-                            cdev->dev.bus_id, queue, qdio_error, status &
-                            QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR ? 'y' : 'n',
-                            siga_error, status &
-                            QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR ? 'y' : 'n',
-                            sbalf15, first_element);
-               QETH_DBF_CARD1(0, trace, "IQTO", card);
-               QETH_DBF_CARD1(0, qerr, "IQTO", card);
-               sprintf(dbf_text, "%4x%4x", first_element, count);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               sprintf(dbf_text, "%2x%4x%2x", queue, status, sbalf15);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               sprintf(dbf_text, "%4x%4x", qdio_error, siga_error);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_TEXT1(0, qerr, dbf_text);
-               /* we maybe do recovery or dst_link_failures
-                * in qeth_free_buffer */
-       }
-
-       if (mycnt) {
-               last_pci = atomic_read(&card->last_pci_pos[queue]);
-               for (;;) {
-                       qeth_free_buffer(card, queue, first_element,
-                                        qdio_error, siga_error);
-                       if (first_element == last_pci)
-                               last_pci_hit = 1;
-                       mycnt--;
-                       if (mycnt > 0)
-                               first_element = (first_element + 1) &
-                                   (QDIO_MAX_BUFFERS_PER_Q - 1);
-                       else
-                               break;
-               }
-       }
-
-       buffers_used = atomic_add_return(-count,
-                                        &card->outbound_used_buffers[queue])
-                      + count;
-
-       switch (card->send_state[queue]) {
-       case SEND_STATE_PACK:
-               __qeth_try_to_flush_packets(card, last_pci_hit, queue);
-               break;
-       default:
-               break;
-       }
-
-       /* we don't have to start the queue, if it was started already */
-       if (buffers_used < QDIO_MAX_BUFFERS_PER_Q - 1)
-               return;
-
-out:
-       netif_wake_queue(card->dev);
-}
-
-static long
-__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
-{
-       if (!IS_ERR(irb))
-               return 0;
-
-       switch (PTR_ERR(irb)) {
-       case -EIO:
-               PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
-               break;
-       case -ETIMEDOUT:
-               PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
-               break;
-       default:
-               PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
-                          cdev->dev.bus_id);
-       }
-       return PTR_ERR(irb);
-}
-
-static void
-qeth_interrupt_handler_read(struct ccw_device *cdev, unsigned long intparm,
-                           struct irb *irb)
-{
-       int cstat, dstat;
-       int problem;
-       struct qeth_card *card;
-       int rqparam;
-       char dbf_text[15];
-       int result;
-
-       if (__qeth_check_irb_error(cdev, irb))
-               return;
-
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
-       rqparam = intparm;
-
-       sprintf(dbf_text, "rint%s", cdev->dev.bus_id);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x%4x", cstat, dstat);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x", rqparam);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-
-       card = CARD_FROM_CDEV(cdev);
-       if (!card)
-               return;
-
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
-               atomic_set(&card->clear_succeeded0, 1);
-               wake_up(&card->wait_q);
-               return;
-       }
-
-       if (!rqparam) {
-               PRINT_STUPID("got unsolicited interrupt in read handler "
-                            "for %s\n", cdev->dev.bus_id);
-               return;
-       }
-
-       if ((dstat == 0) && (cstat == 0))
-               return;
-
-       if (irb->esw.esw0.erw.cons) {
-               PRINT_WARN("sense data available on read channel.\n");
-               HEXDUMP16(WARN, "irb: ", irb);
-               HEXDUMP16(WARN, "sense data: ", irb->ecw);
-               sprintf(dbf_text, "RSNS%s", cdev->dev.bus_id);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_HEX0(0, sense, irb, QETH_DBF_SENSE_LEN);
-       }
-
-       if (cstat != 0) {
-               PRINT_WARN("got nonzero-nonpci channel status in read_"
-                          "handler (device %s, devstat 0x%02x, schstat "
-                          "0x%02x, rqparam 0x%x)\n", cdev->dev.bus_id,
-                          dstat, cstat, rqparam);
-       }
-
-       problem = qeth_get_cards_problem(cdev, card->dma_stuff->recbuf,
-                                        dstat, cstat, rqparam,
-                                        (char *) irb, (char *) irb->ecw);
-
-       /* detect errors in dstat here */
-       if ((dstat & DEV_STAT_UNIT_EXCEP) || (dstat & DEV_STAT_UNIT_CHECK)) {
-               PRINT_WARN("unit check/exception in read_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x, "
-                          "rqparam 0x%x)\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-
-               if (!atomic_read(&card->is_hardsetup)) {
-                       if ((problem) && (qeth_is_to_recover(card, problem)))
-                               atomic_set(&card->break_out,
-                                          QETH_BREAKOUT_AGAIN);
-                       else
-                               atomic_set(&card->break_out,
-                                          QETH_BREAKOUT_LEAVE);
-                       goto wakeup_out;
-               } else
-                       goto recover;
-       }
-
-       if (!(dstat & DEV_STAT_CHN_END)) {
-               PRINT_WARN("didn't get device end in read_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x, "
-                          "rqparam 0x%x)\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-               goto wakeup_out;
-       }
-
-       if ((rqparam == IDX_ACTIVATE_WRITE_STATE) || (rqparam == NOP_STATE)) {
-               goto wakeup_out;
-       }
-
-       /* at this point, (maybe channel end and) device end has appeared */
-
-       /* we don't start the next read until we have examined the buffer. */
-       if ((rqparam != IDX_ACTIVATE_READ_STATE) &&
-           (rqparam != IDX_ACTIVATE_WRITE_STATE))
-               qeth_issue_next_read(card);
-
-recover:
-       if (qeth_is_to_recover(card, problem)) {
-               QETH_DBF_CARD2(1, trace, "rscd", card);
-               qeth_schedule_recovery(card);
-               goto wakeup_out;
-       }
-
-       if (!IS_IPA(card->dma_stuff->recbuf) ||
-           IS_IPA_REPLY(card->dma_stuff->recbuf)) {
-               /* setup or unknown data */
-               result = qeth_look_for_arp_data(card);
-               switch (result) {
-               case ARP_RETURNCODE_ERROR:
-               case ARP_RETURNCODE_LASTREPLY:
-                       qeth_wakeup_ioctl(card);
-                       return;
-               default:
-                       break;
-               }
-       }
-
-wakeup_out:
-       memcpy(card->ipa_buf, card->dma_stuff->recbuf, QETH_BUFSIZE);
-       qeth_wakeup(card);
-}
-
-static void
-qeth_interrupt_handler_write(struct ccw_device *cdev, unsigned long intparm,
-                            struct irb *irb)
-{
-       int cstat, dstat, rqparam;
-       struct qeth_card *card;
-       int problem;
-       char dbf_text[15];
-
-       if (__qeth_check_irb_error(cdev, irb))
-               return;
-
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
-       rqparam = intparm;
-
-       sprintf(dbf_text, "wint%s", cdev->dev.bus_id);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x%4x", cstat, dstat);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x", rqparam);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-
-       card = CARD_FROM_CDEV(cdev);
-       if (!card)
-               return;
-
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
-               atomic_set(&card->clear_succeeded1, 1);
-               wake_up(&card->wait_q);
-               goto out;
-       }
-
-       if (!rqparam) {
-               PRINT_STUPID("got unsolicited interrupt in write handler "
-                            "for %s\n", cdev->dev.bus_id);
-               return;
-       }
-
-       if ((dstat == 0) && (cstat == 0))
-               goto out;
-
-       if (irb->esw.esw0.erw.cons) {
-               PRINT_WARN("sense data available on write channel.\n");
-               HEXDUMP16(WARN, "irb: ", irb);
-               HEXDUMP16(WARN, "sense data: ", irb->ecw);
-               sprintf(dbf_text, "WSNS%s", cdev->dev.bus_id);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_HEX0(0, sense, irb, QETH_DBF_SENSE_LEN);
-       }
-
-       if (cstat != 0) {
-               PRINT_WARN("got nonzero channel status in write_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x, "
-                          "rqparam 0x%x)\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-       }
-
-       problem = qeth_get_cards_problem(cdev, NULL,
-                                        dstat, cstat, rqparam,
-                                        (char *) irb, (char *) irb->ecw);
-
-       /* detect errors in dstat here */
-       if ((dstat & DEV_STAT_UNIT_EXCEP) || (dstat & DEV_STAT_UNIT_CHECK)) {
-               PRINT_WARN("unit check/exception in write_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x, "
-                          "rqparam 0x%x)\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-               if (!atomic_read(&card->is_hardsetup)) {
-                       if (problem == PROBLEM_RESETTING_EVENT_INDICATOR) {
-                               atomic_set(&card->break_out,
-                                          QETH_BREAKOUT_AGAIN);
-                               qeth_wakeup(card);
-                               goto out;
-                       }
-                       atomic_set(&card->break_out, QETH_BREAKOUT_LEAVE);
-                       goto out;
-               } else
-                       goto recover;
-       }
-
-       if (dstat == DEV_STAT_DEV_END)
-               goto out;
-
-       if (!(dstat & DEV_STAT_CHN_END)) {
-               PRINT_WARN("didn't get device end in write_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x, "
-                          "rqparam 0x%x)\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-               goto out;
-       }
-
-recover:
-       if (qeth_is_to_recover(card, problem)) {
-               QETH_DBF_CARD2(1, trace, "wscd", card);
-               qeth_schedule_recovery(card);
-               goto out;
-       }
-
-       /* at this point, (maybe channel end and) device end has appeared */
-       if ((rqparam == IDX_ACTIVATE_READ_STATE) ||
-           (rqparam == IDX_ACTIVATE_WRITE_STATE) || (rqparam == NOP_STATE)) {
-               qeth_wakeup(card);
-               goto out;
-       }
-
-       /* well, a write has been done successfully. */
-
-out:
-       /* all statuses are final statuses on the write channel */
-       atomic_set(&card->write_busy, 0);
-}
-
-static void
-qeth_interrupt_handler_qdio(struct ccw_device *cdev, unsigned long intparm,
-                           struct irb *irb)
-{
-       int cstat, dstat, rqparam;
-       char dbf_text[15];
-       struct qeth_card *card;
-
-       if (__qeth_check_irb_error(cdev, irb))
-               return;
-
-       cstat = irb->scsw.cstat;
-       dstat = irb->scsw.dstat;
-       rqparam = intparm;
-
-       sprintf(dbf_text, "qint%s", cdev->dev.bus_id);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x%4x", cstat, dstat);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       sprintf(dbf_text, "%4x", rqparam);
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-
-       card = CARD_FROM_CDEV(cdev);
-       if (!card)
-               return;
-
-       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
-               atomic_set(&card->clear_succeeded2, 1);
-               wake_up(&card->wait_q);
-               return;
-       }
-
-       if (!rqparam) {
-               PRINT_STUPID("got unsolicited interrupt in qdio handler, "
-                            "device%s\n", cdev->dev.bus_id);
-               return;
-       }
-
-       if ((dstat == 0) && (cstat == 0))
-               return;
-
-       if (irb->esw.esw0.erw.cons) {
-               PRINT_WARN("sense data available on qdio channel.\n");
-               HEXDUMP16(WARN, "irb: ", irb);
-               HEXDUMP16(WARN, "sense data: ", irb->ecw);
-               sprintf(dbf_text, "QSNS%s", cdev->dev.bus_id);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               QETH_DBF_HEX0(0, sense, irb, QETH_DBF_SENSE_LEN);
-       }
-
-       if (rqparam == NOP_STATE) {
-               qeth_wakeup(card);
-               return;
-       }
-
-       if (cstat != 0) {
-               sprintf(dbf_text, "qchk%s", cdev->dev.bus_id);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "%4x%4x", cstat, dstat);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "%4x", rqparam);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               PRINT_WARN("got nonzero channel status in qdio_handler "
-                          "(device %s, devstat 0x%02x, schstat 0x%02x)\n",
-                          cdev->dev.bus_id, dstat, cstat);
-       }
-
-       if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-               PRINT_WARN("got the following dstat on the qdio channel: "
-                          "device %s, dstat 0x%02x, cstat 0x%02x, "
-                          "rqparam=%i\n",
-                          cdev->dev.bus_id, dstat, cstat, rqparam);
-       }
-
-}
-
-static int
-qeth_register_netdev(struct qeth_card *card)
-{
-       int result;
-
-       QETH_DBF_CARD3(0, trace, "rgnd", card);
-
-       /* sysfs magic */
-       SET_NETDEV_DEV(card->dev, &card->gdev->dev);
-       result = register_netdev(card->dev);
-
-       return result;
-}
-
-static void
-qeth_unregister_netdev(struct qeth_card *card)
-{
-       QETH_DBF_CARD3(0, trace, "nrgn", card);
-
-       unregister_netdev(card->dev);
-}
-
-static int
-qeth_stop(struct net_device *dev)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_CARD2(0, trace, "stop", card);
-       QETH_DBF_CARD2(0, setup, "stop", card);
-
-       qeth_save_dev_flag_state(card);
-
-       netif_stop_queue(dev);
-       atomic_set(&card->is_open, 0);
-
-       return 0;
-}
-
-static void
-qeth_softshutdown(struct qeth_card *card)
-{
-       QETH_DBF_CARD3(0, trace, "ssht", card);
-
-       qeth_send_stoplan(card);
-}
-
-static void
-__qeth_clear_card_halt_clear(struct qeth_card *card, int halt)
-{
-       unsigned long flags0, flags1, flags2;
-       int ret0, ret1, ret2;
-
-       atomic_set(&card->clear_succeeded0, 0);
-       atomic_set(&card->clear_succeeded1, 0);
-       atomic_set(&card->clear_succeeded2, 0);
-       
-       spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)), flags0);
-       if (halt)
-               ret0 = ccw_device_halt(CARD_RDEV(card), CLEAR_STATE);
-       else
-               ret0 = ccw_device_clear(CARD_RDEV(card), CLEAR_STATE);
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_RDEV(card)), flags0);
-       
-       spin_lock_irqsave(get_ccwdev_lock(CARD_WDEV(card)), flags1);
-       if (halt)
-               ret1 = ccw_device_halt(CARD_WDEV(card), CLEAR_STATE);
-       else
-               ret1 = ccw_device_clear(CARD_WDEV(card), CLEAR_STATE);
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_WDEV(card)), flags1);
-       
-       spin_lock_irqsave(get_ccwdev_lock(CARD_DDEV(card)), flags2);
-       if (halt)
-               ret2 = ccw_device_halt(CARD_DDEV(card), CLEAR_STATE);
-       else
-               ret2 = ccw_device_clear(CARD_DDEV(card), CLEAR_STATE);
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_DDEV(card)), flags2);
-
-       /* The device owns us an interrupt. */
-       if ((ret0 == 0) && (atomic_read(&card->clear_succeeded0) == 0))
-               wait_event(card->wait_q,
-                          atomic_read(&card->clear_succeeded0) == 1);
-       if ((ret1 == 0) && (atomic_read(&card->clear_succeeded1) == 0))
-               wait_event(card->wait_q,
-                          atomic_read(&card->clear_succeeded1) == 1);
-       if ((ret2 == 0) && (atomic_read(&card->clear_succeeded2) == 0))
-               wait_event(card->wait_q,
-                          atomic_read(&card->clear_succeeded2) == 1);
-}
-
-static void
-qeth_clear_card(struct qeth_card *card, int qdio_clean, int use_halt)
-{
-       QETH_DBF_CARD3(0, trace, qdio_clean?"clrq":"clr", card);
-       QETH_DBF_CARD1(0, setup, qdio_clean?"clrq":"clr", card);
-
-       atomic_set(&card->write_busy, 0);
-       if (qdio_clean)
-               qdio_cleanup(CARD_DDEV(card),
-                            (card->type == QETH_CARD_TYPE_IQD) ?
-                            QDIO_FLAG_CLEANUP_USING_HALT :
-                            QDIO_FLAG_CLEANUP_USING_CLEAR);
-
-       if (use_halt)
-               __qeth_clear_card_halt_clear(card, 1);
-
-       __qeth_clear_card_halt_clear(card, 0);
-}
-
-static void
-qeth_free_card_stuff(struct qeth_card *card)
-{
-       int i, j;
-       struct qeth_vipa_entry *e, *e2;
-
-       if (!card)
-               return;
-
-       QETH_DBF_CARD3(0, trace, "freest", card);
-       QETH_DBF_CARD1(0, setup, "freest", card);
-
-       write_lock(&card->vipa_list_lock);
-       e = card->vipa_list;
-       while (e) {
-               e2 = e->next;
-               kfree(e);
-               e = e2;
-       }
-       write_unlock(&card->vipa_list_lock);
-
-       for (i = 0; i < card->options.inbound_buffer_count; i++) {
-               for (j = 0; j < BUFFER_MAX_ELEMENTS; j++) {
-                       if (card->inbound_buffer_pool_entry[i][j]) {
-                               kfree(card->inbound_buffer_pool_entry[i][j]);
-                               card->inbound_buffer_pool_entry[i][j] = NULL;
-                       }
-               }
-       }
-       for (i = 0; i < card->no_queues; i++)
-               if (card->outbound_ringbuffer[i])
-                       vfree(card->outbound_ringbuffer[i]);
-
-       if (card->stats)
-               kfree(card->stats);
-       if (card->dma_stuff)
-               kfree(card->dma_stuff);
-       if (card->dev)
-               free_netdev(card->dev);
-
-}
-
-static void
-qeth_free_card(struct qeth_card *card)
-{
-
-       if (!card)
-               return;
-
-       QETH_DBF_CARD3(0, trace, "free", card);
-       QETH_DBF_CARD1(0, setup, "free", card);
-
-       vfree(card);            /* we checked against NULL already */
-}
-
-/* also locked from outside (setup_lock) */
-static void
-qeth_remove_card_from_list(struct qeth_card *card)
-{
-       struct qeth_card *cn;
-       unsigned long flags0, flags1, flags2;
-
-       write_lock(&list_lock);
-       if (!card) {
-               QETH_DBF_TEXT2(0, trace, "RMCWNOCD");
-               PRINT_WARN("qeth_remove_card_from_list call with no card!\n");
-               write_unlock(&list_lock);
-               return;
-       }
-
-       QETH_DBF_CARD3(0, trace, "rmcl", card);
-
-       /* check first, if card is in list */
-       if (!firstcard) {
-               QETH_DBF_TEXT2(0, trace, "NOCRDINL");
-               PRINT_WARN
-                   ("qeth_remove_card_from_list called on empty card list!!\n");
-               write_unlock(&list_lock);
-               return;
-       }
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)), flags0);
-       spin_lock_irqsave(get_ccwdev_lock(CARD_WDEV(card)), flags1);
-       spin_lock_irqsave(get_ccwdev_lock(CARD_DDEV(card)), flags2);
-
-       if (firstcard == card)
-               firstcard = card->next;
-       else {
-               cn = firstcard;
-               while (cn->next) {
-                       if (cn->next == card) {
-                               cn->next = card->next;
-                               card->next = NULL;
-                               break;
-                       }
-                       cn = cn->next;
-               }
-       }
-
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_DDEV(card)), flags2);
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_WDEV(card)), flags1);
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_RDEV(card)), flags0);
-
-       write_unlock(&list_lock);
-
-}
-
-static void
-qeth_delete_all_ips(struct qeth_card *card)
-{
-       struct qeth_vipa_entry *e;
-
-       if (atomic_read(&card->is_softsetup)) {
-               qeth_clear_ifa4_list(&card->ip_new_state.ip_ifa);
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm_ifa);
-
-#ifdef QETH_IPV6
-               qeth_clear_ifa6_list(&card->ip_new_state.ip6_ifa);
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm6_ifa);
-#endif /* QETH_IPV6 */
-
-               write_lock(&card->vipa_list_lock);
-               e = card->vipa_list;
-               while (e) {
-                       e->state = VIPA_2_B_REMOVED;
-                       e = e->next;
-               }
-               write_unlock(&card->vipa_list_lock);
-               qeth_start_softsetup_thread(card);
-       }
-}
-
-static void
-qeth_remove_card(struct qeth_card *card, int method)
-{
-       if (!card)
-               return;
-
-       QETH_DBF_CARD2(0, trace, "rmcd", card);
-       QETH_DBF_CARD1(0, setup, "rmcd", card);
-
-       if (method == QETH_REMOVE_CARD_PROPER) {
-               atomic_set(&card->shutdown_phase, QETH_REMOVE_CARD_PROPER);
-               if (atomic_read(&card->is_open)) {
-                       qeth_stop(card->dev);
-                       qeth_wait_nonbusy(QETH_REMOVE_WAIT_TIME);
-               }
-               qeth_delete_all_ips(card);
-       } else {
-               atomic_set(&card->shutdown_phase, QETH_REMOVE_CARD_QUICK);
-       }
-       atomic_set(&card->write_busy, 0);
-
-       QETH_DBF_TEXT4(0, trace, "freeskbs");
-       qeth_free_all_skbs(card);
-
-       QETH_DBF_TEXT2(0, trace, "upthrsem");
-
-       up(&card->softsetup_thread_sem);
-       up(&card->reinit_thread_sem);
-       while ((atomic_read(&card->softsetup_thread_is_running)) ||
-              (atomic_read(&card->reinit_counter))) {
-               qeth_wait_nonbusy(QETH_WAIT_FOR_THREAD_TIME);
-       }
-
-       if (method == QETH_REMOVE_CARD_PROPER) {
-               QETH_DBF_TEXT4(0, trace, "softshut");
-               qeth_softshutdown(card);
-               qeth_wait_nonbusy(QETH_REMOVE_WAIT_TIME);
-       }
-
-       atomic_set(&card->is_startlaned, 0);    /* paranoia, qeth_stop
-                                                  should prevent
-                                                  further calls of
-                                                  hard_start_xmit */
-
-       if (atomic_read(&card->is_registered)) {
-               QETH_DBF_TEXT2(0, trace, "unregdev");
-               qeth_unregister_netdev(card);
-               qeth_wait_nonbusy(QETH_REMOVE_WAIT_TIME);
-               atomic_set(&card->is_registered, 0);
-       }
-
-       qeth_put_unique_id(card);
-
-       QETH_DBF_TEXT2(0, trace, "clrcard");
-       if (atomic_read(&card->is_hardsetup)) {
-               PRINT_STUPID("clearing card %s\n", card->dev_name);
-               qeth_clear_card(card, 1, 0);
-       }
-
-       atomic_set(&card->is_hardsetup, 0);
-       atomic_set(&card->is_softsetup, 0);
-
-       QETH_DBF_TEXT2(0, trace, "cardrmvd");
-
-}
-
-static void
-qeth_set_multicast_list(struct net_device *dev)
-{
-       struct qeth_card *card = dev->priv;
-
-       QETH_DBF_CARD2(0, trace, "smcl", card);
-
-       qeth_start_softsetup_thread(card);
-}
-
-static int
-qeth_set_mac_address(struct net_device *dev, void *addr)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_CARD2(0, trace, "stmc", card);
-
-       return -EOPNOTSUPP;
-}
-
-static int
-qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_CARD2(0, trace, "ngst", card);
-
-       return 0;
-}
-
-static void
-qeth_generate_tokens(struct qeth_card *card)
-{
-       card->token.issuer_rm_w = 0x00010103UL;
-       card->token.cm_filter_w = 0x00010108UL;
-       card->token.cm_connection_w = 0x0001010aUL;
-       card->token.ulp_filter_w = 0x0001010bUL;
-       card->token.ulp_connection_w = 0x0001010dUL;
-}
-
-static int
-qeth_peer_func_level(int level)
-{
-       if ((level & 0xff) == 8)
-               return (level & 0xff) + 0x400;
-       if (((level >> 8) & 3) == 1)
-               return (level & 0xff) + 0x200;
-       return level;           /* hmmm... don't know what to do with that level. */
-}
-
-/* returns last four digits of bus_id */
-/* FIXME: device driver shouldn't be aware of bus_id format - but don't know
-   what else to use... (CH) */
-static inline __u16
-__raw_devno_from_bus_id(char *id)
-{
-       id += (strlen(id) - 4); 
-       return (__u16) simple_strtoul(id, &id, 16);
-}
-
-static int
-qeth_idx_activate_read(struct qeth_card *card)
-{
-       int result, result2;
-       __u16 temp;
-       unsigned long flags;
-       char dbf_text[15];
-
-       result = result2 = 0;
-
-       memcpy(&card->dma_stuff->write_ccw, WRITE_CCW, sizeof (struct ccw1));
-       card->dma_stuff->write_ccw.count = IDX_ACTIVATE_SIZE;
-       card->dma_stuff->write_ccw.cda =
-           QETH_GET_ADDR(card->dma_stuff->sendbuf);
-
-       memcpy(card->dma_stuff->sendbuf, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE);
-       memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(card->dma_stuff->sendbuf),
-              &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
-
-       memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(card->dma_stuff->sendbuf),
-              &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->sendbuf),
-              &card->func_level, 2);
-
-       temp = __raw_devno_from_bus_id(CARD_DDEV_ID(card));
-       memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(card->dma_stuff->sendbuf), &temp, 2);
-       temp = (card->cula << 8) + card->unit_addr2;
-       memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(card->dma_stuff->sendbuf),
-              &temp, 2);
-
-       QETH_DBF_TEXT2(0, trace, "iarw");
-       QETH_DBF_TEXT2(0, trace, CARD_RDEV_ID(card));
-       QETH_DBF_HEX2(0, control, card->dma_stuff->sendbuf,
-                     QETH_DBF_CONTROL_LEN);
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)), flags);
-       result = ccw_device_start(CARD_RDEV(card), &card->dma_stuff->write_ccw,
-                                 IDX_ACTIVATE_WRITE_STATE, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 = ccw_device_start(CARD_RDEV(card),
-                                          &card->dma_stuff->write_ccw,
-                                          IDX_ACTIVATE_WRITE_STATE, 0, 0);
-               sprintf(dbf_text, "IRW1%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "IRW2%4x", result2);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               PRINT_WARN("qeth_idx_activate_read (write): do_IO returned "
-                          "%i, next try returns %i\n", result, result2);
-       }
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_RDEV(card)), flags);
-
-       if (atomic_read(&card->break_out)) {
-               QETH_DBF_TEXT3(0, trace, "IARWBRKO");
-               return -EIO;
-       }
-
-       if (qeth_sleepon(card, QETH_MPC_TIMEOUT)) {
-               QETH_DBF_TEXT1(0, trace, "IRWT");
-               QETH_DBF_TEXT1(0, trace, CARD_RDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE(wr) on read channel device %s: "
-                         "timeout\n", CARD_RDEV_ID(card));
-               return -EIO;
-       }
-
-/* start reading on read channel, card->read_ccw is not yet used */
-       memcpy(&card->dma_stuff->read_ccw, READ_CCW, sizeof (struct ccw1));
-       card->dma_stuff->read_ccw.count = QETH_BUFSIZE;
-       card->dma_stuff->read_ccw.cda = QETH_GET_ADDR(card->dma_stuff->recbuf);
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)), flags);
-       result2 = 0;
-       result = ccw_device_start(CARD_RDEV(card), &card->dma_stuff->read_ccw,
-                                 IDX_ACTIVATE_READ_STATE, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 = ccw_device_start(CARD_RDEV(card),
-                                          &card->dma_stuff->read_ccw,
-                                          IDX_ACTIVATE_READ_STATE, 0, 0);
-               sprintf(dbf_text, "IRR1%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "IRR2%4x", result2);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               PRINT_WARN("qeth_idx_activate_read (read): do_IO "
-                          "returned %i, next try returns %i\n",
-                          result, result2);
-       }
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_RDEV(card)), flags);
-
-       if (result2) {
-               result = result2;
-               if (result)
-                       return result;
-       }
-
-       if (qeth_sleepon(card, QETH_MPC_TIMEOUT)) {
-               QETH_DBF_TEXT1(0, trace, "IRRT");
-               QETH_DBF_TEXT1(0, trace, CARD_RDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE(rd) on read channel device %s: "
-                         "timeout\n", CARD_RDEV_ID(card));
-               return -EIO;
-       }
-       QETH_DBF_TEXT2(0, trace, "iarr");
-       QETH_DBF_TEXT2(0, trace, CARD_RDEV_ID(card));
-       QETH_DBF_HEX2(0, control, card->dma_stuff->recbuf,
-                     QETH_DBF_CONTROL_LEN);
-
-       if (!(QETH_IS_IDX_ACT_POS_REPLY(card->dma_stuff->recbuf))) {
-               QETH_DBF_TEXT1(0, trace, "IRNR");
-               QETH_DBF_TEXT1(0, trace, CARD_RDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative "
-                         "reply\n", CARD_RDEV_ID(card));
-               return -EIO;
-       }
-
-       card->portname_required =
-           ((!QETH_IDX_NO_PORTNAME_REQUIRED(card->dma_stuff->recbuf)) &&
-            (card->type == QETH_CARD_TYPE_OSAE));
-
-       /*
-        * however, as the portname indication of OSA is wrong, we have to
-        * do this:
-        */
-       card->portname_required = (card->type == QETH_CARD_TYPE_OSAE);
-
-       memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->recbuf), 2);
-       if (temp != qeth_peer_func_level(card->func_level)) {
-               QETH_DBF_TEXT1(0, trace, "IRFL");
-               QETH_DBF_TEXT1(0, trace, CARD_RDEV_ID(card));
-               sprintf(dbf_text, "%4x%4x", card->func_level, temp);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "
-                          "level mismatch (sent: 0x%x, received: 0x%x)\n",
-                          CARD_RDEV_ID(card), card->func_level, temp);
-               result = -EIO;
-       }
-
-       memcpy(&card->token.issuer_rm_r,
-              QETH_IDX_ACT_ISSUER_RM_TOKEN(card->dma_stuff->recbuf),
-              QETH_MPC_TOKEN_LENGTH);
-
-       memcpy(&card->level[0],
-              QETH_IDX_REPLY_LEVEL(card->dma_stuff->recbuf), QETH_MCL_LENGTH);
-
-       return result;
-}
-
-static int
-qeth_idx_activate_write(struct qeth_card *card)
-{
-       int result, result2;
-       __u16 temp;
-       unsigned long flags;
-       char dbf_text[15];
-
-       result = result2 = 0;
-
-       memcpy(&card->dma_stuff->write_ccw, WRITE_CCW, sizeof (struct ccw1));
-       card->dma_stuff->write_ccw.count = IDX_ACTIVATE_SIZE;
-       card->dma_stuff->write_ccw.cda =
-           QETH_GET_ADDR(card->dma_stuff->sendbuf);
-
-       memcpy(card->dma_stuff->sendbuf, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE);
-       memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(card->dma_stuff->sendbuf),
-              &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
-       card->seqno.trans_hdr++;
-
-       memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(card->dma_stuff->sendbuf),
-              &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->sendbuf),
-              &card->func_level, 2);
-
-       temp = __raw_devno_from_bus_id(CARD_DDEV_ID(card));
-       memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(card->dma_stuff->sendbuf), &temp, 2);
-       temp = (card->cula << 8) + card->unit_addr2;
-       memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(card->dma_stuff->sendbuf),
-              &temp, 2);
-
-       QETH_DBF_TEXT2(0, trace, "iaww");
-       QETH_DBF_TEXT2(0, trace, CARD_WDEV_ID(card));
-       QETH_DBF_HEX2(0, control, card->dma_stuff->sendbuf,
-                     QETH_DBF_CONTROL_LEN);
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_WDEV(card)), flags);
-       result = ccw_device_start(CARD_WDEV(card), &card->dma_stuff->write_ccw,
-                                 IDX_ACTIVATE_WRITE_STATE, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 = ccw_device_start(CARD_WDEV(card),
-                                          &card->dma_stuff->write_ccw,
-                                          IDX_ACTIVATE_WRITE_STATE, 0, 0);
-               sprintf(dbf_text, "IWW1%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "IWW2%4x", result2);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               PRINT_WARN("qeth_idx_activate_write (write): do_IO "
-                          "returned %i, next try returns %i\n",
-                          result, result2);
-       }
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_WDEV(card)), flags);
-
-       if (atomic_read(&card->break_out)) {
-               QETH_DBF_TEXT3(0, trace, "IAWWBRKO");
-               return -EIO;
-       }
-
-       if (qeth_sleepon(card, QETH_MPC_TIMEOUT)) {
-               QETH_DBF_TEXT1(0, trace, "IWWT");
-               QETH_DBF_TEXT1(0, trace, CARD_WDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE(wr) on write channel device %s: "
-                         "timeout\n", CARD_WDEV_ID(card));
-               return -EIO;
-       }
-
-       QETH_DBF_TEXT3(0, trace, "idxawrrd");
-       /* start one read on write channel */
-       memcpy(&card->dma_stuff->read_ccw, READ_CCW, sizeof (struct ccw1));
-       card->dma_stuff->read_ccw.count = QETH_BUFSIZE;
-       /* recbuf and card->read_ccw is not yet used by any other
-          read channel program */
-       card->dma_stuff->read_ccw.cda = QETH_GET_ADDR(card->dma_stuff->recbuf);
-
-       spin_lock_irqsave(get_ccwdev_lock(CARD_WDEV(card)), flags);
-       result2 = 0;
-       result = ccw_device_start(CARD_WDEV(card), &card->dma_stuff->read_ccw,
-                                 IDX_ACTIVATE_READ_STATE, 0, 0);
-       if (result) {
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO);
-               result2 = ccw_device_start(CARD_WDEV(card),
-                                          &card->dma_stuff->read_ccw,
-                                          IDX_ACTIVATE_READ_STATE, 0, 0);
-               sprintf(dbf_text, "IWR1%4x", result);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               sprintf(dbf_text, "IWR2%4x", result2);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-               PRINT_WARN("qeth_idx_activate_write (read): do_IO returned "
-                          "%i, next try returns %i\n", result, result2);
-       }
-
-       spin_unlock_irqrestore(get_ccwdev_lock(CARD_WDEV(card)), flags);
-
-       if (result2) {
-               result = result2;
-               if (result)
-                       return result;
-       }
-
-       if (qeth_sleepon(card, QETH_MPC_TIMEOUT)) {
-               QETH_DBF_TEXT1(0, trace, "IWRT");
-               QETH_DBF_TEXT1(0, trace, CARD_WDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE(rd) on write channel device %s: "
-                         "timeout\n", CARD_WDEV_ID(card));
-               return -EIO;
-       }
-       QETH_DBF_TEXT2(0, trace, "iawr");
-       QETH_DBF_TEXT2(0, trace, CARD_WDEV_ID(card));
-       QETH_DBF_HEX2(0, control, card->dma_stuff->recbuf,
-                     QETH_DBF_CONTROL_LEN);
-
-       if (!(QETH_IS_IDX_ACT_POS_REPLY(card->dma_stuff->recbuf))) {
-               QETH_DBF_TEXT1(0, trace, "IWNR");
-               QETH_DBF_TEXT1(0, trace, CARD_WDEV_ID(card));
-               PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative "
-                         "reply\n", CARD_WDEV_ID(card));
-               return -EIO;
-       }
-
-       memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(card->dma_stuff->recbuf), 2);
-       if ((temp & ~0x0100) != qeth_peer_func_level(card->func_level)) {
-               QETH_DBF_TEXT1(0, trace, "IWFM");
-               QETH_DBF_TEXT1(0, trace, CARD_WDEV_ID(card));
-               sprintf(dbf_text, "%4x%4x", card->func_level, temp);
-               QETH_DBF_TEXT1(0, trace, dbf_text);
-               PRINT_WARN("IDX_ACTIVATE on write channel device %s: function "
-                          "level mismatch (sent: 0x%x, received: 0x%x)\n",
-                          CARD_WDEV_ID(card), card->func_level, temp);
-               result = -EIO;
-       }
-
-       return result;
-}
-
-static int
-qeth_cm_enable(struct qeth_card *card)
-{
-       unsigned char *buffer;
-       int result;
-       char dbf_text[15];
-
-       memcpy(card->send_buf, CM_ENABLE, CM_ENABLE_SIZE);
-
-       memcpy(QETH_CM_ENABLE_ISSUER_RM_TOKEN(card->send_buf),
-              &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_CM_ENABLE_FILTER_TOKEN(card->send_buf),
-              &card->token.cm_filter_w, QETH_MPC_TOKEN_LENGTH);
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       CM_ENABLE_SIZE, MPC_SETUP_STATE);
-
-       if (!buffer) {
-               QETH_DBF_TEXT2(0, trace, "CME:NOBF");
-               return -EIO;
-       }
-
-       memcpy(&card->token.cm_filter_r,
-              QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer), QETH_MPC_TOKEN_LENGTH);
-
-       result = qeth_check_idx_response(buffer);
-
-       sprintf(dbf_text, "cme=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_cm_setup(struct qeth_card *card)
-{
-       unsigned char *buffer;
-       int result;
-       char dbf_text[15];
-
-       memcpy(card->send_buf, CM_SETUP, CM_SETUP_SIZE);
-
-       memcpy(QETH_CM_SETUP_DEST_ADDR(card->send_buf),
-              &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_CM_SETUP_CONNECTION_TOKEN(card->send_buf),
-              &card->token.cm_connection_w, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_CM_SETUP_FILTER_TOKEN(card->send_buf),
-              &card->token.cm_filter_r, QETH_MPC_TOKEN_LENGTH);
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       CM_SETUP_SIZE, MPC_SETUP_STATE);
-
-       if (!buffer) {
-               QETH_DBF_TEXT2(0, trace, "CMS:NOBF");
-               return -EIO;
-       }
-
-       memcpy(&card->token.cm_connection_r,
-              QETH_CM_SETUP_RESP_DEST_ADDR(buffer), QETH_MPC_TOKEN_LENGTH);
-
-       result = qeth_check_idx_response(buffer);
-
-       sprintf(dbf_text, "cms=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_ulp_enable(struct qeth_card *card)
-{
-       unsigned char *buffer;
-       __u16 mtu, framesize;
-       __u16 len;
-       __u8 link_type;
-       int result;
-       char dbf_text[15];
-
-       memcpy(card->send_buf, ULP_ENABLE, ULP_ENABLE_SIZE);
-
-       *(QETH_ULP_ENABLE_LINKNUM(card->send_buf)) =
-           (__u8) card->options.portno;
-
-       memcpy(QETH_ULP_ENABLE_DEST_ADDR(card->send_buf),
-              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_ULP_ENABLE_FILTER_TOKEN(card->send_buf),
-              &card->token.ulp_filter_w, QETH_MPC_TOKEN_LENGTH);
-
-       memcpy(QETH_ULP_ENABLE_PORTNAME_AND_LL(card->send_buf),
-              card->options.portname, 9);
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       ULP_ENABLE_SIZE, MPC_SETUP_STATE);
-
-       if (!buffer) {
-               QETH_DBF_TEXT2(0, trace, "ULE:NOBF");
-               return -EIO;
-       }
-
-       memcpy(&card->token.ulp_filter_r,
-              QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer),
-              QETH_MPC_TOKEN_LENGTH);
-
-       /* to be done before qeth_init_ringbuffers and qeth_init_dev */
-       if (qeth_get_mtu_out_of_mpc(card->type)) {
-               memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(buffer), 2);
-               mtu = qeth_get_mtu_outof_framesize(framesize);
-
-               QETH_DBF_CARD2(0, trace, "ule", card);
-               sprintf(dbf_text, "mtu=%4x", mtu);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-
-               if (!mtu)
-                       return -EINVAL;
-
-               card->max_mtu = mtu;
-               card->initial_mtu = mtu;
-               card->inbound_buffer_size = mtu + 2 * PAGE_SIZE;
-       } else {
-               card->initial_mtu = qeth_get_initial_mtu_for_card(card);
-               card->max_mtu = qeth_get_max_mtu_for_card(card->type);
-               card->inbound_buffer_size = DEFAULT_BUFFER_SIZE;
-       }
-
-       memcpy(&len, QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer), 2);
-       if (len >= QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE) {
-               memcpy(&link_type, QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer), 1);
-               card->link_type = link_type;
-               sprintf(dbf_text, "link=%2x", link_type);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       } else
-               card->link_type = 0;
-
-       result = qeth_check_idx_response(buffer);
-
-       sprintf(dbf_text, "ule=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_ulp_setup(struct qeth_card *card)
-{
-       unsigned char *buffer;
-       __u16 temp;
-       int result;
-       char dbf_text[15];
-
-       memcpy(card->send_buf, ULP_SETUP, ULP_SETUP_SIZE);
-
-       memcpy(QETH_ULP_SETUP_DEST_ADDR(card->send_buf),
-              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_ULP_SETUP_CONNECTION_TOKEN(card->send_buf),
-              &card->token.ulp_connection_w, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_ULP_SETUP_FILTER_TOKEN(card->send_buf),
-              &card->token.ulp_filter_r, QETH_MPC_TOKEN_LENGTH);
-
-       temp = __raw_devno_from_bus_id(CARD_DDEV_ID(card));
-       memcpy(QETH_ULP_SETUP_CUA(card->send_buf), &temp, 2);
-       temp = (card->cula << 8) + card->unit_addr2;
-       memcpy(QETH_ULP_SETUP_REAL_DEVADDR(card->send_buf), &temp, 2);
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       ULP_SETUP_SIZE, MPC_SETUP_STATE);
-
-       if (!buffer) {
-               QETH_DBF_TEXT2(0, trace, "ULS:NOBF");
-               return -EIO;
-       }
-
-       memcpy(&card->token.ulp_connection_r,
-              QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer),
-              QETH_MPC_TOKEN_LENGTH);
-
-       result = qeth_check_idx_response(buffer);
-
-       sprintf(dbf_text, "uls=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_qdio_establish(struct qeth_card *card)
-{
-       int result;
-       char *adapter_area;
-       char dbf_text[15];
-       void **input_array, **output_array, **ptr;
-       int i, j;
-       struct qdio_initialize init_data;
-
-       adapter_area = vmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
-       if (!adapter_area)
-               return -ENOMEM;
-       memset(adapter_area, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
-
-       adapter_area[0] = _ascebc['P'];
-       adapter_area[1] = _ascebc['C'];
-       adapter_area[2] = _ascebc['I'];
-       adapter_area[3] = _ascebc['T'];
-       *((unsigned int *) (&adapter_area[4])) = PCI_THRESHOLD_A;
-       *((unsigned int *) (&adapter_area[8])) = PCI_THRESHOLD_B;
-       *((unsigned int *) (&adapter_area[12])) = PCI_TIMER_VALUE;
-
-       input_array = vmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof (void *));
-       if (!input_array) {
-               vfree(adapter_area);
-               return -ENOMEM;
-       }
-       ptr = input_array;
-       for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) {
-               *ptr = (void *) virt_to_phys(&card->inbound_qdio_buffers[j]);
-               ptr++;
-       }
-
-       output_array = vmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof (void *) *
-                              card->no_queues);
-       if (!output_array) {
-               vfree(input_array);
-               vfree(adapter_area);
-               return -ENOMEM;
-       }
-       ptr = output_array;
-       for (i = 0; i < card->no_queues; i++)
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) {
-                       *ptr = (void *) virt_to_phys
-                           (&card->outbound_ringbuffer[i]->buffer[j]);
-                       ptr++;
-               }
-
-       init_data.cdev = CARD_DDEV(card);
-       init_data.q_format = qeth_get_q_format(card->type);
-       init_data.qib_param_field_format = 0;
-       init_data.qib_param_field = adapter_area;
-       init_data.input_slib_elements = NULL;
-       init_data.output_slib_elements = NULL;
-       init_data.min_input_threshold = card->options.polltime;
-       init_data.max_input_threshold = card->options.polltime;
-       init_data.min_output_threshold = QETH_MIN_OUTPUT_THRESHOLD;
-       init_data.max_output_threshold = QETH_MAX_OUTPUT_THRESHOLD;
-       init_data.no_input_qs = 1;
-       init_data.no_output_qs = card->no_queues;
-       init_data.input_handler = qeth_qdio_input_handler;
-       init_data.output_handler = qeth_qdio_output_handler;
-       init_data.int_parm = (unsigned long) card;
-       init_data.flags = QDIO_INBOUND_0COPY_SBALS |
-           QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
-       init_data.input_sbal_addr_array = input_array;
-       init_data.output_sbal_addr_array = output_array;
-
-       result = qdio_initialize(&init_data);
-
-       vfree(input_array);
-       vfree(output_array);
-       vfree(adapter_area);
-
-       sprintf(dbf_text, "qde=%4i", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_qdio_activate(struct qeth_card *card)
-{
-       int result;
-       char dbf_text[15];
-
-       result = qdio_activate(CARD_DDEV(card), 0);
-
-       sprintf(dbf_text, "qda=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static int
-qeth_dm_act(struct qeth_card *card)
-{
-       unsigned char *buffer;
-       int result;
-       char dbf_text[15];
-
-       memcpy(card->send_buf, DM_ACT, DM_ACT_SIZE);
-
-       memcpy(QETH_DM_ACT_DEST_ADDR(card->send_buf),
-              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
-       memcpy(QETH_DM_ACT_CONNECTION_TOKEN(card->send_buf),
-              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
-
-       buffer = qeth_send_control_data(card, card->send_buf,
-                                       DM_ACT_SIZE, MPC_SETUP_STATE);
-
-       if (!buffer) {
-               QETH_DBF_TEXT2(0, trace, "DMA:NOBF");
-               return -EIO;
-       }
-
-       result = qeth_check_idx_response(buffer);
-
-       sprintf(dbf_text, "dma=%4x", result);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       return result;
-}
-
-static inline int
-__qeth_verify_dev_vlan(struct net_device *dev,struct qeth_card *card)
-{
-#ifdef QETH_VLAN
-       struct vlan_group *vlan_grp;
-       int i;
-       int result = 0;
-
-       /* check all vlan devices */
-       vlan_grp = (struct vlan_group *) card->vlangrp;
-       if (vlan_grp) {
-               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
-                       if (vlan_grp->vlan_devices[i] == dev) {
-                               result = QETH_VERIFY_IS_VLAN_DEV;
-                       }
-               }
-       }
-       return result;
-#endif
-       return 0;
-}
-
-#if defined(QETH_VLAN)||defined(QETH_IPV6)
-static int
-qeth_verify_dev(struct net_device *dev)
-{
-       struct qeth_card *tmp;
-       int result = 0;
-
-       read_lock(&list_lock);
-       tmp = firstcard;
-       for (; tmp && (!result); tmp = tmp->next) {
-               if (atomic_read(&tmp->shutdown_phase))
-                       continue;
-               result = (dev == tmp->dev)?
-                       QETH_VERIFY_IS_REAL_DEV:__qeth_verify_dev_vlan(dev, tmp);
-       }
-       read_unlock(&list_lock);
-       return result;
-}
-#endif /* defined(QETH_VLAN)||defined(QETH_IPV6) */
-
-static int
-qeth_verify_card(struct qeth_card *card)
-{
-       struct qeth_card *tmp;
-       int result = 0;
-
-       read_lock(&list_lock);
-       tmp = firstcard;
-       while (tmp) {
-               if ((card == tmp) && (!atomic_read(&card->shutdown_phase))) {
-                       result = 1;
-                       break;
-               }
-               tmp = tmp->next;
-       }
-       read_unlock(&list_lock);
-       return result;
-}
-
-static inline struct qeth_card *
-__qeth_get_card_from_dev(struct net_device *dev)
-{
-#ifdef QETH_VLAN
-       if (qeth_verify_dev(dev) == QETH_VERIFY_IS_VLAN_DEV)
-               return (struct qeth_card *) VLAN_DEV_INFO(dev)->real_dev->priv;
-       else
-#endif
-               return (struct qeth_card *) dev->priv;
-}
-
-#ifdef QETH_IPV6
-/* FIXME: don't put extern declarations in a c file, use a header that's
- * shared with the definition for this! */
-extern struct neigh_table arp_tbl;
-static int (*qeth_old_arp_constructor) (struct neighbour *);
-static struct neigh_ops arp_direct_ops_template = {
-       .family = AF_INET,
-       .destructor = NULL,
-       .solicit = NULL,
-       .error_report = NULL,
-       .output = dev_queue_xmit,
-       .connected_output = dev_queue_xmit,
-       .hh_output = dev_queue_xmit,
-       .queue_xmit = dev_queue_xmit
-};
-
-/*
- * FIXME:
- * as we have neighbour structures point to this structure, even
- * after our life time, this will stay in memory as a leak 
- */
-static struct neigh_ops *arp_direct_ops;
-
-
-static int
-qeth_arp_constructor(struct neighbour *neigh)
-{
-       char dbf_text[15];
-       struct net_device *dev = neigh->dev;
-       struct in_device *in_dev = in_dev_get(dev);
-
-       if (in_dev == NULL)
-               return -EINVAL;
-
-       QETH_DBF_TEXT4(0, trace, "arpconst");
-       if (!qeth_verify_dev(dev)) {
-
-               in_dev_put(in_dev);
-               return qeth_old_arp_constructor(neigh);
-       }
-
-       neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
-       if (in_dev->arp_parms)
-               neigh->parms = in_dev->arp_parms;
-
-       in_dev_put(in_dev);
-
-       sprintf(dbf_text, "%08x", ntohl(*((__u32 *) (neigh->primary_key))));
-       QETH_DBF_TEXT4(0, trace, dbf_text);
-       QETH_DBF_HEX4(0, trace, &neigh, sizeof (void *));
-
-       neigh->nud_state = NUD_NOARP;
-       neigh->ops = arp_direct_ops;
-       neigh->output = neigh->ops->queue_xmit;
-       return 0;
-}
-
-static int
-qeth_hard_header(struct sk_buff *skb, struct net_device *dev,
-                unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-       struct qeth_card *card;
-
-       QETH_DBF_TEXT5(0, trace, "hardhdr");
-
-       card = __qeth_get_card_from_dev(dev);
-       return card->hard_header(skb, dev, type, daddr, saddr, len);
-}
-
-static void
-qeth_header_cache_update(struct hh_cache *hh,
-                        struct net_device *dev, unsigned char *haddr)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_TEXT5(0, trace, "hdrcheup");
-       return card->header_cache_update(hh, dev, haddr);
-}
-
-static int
-qeth_rebuild_header(struct sk_buff *skb)
-{
-       struct qeth_card *card;
-       QETH_DBF_TEXT5(0, trace, "rebldhdr");
-       if (skb->protocol == __constant_htons(ETH_P_IP))
-               return 0;
-
-       card = __qeth_get_card_from_dev(skb->dev);
-
-       return card->rebuild_header(skb);
-}
-
-int
-qeth_ipv6_generate_eui64(u8 * eui, struct net_device *dev)
-{
-       switch (dev->type) {
-       case ARPHRD_ETHER:
-       case ARPHRD_FDDI:
-       case ARPHRD_IEEE802_TR:
-               if (dev->addr_len != ETH_ALEN)
-                       return -1;
-               memcpy(eui, dev->dev_addr, 3);
-               memcpy(eui + 5, dev->dev_addr + 3, 3);
-               eui[3] = (dev->dev_id >> 8) & 0xff;
-               eui[4] = dev->dev_id & 0xff;
-               return 0;
-       }
-       return -1;
-
-}
-#endif /* QETH_IPV6 */
-
-static void
-qeth_ipv6_init_card(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       card->hard_header = qeth_get_hard_header(card->link_type);
-       card->rebuild_header = qeth_get_rebuild_header(card->link_type);
-       card->hard_header_cache = qeth_get_hard_header_cache(card->link_type);
-       card->header_cache_update =
-           qeth_get_header_cache_update(card->link_type);
-       card->type_trans = qeth_get_type_trans(card->link_type);
-       card->dev->dev_id = card->unique_id & 0xffff;
-       if (!(card->unique_id & UNIQUE_ID_NOT_BY_CARD))
-               card->dev->generate_eui64 = qeth_ipv6_generate_eui64;
-#endif /* QETH_IPV6 */
-}
-
-#ifdef QETH_VLAN
-static void
-qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-       struct qeth_card *card;
-       card = (struct qeth_card *) dev->priv;
-       spin_lock_irq(&card->vlan_lock);
-       card->vlangrp = grp;
-       spin_unlock_irq(&card->vlan_lock);
-}
-static void
-qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
-{
-       struct qeth_card *card;
-       card = (struct qeth_card *) dev->priv;
-       spin_lock_irq(&card->vlan_lock);
-       if (card->vlangrp)
-               card->vlangrp->vlan_devices[vid] = NULL;
-       spin_unlock_irq(&card->vlan_lock);
-}
-#endif
-
-static void
-qeth_tx_timeout(struct net_device *dev)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-       QETH_DBF_CARD2(1, trace, "XMTO", card);
-       card->stats->tx_errors++;
-       atomic_set(&card->problem, PROBLEM_TX_TIMEOUT);
-       qeth_schedule_recovery(card);
-}
-
-static void*
-__qeth_rebuild_header_func(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       return (!(qeth_get_additional_dev_flags(card->type) & IFF_NOARP)) ?
-               (qeth_get_rebuild_header(card->link_type) ?
-                qeth_rebuild_header : NULL) : NULL;
-#endif /* QETH_IPV6 */
-       return NULL;
-}
-
-static void*
-__qeth_hard_header_func(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       return (!(qeth_get_additional_dev_flags(card->type) & IFF_NOARP)) ?
-               (qeth_get_hard_header(card->link_type) ?
-                qeth_hard_header : NULL) : NULL;
-#endif /* QETH_IPV6 */
-       return NULL;
-}
-
-static void*
-__qeth_header_cache_update_func(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       return (!(qeth_get_additional_dev_flags(card->type) & IFF_NOARP)) ?
-               (qeth_get_header_cache_update(card->link_type) ?
-                qeth_header_cache_update : NULL) : NULL;
-#endif /* QETH_IPV6 */
-       return NULL;
-}
-
-static void*
-__qeth_hard_header_cache_func(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       return (!(qeth_get_additional_dev_flags(card->type) & IFF_NOARP)) ?
-               qeth_get_hard_header_cache(card->link_type) : NULL;
-#endif /* QETH_IPV6 */
-       return NULL;
-}
-
-static int
-qeth_init_dev(struct net_device *dev)
-{
-       struct qeth_card *card;
-
-       card = (struct qeth_card *) dev->priv;
-
-       QETH_DBF_CARD3(0, trace, "inid", card);
-
-       dev->rebuild_header = __qeth_rebuild_header_func(card);
-       dev->hard_header = __qeth_hard_header_func(card);
-       dev->header_cache_update = __qeth_header_cache_update_func(card);
-       dev->hard_header_cache = __qeth_hard_header_cache_func(card);
-       dev->hard_header_parse = NULL;
-
-       dev->flags |= qeth_get_additional_dev_flags(card->type);
-
-       dev->flags |= ((card->options.fake_broadcast == FAKE_BROADCAST) ||
-                      (card->broadcast_capable)) ? IFF_BROADCAST : 0;
-
-        /* is done in hardsetup_card... see comment below
-        qeth_send_qipassist(card,4);*/
-
-       /* that was the old place. one id. we need to make sure, that
-        * hydra knows about us going to use the same id again, so we
-        * do that in hardsetup_card every time
-        qeth_get_unique_id(card);*/
-
-       dev->tx_queue_len = qeth_get_device_tx_q_len(card->type);
-       dev->hard_header_len =
-               qeth_get_hlen(card->link_type) + card->options.add_hhlen;
-       netif_start_queue(dev);
-
-       dev->mtu = card->initial_mtu;
-
-       qeth_ipv6_init_card(card);
-
-       return 0;
-}
-
-static int
-qeth_get_unitaddr(struct qeth_card *card)
-{
-       char *prcd;
-       int result = 0;
-       char dbf_text[15];
-       int length;
-
-       QETH_DBF_CARD3(0, trace, "gtua", card);
-
-       result = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length);
-       if (result) {
-               sprintf(dbf_text, "rcd%4x", result);
-               QETH_DBF_TEXT3(0, trace, dbf_text);
-               PRINT_ERR("read_conf_data for device %s returned %i\n",
-                         CARD_DDEV_ID(card), result);
-               return result;
-       }
-
-       card->chpid = prcd[30];
-       card->unit_addr2 = prcd[31];
-       card->cula = prcd[63];
-       card->is_guest_lan= ((prcd[0x10] == _ascebc['V']) &&
-                            (prcd[0x11] == _ascebc['M']));
-
-       sprintf(dbf_text, "chpid:%02x", card->chpid);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-       sprintf(dbf_text, "unad2:%02x", card->unit_addr2);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-       sprintf(dbf_text, "cula:%02x", card->cula);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       return 0;
-}
-
-static int
-qeth_send_nops(struct qeth_card *card)
-{
-       int result, result2;
-       unsigned long saveflags;
-
-       card->dma_stuff->write_ccw.cmd_code = CCW_NOP_CMD;
-       card->dma_stuff->write_ccw.flags = CCW_FLAG_SLI;
-       card->dma_stuff->write_ccw.count = CCW_NOP_COUNT;
-       card->dma_stuff->write_ccw.cda = (unsigned long) NULL;
-
-#define DO_SEND_NOP(cdev) \
-do { \
-       QETH_DBF_TEXT3(0, trace, "snnp"); \
-       QETH_DBF_TEXT3(0, trace, cdev->dev.bus_id); \
-\
-       spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); \
-       ccw_device_set_options(cdev, 0); \
-        result=ccw_device_start(cdev,&card->dma_stuff->write_ccw, \
-                               NOP_STATE,0,0); \
-        if (result) { \
-               qeth_delay_millis(QETH_WAIT_BEFORE_2ND_DOIO); \
-                result2=ccw_device_start(cdev,&card->dma_stuff->write_ccw, \
-                                        NOP_STATE,0,0); \
-                PRINT_WARN("qeth_send_nops on device %s: do_IO returned %i, " \
-                           "next try returns %i\n", \
-                           cdev->dev.bus_id,result,result2); \
-               result=result2; \
-        } \
-        spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); \
-\
-       if (result) goto exit; \
-\
-        if (qeth_sleepon(card,QETH_NOP_TIMEOUT)) { \
-               QETH_DBF_TEXT2(0,trace,"snnp:tme"); \
-               result=-EIO; \
-               goto exit; \
-        } \
-} while (0)
-
-       DO_SEND_NOP(CARD_RDEV(card));
-       DO_SEND_NOP(CARD_WDEV(card));
-       DO_SEND_NOP(CARD_DDEV(card));
-
-exit:
-       return result;
-}
-
-static void
-qeth_clear_card_structures(struct qeth_card *card)
-{
-       int i, j;
-
-       if (!card) {
-               QETH_DBF_TEXT2(0, trace, "clrCRDnc");
-               return;
-       }
-
-       QETH_DBF_CARD3(0, trace, "clcs", card);
-
-       atomic_set(&card->is_startlaned, 0);
-
-       for (i = 0; i < QETH_MAX_QUEUES; i++) {
-               card->send_state[i] = SEND_STATE_DONT_PACK;
-               card->outbound_first_free_buffer[i] = 0;
-               atomic_set(&card->outbound_used_buffers[i], 0);
-               atomic_set(&card->outbound_ringbuffer_lock[i], 0);
-
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) {
-                       card->outbound_buffer_send_state[i][j] =
-                           SEND_STATE_DONT_PACK;
-                       card->send_retries[i][j] = 0;
-
-                       if (i < card->no_queues) {
-                               card->outbound_ringbuffer[i]->
-                                   ringbuf_element[j].next_element_to_fill = 0;
-                               card->outbound_bytes_in_buffer[i] = 0;
-                               skb_queue_head_init(&card->
-                                                   outbound_ringbuffer[i]->
-                                                   ringbuf_element[j].
-                                                   skb_list);
-                       }
-               }
-       }
-
-       for (i = 0; i < card->options.inbound_buffer_count; i++) {
-               xchg((int *) &card->inbound_buffer_pool_entry_used[i],
-                    BUFFER_UNUSED);
-       }
-
-       spin_lock_init(&card->requeue_input_lock);
-       atomic_set(&card->requeue_position, 0);
-       atomic_set(&card->requeue_counter, 0);
-
-       card->seqno.trans_hdr = 0;
-       card->seqno.pdu_hdr = 0;
-       card->seqno.pdu_hdr_ack = 0;
-       card->seqno.ipa = 0;
-
-       qeth_clear_ifa4_list(&card->ip_current_state.ip_ifa);
-       qeth_clear_ifa4_list(&card->ip_new_state.ip_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_current_state.ipm_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm_ifa);
-
-#ifdef QETH_IPV6
-       qeth_clear_ifa6_list(&card->ip_current_state.ip6_ifa);
-       qeth_clear_ifa6_list(&card->ip_new_state.ip6_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_current_state.ipm6_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm6_ifa);
-#endif /* QETH_IPV6 */
-}
-
-static void
-qeth_init_input_buffers(struct qeth_card *card)
-{
-       int i;
-
-       /* slowly, slowly (we don't want to enqueue all buffers
-        * at one time) */
-       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
-               atomic_set(&card->inbound_buffer_refcnt[i], 1);
-       }
-       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
-               atomic_set(&card->inbound_buffer_refcnt[i], 0);
-               /* only try to queue as many buffers as we have at all */
-               if (i < card->options.inbound_buffer_count)
-                       qeth_queue_input_buffer(card,i,0);
-       }
-       qdio_synchronize(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0);
-}
-
-/* initializes all the structures for a card */
-static int
-qeth_hardsetup_card(struct qeth_card *card, int in_recovery)
-{
-       int result, q, breakout;
-       unsigned long flags;
-       int laps = QETH_HARDSETUP_LAPS;
-       int clear_laps;
-       int cleanup_qdio;
-       char dbf_text[15];
-       int i, r;
-
-       /* setup name and so on */
-       atomic_set(&card->shutdown_phase, 0);
-
-       if (atomic_read(&card->is_hardsetup)) {
-               QETH_DBF_CARD2(1, trace, "hscd", card);
-               PRINT_ALL("card is already hardsetup.\n");
-               return 0;
-       }
-
-       cleanup_qdio = in_recovery;     /* if we are in recovery, we clean
-                                          the qdio stuff up */
-
-       down(&card->hardsetup_sema);
-       atomic_set(&card->write_busy, 0);
-
-       do {
-               if (in_recovery) {
-                       PRINT_STUPID("qeth: recovery: quiescing %s...\n",
-                                    card->dev_name);
-                       QETH_DBF_CARD2(0, trace, "Rqsc", card);
-                       qeth_wait_nonbusy(QETH_QUIESCE_WAIT_BEFORE_CLEAR);
-               }
-               clear_laps = QETH_HARDSETUP_CLEAR_LAPS;
-               do {
-                       if (in_recovery)
-                               PRINT_STUPID("clearing card %s\n",
-                                            card->dev_name);
-                       qeth_clear_card(card, cleanup_qdio,
-                                       (card->type == QETH_CARD_TYPE_OSAE));
-                       result = qeth_send_nops(card);
-                       breakout = atomic_read(&card->break_out);
-               } while ((--clear_laps) && (result));
-               if (result) {
-                       goto exit;
-               }
-
-               if (in_recovery) {
-                       PRINT_STUPID("qeth: recovery: still quiescing %s...\n",
-                                    card->dev_name);
-                       QETH_DBF_CARD2(0, trace, "RQsc", card);
-                       qeth_wait_nonbusy(QETH_QUIESCE_WAIT_AFTER_CLEAR);
-               } else {
-                       atomic_set(&card->shutdown_phase, 0);
-               }
-
-               cleanup_qdio = 0;       /* qdio was cleaned now, if necessary */
-
-               result = qeth_get_unitaddr(card);
-               if (result)
-                       goto exit;
-
-               qeth_generate_tokens(card);
-
-#define PRINT_TOKENS do { \
-               sprintf(dbf_text,"stra    "); \
-               memcpy(&dbf_text[4],&card->seqno.trans_hdr,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"spdu    "); \
-               memcpy(&dbf_text[4],&card->seqno.pdu_hdr,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"spda    "); \
-               memcpy(&dbf_text[4],&card->seqno.pdu_hdr_ack,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"sipa    "); \
-               memcpy(&dbf_text[4],&card->seqno.ipa,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tisw    "); \
-               memcpy(&dbf_text[4],&card->token.issuer_rm_w,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tisr    "); \
-               memcpy(&dbf_text[4],&card->token.issuer_rm_r,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tcfw    "); \
-               memcpy(&dbf_text[4],&card->token.cm_filter_w,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tcfr    "); \
-               memcpy(&dbf_text[4],&card->token.cm_filter_r,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tccw    "); \
-               memcpy(&dbf_text[4],&card->token.cm_connection_w,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tccr    "); \
-               memcpy(&dbf_text[4],&card->token.cm_connection_r,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tufw    "); \
-               memcpy(&dbf_text[4],&card->token.ulp_filter_w,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tufr    "); \
-               memcpy(&dbf_text[4],&card->token.ulp_filter_r,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tucw    "); \
-               memcpy(&dbf_text[4],&card->token.ulp_connection_w,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-               sprintf(dbf_text,"tucr    "); \
-               memcpy(&dbf_text[4],&card->token.ulp_connection_r,4); \
-               QETH_DBF_HEX3(0,trace,dbf_text,QETH_DBF_TRACE_LEN); \
-       } while (0)
-
-               PRINT_TOKENS;
-
-               /* card->break_out and problem will be set here to 0
-                * (in each lap) (there can't be a problem at this
-                * early time) */
-               atomic_set(&card->problem, 0);
-               atomic_set(&card->break_out, 0);
-
-#define CHECK_ERRORS \
-               breakout=atomic_read(&card->break_out); \
-               if (breakout==QETH_BREAKOUT_AGAIN) \
-                       continue; \
-               else if (breakout==QETH_BREAKOUT_LEAVE) { \
-                       result=-EIO; \
-                       goto exit; \
-               } \
-               if (result) goto exit
-
-               QETH_DBF_TEXT2(0, trace, "hsidxard");
-               result = qeth_idx_activate_read(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hsidxawr");
-               result = qeth_idx_activate_write(card);
-               CHECK_ERRORS;
-
-               QETH_DBF_TEXT2(0, trace, "hsissurd");
-               /* from here, there will always be an outstanding read */
-               spin_lock_irqsave(get_ccwdev_lock(CARD_RDEV(card)), flags);
-               qeth_issue_next_read(card);
-               spin_unlock_irqrestore(get_ccwdev_lock(CARD_RDEV(card)), flags);
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hscmenab");
-               result = qeth_cm_enable(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hscmsetu");
-               result = qeth_cm_setup(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hsulpena");
-               result = qeth_ulp_enable(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hsulpset");
-               result = qeth_ulp_setup(card);
-               CHECK_ERRORS;
-
-               cleanup_qdio = 1;
-
-               QETH_DBF_TEXT2(0, trace, "hsqdioes");
-               result = qeth_qdio_establish(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hsqdioac");
-               result = qeth_qdio_activate(card);
-               CHECK_ERRORS;
-
-               PRINT_TOKENS;
-               QETH_DBF_TEXT2(0, trace, "hsdmact");
-               result = qeth_dm_act(card);
-               CHECK_ERRORS;
-       } while ((laps--) && (breakout == QETH_BREAKOUT_AGAIN));
-       if (breakout == QETH_BREAKOUT_AGAIN) {
-               QETH_DBF_CARD2(0, trace, "hsnr", card);
-               PRINT_ERR("qeth: recovery not successful on device "
-                         "%s/%s/%s; giving up.\n",
-                         CARD_RDEV_ID(card),
-                         CARD_WDEV_ID(card), CARD_DDEV_ID(card));
-               result = -EIO;
-               goto exit;
-       }
-
-       qeth_clear_ifa4_list(&card->ip_current_state.ip_ifa);
-       qeth_clear_ifa4_list(&card->ip_new_state.ip_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_current_state.ipm_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm_ifa);
-
-#ifdef QETH_IPV6
-       qeth_clear_ifa6_list(&card->ip_current_state.ip6_ifa);
-       qeth_clear_ifa6_list(&card->ip_new_state.ip6_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_current_state.ipm6_ifa);
-       qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm6_ifa);
-#endif /* QETH_IPV6 */
-
-       if (!atomic_read(&card->is_registered)) {
-               card->dev->dev_addr[0] = 0;     /* we don't know the mac addr yet */
-               card->dev->dev_addr[1] = 0;
-               card->dev->dev_addr[2] = 0;
-               card->dev->dev_addr[3] = 0;
-               card->dev->dev_addr[4] = 0;
-               card->dev->dev_addr[5] = 0;
-               card->dev->broadcast[0] = card->dev->broadcast[1] = 0xff;
-               card->dev->broadcast[2] = card->dev->broadcast[3] = 0xff;
-               card->dev->broadcast[4] = card->dev->broadcast[5] = 0xff;
-
-               card->dev->type = qeth_get_arphrd_type(card->type,
-                                                      card->link_type);
-
-               card->dev->init = qeth_init_dev;
-
-               card->ipa_timeout = qeth_get_ipa_timeout(card->type);
-       }
-
-       atomic_set(&card->is_hardsetup, 1);
-       atomic_set(&card->is_softsetup, 0);
-       atomic_set(&card->startlan_attempts, 1);
-
-       for (q = 0; q < card->no_queues; q++)
-               card->send_state[q] = SEND_STATE_DONT_PACK;
-
-       /* we need to know first, whether we should include a value
-        * into eui-64 address generation */
-       QETH_DBF_TEXT2(0, trace, "qipassi4");
-       r = qeth_send_qipassist(card, 4);
-       if (r) {
-               PRINT_WARN("couldn't send QIPASSIST4 on %s: "
-                          "0x%x\n", card->dev_name, r);
-               sprintf(dbf_text, "QIP4%4x", r);
-               QETH_DBF_TEXT2(0, trace, dbf_text);
-       }
-
-       sprintf(dbf_text, "%4x%4x", card->ipa_supported, card->ipa_enabled);
-       QETH_DBF_TEXT2(0, trace, dbf_text);
-
-       qeth_get_unique_id(card);
-
-       /* print out status */
-       if (in_recovery) {
-               qeth_clear_card_structures(card);
-               qeth_init_input_buffers(card);
-               QETH_DBF_TEXT1(0, trace, "RECOVSUC");
-               PRINT_INFO("qeth: recovered device %s/%s/%s (%s) "
-                          "successfully.\n",
-                          CARD_RDEV_ID(card),
-                          CARD_WDEV_ID(card),
-                          CARD_DDEV_ID(card), card->dev_name);
-       } else {
-               QETH_DBF_TEXT2(0, trace, "hrdsetok");
-
-               switch (card->type) {
-               case QETH_CARD_TYPE_OSAE:
-                       /* 
-                        * VM will use a non-zero first character to indicate
-                        * a HiperSockets like reporting of the level
-                        * OSA sets the first character to zero
-                        */
-                       if (!card->level[0]) {
-                               sprintf(card->level, "%02x%02x", card->level[2],
-                                       card->level[3]);
-                               card->level[QETH_MCL_LENGTH] = 0;
-                               break;
-                       }
-                       /* fallthrough */
-               case QETH_CARD_TYPE_IQD:
-                       card->level[0] = (char) _ebcasc[(__u8) card->level[0]];
-                       card->level[1] = (char) _ebcasc[(__u8) card->level[1]];
-                       card->level[2] = (char) _ebcasc[(__u8) card->level[2]];
-                       card->level[3] = (char) _ebcasc[(__u8) card->level[3]];
-                       card->level[QETH_MCL_LENGTH] = 0;
-                       break;
-               default:
-                       memset(&card->level[0], 0, QETH_MCL_LENGTH + 1);
-               }
-
-               sprintf(dbf_text, "lvl:%s", card->level);
-               QETH_DBF_TEXT2(0, setup, dbf_text);
-
-               if (card->portname_required) {
-                       sprintf(dbf_text, "%s", card->options.portname + 1);
-                       for (i = 0; i < 8; i++)
-                               dbf_text[i] =
-                                   (char) _ebcasc[(__u8) dbf_text[i]];
-                       dbf_text[8] = 0;
-                       printk("qeth: Device %s/%s/%s is a%s card%s%s%s\n"
-                              "with link type %s (portname: %s)\n",
-                              CARD_RDEV_ID(card),
-                              CARD_WDEV_ID(card),
-                              CARD_DDEV_ID(card),
-                              qeth_get_cardname(card->type,
-                                                card->is_guest_lan),
-                              (card->level[0]) ? " (level: " : "",
-                              (card->level[0]) ? card->level : "",
-                              (card->level[0]) ? ")" : "",
-                              qeth_get_link_type_name(card->type,
-                                                      card->link_type),
-                              dbf_text);
-               } else {
-                       if (card->options.portname[0])
-                               printk("qeth: Device %s/%s/%s is a%s "
-                                      "card%s%s%s\nwith link type %s "
-                                      "(no portname needed by interface).\n",
-                                      CARD_RDEV_ID(card),
-                                      CARD_WDEV_ID(card),
-                                      CARD_DDEV_ID(card),
-                                      qeth_get_cardname(card->type,
-                                                        card->is_guest_lan),
-                                      (card->level[0]) ? " (level: " : "",
-                                      (card->level[0]) ? card->level : "",
-                                      (card->level[0]) ? ")" : "",
-                                      qeth_get_link_type_name(card->type,
-                                                              card->link_type));
-                       else
-                               printk("qeth: Device %s/%s/%s is a%s "
-                                      "card%s%s%s\nwith link type %s.\n",
-                                      CARD_RDEV_ID(card),
-                                      CARD_WDEV_ID(card),
-                                      CARD_DDEV_ID(card),
-                                      qeth_get_cardname(card->type,
-                                                        card->is_guest_lan),
-                                      (card->level[0]) ? " (level: " : "",
-                                      (card->level[0]) ? card->level : "",
-                                      (card->level[0]) ? ")" : "",
-                                      qeth_get_link_type_name(card->type,
-                                                              card->link_type));
-               }
-       }
-
-exit:
-       up(&card->hardsetup_sema);
-       return result;
-}
-
-static int
-qeth_reinit_thread(void *param)
-{
-       struct qeth_card *card = (struct qeth_card *) param;
-       int already_registered;
-       int already_hardsetup;
-       int retry = QETH_RECOVERY_HARDSETUP_RETRY;
-       int result;
-       char name[15];
-
-       QETH_DBF_CARD1(0, trace, "RINI", card);
-
-       /* set a nice name ... */
-       sprintf(name, "qethrinid%s", CARD_BUS_ID(card));
-       daemonize(name);
-
-       if (atomic_read(&card->shutdown_phase))
-               goto out_wakeup;
-       down_interruptible(&card->reinit_thread_sem);
-       if (atomic_read(&card->shutdown_phase))
-               goto out_wakeup;
-
-       QETH_DBF_TEXT1(0, trace, "ri-gotin");
-       PRINT_STUPID("entering recovery (reinit) thread for device %s\n",
-                    card->dev_name);
-
-       atomic_set(&card->is_startlaned, 0);
-       atomic_set(&card->is_softsetup, 0);
-
-       read_lock(&list_lock);
-       if (!qeth_verify_card(card))
-               goto out;
-       QETH_DBF_TEXT1(0, trace, "ri-vrfd");
-
-       atomic_set(&card->write_busy, 0);
-       qeth_set_dev_flag_norunning(card);
-       already_hardsetup = atomic_read(&card->is_hardsetup);
-       already_registered = atomic_read(&card->is_registered);
-       if (already_hardsetup) {
-               atomic_set(&card->is_hardsetup, 0);
-
-               if (-1 == my_spin_lock_nonbusy(card, &setup_lock))
-                       goto out;
-               if (atomic_read(&card->shutdown_phase))
-                       goto out_wakeup;
-
-               atomic_set(&card->escape_softsetup, 1);
-
-               if (-1 == my_down_trylock_nonbusy(card, &card->softsetup_sema)) {
-                       atomic_set(&card->escape_softsetup, 0);
-                       goto out;
-               }
-               atomic_set(&card->escape_softsetup, 0);
-               if (atomic_read(&card->shutdown_phase)) {
-                       up(&card->softsetup_sema);
-                       goto out_wakeup;
-               }
-               if (!qeth_verify_card(card))
-                       goto out;
-
-               if (already_registered)
-                       netif_stop_queue(card->dev);
-
-               qeth_wait_nonbusy(QETH_QUIESCE_NETDEV_TIME);
-
-               atomic_set(&card->is_startlaned, 0);
-
-               QETH_DBF_TEXT1(0, trace, "ri-frskb");
-               qeth_free_all_skbs(card);
-               do {
-                       QETH_DBF_TEXT1(0, trace, "ri-hrdst");
-                       result = qeth_hardsetup_card(card, 1);
-               } while (result && (retry--));
-
-               /* tries to remove old ips, that's paranoid, but ok */
-               qeth_clear_ifa4_list(&card->ip_new_state.ip_ifa);
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm_ifa);
-
-#ifdef QETH_IPV6
-               qeth_clear_ifa6_list(&card->ip_new_state.ip6_ifa);
-               qeth_clear_ifamc_list(&card->ip_mc_new_state.ipm6_ifa);
-#endif /* QETH_IPV6 */
-
-               if (result) {
-                       QETH_DBF_TEXT1(0, trace, "ri-nosuc");
-                       PRINT_ERR("qeth: RECOVERY WAS NOT SUCCESSFUL ON %s "
-                                 "(%s/%s/%s), GIVING UP, "
-                                 "OUTGOING PACKETS WILL BE DISCARDED!\n",
-                                 card->dev_name,
-                                 CARD_RDEV_ID(card),
-                                 CARD_WDEV_ID(card),
-                                 CARD_DDEV_ID(card));
-                       /* early leave hard_start_xmit! */
-                       atomic_set(&card->is_startlaned, 0);
-                       qeth_wakeup_procfile();
-               } else {
-                       QETH_DBF_TEXT1(0, trace, "ri-sftst");
-                       qeth_softsetup_card(card, QETH_LOCK_ALREADY_HELD);
-                       up(&card->softsetup_sema);
-
-                       if (!already_registered) {
-                               QETH_DBF_TEXT1(0, trace, "ri-regcd");
-                               qeth_register_netdev(card);
-                       }
-                       qeth_restore_dev_flag_state(card);
-                       netif_wake_queue(card->dev);
-                       qeth_wakeup_procfile();
-               }
-               spin_unlock(&setup_lock);
-       }
-out:
-       atomic_set(&card->in_recovery, 0);
-       read_unlock(&list_lock);
-       QETH_DBF_TEXT1(0, trace, "ri-leave");
-out_wakeup:
-       up(&card->reinit_thread_sem);
-       atomic_dec(&card->reinit_counter);
-
-       return 0;
-}
-
-static void
-qeth_fill_qeth_card_options(struct qeth_card *card)
-{
-       int i;
-
-       card->options.portname[0] = 0;
-       for (i = 1; i < 9; i++)
-               card->options.portname[i] = _ascebc[' '];
-       strcpy(card->options.devname, " ");
-       card->options.routing_type4 = NO_ROUTER;
-#ifdef QETH_IPV6
-       card->options.routing_type6 = NO_ROUTER;
-#endif /* QETH_IPV6 */
-       card->options.portno = 0;
-       card->options.checksum_type = QETH_CHECKSUM_DEFAULT;
-       card->options.do_prio_queueing = QETH_PRIOQ_DEFAULT;
-       card->options.default_queue = QETH_DEFAULT_QUEUE;
-       card->options.inbound_buffer_count = DEFAULT_BUFFER_COUNT;
-       card->options.polltime = QETH_MAX_INPUT_THRESHOLD;
-       card->options.macaddr_mode = MACADDR_NONCANONICAL;
-       card->options.broadcast_mode = BROADCAST_ALLRINGS;
-       card->options.fake_broadcast = DONT_FAKE_BROADCAST;
-       card->options.ena_ipat = ENABLE_TAKEOVER;
-       card->options.add_hhlen = DEFAULT_ADD_HHLEN;
-       card->options.fake_ll = DONT_FAKE_LL;
-}
-
-static void qeth_setup(struct net_device *dev)
-{
-       dev->tx_timeout = &qeth_tx_timeout;
-       dev->watchdog_timeo = QETH_TX_TIMEOUT;
-       dev->open = qeth_open;
-       dev->stop = qeth_stop;
-       dev->set_config = qeth_set_config;
-       dev->hard_start_xmit = qeth_hard_start_xmit;
-       dev->do_ioctl = qeth_do_ioctl;
-       dev->get_stats = qeth_get_stats;
-       dev->change_mtu = qeth_change_mtu;
-#ifdef QETH_VLAN
-       dev->vlan_rx_register = qeth_vlan_rx_register;
-       dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
-#endif
-       dev->set_multicast_list = qeth_set_multicast_list;
-       dev->set_mac_address = qeth_set_mac_address;
-       dev->neigh_setup = qeth_neigh_setup;
-       dev->addr_len = OSA_ADDR_LEN;   /* is ok for eth, tr, atm lane */
-       SET_MODULE_OWNER(dev);
-}
-
-static int
-qeth_alloc_card_stuff(struct qeth_card *card)
-{
-       if (!card)
-               return -EINVAL;
-
-       QETH_DBF_TEXT3(0, trace, "alccrdst");
-
-       card->dma_stuff =
-           (struct qeth_dma_stuff *) kmalloc(sizeof (struct qeth_dma_stuff),
-                                             GFP_KERNEL | GFP_DMA);
-       if (!card->dma_stuff)
-               goto exit_dma;
-       memset(card->dma_stuff, 0, sizeof (struct qeth_dma_stuff));
-
-       card->dma_stuff->recbuf = (char *) kmalloc(QETH_BUFSIZE,
-                                                  GFP_KERNEL | GFP_DMA);
-       if (!card->dma_stuff->recbuf)
-               goto exit_dma1;
-       memset(card->dma_stuff->recbuf, 0, QETH_BUFSIZE);
-
-       card->dma_stuff->sendbuf = (char *) kmalloc(QETH_BUFSIZE,
-                                                   GFP_KERNEL | GFP_DMA);
-       if (!card->dma_stuff->sendbuf)
-               goto exit_dma2;
-       memset(card->dma_stuff->sendbuf, 0, QETH_BUFSIZE);
-
-       card->dev = alloc_netdev(0, "", qeth_setup);
-       if (!card->dev)
-               goto exit_dev;
-
-       card->stats =
-           (struct net_device_stats *)
-           kmalloc(sizeof (struct net_device_stats), GFP_KERNEL);
-       if (!card->stats)
-               goto exit_stats;
-       memset(card->stats, 0, sizeof (struct net_device_stats));
-
-       /* setup net_device stuff */
-       card->dev->priv = card;
-
-       /* setup net_device_stats stuff */
-       /* =nothing yet */
-
-       return 0;
-
-       /* these are quick exits in case of failures of the kmallocs */
-exit_stats:
-       free_netdev(card->dev);
-exit_dev:
-       kfree(card->dma_stuff->sendbuf);
-exit_dma2:
-       kfree(card->dma_stuff->recbuf);
-exit_dma1:
-       kfree(card->dma_stuff);
-exit_dma:
-       return -ENOMEM;
-}
-
-static struct qeth_card *
-qeth_alloc_card(void)
-{
-       struct qeth_card *card;
-
-       QETH_DBF_TEXT3(0, trace, "alloccrd");
-       card = (struct qeth_card *) vmalloc(sizeof (struct qeth_card));
-       if (!card)
-               return NULL;
-       memset(card, 0, sizeof (struct qeth_card));
-       init_waitqueue_head(&card->wait_q);
-       init_waitqueue_head(&card->ioctl_wait_q);
-
-       qeth_fill_qeth_card_options(card);
-
-       init_MUTEX(&card->softsetup_sema);
-       init_MUTEX(&card->hardsetup_sema);
-       spin_lock_init(&card->ioctl_lock);
-#ifdef QETH_VLAN
-       spin_lock_init(&card->vlan_lock);
-       card->vlangrp = NULL;
-#endif
-       card->unique_id = 0;
-       sema_init(&card->reinit_thread_sem, 0);
-       up(&card->reinit_thread_sem);
-
-       /* setup card stuff */
-       card->ip_current_state.ip_ifa = NULL;
-       card->ip_new_state.ip_ifa = NULL;
-       card->ip_mc_current_state.ipm_ifa = NULL;
-       card->ip_mc_new_state.ipm_ifa = NULL;
-
-#ifdef QETH_IPV6
-       card->ip_current_state.ip6_ifa = NULL;
-       card->ip_new_state.ip6_ifa = NULL;
-       card->ip_mc_current_state.ipm6_ifa = NULL;
-       card->ip_mc_new_state.ipm6_ifa = NULL;
-#endif /* QETH_IPV6 */
-
-       card->csum_enable_mask = IPA_CHECKSUM_DEFAULT_ENABLE_MASK;
-
-       /* and return to the sender */
-       return card;
-
-}
-
-static int
-qeth_init_ringbuffers1(struct qeth_card *card)
-{
-       int i, j;
-
-       QETH_DBF_CARD3(0, trace, "irb1", card);
-
-       for (i = 0; i < card->no_queues; i++) {
-               card->outbound_ringbuffer[i] =
-                   vmalloc(sizeof (struct qeth_ringbuffer));
-               if (!card->outbound_ringbuffer[i]) {
-                       for (j = i - 1; j >= 0; j--) {
-                               vfree(card->outbound_ringbuffer[j]);
-                               card->outbound_ringbuffer[j] = NULL;
-                       }
-                       return -ENOMEM;
-               }
-               memset(card->outbound_ringbuffer[i], 0,
-                      sizeof (struct qeth_ringbuffer));
-               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++)
-                       skb_queue_head_init(&card->outbound_ringbuffer[i]->
-                                           ringbuf_element[j].skb_list);
-       }
-
-       return 0;
-}
-
-static int
-qeth_init_ringbuffers2(struct qeth_card *card)
-{
-       int i, j;
-
-       QETH_DBF_CARD3(0, trace, "irb2", card);
-
-       for (i = 0; i < card->options.inbound_buffer_count; i++) {
-               for (j = 0; j < BUFFER_MAX_ELEMENTS; j++) {
-                       card->inbound_buffer_pool_entry[i][j] =
-                               kmalloc(PAGE_SIZE, GFP_KERNEL);
-                       if (!card->inbound_buffer_pool_entry[i][j]) {
-                               goto out;
-                       }
-               }
-               card->inbound_buffer_pool_entry_used[i] = BUFFER_UNUSED;
-       }
-
-       spin_lock_init(&card->requeue_input_lock);
-
-       return 0;
-out:
-       for (i = 0; i < card->options.inbound_buffer_count; i++) {
-               for (j = 0; j < QDIO_MAX_ELEMENTS_PER_BUFFER; j++) {
-                       if (card->inbound_buffer_pool_entry[i][j]) {
-                               if (j < BUFFER_MAX_ELEMENTS)
-                                       kfree(card->
-                                             inbound_buffer_pool_entry[i][j]);
-                               card->inbound_buffer_pool_entry[i][j] = NULL;
-                       }
-               }
-       }
-       for (i = 0; i < card->no_queues; i++) {
-               vfree(card->outbound_ringbuffer[i]);
-               card->outbound_ringbuffer[i] = NULL;
-       }
-       return -ENOMEM;
-
-}
-
-/* also locked from outside (setup_lock) */
-static void
-qeth_insert_card_into_list(struct qeth_card *card)
-{
-       QETH_DBF_CARD3(0, trace, "icil", card);
-
-       write_lock(&list_lock);
-       card->next = firstcard;
-       firstcard = card;
-       write_unlock(&list_lock);
-}
-
-static int
-qeth_determine_card_type(struct qeth_card *card)
-{
-       int i = 0;
-       char dbf_text[15];
-
-       while (known_devices[i][4]) {
-               if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
-                   (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
-                       card->type = known_devices[i][4];
-                       if (card->options.ena_ipat == ENABLE_TAKEOVER)
-                               card->func_level = known_devices[i][6];
-                       else
-                               card->func_level = known_devices[i][7];
-                       card->no_queues = known_devices[i][8];
-                       card->is_multicast_different = known_devices[i][9];
-                       QETH_DBF_TEXT2(0, setup, CARD_BUS_ID(card));
-                       sprintf(dbf_text, "ctyp%4x", card->type);
-                       QETH_DBF_TEXT2(0, setup, dbf_text);
-                       return 0;
-               }
-               i++;
-       }
-       card->type = QETH_CARD_TYPE_UNKNOWN;
-       QETH_DBF_TEXT2(0, setup, CARD_BUS_ID(card));
-       sprintf(dbf_text, "ctypUNKN");
-       QETH_DBF_TEXT2(0, setup, dbf_text);
-       PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card));
-       return -ENOENT;
-}
-
-static int
-qeth_getint(char *s, int longint)
-{
-       int cnt;
-       int hex;
-       int result;
-       char c;
-
-       if (!s)
-               return -1;
-       hex = ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) ? 1 : 0;
-       cnt = (hex) ? 2 : 0;    /* start from the first real digit */
-       if (!(s[cnt]))
-               return -1;
-       result = 0;
-       while ((c = s[cnt++])) {
-               if (hex) {
-                       if (isxdigit(c))
-                               result = result * 16 + qeth_getxdigit(c);
-                       else
-                               return -1;
-               } else {
-                       if (isdigit(c))
-                               result = result * 10 + c - '0';
-                       else
-                               return -1;
-               }
-               /* prevent overflow, 0xffff is enough for us */
-               if (longint) {
-                       if (result > 0xfffffff)
-                               return -1;
-               } else {
-                       if (result > 0xffff)
-                               return -1;
-               }
-       }
-       return result;
-}
-
-static void
-__qeth_correct_routing_status_v4(struct qeth_card *card)
-{
-       if (card->options.routing_type4 == NO_ROUTER)
-               return;
-
-       if (card->type == QETH_CARD_TYPE_IQD) {
-               /* if it's not a mc router, it's no router */
-               if ((card->options.routing_type4 == PRIMARY_ROUTER) ||
-                   (card->options.routing_type4 == SECONDARY_ROUTER)) {
-                       PRINT_WARN("routing not applicable, reset "
-                                  "routing status for ipv4. \n");
-                       card->options.routing_type4 = NO_ROUTER;
-               }
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-       } else {
-               /* if it's a mc router, it's no router */
-               if ((!qeth_is_supported(IPA_OSA_MC_ROUTER_AVAIL) &&
-                    (card->options.routing_type4 == MULTICAST_ROUTER)) ||
-                   (card->options.routing_type4 == PRIMARY_CONNECTOR) ||
-                   (card->options.routing_type4 == SECONDARY_CONNECTOR)) {
-                       PRINT_WARN("routing not applicable, reset "
-                                  "routing status for ipv4. (Did you mean "
-                                  "primary_router or secondary_router?)\n");
-                       card->options.routing_type4 = NO_ROUTER;
-               }
-       }
-}
-
-static void
-__qeth_correct_routing_status_v6(struct qeth_card *card)
-{
-#ifdef QETH_IPV6
-       if (card->options.routing_type6 == NO_ROUTER)
-               return;
-       if (card->type == QETH_CARD_TYPE_IQD) {
-               /* if it's not a mc router, it's no router */
-               if ((card->options.routing_type6 == PRIMARY_ROUTER) ||
-                   (card->options.routing_type6 == SECONDARY_ROUTER)) {
-                       PRINT_WARN("routing not applicable, reset "
-                                  "routing status for ipv6. \n");
-                       card->options.routing_type6 = NO_ROUTER;
-               }
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-       } else {
-               /* if it's a mc router, it's no router */
-               if ((!qeth_is_supported(IPA_OSA_MC_ROUTER_AVAIL) &&
-                    (card->options.routing_type6 == MULTICAST_ROUTER)) ||
-                   (card->options.routing_type6 == PRIMARY_CONNECTOR) ||
-                   (card->options.routing_type6 == SECONDARY_CONNECTOR)) {
-                       PRINT_WARN("routing not applicable, reset "
-                                  "routing status for ipv6. (Did you mean "
-                                  "primary_router or secondary_router?)\n");
-                       card->options.routing_type6 = NO_ROUTER;
-               }
-       }
-#endif /* QETH_IPV6 */
-}
-
-static void
-qeth_correct_routing_status(struct qeth_card *card)
-{
-       __qeth_correct_routing_status_v4(card);
-       __qeth_correct_routing_status_v6(card);
-}
-
-static int
-qeth_init_netdev(struct qeth_card *card)
-{
-
-       int result;
-       char dbf_text[15];
-
-       result = qeth_register_netdev(card);
-       if (result) {
-               PRINT_ALL("         register_netdev %s -- rc=%i\n",
-                         card->dev_name, result);
-               sprintf(dbf_text, "rgnd%4x", (__u16) result);
-               QETH_DBF_TEXT2(1, trace, dbf_text);
-               atomic_set(&card->is_registered, 0);
-               goto out;
-       }
-       strcpy(card->dev_name, card->dev->name);
-       atomic_set(&card->write_busy, 0);
-       atomic_set(&card->is_registered, 1);
-
-       result = qeth_softsetup_card(card, QETH_WAIT_FOR_LOCK);
-
-       if (!result) {
-               qeth_init_input_buffers(card);
-       } else {
-               QETH_DBF_TEXT2(0, trace, "SSFAILED");
-               PRINT_WARN("soft-setup of card failed!\n");
-       }
-
-       INIT_WORK(&card->tqueue, qeth_softsetup_thread_starter, card);
-       schedule_work(&card->tqueue);
-out:
-       qeth_wakeup_procfile();
-       return result;
-
-}
-
-static int
-qeth_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct qeth_card *card;
-       struct net_device *dev = (struct net_device *) ptr;
-
-       QETH_DBF_TEXT3(0, trace, "devevent");
-       QETH_DBF_HEX3(0, trace, &event, sizeof (unsigned long));
-       QETH_DBF_HEX3(0, trace, &dev, sizeof (void *));
-
-       card = __qeth_get_card_from_dev(dev);
-       if (qeth_does_card_exist(card)) {
-               qeth_save_dev_flag_state(card);
-               switch (event) {
-               default:
-                       qeth_start_softsetup_thread(card);
-                       break;
-               }
-       }
-
-       return NOTIFY_DONE;
-}
-
-static int
-qeth_ip_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct qeth_card *card;
-       struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
-       struct net_device *dev = ifa->ifa_dev->dev;
-       char dbf_text[15];
-
-       QETH_DBF_TEXT3(0, trace, "ipevent");
-       QETH_DBF_HEX3(0, trace, &event, sizeof (unsigned long));
-       QETH_DBF_HEX3(0, trace, &dev, sizeof (void *));
-       sprintf(dbf_text, "%08x", ifa->ifa_address);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-       sprintf(dbf_text, "%08x", ifa->ifa_mask);
-       QETH_DBF_TEXT3(0, trace, dbf_text);
-
-       card = __qeth_get_card_from_dev(dev);
-       if (qeth_does_card_exist(card)) {
-               QETH_DBF_HEX3(0, trace, &card, sizeof (void *));
-               qeth_save_dev_flag_state(card);
-               qeth_start_softsetup_thread(card);
-       }
-
-       return NOTIFY_DONE;
-}
-
-#ifdef QETH_IPV6
-static int
-qeth_ip6_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct qeth_card *card;
-       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *) ptr;
-       struct net_device *dev = ifa->idev->dev;
-
-       QETH_DBF_TEXT3(0, trace, "ip6event");
-       QETH_DBF_HEX3(0, trace, &event, sizeof (unsigned long));
-       QETH_DBF_HEX3(0, trace, &dev, sizeof (void *));
-       QETH_DBF_HEX3(0, trace, ifa->addr.s6_addr, QETH_DBF_TRACE_LEN);
-       QETH_DBF_HEX3(0, trace, ifa->addr.s6_addr + QETH_DBF_TRACE_LEN,
-                     QETH_DBF_TRACE_LEN);
-
-       card = __qeth_get_card_from_dev(dev);
-       if (qeth_does_card_exist(card)) {
-               QETH_DBF_HEX3(0, trace, &card, sizeof (void *));
-               qeth_save_dev_flag_state(card);
-               qeth_start_softsetup_thread(card);
-       }
-
-       return NOTIFY_DONE;
-}
-#endif /* QETH_IPV6 */
-
-static int
-qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       struct qeth_card *card;
-
-       read_lock(&list_lock);
-       if (firstcard) {
-               card = firstcard;
-       clear_another_one:
-               if (card->type == QETH_CARD_TYPE_IQD) {
-                       ccw_device_halt(CARD_DDEV(card), 0);
-                       ccw_device_clear(CARD_RDEV(card), 0);
-                       ccw_device_clear(CARD_WDEV(card), 0);
-                       ccw_device_clear(CARD_DDEV(card), 0);
-               } else {
-                       ccw_device_clear(CARD_DDEV(card), 0);
-                       ccw_device_clear(CARD_RDEV(card), 0);
-                       ccw_device_clear(CARD_WDEV(card), 0);
-               }
-               if (card->next) {
-                       card = card->next;
-                       goto clear_another_one;
-               }
-       }
-       read_unlock(&list_lock);
-
-       return 0;
-}
-
-static struct notifier_block qeth_dev_notifier = {
-       qeth_dev_event,
-       0
-};
-
-static struct notifier_block qeth_ip_notifier = {
-       qeth_ip_event,
-       0
-};
-
-#ifdef QETH_IPV6
-static struct notifier_block qeth_ip6_notifier = {
-       qeth_ip6_event,
-       0
-};
-#endif /* QETH_IPV6 */
-
-static struct notifier_block qeth_reboot_notifier = {
-       qeth_reboot_event,
-       0
-};
-
-static void
-qeth_register_notifiers(void)
-{
-       int r;
-
-       QETH_DBF_TEXT5(0, trace, "regnotif");
-       /* register to be notified on events */
-       r = register_netdevice_notifier(&qeth_dev_notifier);
-
-       r = register_inetaddr_notifier(&qeth_ip_notifier);
-#ifdef QETH_IPV6
-       r = register_inet6addr_notifier(&qeth_ip6_notifier);
-#endif /* QETH_IPV6 */
-       r = register_reboot_notifier(&qeth_reboot_notifier);
-}
-
-static void __exit
-qeth_unregister_notifiers(void)
-{
-       int r;
-
-       QETH_DBF_TEXT5(0, trace, "unregnot");
-       r = unregister_netdevice_notifier(&qeth_dev_notifier);
-       r = unregister_inetaddr_notifier(&qeth_ip_notifier);
-#ifdef QETH_IPV6
-       r = unregister_inet6addr_notifier(&qeth_ip6_notifier);
-#endif /* QETH_IPV6 */
-       r = unregister_reboot_notifier(&qeth_reboot_notifier);
-
-}
-
-static int
-qeth_procfile_open(struct inode *inode, struct file *file)
-{
-       int length = 0;
-       struct qeth_card *card;
-       char checksum_str[5], queueing_str[14], router_str[8], bufsize_str[4];
-       char *buffer;
-       int rc = 0;
-       int size;
-       struct tempinfo *info;
-
-       info = (struct tempinfo *) vmalloc(sizeof (struct tempinfo));
-       if (info == NULL) {
-               PRINT_WARN("No memory available for data\n");
-               return -ENOMEM;
-       } else {
-               file->private_data = (void *) info;
-       }
-
-       /* lock all the stuff */
-       read_lock(&list_lock);
-       card = firstcard;
-       size = 200;             /* 2 lines plus some sanity space */
-       while (card) {
-               size += 90;     /* if device name is > 10 chars, (should never
-                                  happen...), we'll need that */
-               card = card->next;
-       }
-
-       buffer = info->data = (char *) vmalloc(size);
-       if (info->data == NULL) {
-               PRINT_WARN("No memory available for data\n");
-               vfree(info);
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       QETH_DBF_TEXT2(0, trace, "procread");
-       length += sprintf(buffer + length,
-                         "devices                  CHPID     "
-                         "device     cardtype port chksum prio-q'ing "
-                         "rtr fsz cnt\n");
-       length += sprintf(buffer + length,
-                         "-------------------------- --- ----"
-                         "------ -------------- --     -- ---------- "
-                         "--- --- ---\n");
-       card = firstcard;
-       while (card) {
-               strcpy(checksum_str,
-                      (card->options.checksum_type == SW_CHECKSUMMING) ? "SW" :
-                      (card->options.checksum_type == HW_CHECKSUMMING) ? "HW" :
-                      "no");
-               if (card->options.do_prio_queueing == NO_PRIO_QUEUEING) {
-                       sprintf(queueing_str, "always_q_%i",
-                               card->options.default_queue);
-               } else {
-                       strcpy(queueing_str, (card->options.do_prio_queueing
-                                             ==
-                                             PRIO_QUEUEING_PREC) ? "by_prec." :
-                              "by_ToS");
-               }
-
-               /* FIXME: this is really a mess... */
-
-#ifdef QETH_IPV6
-               if (atomic_read(&card->rt4fld) || atomic_read(&card->rt6fld))
-                       strcpy(router_str, "FLD");
-#else/* QETH_IPV6 */
-               if (atomic_read(&card->rt4fld))
-                       strcpy(router_str, "FLD");
-#endif /* QETH_IPV6 */
-               else if (((card->options.routing_type4 & ROUTER_MASK) ==
-                         PRIMARY_ROUTER)
-#ifdef QETH_IPV6
-                        &&
-                        (((card->options.routing_type6 & ROUTER_MASK) ==
-                         PRIMARY_ROUTER) ||
-                         (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "pri");
-               } else
-                   if (((card->options.routing_type4 & ROUTER_MASK) ==
-                        SECONDARY_ROUTER)
-#ifdef QETH_IPV6
-                       &&
-                       (((card->options.routing_type6 & ROUTER_MASK) ==
-                        SECONDARY_ROUTER) ||
-                        (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "sec");
-               } else
-                   if (((card->options.routing_type4 & ROUTER_MASK) ==
-                        MULTICAST_ROUTER)
-#ifdef QETH_IPV6
-                       &&
-                       (((card->options.routing_type6 & ROUTER_MASK) ==
-                        MULTICAST_ROUTER) ||
-                        (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "mc");
-               } else
-                   if (((card->options.routing_type4 & ROUTER_MASK) ==
-                        PRIMARY_CONNECTOR)
-#ifdef QETH_IPV6
-                       &&
-                       (((card->options.routing_type6 & ROUTER_MASK) ==
-                        PRIMARY_CONNECTOR) ||
-                        (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "p.c");
-               } else
-                   if (((card->options.routing_type4 & ROUTER_MASK) ==
-                        SECONDARY_CONNECTOR)
-#ifdef QETH_IPV6
-                       &&
-                       (((card->options.routing_type6 & ROUTER_MASK) ==
-                        SECONDARY_CONNECTOR) ||
-                        (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "s.c");
-               } else
-                   if (((card->options.routing_type4 & ROUTER_MASK) ==
-                        NO_ROUTER)
-#ifdef QETH_IPV6
-                       &&
-                       (((card->options.routing_type6 & ROUTER_MASK) ==
-                        NO_ROUTER) ||
-                        (!qeth_is_supported(IPA_IPv6)))
-#endif /* QETH_IPV6 */
-                   ) {
-                       strcpy(router_str, "no");
-               } else {
-                       strcpy(router_str, "mix");
-               }
-               strcpy(bufsize_str,
-                      (BUFFER_SIZE == 16384) ? "16k" :
-                      (BUFFER_SIZE == 24576) ? "24k" :
-                      (BUFFER_SIZE == 32768) ? "32k" :
-                      (BUFFER_SIZE == 40960) ? "40k" : "64k");
-
-               if (!atomic_read(&card->is_startlaned)) {
-                       length += sprintf(buffer + length,
-                                         "%s/%s/%s x%02X %10s %14s %2i"
-                                         "  +++ CABLE PULLED +++\n",
-                                         CARD_RDEV_ID(card),
-                                         CARD_WDEV_ID(card),
-                                         CARD_DDEV_ID(card),
-                                         card->chpid,
-                                         card->dev_name,
-                                         qeth_get_cardname_short
-                                         (card->type, card->link_type,
-                                          card->is_guest_lan),
-                                         card->options.portno);
-               } else {
-                       length += sprintf(buffer + length,
-                                         "%s/%s/%s x%02X %10s %14s %2i"
-                                         "     %2s %10s %3s %3s %3i\n",
-                                         CARD_RDEV_ID(card),
-                                         CARD_WDEV_ID(card),
-                                         CARD_DDEV_ID(card),
-                                         card->chpid, card->dev_name,
-                                         qeth_get_cardname_short
-                                         (card->type, card->link_type,
-                                          card->is_guest_lan),
-                                         card->options.portno, checksum_str,
-                                         queueing_str, router_str, bufsize_str,
-                                         card->options.inbound_buffer_count);
-               }
-               card = card->next;
-       }
-
-out:
-       info->len = length;
-       /* unlock all the stuff */
-       read_unlock(&list_lock);
-       return rc;
-}
-
-#define _OUTP_IT(x...) c+=sprintf(buffer+c,x)
-
-#ifdef QETH_PERFORMANCE_STATS
-static int
-qeth_perf_procfile_read(char *buffer, char **buffer_location,
-                       off_t offset, int buffer_length, int *eof, void *data)
-{
-       int c = 0;
-       struct qeth_card *card;
-       /* we are always called with buffer_length=4k, so we all
-          deliver on the first read */
-       if (offset > 0)
-               return 0;
-
-       QETH_DBF_TEXT2(0, trace, "perfpfrd");
-
-       card = firstcard;
-
-       while (card) {
-               _OUTP_IT("For card with devnos %s/%s/%s (%s):\n",
-                        CARD_RDEV_ID(card),
-                        CARD_WDEV_ID(card),
-                        CARD_DDEV_ID(card), card->dev_name);
-               _OUTP_IT("  Skb's/buffers received                 : %i/%i\n",
-                        card->perf_stats.skbs_rec, card->perf_stats.bufs_rec);
-               _OUTP_IT("  Skb's/buffers sent                     : %i/%i\n",
-                        card->perf_stats.skbs_sent,
-                        card->perf_stats.bufs_sent);
-               _OUTP_IT("\n");
-               _OUTP_IT("  Skb's/buffers sent without packing     : %i/%i\n",
-                        card->perf_stats.skbs_sent_dont_pack,
-                        card->perf_stats.bufs_sent_dont_pack);
-               _OUTP_IT("  Skb's/buffers sent with packing        : %i/%i\n",
-                        card->perf_stats.skbs_sent_pack,
-                        card->perf_stats.bufs_sent_pack);
-               _OUTP_IT("\n");
-               _OUTP_IT("  Packing state changes no pkg.->packing : %i/%i\n",
-                        card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp);
-               _OUTP_IT("  Current buffer usage (outbound q's)    : "
-                        "%i/%i/%i/%i\n",
-                        atomic_read(&card->outbound_used_buffers[0]),
-                        atomic_read(&card->outbound_used_buffers[1]),
-                        atomic_read(&card->outbound_used_buffers[2]),
-                        atomic_read(&card->outbound_used_buffers[3]));
-               _OUTP_IT("\n");
-               _OUTP_IT("  Inbound time (in us)                   : %i\n",
-                        card->perf_stats.inbound_time);
-               _OUTP_IT("  Inbound cnt                            : %i\n",
-                        card->perf_stats.inbound_cnt);
-               _OUTP_IT("  Outbound time (in us, incl QDIO)       : %i\n",
-                        card->perf_stats.outbound_time);
-               _OUTP_IT("  Outbound cnt                           : %i\n",
-                        card->perf_stats.outbound_cnt);
-               _OUTP_IT("  Watermarks: L/H=%i/%i\n",
-                        LOW_WATERMARK_PACK, HIGH_WATERMARK_PACK);
-               _OUTP_IT("\n");
-
-               card = card->next;
-       }
-
-       return c;
-}
-
-static struct proc_dir_entry *qeth_perf_proc_file;
-
-#endif /* QETH_PERFORMANCE_STATS */
-
-static int
-qeth_ipato_procfile_open(struct inode *inode, struct file *file)
-{
-       char text[33];
-       struct ipato_entry *ipato_entry;
-       struct qeth_card *card;
-       struct qeth_vipa_entry *vipa_entry;
-       int rc = 0;
-       struct tempinfo *info;
-       int size;
-       char entry_type[5];
-
-       info = (struct tempinfo *) vmalloc(sizeof (struct tempinfo));
-       if (info == NULL) {
-               PRINT_WARN("No memory available for data\n");
-               return -ENOMEM;
-       } else {
-               file->private_data = (void *) info;
-       }
-       info->len = 0;
-
-       QETH_DBF_TEXT2(0, trace, "ipatorea");
-       /* lock all the stuff */
-       spin_lock(&ipato_list_lock);
-       read_lock(&list_lock);
-
-       size = 64;              /* for inv4/6 etc. */
-
-       ipato_entry = ipato_entries;
-       while (ipato_entry) {
-               ipato_entry = ipato_entry->next;
-               size += 64;
-       }
-       card = firstcard;
-       while (card) {
-               read_lock(&card->vipa_list_lock);
-               vipa_entry = card->vipa_list;
-               while (vipa_entry) {
-                       vipa_entry = vipa_entry->next;
-                       size += 64;
-               }
-               /*read_unlock(&card->vipa_list_lock); don't unlock it here */
-               card = card->next;
-       }
-       info->data = (char *) vmalloc(size);
-       if (info->data == NULL) {
-               PRINT_WARN("No memory available for data\n");
-               vfree(info);
-               rc = -ENOMEM;
-               goto out;
-       }
-#define _IOUTP_IT(x...) info->len+=sprintf(info->data+info->len,x)
-       if (ipato_inv4)
-               _IOUTP_IT("inv4\n");
-       ipato_entry = ipato_entries;
-       text[8] = 0;
-       while (ipato_entry) {
-               if (ipato_entry->version == 4) {
-                       qeth_convert_addr_to_text(4, ipato_entry->addr, text);
-                       _IOUTP_IT("add4 %s/%i%s%s\n", text,
-                                 ipato_entry->mask_bits,
-                                 ipato_entry->dev_name[0] ? ":" : "",
-                                 ipato_entry->dev_name[0] ?
-                                 ipato_entry->dev_name : "");
-               }
-               ipato_entry = ipato_entry->next;
-       }
-
-       if (ipato_inv6)
-               _IOUTP_IT("inv6\n");
-       ipato_entry = ipato_entries;
-       text[32] = 0;
-       while (ipato_entry) {
-               if (ipato_entry->version == 6) {
-                       qeth_convert_addr_to_text(6, ipato_entry->addr, text);
-                       _IOUTP_IT("add6 %s/%i%s%s\n", text,
-                                 ipato_entry->mask_bits,
-                                 ipato_entry->dev_name[0] ? ":" : "",
-                                 ipato_entry->dev_name[0] ?
-                                 ipato_entry->dev_name : "");
-               }
-               ipato_entry = ipato_entry->next;
-       }
-       card = firstcard;
-       while (card) {
-               vipa_entry = card->vipa_list;
-               while (vipa_entry) {
-                       strcpy(entry_type, (vipa_entry->flag ==
-                                           IPA_SETIP_VIPA_FLAGS) ?
-                              "vipa" : "rxip");
-                       if (vipa_entry->version == 4) {
-                               _IOUTP_IT("add_%s4 %02x%02x%02x%02x:%s\n",
-                                         entry_type,
-                                         vipa_entry->ip[0],
-                                         vipa_entry->ip[1],
-                                         vipa_entry->ip[2],
-                                         vipa_entry->ip[3], card->dev_name);
-                       } else {
-                               _IOUTP_IT("add_%s6 %02x%02x%02x%02x"
-                                         "%02x%02x%02x%02x"
-                                         "%02x%02x%02x%02x"
-                                         "%02x%02x%02x%02x:%s\n",
-                                         entry_type,
-                                         vipa_entry->ip[0],
-                                         vipa_entry->ip[1],
-                                         vipa_entry->ip[2],
-                                         vipa_entry->ip[3],
-                                         vipa_entry->ip[4],
-                                         vipa_entry->ip[5],
-                                         vipa_entry->ip[6],
-                                         vipa_entry->ip[7],
-                                         vipa_entry->ip[8],
-                                         vipa_entry->ip[9],
-                                         vipa_entry->ip[10],
-                                         vipa_entry->ip[11],
-                                         vipa_entry->ip[12],
-                                         vipa_entry->ip[13],
-                                         vipa_entry->ip[14],
-                                         vipa_entry->ip[15], card->dev_name);
-                       }
-                       vipa_entry = vipa_entry->next;
-               }
-               card = card->next;
-       }
-out:
-       /* unlock all the stuff */
-       card = firstcard;
-       while (card) {
-               /*read_lock(&card->vipa_list_lock); don't lock it here */
-               read_unlock(&card->vipa_list_lock);
-               card = card->next;
-       }
-       read_unlock(&list_lock);
-       spin_unlock(&ipato_list_lock);
-
-       return rc;
-}
-
-static ssize_t
-qeth_procfile_read(struct file *file, char *user_buf,
-                  size_t user_len, loff_t * offset)
-{
-       loff_t len;
-       struct tempinfo *p_info = (struct tempinfo *) file->private_data;
-
-       if (*offset >= p_info->len) {
-               return 0;
-       } else {
-               len = __min(user_len, (p_info->len - *offset));
-               if (copy_to_user(user_buf, &(p_info->data[*offset]), len))
-                       return -EFAULT;
-               (*offset) += len;
-               return len;
-       }
-}
-
-/* ATT: this is also the procfile release function for the ipato
- * procfs entry */
-static int
-qeth_procfile_release(struct inode *inode, struct file *file)
-{
-       struct tempinfo *p_info = (struct tempinfo *) file->private_data;
-
-       if (p_info) {
-               if (p_info->data)
-                       vfree(p_info->data);
-               vfree(p_info);
-       }
-
-       return 0;
-}
-
-static ssize_t
-qeth_ipato_procfile_write(struct file *file,
-                         const char *user_buffer,
-                         size_t user_len, loff_t * offset)
-{
-       int add, version;
-       char text[33];
-       __u8 addr[16];
-       int len, i, flag;
-       int mask_bits;
-       char *buffer;
-       int dev_name_there;
-       char *dev_name_ptr;
-       struct qeth_card *card;
-#define BUFFER_LEN (10+32+1+5+1+DEV_NAME_LEN+1)
-
-       if (*offset > 0)
-               return user_len;
-       buffer =
-           vmalloc(__max(__max(user_len + 1, BUFFER_LEN), QETH_DBF_MISC_LEN));
-
-       if (buffer == NULL)
-               return -ENOMEM;
-       /* BUFFER_LEN=command incl. blank+addr+slash+mask_bits+
-        * colon+DEV_NAME_LEN+zero */
-       memset(buffer, 0, BUFFER_LEN);
-
-       if (copy_from_user(buffer, user_buffer, user_len)) {
-               vfree(buffer);
-               return -EFAULT;
-       }
-
-       QETH_DBF_TEXT2(0, trace, "ipatowri");
-       QETH_DBF_TEXT2(0, misc, buffer);
-       if (!strncmp(buffer, "inv4", 4)) {
-               ipato_inv4 = 1 - ipato_inv4;
-               goto out;
-       }
-       if (!strncmp(buffer, "inv6", 4)) {
-               ipato_inv6 = 1 - ipato_inv6;
-               goto out;
-       }
-       if ((!strncmp(buffer, "add4 ", 5)) ||
-           (!strncmp(buffer, "add6 ", 5)) ||
-           (!strncmp(buffer, "del4 ", 5)) || (!strncmp(buffer, "del6 ", 5))) {
-               text[8] = 0;
-               text[32] = 0;
-               add = !strncmp(buffer, "add", 3);
-               version = (buffer[3] == '4') ? 4 : 6;
-               len = (version == 4) ? 8 : 32;
-               strncpy(text, buffer + 5, len);
-               if (qeth_convert_text_to_addr(version, text, addr)) {
-                       PRINT_ERR("error in parsing ipato information "
-                                 "(addr)\n");
-                       goto out;
-               }
-               strncpy(text, buffer + 5 + len + 1, 10);
-               /* we prepare mask_bits for qeth_getints */
-               dev_name_there = 0;
-               for (i = 5 + len + 1; i < BUFFER_LEN; i++) {
-                       if (*(buffer + i) == '\n') {
-                               *(buffer + i) = 0;
-                               break;
-                       }
-                       if (*(buffer + i) == ':') {
-                               *(buffer + i) = 0;      /* so that qeth_getint works */
-                               dev_name_there = i;
-                               break;
-                       }
-                       if (*(buffer + i) == 0)
-                               break;
-               }
-               mask_bits = qeth_getint(buffer + 5 + len + 1, 0);
-               if ((mask_bits < 0)
-                   || (mask_bits > ((version == 4) ? 32 : 128))) {
-                       PRINT_ERR("error in parsing ipato information "
-                                 "(mask bits)\n");
-                       goto out;
-               }
-               if (dev_name_there) {
-                       dev_name_ptr = buffer + dev_name_there + 1;
-                       /* wipe out the linefeed */
-                       for (i = dev_name_there + 1;
-                            i < dev_name_there + 1 + DEV_NAME_LEN + 1; i++)
-                               if (*(buffer + i) == '\n')
-                                       *(buffer + i) = 0;
-               } else
-                       dev_name_ptr = NULL;
-
-               if (add)
-                       qeth_add_ipato_entry(version, addr, mask_bits,
-                                            dev_name_ptr);
-               else
-                       qeth_del_ipato_entry(version, addr, mask_bits,
-                                            dev_name_ptr);
-               goto out;
-       }
-       if ((!strncmp(buffer, "add_vipa4 ", 10)) ||
-           (!strncmp(buffer, "add_rxip4 ", 10)) ||
-           (!strncmp(buffer, "add_vipa6 ", 10)) ||
-           (!strncmp(buffer, "add_rxip6 ", 10)) ||
-           (!strncmp(buffer, "del_vipa4 ", 10)) ||
-           (!strncmp(buffer, "del_rxip4 ", 10)) ||
-           (!strncmp(buffer, "del_vipa6 ", 10)) ||
-           (!strncmp(buffer, "del_rxip6 ", 10))) {
-               text[8] = 0;
-               text[32] = 0;
-               add = !strncmp(buffer, "add", 3);
-               flag =
-                   (!strncmp(buffer + 4, "vipa", 4)) ? IPA_SETIP_VIPA_FLAGS :
-                   IPA_SETIP_TAKEOVER_FLAGS;
-               version = (buffer[8] == '4') ? 4 : 6;
-               len = (version == 4) ? 8 : 32;
-               strncpy(text, buffer + 10, len);
-               if (qeth_convert_text_to_addr(version, text, addr)) {
-                       PRINT_ERR("error in parsing vipa/rxip information "
-                                 "(addr)\n");
-                       goto out;
-               }
-               if (*(buffer + 10 + len) != ':') {
-                       PRINT_ERR("error in parsing vipa/rxip information "
-                                 "(no interface)\n");
-                       goto out;
-               }
-               /* interface name is at buffer+10+len+1 */
-               /* wipe out the \n */
-               for (i = 10 + len + 1; i < 10 + len + 1 + DEV_NAME_LEN + 1; i++)
-                       if (*(buffer + i) == '\n')
-                               *(buffer + i) = 0;
-               card = qeth_get_card_by_name(buffer + 10 + len + 1);
-               if (!card) {
-                       PRINT_ERR("error in parsing vipa/rxip information "
-                                 "(unknown interface)\n");
-                       goto out;
-               }
-               if (add)
-                       i = qeth_add_vipa_entry(card, version, addr, flag);
-               else
-                       i = qeth_del_vipa_entry(card, version, addr, flag);
-               if (!i)
-                       qeth_start_softsetup_thread(card);
-               goto out;
-       }
-       PRINT_ERR("unknown ipato information command\n");
-out:
-       vfree(buffer);
-       *offset = *offset + user_len;
-#undef BUFFER_LEN
-       return user_len;
-}
-
-static int
-qeth_procfile_getinterfaces(unsigned long arg)
-{
-       struct qeth_card *card;
-
-       char parms[16];
-       char *buffer;
-       char *buffer_pointer;
-       __u32 version, valid_fields, qeth_version, number_of_devices, if_index;
-       __u32 data_size, data_len;
-       unsigned long ioctl_flags;
-       int result = 0;
-
-       /* the struct of version 0 is:
-          typedef struct dev_list
-          {
-          char device_name[IFNAME_MAXLEN]; // OSA-Exp device name (e.g. eth0)
-          __u32 if_index;                  // interface index from kernel
-          __u32 flags;                    // device charateristics
-          } __attribute__((packed)) DEV_LIST;
-
-          typedef struct osaexp_dev_ver0
-          {
-          __u32 version;                // structure version
-          __u32 valid_fields;           // bitmask of fields that are really filled
-          __u32 qeth_version;           // qeth driver version
-          __u32 number_of_devices;      // number of OSA Express devices
-          struct dev_list devices[0]; // list of OSA Express devices
-          } __attribute__((packed)) OSAEXP_DEV_VER0;
-        */
-
-       version = 0;
-       valid_fields = 0;
-       qeth_version = 0;
-       number_of_devices = 0;
-
-       if (copy_from_user((void *) parms, (void *) arg, sizeof (parms)))
-               return -EFAULT;
-       memcpy(&data_size, parms, sizeof (__u32));
-
-       if (!(data_size > 0))
-               return -EFAULT;
-       if (data_size > IOCTL_MAX_TRANSFER_SIZE)
-               return -EFAULT;
-       if (!access_ok(VERIFY_WRITE, (void *) arg, data_size))
-               return -EFAULT;
-
-       read_lock(&list_lock);
-       card = firstcard;
-#define IOCTL_USER_STRUCT_SIZE (DEV_NAME_LEN*sizeof(char)) + \
-       sizeof(__u32) + sizeof(__u32)
-       while (card) {
-               if (card->type == QETH_CARD_TYPE_OSAE)
-                       number_of_devices =
-                           number_of_devices + IOCTL_USER_STRUCT_SIZE;
-               card = card->next;
-       }
-#undef IOCTL_USER_STRUCT_SIZE
-       if ((number_of_devices + 4 * sizeof (__u32)) >= data_size) {
-               result = -ENOMEM;
-               goto out;
-       }
-
-       number_of_devices = 0;
-       card = firstcard;
-       buffer = (char *) vmalloc(data_size);
-       if (!buffer) {
-               result = -EFAULT;
-               goto out;
-       }
-       buffer_pointer = ((char *) (buffer)) + (4 * sizeof (__u32));
-       while (card) {
-               if ((card->type == QETH_CARD_TYPE_OSAE) &&
-                   (atomic_read(&card->is_hardsetup)) &&
-                   (atomic_read(&card->is_registered))) {
-
-                       memcpy(buffer_pointer, card->dev_name, DEV_NAME_LEN);
-                       buffer_pointer = buffer_pointer + DEV_NAME_LEN;
-                       if_index = card->dev->ifindex;
-                       memcpy(buffer_pointer, &if_index, sizeof (__u32));
-                       buffer_pointer = buffer_pointer + sizeof (__u32);
-                       memcpy(buffer_pointer, &ioctl_flags, sizeof (__u32));
-                       buffer_pointer = buffer_pointer + sizeof (__u32);
-                       number_of_devices = number_of_devices + 1;
-               }
-               card = card->next;
-       }
-
-       /* we copy the real size */
-       data_len = buffer_pointer - buffer;
-
-       buffer_pointer = buffer; 
-       /* copy the header information at the beginning of the buffer */
-       memcpy(buffer_pointer, &version, sizeof (__u32));
-       memcpy(((char *) buffer_pointer) + sizeof (__u32), &valid_fields,
-              sizeof (__u32));
-       memcpy(((char *) buffer_pointer) + (2 * sizeof (__u32)), &qeth_version,
-              sizeof (__u32));
-       memcpy(((char *) buffer_pointer) + (3 * sizeof (__u32)),
-              &number_of_devices, sizeof (__u32));
-       if (copy_to_user((char *) arg, buffer, data_len))
-               result = -EFAULT;
-       vfree(buffer);
-out:
-       read_unlock(&list_lock);
-       return result;
-
-#undef PARMS_BUFFERLENGTH
-
-};
-
-static int
-qeth_procfile_interfacechanges(unsigned long arg)
-{
-       return qeth_sleepon_procfile();
-
-}
-
-static int
-qeth_procfile_ioctl(struct inode *inode, struct file *file,
-                   unsigned int cmd, unsigned long arg)
-{
-
-       int result;
-       if (!down_interruptible(&qeth_procfile_ioctl_lock)) {
-               switch (cmd) {
-                       case QETH_IOCPROC_OSAEINTERFACES:
-                               result = qeth_procfile_getinterfaces(arg);
-                               break;
-                       case QETH_IOCPROC_INTERFACECHANGES:
-                               result = qeth_procfile_interfacechanges(arg);
-                               break;
-                       default:
-                               result = -EOPNOTSUPP;
-               }
-               up(&qeth_procfile_ioctl_lock);
-       } else
-               result = -ERESTARTSYS;
-       return result;
-};
-
-static struct file_operations qeth_procfile_fops = {
-       .owner = THIS_MODULE,
-       .ioctl = qeth_procfile_ioctl,
-       .read = qeth_procfile_read,
-       .open = qeth_procfile_open,
-       .release = qeth_procfile_release,
-};
-
-static struct proc_dir_entry *qeth_proc_file;
-
-static struct file_operations qeth_ipato_procfile_fops = {
-       .owner = THIS_MODULE,
-       .read = qeth_procfile_read,     /* same as above! */
-       .write = qeth_ipato_procfile_write,
-       .open = qeth_ipato_procfile_open,
-       .release = qeth_procfile_release        /* same as above! */
-};
-
-static struct proc_dir_entry *qeth_ipato_proc_file;
-
-static inline void
-__qeth_add_procfs_perf(void)
-{
-#ifdef QETH_PERFORMANCE_STATS
-       proc_perf_file_registration = 0;
-       qeth_perf_proc_file = create_proc_entry(QETH_PERF_PROCFILE_NAME,
-                                               S_IFREG | 0444, &proc_root);
-       if (qeth_perf_proc_file) {
-               qeth_perf_proc_file->read_proc = &qeth_perf_procfile_read;
-       } else
-               proc_perf_file_registration = -1;
-
-       if (proc_perf_file_registration)
-               PRINT_WARN("was not able to register perf. proc-file (%i).\n",
-                          proc_perf_file_registration);
-#endif /* QETH_PERFORMANCE_STATS */
-}
-
-static void
-qeth_add_procfs_entries(void)
-{
-       proc_file_registration = 0;
-       qeth_proc_file = create_proc_entry(QETH_PROCFILE_NAME,
-                                          S_IFREG | 0444, &proc_root);
-       if (qeth_proc_file) {
-               qeth_proc_file->proc_fops = &qeth_procfile_fops;
-               sema_init(&qeth_procfile_ioctl_sem,
-                         PROCFILE_SLEEP_SEM_MAX_VALUE);
-               sema_init(&qeth_procfile_ioctl_lock,
-                         PROCFILE_IOCTL_SEM_MAX_VALUE);
-       } else
-               proc_file_registration = -1;
-
-       if (proc_file_registration)
-               PRINT_WARN("was not able to register proc-file (%i).\n",
-                          proc_file_registration);
-       proc_ipato_file_registration = 0;
-       qeth_ipato_proc_file = create_proc_entry(QETH_IPA_PROCFILE_NAME,
-                                                S_IFREG | 0644, &proc_root);
-       if (qeth_ipato_proc_file) {
-               qeth_ipato_proc_file->proc_fops = &qeth_ipato_procfile_fops;
-       } else
-               proc_ipato_file_registration = -1;
-
-       if (proc_ipato_file_registration)
-               PRINT_WARN("was not able to register ipato-proc-file (%i).\n",
-                          proc_ipato_file_registration);
-       __qeth_add_procfs_perf();
-}
-
-static void __exit
-qeth_remove_procfs_entries(void)
-{
-       if (!proc_file_registration)    /* means if it went ok earlier */
-               remove_proc_entry(QETH_PROCFILE_NAME, &proc_root);
-
-       if (!proc_ipato_file_registration)      /* means if it went ok earlier */
-               remove_proc_entry(QETH_IPA_PROCFILE_NAME, &proc_root);
-
-#ifdef QETH_PERFORMANCE_STATS
-       if (!proc_perf_file_registration)       /* means if it went ok earlier */
-               remove_proc_entry(QETH_PERF_PROCFILE_NAME, &proc_root);
-#endif /* QETH_PERFORMANCE_STATS */
-}
-
-static int
-qeth_register_dbf_views(void)
-{
-       qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME,
-                                       QETH_DBF_SETUP_INDEX,
-                                       QETH_DBF_SETUP_NR_AREAS,
-                                       QETH_DBF_SETUP_LEN);
-       if (!qeth_dbf_setup)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_setup, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_setup, QETH_DBF_SETUP_LEVEL);
-
-       qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME,
-                                      QETH_DBF_MISC_INDEX,
-                                      QETH_DBF_MISC_NR_AREAS,
-                                      QETH_DBF_MISC_LEN);
-       if (!qeth_dbf_misc)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_misc, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_misc, QETH_DBF_MISC_LEVEL);
-
-       qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME,
-                                      QETH_DBF_DATA_INDEX,
-                                      QETH_DBF_DATA_NR_AREAS,
-                                      QETH_DBF_DATA_LEN);
-       if (!qeth_dbf_data)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_data, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_data, QETH_DBF_DATA_LEVEL);
-
-       qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME,
-                                         QETH_DBF_CONTROL_INDEX,
-                                         QETH_DBF_CONTROL_NR_AREAS,
-                                         QETH_DBF_CONTROL_LEN);
-       if (!qeth_dbf_control)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_control, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_control, QETH_DBF_CONTROL_LEVEL);
-
-       qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME,
-                                       QETH_DBF_SENSE_INDEX,
-                                       QETH_DBF_SENSE_NR_AREAS,
-                                       QETH_DBF_SENSE_LEN);
-       if (!qeth_dbf_sense)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_sense, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_sense, QETH_DBF_SENSE_LEVEL);
-
-       qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME,
-                                      QETH_DBF_QERR_INDEX,
-                                      QETH_DBF_QERR_NR_AREAS,
-                                      QETH_DBF_QERR_LEN);
-       if (!qeth_dbf_qerr)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_qerr, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_qerr, QETH_DBF_QERR_LEVEL);
-
-       qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME,
-                                       QETH_DBF_TRACE_INDEX,
-                                       QETH_DBF_TRACE_NR_AREAS,
-                                       QETH_DBF_TRACE_LEN);
-       if (!qeth_dbf_trace)
-               return -ENOMEM;
-
-       debug_register_view(qeth_dbf_trace, &debug_hex_ascii_view);
-       debug_set_level(qeth_dbf_trace, QETH_DBF_TRACE_LEVEL);
-
-       return 0;
-}
-
-static void
-qeth_unregister_dbf_views(void)
-{
-       if (qeth_dbf_setup)
-               debug_unregister(qeth_dbf_setup);
-       if (qeth_dbf_qerr)
-               debug_unregister(qeth_dbf_qerr);
-       if (qeth_dbf_sense)
-               debug_unregister(qeth_dbf_sense);
-       if (qeth_dbf_misc)
-               debug_unregister(qeth_dbf_misc);
-       if (qeth_dbf_data)
-               debug_unregister(qeth_dbf_data);
-       if (qeth_dbf_control)
-               debug_unregister(qeth_dbf_control);
-       if (qeth_dbf_trace)
-               debug_unregister(qeth_dbf_trace);
-}
-
-#ifdef QETH_IPV6
-static int
-qeth_ipv6_init(void)
-{
-       qeth_old_arp_constructor = arp_tbl.constructor;
-       write_lock(&arp_tbl.lock);
-       arp_tbl.constructor = qeth_arp_constructor;
-       write_unlock(&arp_tbl.lock);
-
-       /* generate the memory leak here - FIXME*/
-       arp_direct_ops = (struct neigh_ops*)
-               kmalloc(sizeof(struct neigh_ops), GFP_KERNEL);
-       if (!arp_direct_ops)
-               return -ENOMEM;
-
-       memcpy(arp_direct_ops, &arp_direct_ops_template,
-              sizeof(struct neigh_ops));
-       return 0;
-
-}
-
-static void
-qeth_ipv6_uninit(void)
-{
-       write_lock(&arp_tbl.lock);
-       arp_tbl.constructor = qeth_old_arp_constructor;
-       write_unlock(&arp_tbl.lock);
-}
-#endif /* QETH_IPV6 */
-
-static int
-qeth_get_internal_functions(void)
-{
-       struct net_device *dev;
-#ifdef CONFIG_NET_ETHERNET
-       dev = alloc_etherdev(0);
-       if (!dev) {
-               PRINT_ERR("Not enough memory for internal functions.\n");
-               return -ENOMEM;
-       }
-       qeth_my_eth_header = dev->hard_header;
-       qeth_my_eth_rebuild_header = dev->rebuild_header;
-       qeth_my_eth_header_cache = dev->hard_header_cache;
-       qeth_my_eth_header_cache_update = dev->header_cache_update;
-       free_netdev(dev);
-#endif
-#ifdef CONFIG_TR
-       dev = alloc_trdev(0);
-       if (!dev) {
-               PRINT_ERR("Not enough memory for internal functions.\n");
-               return -ENOMEM;
-       }
-       qeth_my_tr_header = dev->hard_header;
-       qeth_my_tr_rebuild_header = dev->rebuild_header;
-       free_netdev(dev);
-#endif
-       return 0;
-}
-
-static struct ccw_device_id qeth_ids[] = {
-      {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
-      {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
-       {},
-};
-
-MODULE_DEVICE_TABLE(ccw, qeth_ids);
-
-static struct ccw_driver qeth_ccw_driver = {
-       .name = "qeth",
-       .ids = qeth_ids,
-       .probe = ccwgroup_probe_ccwdev,
-       .remove = ccwgroup_remove_ccwdev,
-};
-
-static struct device *qeth_root_dev;
-
-static struct ccwgroup_driver qeth_ccwgroup_driver;
-static ssize_t
-qeth_group_store(struct device_driver *drv, const char *buf, size_t count)
-{
-       const char *start, *end;
-       char bus_ids[3][BUS_ID_SIZE], *argv[3];
-       int i;
-
-       pr_debug("group_store %s\n", buf);
-       start = buf;
-       for (i = 0; i < 3; i++) {
-               static const char delim[] = { ',', ',', '\n' };
-               int len;
-
-               if (!(end = strchr(start, delim[i])))
-                       return count;
-               len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
-               strncpy(bus_ids[i], start, len);
-               bus_ids[i][len] = '\0';
-               start = end + 1;
-               argv[i] = bus_ids[i];
-       }
-       pr_debug("creating qeth group device from '%s', '%s' and '%s'\n",
-                bus_ids[0], bus_ids[1], bus_ids[2]);
-       ccwgroup_create(qeth_root_dev, qeth_ccwgroup_driver.driver_id,
-                       &qeth_ccw_driver, 3, argv);
-       return count;
-}
-
-static DRIVER_ATTR(group, 0200, 0, qeth_group_store);
-
-static ssize_t
-qeth_bufcnt_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%i\n", card->options.inbound_buffer_count);
-}
-
-static ssize_t
-qeth_bufcnt_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       unsigned long cnt;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_softsetup))
-               return -EPERM;
-
-       cnt = simple_strtoul(buf, &tmp, 16);
-       cnt = (cnt < BUFCNT_MIN) ? BUFCNT_MIN :
-               ((cnt > BUFCNT_MAX) ? BUFCNT_MAX : cnt);
-       card->options.inbound_buffer_count = cnt;
-
-       return count;
-}
-
-static DEVICE_ATTR(bufcnt, 0644, qeth_bufcnt_show, qeth_bufcnt_store);
-
-static ssize_t
-qeth_portname_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-       char tmp[9];
-       int i;
-
-       if (!card)
-               return -EINVAL;
-
-       if (card->portname_required) {
-               sprintf(tmp, "%s", card->options.portname + 1);
-               for (i = 0; i < 8; i++)
-                       tmp[i] = (char) _ebcasc[(__u8) tmp[i]];
-               tmp[8] = 0;
-               return sprintf(buf, "%s\n", tmp);
-       } else
-               return sprintf(buf, "%s\n", "no portname required");
-}
-
-static ssize_t
-qeth_portname_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int i;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       if ((strlen(tmp) > 8) || (strlen(tmp) < 2))
-               return -EINVAL;
-
-       card->options.portname[0] = strlen(tmp);
-       /* for beauty reasons: */
-       for (i = 1; i < 9; i++)
-               card->options.portname[i] = ' ';
-       strcpy(card->options.portname + 1, tmp);
-       for (i = 1; i < 9; i++)
-               card->options.portname[i] =
-                       _ascebc[(unsigned char)card->options.portname[i]];
-
-       return count;
-}
-
-static DEVICE_ATTR(portname, 0644, qeth_portname_show, qeth_portname_store);
-
-static ssize_t
-qeth_route4_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       if (atomic_read(&card->rt4fld))
-               return sprintf(buf, "%s\n", "FLD");
-
-       switch (card->options.routing_type4 & ROUTER_MASK) {
-       case PRIMARY_ROUTER:
-               return sprintf(buf, "%s\n", "primary router");
-       case SECONDARY_ROUTER:
-               return sprintf(buf, "%s\n", "secondary router");
-       case MULTICAST_ROUTER:
-               return sprintf(buf, "%s\n", "multicast router");
-       case PRIMARY_CONNECTOR:
-               return sprintf(buf, "%s\n", "primary connector");
-       case SECONDARY_CONNECTOR:
-               return sprintf(buf, "%s\n", "secondary connector");
-       default:
-               return sprintf(buf, "%s\n", "no");
-       }
-}
-
-static ssize_t
-qeth_route4_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int cnt;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       cnt = strlen(tmp);
-       if (!strncmp(tmp, "primary_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "pri4", card);
-               card->options.routing_type4 =
-                       PRIMARY_ROUTER | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "secondary_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "sec4", card);
-               card->options.routing_type4 =
-                       SECONDARY_ROUTER | RESET_ROUTING_FLAG;
-       }  else if (!strncmp(tmp, "multicast_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "mcr4", card);
-               card->options.routing_type4 =
-                       MULTICAST_ROUTER | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "primary_connector", cnt)) {
-               QETH_DBF_CARD2(0, trace, "prc4", card);
-               card->options.routing_type4 =
-                       PRIMARY_CONNECTOR | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "secondary_connector", cnt)) {
-               QETH_DBF_CARD2(0, trace, "scc4", card);
-               card->options.routing_type4 =
-                       SECONDARY_CONNECTOR | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "no_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "nor4", card);
-               card->options.routing_type4 = NO_ROUTER | RESET_ROUTING_FLAG;
-       } else {
-               PRINT_WARN("unknown command input in route4 attribute\n");
-               return -EINVAL;
-       }
-       __qeth_correct_routing_status_v4(card);
-       atomic_set(&card->enable_routing_attempts4, QETH_ROUTING_ATTEMPTS);
-       if (atomic_read(&card->is_softsetup))
-               qeth_start_softsetup_thread(card);
-       return count;
-}
-
-static DEVICE_ATTR(route4, 0644, qeth_route4_show, qeth_route4_store);
-
-static ssize_t
-qeth_route6_show(struct device *dev, char *buf)
-{
-#ifdef QETH_IPV6
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       if (atomic_read(&card->rt6fld))
-               return sprintf(buf, "%s\n", "FLD");
-
-       if (!qeth_is_supported(IPA_IPv6))
-               return sprintf(buf, "%s\n", "n/a");
-
-       switch (card->options.routing_type6 & ROUTER_MASK) {
-       case PRIMARY_ROUTER:
-               return sprintf(buf, "%s\n", "primary router");
-       case SECONDARY_ROUTER:
-               return sprintf(buf, "%s\n", "secondary router");
-       case MULTICAST_ROUTER:
-               return sprintf(buf, "%s\n", "multicast router");
-       case PRIMARY_CONNECTOR:
-               return sprintf(buf, "%s\n", "primary connector");
-       case SECONDARY_CONNECTOR:
-               return sprintf(buf, "%s\n", "secondary connector");
-       default:
-               return sprintf(buf, "%s\n", "no");
-       }
-#endif /* QETH_IPV6 */
-       return sprintf(buf, "%s\n", "n/a");
-}
-
-static ssize_t
-qeth_route6_store(struct device *dev, const char *buf, size_t count)
-{
-#ifdef QETH_IPV6
-       struct qeth_card *card = dev->driver_data;
-       int cnt;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       cnt = strlen(tmp);
-       if (!strncmp(tmp, "primary_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "pri6", card);
-               card->options.routing_type6 =
-                       PRIMARY_ROUTER | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "secondary_router", cnt)) {
-                               QETH_DBF_TEXT2(0, trace, "sec6");
-               QETH_DBF_CARD2(0, trace, "sec6", card);
-               card->options.routing_type6 =
-                       SECONDARY_ROUTER | RESET_ROUTING_FLAG;
-       }  else if (!strncmp(tmp, "multicast_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "mcr6", card);
-               card->options.routing_type6 =
-                       MULTICAST_ROUTER | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "primary_connector", cnt)) {
-               QETH_DBF_CARD2(0, trace, "prc6", card);
-               card->options.routing_type6 =
-                       PRIMARY_CONNECTOR | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "secondary_connector", cnt)) {
-               QETH_DBF_CARD2(0, trace, "scc6", card);
-               card->options.routing_type6 =
-                       SECONDARY_CONNECTOR | RESET_ROUTING_FLAG;
-       } else if (!strncmp(tmp, "no_router", cnt)) {
-               QETH_DBF_CARD2(0, trace, "nor6", card);
-               card->options.routing_type6 = NO_ROUTER | RESET_ROUTING_FLAG;
-       } else {
-               PRINT_WARN("unknown command input in route6 attribute\n");
-               return -EINVAL;
-       }
-       __qeth_correct_routing_status_v6(card);
-       atomic_set(&card->enable_routing_attempts6, QETH_ROUTING_ATTEMPTS);
-       if (atomic_read(&card->is_softsetup))
-               qeth_start_softsetup_thread(card);
-       return count;
-#endif /* QETH_IPV6 */
-       return -EINVAL;
-}
-
-static DEVICE_ATTR(route6, 0644, qeth_route6_show, qeth_route6_store);
-
-
-static ssize_t
-qeth_checksum_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       switch (card->options.checksum_type) {
-       case SW_CHECKSUMMING:
-               return sprintf(buf, "%s\n", "sw");
-       case HW_CHECKSUMMING:
-               return sprintf(buf, "%s\n", "hw");
-       default:
-               return sprintf(buf, "%s\n", "no");
-       }
-}
-
-static ssize_t
-qeth_checksum_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int cnt;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       cnt = strlen(tmp);
-       if (!strncmp(tmp, "sw_checksumming", cnt))
-               card->options.checksum_type = SW_CHECKSUMMING;
-       else if (!strncmp(tmp, "hw_checksumming", cnt))
-               card->options.checksum_type = HW_CHECKSUMMING;
-       else if (!strncmp(tmp, "no_checksumming", cnt))
-               card->options.checksum_type = NO_CHECKSUMMING;
-       else
-               PRINT_WARN("unknown checksumming type '%s'\n", tmp);
-
-       return count;
-}
-
-static DEVICE_ATTR(checksumming, 0644, qeth_checksum_show, qeth_checksum_store);
-
-static ssize_t
-qeth_prioq_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       switch (card->options.do_prio_queueing) {
-       case PRIO_QUEUEING_PREC:
-               return sprintf(buf, "%s\n", "by precedence");
-       case PRIO_QUEUEING_TOS:
-               return sprintf(buf, "%s\n", "by type of service");
-       default:
-               return sprintf(buf, "always queue %i\n",
-                              card->options.default_queue);
-       }
-}
-
-static ssize_t
-qeth_prioq_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int cnt;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       cnt = strlen(tmp);
-       if (!strncmp(tmp, "prio_queueing_prec", cnt))
-               card->options.do_prio_queueing = PRIO_QUEUEING_PREC;
-       else if (!strncmp(tmp, "prio_queueing_tos", cnt))
-               card->options.do_prio_queueing = PRIO_QUEUEING_TOS;
-       else if (!strncmp(tmp, "no_prio_queueing:0", cnt)) {
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-               card->options.default_queue = 0;
-       } else if (!strncmp(tmp, "no_prio_queueing:1", cnt)) {
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-               card->options.default_queue = 1;
-       } else if (!strncmp(tmp, "no_prio_queueing:2", cnt)) {
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-               card->options.default_queue = 2;
-       } else if (!strncmp(tmp, "no_prio_queueing:3", cnt)) {
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-               card->options.default_queue = 3;
-       } else if (!strncmp(tmp, "no_prio_queueing", cnt)) {
-               card->options.do_prio_queueing = NO_PRIO_QUEUEING;
-               card->options.default_queue = QETH_DEFAULT_QUEUE;
-       } else
-               PRINT_WARN("unknown queueing type '%s'\n", tmp);
-
-       return count;
-}
-
-static DEVICE_ATTR(priority_queueing, 0644, qeth_prioq_show, qeth_prioq_store);
-
-static ssize_t
-qeth_portno_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%i\n", card->options.portno);
-}
-
-static ssize_t
-qeth_portno_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int i;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if ((i < 0) || (i > MAX_PORTNO)) {
-               PRINT_ERR("portno %i out of range\n", i);
-               return -EINVAL;
-       }
-       card->options.portno = i;
-
-       return count;
-}
-
-static DEVICE_ATTR(portno, 0644, qeth_portno_show, qeth_portno_store);
-
-static ssize_t
-qeth_polltime_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%i\n", card->options.polltime);
-}
-
-static ssize_t
-qeth_polltime_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int i;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i < 0) {
-               PRINT_ERR("polltime %i invalid\n", i);
-               return -EINVAL;
-       }
-       card->options.polltime = i;
-
-       return count;
-}
-
-static DEVICE_ATTR(polltime, 0644, qeth_polltime_show, qeth_polltime_store);
-
-static ssize_t
-qeth_hhlen_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%i\n", card->options.add_hhlen);
-}
-
-static ssize_t
-qeth_hhlen_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int i;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if ((i < 0) || (i > MAX_ADD_HHLEN)) {
-               PRINT_ERR("add_hhlen out of range\n");
-               return -EINVAL;
-       }
-       card->options.add_hhlen = i;
-
-       return count;
-}
-
-static DEVICE_ATTR(add_hhlen, 0644, qeth_hhlen_show, qeth_hhlen_store);
-
-static ssize_t
-qeth_takeover_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%s\n",
-                      (card->options.ena_ipat == ENABLE_TAKEOVER)?"1":"0");
-}
-
-static ssize_t
-qeth_takeover_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int i;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i == 1)
-               card->options.ena_ipat = ENABLE_TAKEOVER;
-       else if (i == 0)
-               card->options.ena_ipat = DISABLE_TAKEOVER;
-       else
-               return -EINVAL;
-
-       return count;
-}
-
-static DEVICE_ATTR(enable_takeover, 0644, qeth_takeover_show, qeth_takeover_store);
-
-static ssize_t
-qeth_macaddr_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%s\n",
-                      (card->options.macaddr_mode == MACADDR_CANONICAL)?"1":"0");
-}
-
-static ssize_t
-qeth_macaddr_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int i;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i == 0)
-               card->options.macaddr_mode = MACADDR_NONCANONICAL;
-       else if (i == 1)
-               card->options.macaddr_mode = MACADDR_CANONICAL;
-       else
-               return -EINVAL;
-
-       return count;
-}
-
-static DEVICE_ATTR(canonical_macaddr, 0644, qeth_macaddr_show, qeth_macaddr_store);
-
-static ssize_t
-qeth_fakebr_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%s\n",
-                      (card->options.fake_broadcast == FAKE_BROADCAST)?"1":"0");
-}
-
-static ssize_t
-qeth_fakebr_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int i;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i == 0)
-               card->options.fake_broadcast = DONT_FAKE_BROADCAST;
-       else if (i == 1)
-               card->options.fake_broadcast = FAKE_BROADCAST;
-       else
-               return -EINVAL;
-
-       return count;
-}
-
-static DEVICE_ATTR(fake_broadcast, 0644, qeth_fakebr_show, qeth_fakebr_store);
-
-static ssize_t
-qeth_fakell_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%s\n",
-                      (card->options.fake_ll == FAKE_LL)?"1":"0");
-}
-
-static ssize_t
-qeth_fakell_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int i;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i == 0)
-               card->options.fake_ll = DONT_FAKE_LL;
-       else if (i == 1)
-               card->options.fake_ll = FAKE_LL;
-       else
-               return -EINVAL;
-
-       return count;
-}
-
-static DEVICE_ATTR(fake_ll, 0644, qeth_fakell_show, qeth_fakell_store);
-
-static ssize_t
-qeth_broadcast_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       return sprintf(buf, "%s\n",
-                      (card->options.broadcast_mode == BROADCAST_ALLRINGS)
-                      ?"allrings":"local");
-}
-
-static ssize_t
-qeth_broadcast_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       char *tmp;
-       int cnt;
-
-       if (!card)
-               return count;
-
-       if (atomic_read(&card->is_hardsetup))
-               return -EPERM;
-
-       /* Remove trailing '\n'. */
-       tmp = strsep((char **) &buf, "\n");
-       cnt = strlen(tmp);
-       if (!strncmp(tmp, "broadcast_allrings", cnt))
-               card->options.broadcast_mode = BROADCAST_ALLRINGS;
-       else if (!strncmp(tmp, "broadcast_local", cnt))
-               card->options.broadcast_mode = BROADCAST_LOCAL;
-       else
-               PRINT_WARN("unknown broadcast type '%s'\n", tmp);
-
-       return count;
-}
-
-static DEVICE_ATTR(broadcast_mode, 0644, qeth_broadcast_show, qeth_broadcast_store);
-
-static ssize_t
-qeth_recover_store(struct device *dev, const char *buf, size_t count)
-{
-       struct qeth_card *card = dev->driver_data;
-       int i;
-       char *tmp;
-
-       if (!card)
-               return count;
-
-       i = simple_strtoul(buf, &tmp, 16);
-       if (i == 1) {
-               QETH_DBF_CARD2(0, trace, "UTRC", card);
-               atomic_set(&card->problem, PROBLEM_USER_TRIGGERED_RECOVERY);
-               qeth_schedule_recovery(card);
-               return count;
-       } else
-               return -EINVAL;
-}
-
-static DEVICE_ATTR(recover, 0200, 0, qeth_recover_store);
-
-static ssize_t
-qeth_card_type_show(struct device *dev, char *buf)
-{
-       struct qeth_card *card = dev->driver_data;
-
-       if (!card)
-               return -EINVAL;
-
-       if (!atomic_read(&card->is_softsetup))
-               return sprintf(buf, "n/a\n");
-
-       return sprintf(buf, "%s\n",
-                      qeth_get_cardname_short(card->type, card->link_type,
-                                              card->is_guest_lan));
-}
-
-static DEVICE_ATTR(card_type, 0444, qeth_card_type_show, NULL);
-
-static struct attribute * qeth_attrs[] = {
-       &dev_attr_bufcnt.attr,
-       &dev_attr_portname.attr,
-       &dev_attr_route4.attr,
-       &dev_attr_route6.attr,
-       &dev_attr_checksumming.attr,
-       &dev_attr_priority_queueing.attr,
-       &dev_attr_portno.attr,
-       &dev_attr_polltime.attr,
-       &dev_attr_add_hhlen.attr,
-       &dev_attr_enable_takeover.attr,
-       &dev_attr_canonical_macaddr.attr,
-       &dev_attr_fake_broadcast.attr,
-       &dev_attr_fake_ll.attr,
-       &dev_attr_broadcast_mode.attr,
-       &dev_attr_recover.attr,
-       &dev_attr_card_type.attr,
-       NULL,
-};
-
-static struct attribute_group qeth_attr_group = {
-       .attrs = qeth_attrs,
-};
-
-static inline int
-__qeth_create_attributes(struct device *dev)
-{
-       return sysfs_create_group(&dev->kobj, &qeth_attr_group);
-}
-
-static inline void
-__qeth_remove_attributes(struct device *dev)
-{
-       sysfs_remove_group(&dev->kobj, &qeth_attr_group);
-}
-
-static int
-qeth_probe_device(struct ccwgroup_device *gdev)
-{
-       struct qeth_card *card;
-       int ret;
-
-       if (!get_device(&gdev->dev))
-               return -ENODEV;
-
-       card = qeth_alloc_card();
-       if (!card) {
-               put_device(&gdev->dev);
-               return -ENOMEM;
-       }
-
-       gdev->dev.driver_data = card;
-       card->gdev = gdev;
-
-       gdev->cdev[0]->handler = qeth_interrupt_handler_read;
-
-       gdev->cdev[1]->handler = qeth_interrupt_handler_write;
-
-       gdev->cdev[2]->handler = qeth_interrupt_handler_qdio;
-
-       ret = __qeth_create_attributes(&gdev->dev);
-       if (ret != 0)
-               goto out;
-
-       return 0;
-out:
-       put_device(&gdev->dev);
-       qeth_free_card(card);
-       return ret;
-}
-
-/* 
- * Replaces qeth_probe and qeth_attach_handler. 
- * This is called after piping to the 'online' attribute,
- * when all parameters are ready.
- */
-static int
-qeth_activate(struct qeth_card *card)
-{
-       int result;
-
-       ccw_device_set_online(CARD_RDEV(card));
-       ccw_device_set_online(CARD_WDEV(card));
-       ccw_device_set_online(CARD_DDEV(card));
-
-       QETH_DBF_CARD1(0, setup, "activ", card);
-       QETH_DBF_HEX1(0, setup, &card, sizeof (void *));
-       QETH_DBF_HEX1(0, setup, &card->dev, sizeof (void *));
-       QETH_DBF_HEX1(0, setup, &card->stats, sizeof (void *));
-
-       QETH_DBF_HEX2(0, misc, &card->options, QETH_DBF_MISC_LEN);
-
-       if (qeth_determine_card_type(card)) {
-               PRINT_WARN("%s: not a valid card type\n", __func__);
-               goto out;
-       }
-
-       qeth_insert_card_into_list(card);
-
-       qeth_correct_routing_status(card);
-
-       result = qeth_init_ringbuffers1(card);
-       if (result) {
-               PRINT_WARN("%s: could not init ringbuffers1\n", __func__);
-               goto out_remove;
-       }
-
-       result = qeth_hardsetup_card(card, 0);
-       if (result) {
-               goto out_remove;
-       }
-
-       result = qeth_init_ringbuffers2(card);
-       if (result) {
-               PRINT_WARN("%s: could not init ringbuffers2\n", __func__);
-               goto out_remove;
-       }
-
-       /* this was previously done in chandev_initnetdevice */
-       snprintf(card->dev->name, 8, "%s%%d",
-                qeth_get_dev_basename(card->type, card->link_type));
-       if (qeth_init_netdev(card))
-               goto out_remove;
-
-       return 0;               /* success */
-
-out_remove:
-       qeth_remove_card(card, QETH_REMOVE_CARD_QUICK);
-       qeth_remove_card_from_list(card);
-
-out:
-       QETH_DBF_TEXT4(0, trace, "freecard");
-
-       ccw_device_set_offline(CARD_DDEV(card));
-       ccw_device_set_offline(CARD_WDEV(card));
-       ccw_device_set_offline(CARD_RDEV(card));
-
-       return -ENODEV;
-}
-
-static int
-qeth_set_online(struct ccwgroup_device *gdev)
-{
-       int rc;
-       struct qeth_card *card = gdev->dev.driver_data;
-
-       BUG_ON(!card);
-
-       rc = qeth_alloc_card_stuff(card);
-
-       return rc ? rc : qeth_activate(card);
-
-}
-
-static int
-qeth_set_offline(struct ccwgroup_device *gdev)
-{
-       struct qeth_card *card = gdev->dev.driver_data;
-
-       if (!card)
-               return -ENODEV;
-
-       qeth_remove_card(card, QETH_REMOVE_CARD_PROPER);
-       qeth_remove_card_from_list(card);
-
-       QETH_DBF_TEXT4(0, trace, "freecard");
-
-       ccw_device_set_offline(CARD_DDEV(card));
-       ccw_device_set_offline(CARD_WDEV(card));
-       ccw_device_set_offline(CARD_RDEV(card));
-
-       qeth_free_card_stuff(card);
-
-       return 0;
-}
-
-static void
-qeth_remove_device(struct ccwgroup_device *gdev)
-{
-       struct qeth_card *card = gdev->dev.driver_data;
-
-       if (card && qeth_does_card_exist(card))
-               /* Means that card is already in list. */
-               qeth_set_offline(gdev);
-       __qeth_remove_attributes(&gdev->dev);
-       gdev->dev.driver_data = NULL;
-       if (card)
-               qeth_free_card(card);
-       put_device(&gdev->dev);
-}
-
-static struct ccwgroup_driver qeth_ccwgroup_driver = {
-       .owner = THIS_MODULE,
-       .name = "qeth",
-       .driver_id = 0xD8C5E3C8,
-       .probe = qeth_probe_device,
-       .remove = qeth_remove_device,
-       .set_online = qeth_set_online,
-       .set_offline = qeth_set_offline,
-};
-
-static int __init
-qeth_init(void)
-{
-       int result;
-
-       qeth_eyecatcher();
-
-       printk(KERN_INFO "qeth: loading %s\n", version);
-
-       result = qeth_get_internal_functions();
-       if (result)
-               goto out;
-
-       qeth_alloc_spare_bufs();
-
-#ifdef QETH_IPV6
-       if (qeth_ipv6_init()) {
-               PRINT_ERR("Out of memory during ipv6 init.\n");
-               goto out_sparebufs;
-       }
-#endif /* QETH_IPV6 */
-
-       result = qeth_register_dbf_views();
-       if (result) {
-               PRINT_ERR("not enough memory for dbf. Will not load module.\n");
-               goto out_ipv6;
-       }
-
-       result = ccwgroup_driver_register(&qeth_ccwgroup_driver);
-       if (result)
-               goto out_dbf;
-
-       result = ccw_driver_register(&qeth_ccw_driver);
-       if (result)
-               goto out_gdrv;
-
-       result = driver_create_file(&qeth_ccwgroup_driver.driver,
-                                   &driver_attr_group);
-       if (result)
-               goto out_cdrv;
-
-       qeth_root_dev = s390_root_dev_register("qeth");
-       if (IS_ERR(qeth_root_dev)) {
-               result = PTR_ERR(qeth_root_dev);
-               goto out_file;
-       }
-       qeth_register_notifiers();
-       qeth_add_procfs_entries();
-
-       return 0;
-
-out_file:
-       driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group);
-out_cdrv:
-       ccw_driver_unregister(&qeth_ccw_driver);
-out_gdrv:
-       ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
-out_dbf:
-       qeth_unregister_dbf_views();
-out_ipv6:
-#ifdef QETH_IPV6
-       qeth_ipv6_uninit();
-out_sparebufs:
-#endif /* QETH_IPV6 */
-       qeth_free_all_spare_bufs();
-out:
-       return result;
-}
-
-static void __exit
-qeth_exit(void)
-{
-#ifdef QETH_IPV6
-       qeth_ipv6_uninit();
-#endif /* QETH_IPV6 */
-       qeth_unregister_notifiers();
-
-       qeth_remove_procfs_entries();
-
-       QETH_DBF_TEXT1(0, trace, "cleanup.");
-
-       driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group);
-       ccw_driver_unregister(&qeth_ccw_driver);
-       ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
-       s390_root_dev_unregister(qeth_root_dev);
-
-       while (firstcard) {
-               struct qeth_card *card = firstcard;
-               qeth_remove_card(card, QETH_REMOVE_CARD_QUICK);
-               qeth_remove_card_from_list(card);
-               qeth_free_card(card);
-       }
-
-       qeth_free_all_spare_bufs();
-
-       qeth_unregister_dbf_views();
-
-       printk("qeth: %s: module removed\n", version);
-}
-
-EXPORT_SYMBOL(qeth_eyecatcher);
-
-module_init(qeth_init);
-module_exit(qeth_exit);
index 728623f..5e1b103 100644 (file)
-/*
- * linux/drivers/s390/net/qeth.h
- *
- * Linux on zSeries OSA Express and HiperSockets support
- *
- * Copyright 2000,2003 IBM Corporation
- * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
- *
- */
 #ifndef __QETH_H__
 #define __QETH_H__
 
-#include <asm/qdio.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+
+#include <linux/if_tr.h>
+#include <linux/trdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 
-#define QETH_NAME " qeth"
+#include <net/ipv6.h>
+#include <linux/in6.h>
+#include <net/if_inet6.h>
+#include <net/addrconf.h>
 
-#define VERSION_QETH_H "$Revision: 1.60 $"
 
-/******************** CONFIG STUFF ***********************/
-//#define QETH_DBF_LIKE_HELL
+#include <asm/bitops.h>
+#include <asm/debug.h>
+#include <asm/qdio.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+
+#include "qeth_mpc.h"
+
+#define VERSION_QETH_H                 "$Revision: 1.98 $"
 
 #ifdef CONFIG_QETH_IPV6
-#define QETH_IPV6
-#define QETH_VERSION_IPV6 ":IPv6"
+#define QETH_VERSION_IPV6      ":IPv6"
 #else
-#define QETH_VERSION_IPV6 ""
-#endif /* CONFIG_QETH_IPV6 */
-
+#define QETH_VERSION_IPV6      ""
+#endif
 #ifdef CONFIG_QETH_VLAN
-#define QETH_VLAN
-#define QETH_VERSION_VLAN ":VLAN"
+#define QETH_VERSION_VLAN      ":VLAN"
 #else
-#define QETH_VERSION_VLAN ""
-#endif /* CONFIG_QETH_VLAN */
-
-/* these values match CHECKSUM_* in include/linux/skbuff.h */
-#define SW_CHECKSUMMING 0
-#define HW_CHECKSUMMING 1
-#define NO_CHECKSUMMING 2
-
-#define QETH_CHECKSUM_DEFAULT NO_CHECKSUMMING
-
-#define QETH_PRIOQ_DEFAULT NO_PRIO_QUEUEING
-#define QETH_DEFAULT_QUEUE 2
-
-/******************** CONFIG STUFF END ***********************/
-/********************* TUNING STUFF **************************/
-#define HIGH_WATERMARK_PACK            5
-#define LOW_WATERMARK_PACK             2
-#define WATERMARK_FUZZ                 2
-
-#define QETH_MAX_INPUT_THRESHOLD 500
-#define QETH_MAX_OUTPUT_THRESHOLD 300  /* ? */
-
-/* only the MAX values are used */
-#define QETH_MIN_INPUT_THRESHOLD 1
-#define QETH_MIN_OUTPUT_THRESHOLD 1
-
-#define QETH_REQUEUE_THRESHOLD (card->options.inbound_buffer_count/4)
-
-#ifdef CONFIG_QETH_PERF_STATS
-#define QETH_PERFORMANCE_STATS
-#endif /* CONFIG_QETH_PERF_STATS */
-
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_VERBOSE_LEVEL 8
-#else /* QETH_DBF_LIKE_HELL */
-#define QETH_VERBOSE_LEVEL 5
-#endif /* QETH_DBF_LIKE_HELL */
-
-#define PCI_THRESHOLD_A (card->options.inbound_buffer_count+1) 
-/* buffers we have to be behind before we get a PCI */
-#define PCI_THRESHOLD_B 0      /* enqueued free buffers left before we get a PCI */
-#define PCI_TIMER_VALUE 3      /* not used, unless the microcode gets patched */
-
-#define DEFAULT_SPARE_BUFFERS 0
-#define MAX_SPARE_BUFFERS 1024
-#define SPAREBUF_MASK 65536
-#define MAX_PORTNO 15
-
-#define QETH_PROCFILE_NAME "qeth"
-#define QETH_PERF_PROCFILE_NAME "qeth_perf"
-#define QETH_IPA_PROCFILE_NAME "qeth_ipa_takeover"
-
-#define SEND_RETRIES_ALLOWED 5
-#define QETH_ROUTING_ATTEMPTS 2
-
-#define QETH_HARDSETUP_LAPS 5
-#define QETH_HARDSETUP_CLEAR_LAPS 3
-#define QETH_RECOVERY_HARDSETUP_RETRY 2
-
-/************************* DEBUG FACILITY STUFF *********************/
-
-#define QETH_DBF_HEX(ex,name,level,addr,len) \
-        do { \
-        if (ex) \
-                debug_exception(qeth_dbf_##name,level,(void*)addr,len); \
-        else \
-                debug_event(qeth_dbf_##name,level,(void*)addr,len); \
-        } while (0)
-#define QETH_DBF_TEXT(ex,name,level,text) \
-        do { \
-        if (ex) \
-                debug_text_exception(qeth_dbf_##name,level,text); \
-        else \
-                debug_text_event(qeth_dbf_##name,level,text); \
-        } while (0)
-
-#define QETH_DBF_CARD(ex,name,level,text,card) \
-       do { \
-               QETH_DBF_TEXT(ex,name,level,text); \
-               QETH_DBF_TEXT(ex,name,level,card->gdev->dev.bus_id); \
-       } while (0)
-
-#define QETH_DBF_HEX0(ex,name,addr,len) QETH_DBF_HEX(ex,name,0,addr,len)
-#define QETH_DBF_HEX1(ex,name,addr,len) QETH_DBF_HEX(ex,name,1,addr,len)
-#define QETH_DBF_HEX2(ex,name,addr,len) QETH_DBF_HEX(ex,name,2,addr,len)
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_HEX3(ex,name,addr,len) QETH_DBF_HEX(ex,name,3,addr,len)
-#define QETH_DBF_HEX4(ex,name,addr,len) QETH_DBF_HEX(ex,name,4,addr,len)
-#define QETH_DBF_HEX5(ex,name,addr,len) QETH_DBF_HEX(ex,name,5,addr,len)
-#define QETH_DBF_HEX6(ex,name,addr,len) QETH_DBF_HEX(ex,name,6,addr,len)
-#else /* QETH_DBF_LIKE_HELL */
-#define QETH_DBF_HEX3(ex,name,addr,len) do {} while (0)
-#define QETH_DBF_HEX4(ex,name,addr,len) do {} while (0)
-#define QETH_DBF_HEX5(ex,name,addr,len) do {} while (0)
-#define QETH_DBF_HEX6(ex,name,addr,len) do {} while (0)
-#endif /* QETH_DBF_LIKE_HELL */
-
-#define QETH_DBF_TEXT0(ex,name,text) QETH_DBF_TEXT(ex,name,0,text)
-#define QETH_DBF_TEXT1(ex,name,text) QETH_DBF_TEXT(ex,name,1,text)
-#define QETH_DBF_TEXT2(ex,name,text) QETH_DBF_TEXT(ex,name,2,text)
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_TEXT3(ex,name,text) QETH_DBF_TEXT(ex,name,3,text)
-#define QETH_DBF_TEXT4(ex,name,text) QETH_DBF_TEXT(ex,name,4,text)
-#define QETH_DBF_TEXT5(ex,name,text) QETH_DBF_TEXT(ex,name,5,text)
-#define QETH_DBF_TEXT6(ex,name,text) QETH_DBF_TEXT(ex,name,6,text)
-#else /* QETH_DBF_LIKE_HELL */
-#define QETH_DBF_TEXT3(ex,name,text) do {} while (0)
-#define QETH_DBF_TEXT4(ex,name,text) do {} while (0)
-#define QETH_DBF_TEXT5(ex,name,text) do {} while (0)
-#define QETH_DBF_TEXT6(ex,name,text) do {} while (0)
-#endif /* QETH_DBF_LIKE_HELL */
-
-#define QETH_DBF_CARD0(ex,name,text,card) QETH_DBF_CARD(ex,name,0,text,card)
-#define QETH_DBF_CARD1(ex,name,text,card) QETH_DBF_CARD(ex,name,1,text,card)
-#define QETH_DBF_CARD2(ex,name,text,card) QETH_DBF_CARD(ex,name,2,text,card)
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_CARD3(ex,name,text,card) QETH_DBF_CARD(ex,name,3,text,card)
-#define QETH_DBF_CARD4(ex,name,text,card) QETH_DBF_CARD(ex,name,4,text,card)
-#define QETH_DBF_CARD5(ex,name,text,card) QETH_DBF_CARD(ex,name,5,text,card)
-#define QETH_DBF_CARD6(ex,name,text,card) QETH_DBF_CARD(ex,name,6,text,card)
-#else /* QETH_DBF_LIKE_HELL */
-#define QETH_DBF_CARD3(ex,name,text,card) do {} while (0)
-#define QETH_DBF_CARD4(ex,name,text,card) do {} while (0)
-#define QETH_DBF_CARD5(ex,name,text,card) do {} while (0)
-#define QETH_DBF_CARD6(ex,name,text,card) do {} while (0)
-#endif /* QETH_DBF_LIKE_HELL */
+#define QETH_VERSION_VLAN      ""
+#endif
 
+/**
+ * Debug Facility stuff
+ */ 
 #define QETH_DBF_SETUP_NAME "qeth_setup"
 #define QETH_DBF_SETUP_LEN 8
 #define QETH_DBF_SETUP_INDEX 3
 #define QETH_DBF_SETUP_NR_AREAS 1
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_SETUP_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_SETUP_LEVEL 3
-#endif /* QETH_DBF_LIKE_HELL */
 
 #define QETH_DBF_MISC_NAME "qeth_misc"
 #define QETH_DBF_MISC_LEN 128
 #define QETH_DBF_MISC_INDEX 1
 #define QETH_DBF_MISC_NR_AREAS 1
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_MISC_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_MISC_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
 
 #define QETH_DBF_DATA_NAME "qeth_data"
 #define QETH_DBF_DATA_LEN 96
 #define QETH_DBF_DATA_INDEX 3
 #define QETH_DBF_DATA_NR_AREAS 1
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_DATA_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_DATA_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
 
 #define QETH_DBF_CONTROL_NAME "qeth_control"
-/* buffers are 255 bytes long, but no prob */
 #define QETH_DBF_CONTROL_LEN 256
 #define QETH_DBF_CONTROL_INDEX 3
 #define QETH_DBF_CONTROL_NR_AREAS 2
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_CONTROL_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_CONTROL_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
 
 #define QETH_DBF_TRACE_NAME "qeth_trace"
 #define QETH_DBF_TRACE_LEN 8
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_TRACE_INDEX 3
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_TRACE_INDEX 2
-#endif /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_TRACE_NR_AREAS 2
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_TRACE_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
-#define QETH_DBF_TRACE_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
+#define QETH_DBF_TRACE_LEVEL 3
 
 #define QETH_DBF_SENSE_NAME "qeth_sense"
 #define QETH_DBF_SENSE_LEN 64
 #define QETH_DBF_SENSE_INDEX 1
 #define QETH_DBF_SENSE_NR_AREAS 1
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_SENSE_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_SENSE_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
 
 #define QETH_DBF_QERR_NAME "qeth_qerr"
 #define QETH_DBF_QERR_LEN 8
 #define QETH_DBF_QERR_INDEX 1
 #define QETH_DBF_QERR_NR_AREAS 2
-#ifdef QETH_DBF_LIKE_HELL
-#define QETH_DBF_QERR_LEVEL 6
-#else /* QETH_DBF_LIKE_HELL */
 #define QETH_DBF_QERR_LEVEL 2
-#endif /* QETH_DBF_LIKE_HELL */
-/****************** END OF DEBUG FACILITY STUFF *********************/
-
-/********************* CARD DATA STUFF **************************/
-
-#define QETH_MAX_PARAMS 150
 
-#define QETH_CARD_TYPE_UNKNOWN 0
-#define QETH_CARD_TYPE_OSAE    10
-#define QETH_CARD_TYPE_IQD     1234
+#define QETH_DBF_TEXT(name,level,text) \
+       do { \
+               debug_text_event(qeth_dbf_##name,level,text); \
+       } while (0)
 
-#define QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT 0x0101
-#define QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT 0x0101
-#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
-#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
+#define QETH_DBF_HEX(name,level,addr,len) \
+       do { \
+               debug_event(qeth_dbf_##name,level,(void*)(addr),len); \
+       } while (0)
 
-#define QETH_MAX_QUEUES 4
+#define QETH_DBF_TEXT_(name,level,text...)                               \
+       do {                                                              \
+               sprintf(qeth_dbf_text_buf, text);                         \
+               debug_text_event(qeth_dbf_##name,level,qeth_dbf_text_buf);\
+       } while (0)
 
-#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe
-#define UNIQUE_ID_NOT_BY_CARD 0x10000
+#define QETH_DBF_SPRINTF(name,level,text...) \
+       do { \
+               debug_sprintf_event(qeth_dbf_trace, level, ##text ); \
+               debug_sprintf_event(qeth_dbf_trace, level, text ); \
+       } while (0)
 
-/* 
- * CU type & model, Dev type & model, card_type, odd_even_restriction,
- * func level, no of queues, multicast is different (multicast-queue_no + 0x100)
+/**
+ * some more debug stuff
  */
-#define QETH_MODELLIST_ARRAY \
-       {{0x1731,0x01,0x1732,0x01,QETH_CARD_TYPE_OSAE,1, \
-         QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
-         QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
-         QETH_MAX_QUEUES,0}, \
-        {0x1731,0x05,0x1732,0x05,QETH_CARD_TYPE_IQD,0, \
-         QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
-         QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
-         QETH_MAX_QUEUES,0x103}, \
-        {0,0,0,0,0,0,0,0,0}}
-
-#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
- /* only the first two bytes are looked at in qeth_get_cardname_short */
-#define QETH_MPC_LINK_TYPE_FAST_ETHERNET 0x01
-#define QETH_MPC_LINK_TYPE_HSTR 0x02
-#define QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET 0x03
-#define QETH_MPC_LINK_TYPE_10GIGABIT_ETHERNET 0x10
-#define QETH_MPC_LINK_TYPE_LANE_ETH100 0x81
-#define QETH_MPC_LINK_TYPE_LANE_TR 0x82
-#define QETH_MPC_LINK_TYPE_LANE_ETH1000 0x83
-#define QETH_MPC_LINK_TYPE_LANE 0x88
-#define QETH_MPC_LINK_TYPE_ATM_NATIVE 0x90
-
-#define DEFAULT_ADD_HHLEN 0
-#define MAX_ADD_HHLEN 1024
-
-#define QETH_HEADER_SIZE       32
-#define QETH_IP_HEADER_SIZE    40
-#define QETH_HEADER_LEN_POS    8
-/* flags for the header: */
-#define QETH_HEADER_PASSTHRU   0x10
-#define QETH_HEADER_IPV6       0x80
-
-#define QETH_ETH_MAC_V4      0x0100 /* like v4 */
-#define QETH_ETH_MAC_V6      0x3333 /* like v6 */
-/* tr mc mac is longer, but that will be enough to detect mc frames */
-#define QETH_TR_MAC_NC       0xc000 /* non-canonical */
-#define QETH_TR_MAC_C        0x0300 /* canonical */
-
-#define QETH_CAST_FLAGS                0x07
-#define QETH_CAST_UNICAST      6
-#define QETH_CAST_MULTICAST    4
-#define QETH_CAST_BROADCAST    5
-#define QETH_CAST_ANYCAST      7
-#define QETH_CAST_NOCAST       0
-
-/* VLAN defines */
-#define QETH_EXT_HEADER_VLAN_FRAME       0x01
-#define QETH_EXT_HEADER_TOKEN_ID         0x02
-#define QETH_EXT_HEADER_INCLUDE_VLAN_TAG  0x04
+#define PRINTK_HEADER  "qeth: "
 
-#define QETH_EXT_HEADER_SRC_MAC_ADDRESS   0x08
-#define QETH_EXT_HEADER_CSUM_HDR_REQ      0x10
-#define QETH_EXT_HEADER_CSUM_TRANSP_REQ   0x20
-#define QETH_EXT_HEADER_CSUM_TRANSP_FRAME_TYPE   0x40
-
-#define QETH_UDP_CSUM_OFFSET   6
-#define QETH_TCP_CSUM_OFFSET   16
-
-#define QETH_VERIFY_IS_REAL_DEV               1
-#define QETH_VERIFY_IS_VLAN_DEV               2
+#define HEXDUMP16(importance,header,ptr) \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+                  *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
+                  *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
+                  *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
+                  *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
+                  *(((char*)ptr)+12),*(((char*)ptr)+13), \
+                  *(((char*)ptr)+14),*(((char*)ptr)+15)); \
+PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+                  *(((char*)ptr)+16),*(((char*)ptr)+17), \
+                  *(((char*)ptr)+18),*(((char*)ptr)+19), \
+                  *(((char*)ptr)+20),*(((char*)ptr)+21), \
+                  *(((char*)ptr)+22),*(((char*)ptr)+23), \
+                  *(((char*)ptr)+24),*(((char*)ptr)+25), \
+                  *(((char*)ptr)+26),*(((char*)ptr)+27), \
+                  *(((char*)ptr)+28),*(((char*)ptr)+29), \
+                  *(((char*)ptr)+30),*(((char*)ptr)+31));
 
-inline static unsigned int
-qeth_get_ipa_timeout(int cardtype)
+static inline void
+qeth_hex_dump(unsigned char *buf, size_t len)
 {
-       switch (cardtype) {
-       case QETH_CARD_TYPE_IQD:
-               return 2000;
-       default:
-               return 20000;
+       size_t i;
+       
+       for (i = 0; i < len; i++) {
+               if (i && !(i % 16))
+                       printk("\n");
+               printk("%02x ", *(buf + i));
        }
+       printk("\n");
 }
 
-inline static unsigned short
-qeth_get_additional_dev_flags(int cardtype)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_IQD:
-               return IFF_NOARP;
-#ifdef QETH_IPV6
-       default:
-               return 0;
-#else /* QETH_IPV6 */
-       default:
-               return IFF_NOARP;
-#endif /* QETH_IPV6 */
-       }
-}
-
-inline static int
-qeth_get_hlen(__u8 link_type)
-{
-#ifdef QETH_IPV6
-       switch (link_type) {
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return QETH_HEADER_SIZE + TR_HLEN;
-       default:
-#ifdef QETH_VLAN
-               return QETH_HEADER_SIZE + VLAN_ETH_HLEN;
-#else
-               return QETH_HEADER_SIZE + ETH_HLEN;
-#endif
-       }
-#else /* QETH_IPV6 */
-#ifdef QETH_VLAN
-       return QETH_HEADER_SIZE + VLAN_HLEN;
-#else
-       return QETH_HEADER_SIZE;
-#endif
-
-#endif /* QETH_IPV6 */
-}
+#define SENSE_COMMAND_REJECT_BYTE 0
+#define SENSE_COMMAND_REJECT_FLAG 0x80
+#define SENSE_RESETTING_EVENT_BYTE 1
+#define SENSE_RESETTING_EVENT_FLAG 0x80
 
-static int (*qeth_my_eth_header) (struct sk_buff *, struct net_device *,
-                                 unsigned short, void *, void *, unsigned);
-#ifdef CONFIG_TR
-static int (*qeth_my_tr_header) (struct sk_buff *, struct net_device *,
-                                unsigned short, void *, void *, unsigned);
-#endif /* CONFIG_TR */
-static int (*qeth_my_eth_rebuild_header) (struct sk_buff *);
-#ifdef CONFIG_TR
-static int (*qeth_my_tr_rebuild_header) (struct sk_buff *);
-#endif /* CONFIG_TR */
-static int (*qeth_my_eth_header_cache) (struct neighbour *, struct hh_cache *);
-static void (*qeth_my_eth_header_cache_update) (struct hh_cache *,
-                                               struct net_device *,
-                                               unsigned char *);
-
-#ifdef QETH_IPV6
-typedef int (*__qeth_temp1) (struct sk_buff *, struct net_device *,
-                            unsigned short, void *, void *, unsigned);
-inline static __qeth_temp1
-qeth_get_hard_header(__u8 link_type)
-{
-       switch (link_type) {
-#ifdef CONFIG_TR
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return qeth_my_tr_header;
-#endif /* CONFIG_TR */
-       default:
-               return qeth_my_eth_header;
-       }
-}
+/*
+ * Common IO related definitions
+ */
+extern struct device *qeth_root_dev;
+extern struct ccw_driver qeth_ccw_driver;
+extern struct ccwgroup_driver qeth_ccwgroup_driver;
 
-typedef int (*__qeth_temp2) (struct sk_buff *);
-inline static __qeth_temp2
-qeth_get_rebuild_header(__u8 link_type)
-{
-       switch (link_type) {
-#ifdef CONFIG_TR
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return qeth_my_tr_rebuild_header;
-#endif /* CONFIG_TR */
-       default:
-               return qeth_my_eth_rebuild_header;
-       }
-}
+#define CARD_RDEV(card) card->read.ccwdev
+#define CARD_WDEV(card) card->write.ccwdev
+#define CARD_DDEV(card) card->data.ccwdev
+#define CARD_BUS_ID(card) card->gdev->dev.bus_id
+#define CARD_RDEV_ID(card) card->read.ccwdev->dev.bus_id
+#define CARD_WDEV_ID(card) card->write.ccwdev->dev.bus_id
+#define CARD_DDEV_ID(card) card->data.ccwdev->dev.bus_id
+#define CHANNEL_ID(channel) channel->ccwdev->dev.bus_id
 
-typedef int (*__qeth_temp3) (struct neighbour *, struct hh_cache *);
-inline static __qeth_temp3
-qeth_get_hard_header_cache(__u8 link_type)
-{
-       switch (link_type) {
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return NULL;
-       default:
-               return qeth_my_eth_header_cache;
-       }
-}
+#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
+               ((struct ccwgroup_device *)cdev->dev.driver_data)\
+               ->dev.driver_data;
 
-typedef void (*__qeth_temp4) (struct hh_cache *, struct net_device *,
-                             unsigned char *);
-inline static __qeth_temp4
-qeth_get_header_cache_update(__u8 link_type)
-{
-       switch (link_type) {
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return NULL;
-       default:
-               return qeth_my_eth_header_cache_update;
-       }
-}
+/**
+ * card stuff
+ */
+#ifdef CONFIG_QETH_PERF_STATS
+struct qeth_perf_stats {
+       unsigned int bufs_rec;
+       unsigned int bufs_sent;
 
-static unsigned short
-qeth_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-       struct ethhdr *eth;
-
-       skb->mac.raw = skb->data;
-       skb_pull(skb, ETH_ALEN * 2 + sizeof (short));
-       eth = skb->mac.ethernet;
-
-       if (*eth->h_dest & 1) {
-               if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
-                       skb->pkt_type = PACKET_BROADCAST;
-               else
-                       skb->pkt_type = PACKET_MULTICAST;
-       } else {
-               skb->pkt_type = PACKET_OTHERHOST;
-       }
-       if (ntohs(eth->h_proto) >= 1536)
-               return eth->h_proto;
-       if (*(unsigned short *) (skb->data) == 0xFFFF)
-               return htons(ETH_P_802_3);
-       return htons(ETH_P_802_2);
-}
+       unsigned int skbs_sent_pack;
+       unsigned int bufs_sent_pack;
 
-typedef unsigned short (*__qeth_temp5) (struct sk_buff *, struct net_device *);
-inline static __qeth_temp5
-qeth_get_type_trans(__u8 link_type)
-{
-       switch (link_type) {
-#ifdef CONFIG_TR
-       case QETH_MPC_LINK_TYPE_HSTR:
-       case QETH_MPC_LINK_TYPE_LANE_TR:
-               return tr_type_trans;
-#endif
-       default:
-               return qeth_eth_type_trans;
-       }
-}
-#endif /* QETH_IPV6 */
+       unsigned int sc_dp_p;
+       unsigned int sc_p_dp;
 
-inline static const char *
-qeth_get_link_type_name(int cardtype, __u8 linktype)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return "unknown";
-       case QETH_CARD_TYPE_OSAE:
-               switch (linktype) {
-               case QETH_MPC_LINK_TYPE_FAST_ETHERNET:
-                       return "Fast Eth";
-               case QETH_MPC_LINK_TYPE_HSTR:
-                       return "HSTR";
-               case QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET:
-                       return "Gigabit Eth";
-               case QETH_MPC_LINK_TYPE_LANE_ETH100:
-                       return "LANE Eth100";
-               case QETH_MPC_LINK_TYPE_LANE_TR:
-                       return "LANE TR";
-               case QETH_MPC_LINK_TYPE_LANE_ETH1000:
-                       return "LANE Eth1000";
-               default:
-                       return "unknown";
-               }
-       case QETH_CARD_TYPE_IQD:
-               return "magic";
-       default:
-               return "unknown";
-       }
-}
+       __u64 inbound_start_time;
+       unsigned int inbound_cnt;
+       unsigned int inbound_time;
+       __u64 outbound_start_time;
+       unsigned int outbound_cnt;
+       unsigned int outbound_time;
+};
+#endif /* CONFIG_QETH_PERF_STATS */
 
-inline static const char *
-qeth_get_dev_basename(int cardtype, __u8 link_type)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return "eth";
-       case QETH_CARD_TYPE_OSAE:
-               switch (link_type) {
-               case QETH_MPC_LINK_TYPE_LANE_TR:
-                       /* fallthrough */
-               case QETH_MPC_LINK_TYPE_HSTR:
-                       return "tr";
-               default:
-                       return "eth";
-               }
-       case QETH_CARD_TYPE_IQD:
-               return "hsi";
-       default:
-               return "eth";
-       }
-}
+/* Routing stuff */
+struct qeth_routing_info {
+       enum qeth_routing_types type;
+};
 
-/* inbound: */
-#define DEFAULT_BUFFER_SIZE 65536
-#define DEFAULT_BUFFER_COUNT 128
-#define BUFCNT_MIN 8
-#define BUFCNT_MAX 128
-#define BUFFER_SIZE (card->inbound_buffer_size)
-#define BUFFER_MAX_ELEMENTS (BUFFER_SIZE>>12)
-       /* 8k for each pair header-buffer: */
+/* IPA stuff */
+struct qeth_ipa_info {
+       __u32 supported_funcs;
+       __u32 enabled_funcs;
+};
 
-inline static int
-qeth_sbal_packing_on_card(int cardtype)
+static inline int
+qeth_is_ipa_supported(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
 {
-       switch (cardtype) {
-       case QETH_CARD_TYPE_IQD:
-               return 0;
-       default:
-               return 1;
-       }
+       return (ipa->supported_funcs & func);
 }
 
-/* 
- * do it this way round -> __MODULE_STRING needs with
- * QETH_PRIO_NICE_LEVELS a single number
- */
-#define QETH_MAX_PRIO_QUEUES QETH_PRIO_NICE_LEVELS+1
-
 static inline int
-qeth_sbalf15_in_retrieable_range(int sbalf15)
+qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
 {
-       return ((sbalf15 >= 15) && (sbalf15 <= 31));
+       return (ipa->supported_funcs & ipa->enabled_funcs & func);
 }
 
-#define INBOUND_BUFFER_POS(card,bufno,sbale) \
-       ( (bufno&SPAREBUF_MASK)? \
-         ( \
-           (sparebufs[bufno&(~SPAREBUF_MASK)].buf+ \
-            PAGE_SIZE*sbale) \
-         ):( \
-             (card->inbound_buffer_pool_entry[card-> \
-              inbound_buffer_entry_no[bufno]][sbale]) \
-           ) )
-
-#define SPAREBUF_UNAVAIL 0
-#define SPAREBUF_FREE 1
-#define SPAREBUF_USED 2
-
-struct sparebufs {
-       char *buf;
-       atomic_t status;
-};
+#define qeth_adp_supported(c,f) \
+       qeth_is_ipa_supported(&c->options.adp, f)
+#define qeth_adp_enabled(c,f) \
+       qeth_is_ipa_enabled(&c->options.adp, f)
+#define qeth_is_supported(c,f) \
+       qeth_is_ipa_supported(&c->options.ipa4, f)
+#define qeth_is_enabled(c,f) \
+       qeth_is_ipa_enabled(&c->options.ipa4, f)
+#ifdef CONFIG_QETH_IPV6
+#define qeth_is_supported6(c,f) \
+       qeth_is_ipa_supported(&c->options.ipa6, f)
+#define qeth_is_enabled6(c,f) \
+       qeth_is_ipa_enabled(&c->options.ipa6, f)
+#else /* CONFIG_QETH_IPV6 */
+#define qeth_is_supported6(c,f) 0
+#define qeth_is_enabled6(c,f) 0
+#endif /* CONFIG_QETH_IPV6 */
+#define qeth_is_ipafunc_supported(c,prot,f) \
+        (prot==QETH_PROT_IPV6)? qeth_is_supported6(c,f):qeth_is_supported(c,f)
+#define qeth_is_ipafunc_enabled(c,prot,f) \
+        (prot==QETH_PROT_IPV6)? qeth_is_enabled6(c,f):qeth_is_enabled(c,f)
+       
 
-#define SEND_STATE_INACTIVE            0
-#define SEND_STATE_DONT_PACK           1
-#define SEND_STATE_PACK                        2
-
-#define QETH_LOCK_UNLOCKED 0
-#define QETH_LOCK_NORMAL 1
-#define QETH_LOCK_FLUSH 2
-
-#define QETH_TX_TIMEOUT 100*HZ /* 100 seconds */
-
-#define QETH_REMOVE_WAIT_TIME 200
-#define QETH_WAIT_FOR_THREAD_TIME 20
-#define QETH_IDLE_WAIT_TIME 10
-#define QETH_WAIT_BEFORE_2ND_DOIO 1000
-
-#define QETH_FAKE_LL_LEN ETH_HLEN      /* 14 */
-#define QETH_FAKE_LL_PROT_LEN 2
-#define QETH_FAKE_LL_ADDR_LEN ETH_ALEN /* 6 */
-#define QETH_FAKE_LL_DEST_MAC_POS 0
-#define QETH_FAKE_LL_SRC_MAC_POS 6
-#define QETH_FAKE_LL_SRC_MAC_POS_IN_QDIO_HDR 6
-#define QETH_FAKE_LL_PROT_POS 12
-#define QETH_FAKE_LL_V4_ADDR_POS 16
+#define QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT 0x0101
+#define QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT 0x0101
+#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
+#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
+
+#define QETH_MODELLIST_ARRAY \
+       {{0x1731,0x01,0x1732,0x01,QETH_CARD_TYPE_OSAE,1, \
+       QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
+       QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
+       QETH_MAX_QUEUES,0}, \
+       {0x1731,0x05,0x1732,0x05,QETH_CARD_TYPE_IQD,0, \
+       QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
+       QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
+       QETH_MAX_QUEUES,0x103}, \
+       {0,0,0,0,0,0,0,0,0}}
+
+#define QETH_REAL_CARD         1
+#define QETH_VLAN_CARD         2
+#define QETH_BUFSIZE           4096
+
+/**
+ * some more defs
+ */ 
+#define IF_NAME_LEN            16      
+#define QETH_TX_TIMEOUT                100 * HZ
+#define QETH_HEADER_SIZE       32
+#define MAX_PORTNO             15
+#define QETH_FAKE_LL_LEN       ETH_HLEN
 #define QETH_FAKE_LL_V6_ADDR_POS 24
+       
+/*IPv6 address autoconfiguration stuff*/
+#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe
+#define UNIQUE_ID_NOT_BY_CARD          0x10000
 
-#define DEV_NAME_LEN 16
-#define IOCTL_MAX_TRANSFER_SIZE 65535
+/*****************************************************************************/
+/* QDIO queue and buffer handling                                            */
+/*****************************************************************************/
+#define QETH_MAX_QUEUES 4
+#define QETH_IN_BUF_SIZE_DEFAULT 65536
+#define QETH_IN_BUF_COUNT_DEFAULT 16
+#define QETH_IN_BUF_COUNT_MIN 8
+#define QETH_IN_BUF_COUNT_MAX 128
+#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
+#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
+               ((card)->qdio.in_buf_pool.buf_count / 4)
+
+/* buffers we have to be behind before we get a PCI */
+#define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1)
+/*enqueued free buffers left before we get a PCI*/
+#define QETH_PCI_THRESHOLD_B(card) 0 
+/*not used unless the microcode gets patched*/
+#define QETH_PCI_TIMER_VALUE(card) 3 
 
+#define QETH_MIN_INPUT_THRESHOLD 1
+#define QETH_MAX_INPUT_THRESHOLD 500
+#define QETH_MIN_OUTPUT_THRESHOLD 1
+#define QETH_MAX_OUTPUT_THRESHOLD 300
+       
+/* priority queing */
+#define QETH_PRIOQ_DEFAULT QETH_NO_PRIO_QUEUEING
+#define QETH_DEFAULT_QUEUE    2
+#define QETH_NO_PRIO_QUEUEING 0
+#define QETH_PRIO_Q_ING_PREC  1
+#define QETH_PRIO_Q_ING_TOS   2
 #define IP_TOS_LOWDELAY 0x10
 #define IP_TOS_HIGHTHROUGHPUT 0x08
 #define IP_TOS_HIGHRELIABILITY 0x04
 #define IP_TOS_NOTIMPORTANT 0x02
 
-#define QETH_RCD_LENGTH 128
-
-#define __max(a,b) ( ((a)>(b))?(a):(b) )
-#define __min(a,b) ( ((a)<(b))?(a):(b) )
-#define QETH_BUFSIZE __max(__max(IPA_PDU_HEADER_SIZE+sizeof(struct arp_cmd), \
-                                IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd)), \
-                          QETH_RCD_LENGTH)
-
-#define QETH_NOP_TIMEOUT 1500
-#define QETH_QUIESCE_NETDEV_TIME 300
-#define QETH_QUIESCE_WAIT_BEFORE_CLEAR 4000
-#define QETH_QUIESCE_WAIT_AFTER_CLEAR 4000
-
-#define NOP_STATE 0x1001
-#define IDX_ACTIVATE_READ_STATE 0x1003
-#define IDX_ACTIVATE_WRITE_STATE 0x1004
-#define MPC_SETUP_STATE 0x1005
-#define CLEAR_STATE 0x1006
-#define IPA_CMD_STATE 0x1007
-#define IPA_IOCTL_STATE 0x1009
-#define IPA_SETIP_FLAG 0x100000
-
-#define QETH_REMOVE_CARD_PROPER 1
-#define QETH_REMOVE_CARD_QUICK 2
-
-#define NO_PRIO_QUEUEING 0
-#define PRIO_QUEUEING_PREC 1
-#define PRIO_QUEUEING_TOS 2
-#define NO_ROUTER 0
-#define PRIMARY_ROUTER 1
-#define SECONDARY_ROUTER 2
-#define MULTICAST_ROUTER 3
-#define PRIMARY_CONNECTOR 4
-#define SECONDARY_CONNECTOR 5
-#define ROUTER_MASK 0xf                /* used to remove SET_ROUTING_FLAG
-                                  from routing_type */
-#define RESET_ROUTING_FLAG 0x10        /* used to indicate, that setting
-                                  the routing type is desired */
-#define BROADCAST_ALLRINGS 0
-#define BROADCAST_LOCAL 1
-#define MACADDR_NONCANONICAL 0
-#define MACADDR_CANONICAL 1
-#define ENABLE_TAKEOVER 0
-#define DISABLE_TAKEOVER 1
-#define FAKE_BROADCAST 0
-#define DONT_FAKE_BROADCAST 1
-
-#define FAKE_LL 0
-#define DONT_FAKE_LL 1
-
-#define QETH_BREAKOUT_LEAVE 1
-#define QETH_BREAKOUT_AGAIN 2
-
-#define QETH_WAIT_FOR_LOCK 0
-#define QETH_DONT_WAIT_FOR_LOCK 1
-#define QETH_LOCK_ALREADY_HELD 2
-
-#define PROBLEM_CARD_HAS_STARTLANED 1
-#define PROBLEM_RECEIVED_IDX_TERMINATE 2
-#define PROBLEM_ACTIVATE_CHECK_CONDITION 3
-#define PROBLEM_RESETTING_EVENT_INDICATOR 4
-#define PROBLEM_COMMAND_REJECT 5
-#define PROBLEM_ZERO_SENSE_DATA 6
-#define PROBLEM_GENERAL_CHECK 7
-#define PROBLEM_BAD_SIGA_RESULT 8
-#define PROBLEM_USER_TRIGGERED_RECOVERY 9
-#define PROBLEM_AFFE 10
-#define PROBLEM_MACHINE_CHECK 11
-#define PROBLEM_TX_TIMEOUT 12
-
-#define CARD_RDEV(card) card->gdev->cdev[0]
-#define CARD_WDEV(card) card->gdev->cdev[1]
-#define CARD_DDEV(card) card->gdev->cdev[2]
-#define CARD_BUS_ID(card) card->gdev->dev.bus_id
-#define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id
-#define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id
-#define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id
-#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
-       ((struct ccwgroup_device *) cdev->dev.driver_data)->dev.driver_data
+/* Packing */
+#define QETH_LOW_WATERMARK_PACK  2
+#define QETH_HIGH_WATERMARK_PACK 5
+#define QETH_WATERMARK_PACK_FUZZ 1
 
-#define SENSE_COMMAND_REJECT_BYTE 0
-#define SENSE_COMMAND_REJECT_FLAG 0x80
-#define SENSE_RESETTING_EVENT_BYTE 1
-#define SENSE_RESETTING_EVENT_FLAG 0x80
-
-#define BUFFER_USED 1
-#define BUFFER_UNUSED -1
+#define QETH_IP_HEADER_SIZE 40
+/* VLAN defines */
+#define QETH_EXT_HDR_VLAN_FRAME        0x01
+#define QETH_EXT_HDR_TOKEN_ID          0x02
+#define QETH_EXT_HDR_INCLUDE_VLAN_TAG  0x04
 
-typedef int (*reg_notifier_t) (struct notifier_block *);
+struct qeth_hdr {
+       __u8  id;
+       __u8  flags;
+       __u16 inbound_checksum;
+       __u32 token;
+       __u16 length;
+       __u8  vlan_prio;
+       __u8  ext_flags;
+       __u16 vlan_id;
+       __u16 frame_offset;
+       __u8  dest_addr[16];
+} __attribute__ ((packed));
 
-struct ipato_entry {
-       int version;
-       __u8 addr[16];
-       int mask_bits;
-       char dev_name[DEV_NAME_LEN];
-       struct ipato_entry *next;
+/* flags for qeth_hdr.flags */
+#define QETH_HDR_PASSTHRU 0x10
+#define QETH_HDR_IPV6     0x80
+#define QETH_HDR_CAST_MASK 0x07
+enum qeth_cast_flags {
+       QETH_CAST_UNICAST   = 0x06,
+       QETH_CAST_MULTICAST = 0x04,
+       QETH_CAST_BROADCAST = 0x05,
+       QETH_CAST_ANYCAST   = 0x07,
+       QETH_CAST_NOCAST    = 0x00,
 };
 
-struct qeth_vipa_entry {
-       int version;
-       __u8 ip[16];
-       int flag;
-       volatile int state;
-       struct qeth_vipa_entry *next;
-};
+/* flags for qeth_hdr.ext_flags */
+#define QETH_HDR_EXT_VLAN_FRAME      0x01
+#define QETH_HDR_EXT_CSUM_HDR_REQ    0x10
+#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
+#define QETH_HDR_EXT_SRC_MAC_ADDR    0x08
 
-struct ip_state {
-       struct in_ifaddr *ip_ifa;       /* pointer to IPv4 adresses */
-       struct inet6_ifaddr *ip6_ifa;
-};
+static inline int
+qeth_is_last_sbale(struct qdio_buffer_element *sbale)
+{
+       return (sbale->flags & SBAL_FLAGS_LAST_ENTRY);
+}
 
-struct qeth_ipm_mac {
-       __u8 mac[ETH_ALEN];
-       __u8 ip[16];
-       struct qeth_ipm_mac *next;
+enum qeth_qdio_buffer_states {
+       /*
+        * inbound: read out by driver; owned by hardware in order to be filled
+        * outbound: owned by driver in order to be filled
+        */
+       QETH_QDIO_BUF_EMPTY,
+       /*
+        * inbound: filled by hardware; owned by driver in order to be read out
+        * outbound: filled by driver; owned by hardware in order to be sent
+        */
+       QETH_QDIO_BUF_PRIMED,
+       /*
+        * inbound only: an error condition has been detected for a buffer
+        *     the buffer will be discarded (not read out)
+        */
+       QETH_QDIO_BUF_ERROR,
 };
 
-struct ip_mc_state {
-       struct qeth_ipm_mac *ipm_ifa;
-       struct qeth_ipm_mac *ipm6_ifa;
+enum qeth_qdio_info_states {
+       QETH_QDIO_UNINITIALIZED,
+       QETH_QDIO_ALLOCATED,
+       QETH_QDIO_ESTABLISHED,
 };
 
-struct addr_request {
-       struct addr_request *next;
-       int request_type;
-       __u8 mac[ETH_ALEN];
-       __u8 ip[16];
-};
+struct qeth_buffer_pool_entry {
+       struct list_head list;
+       struct list_head init_list;
+       void *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
+};     
 
-struct qeth_card_options {
-       char devname[DEV_NAME_LEN];
-       volatile int routing_type4;
-#ifdef QETH_IPV6
-       volatile int routing_type6;
-#endif /* QETH_IPV6 */
-       int checksum_type;
-       int do_prio_queueing;
-       int default_queue;
-       int inbound_buffer_count;
-       int polltime;
-       char portname[9];
-       int portno;
-       int broadcast_mode;
-       int macaddr_mode;
-       int ena_ipat;
-       int fake_broadcast;
-       int add_hhlen;
-       int fake_ll;
+struct qeth_qdio_buffer_pool {
+       struct list_head entry_list;
+       int buf_count;
 };
 
-struct qeth_hdr {
-       __u8 id;
-       __u8 flags;
-       __u16 inbound_checksum;
-       __u32 token;
-       __u16 length;
-       __u8 vlan_prio;
-       __u8 ext_flags;
-       __u16 vlan_id;
-       __u16 frame_offset;
-       __u8 dest_addr[16];
+struct qeth_qdio_buffer {
+       struct qdio_buffer *buffer;
+       volatile enum qeth_qdio_buffer_states state;
+       /* the buffer pool entry currently associated to this buffer */
+       struct qeth_buffer_pool_entry *pool_entry;
 };
 
-struct qeth_ringbuffer_element {
+struct qeth_qdio_q {
+       struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
+       struct qeth_qdio_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
+       /* 
+        * buf_to_process means "buffer primed by hardware,
+        * has to be read in by driver"; current state PRIMED
+        */
+       volatile int next_buf_to_process;
+       /*
+        * buf_to_init means "buffer must be initialized by driver and must
+        * be made available for hardware" -> state is set to EMPTY
+        */
+       volatile int next_buf_to_init;
+} __attribute__ ((aligned(256)));
+
+struct qeth_qdio_out_buffer {
+       struct qdio_buffer *buffer;
+       volatile enum qeth_qdio_buffer_states state;
+       volatile int next_element_to_fill;
        struct sk_buff_head skb_list;
-       int next_element_to_fill;
-} __attribute__ ((packed));
-
-struct qeth_ringbuffer {
-       struct qdio_buffer buffer[QDIO_MAX_BUFFERS_PER_Q];
-       struct qeth_ringbuffer_element ringbuf_element[QDIO_MAX_BUFFERS_PER_Q];
-}__attribute__ ((packed, aligned(PAGE_SIZE)));
-
-struct qeth_dma_stuff {
-       unsigned char *sendbuf;
-       unsigned char *recbuf;
-       struct ccw1 read_ccw;
-       struct ccw1 write_ccw;
-}__attribute__ ((packed, aligned(PAGE_SIZE)));
-
-struct qeth_perf_stats {
-       unsigned int skbs_rec;
-       unsigned int bufs_rec;
-
-       unsigned int skbs_sent;
-       unsigned int bufs_sent;
-
-       unsigned int skbs_sent_dont_pack;
-       unsigned int bufs_sent_dont_pack;
-       unsigned int skbs_sent_pack;
-       unsigned int bufs_sent_pack;
-       unsigned int skbs_sent_pack_better;
-       unsigned int bufs_sent_pack_better;
+};
 
-       unsigned int sc_dp_p;
-       unsigned int sc_p_dp;
+struct qeth_card;
+
+struct qeth_qdio_out_q {
+       struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
+       struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
+       int queue_no;
+       struct qeth_card *card;
+       struct tasklet_struct tasklet;
+       spinlock_t lock;
+       volatile int do_pack;
+       /*
+        * index of buffer to be filled by driver; state EMPTY or PACKING
+        */
+       volatile int next_buf_to_fill;
+       volatile int next_buf_to_flush;
+       /*
+        * number of buffers that are currently filled (PRIMED)
+        * -> these buffers are hardware-owned
+        */
+       atomic_t used_buffers;
+       /* indicates whether PCI flag must be set (or if one is outstanding) */
+       atomic_t set_pci_flags_count;
+} __attribute__ ((aligned(256)));
+
+struct qeth_qdio_info {
+       volatile enum qeth_qdio_info_states state;
+       /* input */
+       struct qeth_qdio_q *in_q;
+       struct qeth_qdio_buffer_pool in_buf_pool;
+       struct qeth_qdio_buffer_pool init_pool;
+       int in_buf_size;
+       struct tasklet_struct in_tasklet;
+
+       /* output */
+       int no_out_queues;
+       struct qeth_qdio_out_q **out_qs;
+
+       /* priority queueing */
+       int do_prio_queueing;
+       int default_out_queue;
+};
 
-       __u64 inbound_start_time;
-       unsigned int inbound_cnt;
-       unsigned int inbound_time;
-       __u64 outbound_start_time;
-       unsigned int outbound_cnt;
-       unsigned int outbound_time;
+enum qeth_send_errors {
+       QETH_SEND_ERROR_NONE,
+       QETH_SEND_ERROR_LINK_FAILURE,
+       QETH_SEND_ERROR_RETRY,
+       QETH_SEND_ERROR_KICK_IT,
 };
 
-/* ugly. I know. */
-struct qeth_card {     /* pointed to by dev->priv */
+#define QETH_ETH_MAC_V4      0x0100 /* like v4 */
+#define QETH_ETH_MAC_V6      0x3333 /* like v6 */
+/* tr mc mac is longer, but that will be enough to detect mc frames */
+#define QETH_TR_MAC_NC       0xc000 /* non-canonical */
+#define QETH_TR_MAC_C        0x0300 /* canonical */
 
-       /* pointer to options (defaults + parameters) */
-       struct qeth_card_options options;
+#define DEFAULT_ADD_HHLEN 0
+#define MAX_ADD_HHLEN 1024
 
-       atomic_t is_startlaned; /* card did not get a stoplan */
-                               /* also 0 when card is gone after a
-                                * machine check */
-
-       __u8 link_type;
-
-       int is_guest_lan;
-
-       /* inbound buffer management */
-       atomic_t inbound_buffer_refcnt[QDIO_MAX_BUFFERS_PER_Q];
-       struct qdio_buffer inbound_qdio_buffers[QDIO_MAX_BUFFERS_PER_Q];
-       /* inbound data area */
-       void *inbound_buffer_pool_entry[QDIO_MAX_BUFFERS_PER_Q]
-           [QDIO_MAX_ELEMENTS_PER_BUFFER];
-       volatile int inbound_buffer_pool_entry_used[QDIO_MAX_BUFFERS_PER_Q];
-       int inbound_buffer_entry_no[QDIO_MAX_BUFFERS_PER_Q];
-
-       /* for requeueing of buffers */
-       spinlock_t requeue_input_lock;
-       atomic_t requeue_position;
-       atomic_t requeue_counter;
-
-       /* outbound QDIO stuff */
-       volatile int send_state[QETH_MAX_QUEUES];
-       volatile int outbound_first_free_buffer[QETH_MAX_QUEUES];
-       atomic_t outbound_used_buffers[QETH_MAX_QUEUES];
-       int outbound_buffer_send_state[QETH_MAX_QUEUES]
-           [QDIO_MAX_BUFFERS_PER_Q];
-       int send_retries[QETH_MAX_QUEUES][QDIO_MAX_BUFFERS_PER_Q];
-       volatile int outbound_bytes_in_buffer[QETH_MAX_QUEUES];
-       struct qeth_ringbuffer *outbound_ringbuffer[QETH_MAX_QUEUES];
-       atomic_t outbound_ringbuffer_lock[QETH_MAX_QUEUES];
-       atomic_t last_pci_pos[QETH_MAX_QUEUES];
-
-#ifdef QETH_IPV6
-       int (*hard_header) (struct sk_buff *, struct net_device *,
-                           unsigned short, void *, void *, unsigned);
-       int (*rebuild_header) (struct sk_buff *);
-       int (*hard_header_cache) (struct neighbour *, struct hh_cache *);
-       void (*header_cache_update) (struct hh_cache *, struct net_device *,
-                                    unsigned char *);
-       unsigned short (*type_trans) (struct sk_buff *, struct net_device *);
-#endif /* QETH_IPV6 */
+/**
+ * buffer stuff for read channel
+ */
+#define QETH_CMD_BUFFER_NO     8       
 
-#ifdef QETH_VLAN
-       struct vlan_group *vlangrp;
-       spinlock_t vlan_lock;
-#endif
+/**
+ *  channel state machine
+ */
+enum qeth_channel_states {
+       CH_STATE_UP,
+       CH_STATE_DOWN,
+       CH_STATE_ACTIVATING,
+       CH_STATE_HALTED,
+       CH_STATE_STOPPED,
+};
+/**
+ * card state machine
+ */
+enum qeth_card_states {
+       CARD_STATE_DOWN,
+       CARD_STATE_HARDSETUP,
+       CARD_STATE_SOFTSETUP,
+       CARD_STATE_UP_LAN_OFFLINE,
+       CARD_STATE_UP_LAN_ONLINE,
+       CARD_STATE_RECOVER,
+};
 
-       char dev_name[DEV_NAME_LEN];    /* pointed to by dev->name */
-       struct net_device *dev;
-       struct net_device_stats *stats;
+/**
+ * Protocol versions
+ */ 
+enum qeth_prot_versions {
+       QETH_PROT_SNA  = 0x0001,
+       QETH_PROT_IPV4 = 0x0004,
+       QETH_PROT_IPV6 = 0x0006,
+};
 
-       int no_queues;
+enum qeth_ip_types {
+       QETH_IP_TYPE_NORMAL,
+       QETH_IP_TYPE_VIPA,
+       QETH_IP_TYPE_RXIP,
+};
 
-#ifdef QETH_PERFORMANCE_STATS
-       struct qeth_perf_stats perf_stats;
-#endif /* QETH_PERFORMANCE_STATS */
-
-       /* our state */
-       atomic_t is_registered; /* card registered as netdev? */
-       atomic_t is_hardsetup;  /* card has gone through hardsetup */
-       atomic_t is_softsetup;  /* card is setup by softsetup */
-       atomic_t is_open;       /* card is in use */
-
-       /* prevents deadlocks :-O */
-       struct semaphore softsetup_sema;
-       struct semaphore hardsetup_sema;
-       spinlock_t ioctl_lock;
-       atomic_t softsetup_thread_is_running;
-       struct semaphore softsetup_thread_sem;
-       struct work_struct tqueue_sst;
-
-       atomic_t escape_softsetup;      /* active, when recovery has to
-                                          wait for softsetup */
-       struct semaphore reinit_thread_sem;
-       atomic_t in_recovery;
-       atomic_t reinit_counter;
-
-       /* problem management */
-       atomic_t break_out;
-       atomic_t problem;
-       struct work_struct tqueue;
-
-       struct {
-               __u32 trans_hdr;
-               __u32 pdu_hdr;
-               __u32 pdu_hdr_ack;
-               __u32 ipa;
-       } seqno;
-
-       struct {
-               __u32 issuer_rm_w;
-               __u32 issuer_rm_r;
-               __u32 cm_filter_w;
-               __u32 cm_filter_r;
-               __u32 cm_connection_w;
-               __u32 cm_connection_r;
-               __u32 ulp_filter_w;
-               __u32 ulp_filter_r;
-               __u32 ulp_connection_w;
-               __u32 ulp_connection_r;
-       } token;
-
-       /* this is card-related */
-       int type;
-       __u16 func_level;
-       int initial_mtu;
-       int max_mtu;
-       int inbound_buffer_size;
-
-       int is_multicast_different;     /* if multicast traffic is to be sent
-                                          on a different queue, this is the
-                                          queue+no_queues */
-       __u32 ipa_supported;
-       __u32 ipa_enabled;
-       __u32 ipa6_supported;
-       __u32 ipa6_enabled;
-       __u32 adp_supported;
-
-       __u32 csum_enable_mask;
-
-       atomic_t startlan_attempts;
-       atomic_t enable_routing_attempts4;
-       atomic_t rt4fld;
-#ifdef QETH_IPV6
-       atomic_t enable_routing_attempts6;
-       atomic_t rt6fld;
-#endif /* QETH_IPV6 */
-       int unique_id;
+enum qeth_cmd_buffer_state {
+       BUF_STATE_FREE,
+       BUF_STATE_LOCKED,
+       BUF_STATE_PROCESSED,
+};
+/**
+ * IP address and multicast list 
+ */ 
+struct qeth_ipaddr {
+       struct list_head entry;
+       enum qeth_ip_types type;
+       enum qeth_ipa_setdelip_flags set_flags;
+       enum qeth_ipa_setdelip_flags del_flags;
+       int is_multicast;
+       volatile int users;
+       enum qeth_prot_versions proto;
+       unsigned char mac[OSA_ADDR_LEN];
+       union {
+               struct {
+                       unsigned int addr;
+                       unsigned int mask;
+               } a4;
+               struct {
+                       struct in6_addr addr;
+                       unsigned int pfxlen;
+               } a6;
+       } u;
+};
 
-       /* device and I/O data */
-       struct ccwgroup_device *gdev;
-       unsigned short unit_addr2;
-       unsigned short cula;
-       unsigned short chpid;
+struct qeth_ipato_entry {
+       struct list_head entry;
+       enum qeth_prot_versions proto;
+       char addr[16];
+       int mask_bits;
+};
 
-       unsigned char ipa_buf[QETH_BUFSIZE];
-       unsigned char send_buf[QETH_BUFSIZE];
+struct qeth_ipato {
+       int enabled;
+       int invert4;
+       int invert6;
+       struct list_head entries;
+};
 
-/* IOCTL Stuff */
-       unsigned char *ioctl_data_buffer;
-       unsigned char *ioctl_buffer_pointer;
-       int ioctl_returncode;
-       int ioctl_buffersize;
-       int number_of_entries;
+struct qeth_channel;
 
-       atomic_t ioctl_data_has_arrived;
-       wait_queue_head_t ioctl_wait_q;
+struct qeth_cmd_buffer {
+       enum qeth_cmd_buffer_state state;
+       struct qeth_channel *channel;
+       unsigned char *data;
+       int rc;
+       void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
+};
 
-/* stuff under 2 gb */
-       struct qeth_dma_stuff *dma_stuff;
 
-       unsigned int ipa_timeout;
+/**
+ * definition of a qeth channel, used for read and write
+ */ 
+struct qeth_channel {
+       enum qeth_channel_states state;
+       struct ccw1 ccw;
+       spinlock_t iob_lock;
+       wait_queue_head_t wait_q;
+       struct tasklet_struct irq_tasklet;
+       struct ccw_device *ccwdev;
+/*command buffer for control data*/
+       struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
+       atomic_t irq_pending;
+       volatile int io_buf_no;
+       volatile int buf_no;
+};
 
-       atomic_t write_busy;
+/**
+ *  OSA card related definitions
+ */ 
+struct qeth_token {
+       __u32 issuer_rm_w;
+       __u32 issuer_rm_r;
+       __u32 cm_filter_w;
+       __u32 cm_filter_r;
+       __u32 cm_connection_w;
+       __u32 cm_connection_r;
+       __u32 ulp_filter_w;
+       __u32 ulp_filter_r;
+       __u32 ulp_connection_w;
+       __u32 ulp_connection_r;
+};
 
-       /* vipa stuff */
-       rwlock_t vipa_list_lock;
-       struct qeth_vipa_entry *vipa_list;
+struct qeth_seqno {
+       __u32 trans_hdr;
+       __u32 pdu_hdr;
+       __u32 pdu_hdr_ack;
+       __u32 ipa;
+};
 
-       /* state information when doing I/O */
-       atomic_t shutdown_phase;
-       atomic_t data_has_arrived;
+struct qeth_reply {
+       struct list_head list;
        wait_queue_head_t wait_q;
+       int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
+       int seqno;      
+       int received;
+       int rc;
+       void *param;
+       struct qeth_card *card;
+       atomic_t refcnt;
+};
 
-       atomic_t clear_succeeded0;
-       atomic_t clear_succeeded1;
-       atomic_t clear_succeeded2;
-
-       /* bookkeeping of IP and multicast addresses */
-       struct ip_state ip_current_state;
-       struct ip_state ip_new_state;
-
-       struct ip_mc_state ip_mc_current_state;
-       struct ip_mc_state ip_mc_new_state;
+struct qeth_card_info {
 
-       int broadcast_capable;
+       char if_name[IF_NAME_LEN];
+       unsigned short unit_addr2;
+       unsigned short cula;
+       unsigned short chpid;
+       __u16 func_level;
+       char mcl_level[QETH_MCL_LENGTH + 1];
+       int guestlan;
        int portname_required;
+       int portno;
+       char portname[9];
+       enum qeth_card_types type;
+       enum qeth_link_types link_type;
+       int is_multicast_different;
+       int initial_mtu;
+       int max_mtu;
+       int broadcast_capable;
+       int unique_id;
+       __u32 csum_mask;
+};
 
-       int realloc_message;
+struct qeth_card_options {
+       struct qeth_routing_info route4;
+       struct qeth_ipa_info ipa4;
+       struct qeth_ipa_info adp; /*Adapter parameters*/
+#ifdef CONFIG_QETH_IPV6
+       struct qeth_routing_info route6;
+       struct qeth_ipa_info ipa6;
+#endif /* QETH_IPV6 */
+       enum qeth_checksum_types checksum_type;
+       int broadcast_mode;
+       int macaddr_mode;
+       int enable_takeover;
+       int fake_broadcast;
+       int add_hhlen;
+       int fake_ll;
+};
 
-       char level[QETH_MCL_LENGTH + 1];
+/*
+ * thread bits for qeth_card thread masks
+ */
+enum qeth_threads {
+       QETH_SET_IP_THREAD  = 1,
+       QETH_SET_MC_THREAD  = 2,
+       QETH_RECOVER_THREAD = 4,
+};
 
-       volatile int saved_dev_flags;
+struct qeth_card {
+       struct list_head list;
+       enum qeth_card_states state;
+       int lan_online;
+       spinlock_t lock;
+/*hardware and sysfs stuff*/   
+       struct ccwgroup_device *gdev;
+       struct qeth_channel read;
+       struct qeth_channel write;
+       struct qeth_channel data;
+       
+       struct net_device *dev;
+       struct net_device_stats stats;
+       
+       struct qeth_card_info info; 
+       struct qeth_token token;
+       struct qeth_seqno seqno;
+       struct qeth_card_options options;
+       
+       wait_queue_head_t wait_q;
+#ifdef CONFIG_QETH_VLAN         
+       spinlock_t vlanlock;
+       struct vlan_group *vlangrp;
+#endif
+       struct work_struct kernel_thread_starter;
+       spinlock_t thread_mask_lock;
+       volatile unsigned long thread_start_mask;
+       volatile unsigned long thread_allowed_mask;
+       volatile unsigned long thread_running_mask;
+       spinlock_t ip_lock;     
+       struct list_head ip_list;
+       struct list_head ip_tbd_list;
+       struct qeth_ipato ipato;
+       struct list_head cmd_waiter_list;
+       /* QDIO buffer handling */
+       struct qeth_qdio_info qdio;
+#ifdef CONFIG_QETH_PERF_STATS
+       struct qeth_perf_stats perf_stats;
+#endif /* CONFIG_QETH_PERF_STATS */
+       int use_hard_stop;
+};
 
-       /* for our linked list */
-       struct qeth_card *next;
+struct qeth_card_list_struct {
+       struct list_head list;
+       rwlock_t rwlock;
 };
 
-inline static int
-qeth_get_arphrd_type(int cardtype, int linktype)
-{
-       switch (cardtype) {
-       case QETH_CARD_TYPE_OSAE:
-               switch (linktype) {
-               case QETH_MPC_LINK_TYPE_LANE_TR:
-                       /* fallthrough */
-               case QETH_MPC_LINK_TYPE_HSTR:
-                       return ARPHRD_IEEE802_TR;
-               default:
-                       return ARPHRD_ETHER;
-               }
-       case QETH_CARD_TYPE_IQD:
-               return ARPHRD_ETHER;
-       default:
-               return ARPHRD_ETHER;
-       }
-}
+extern struct qeth_card_list_struct qeth_card_list;
+
+/*some helper functions*/
 
 inline static __u8
-qeth_get_adapter_type_for_ipa(int link_type)
+qeth_get_ipa_adp_type(enum qeth_link_types link_type)
 {
        switch (link_type) {
-       case QETH_MPC_LINK_TYPE_HSTR:
+       case QETH_LINK_TYPE_HSTR:
                return 2;
        default:
                return 1;
        }
 }
 
-inline static const char *
-qeth_get_cardname(int cardtype, int is_guest_lan)
+inline static int
+qeth_get_hlen(__u8 link_type)
 {
-
-       if (is_guest_lan) {
-               switch (cardtype) {
-               case QETH_CARD_TYPE_UNKNOWN:
-                       return "n unknown";
-               case QETH_CARD_TYPE_OSAE:
-                       return " Guest LAN QDIO";
-               case QETH_CARD_TYPE_IQD:
-                       return " Guest LAN Hiper";
-               default: return
-                                " strange";
-               }
-       } else {
-               switch (cardtype) {
-               case QETH_CARD_TYPE_UNKNOWN:
-                       return "n unknown";
-               case QETH_CARD_TYPE_OSAE:
-                       return "n OSD Express";
-               case QETH_CARD_TYPE_IQD:
-                       return " HiperSockets";
-               default:
-                       return " strange";
-               }
+#ifdef CONFIG_QETH_IPV6
+       switch (link_type) {
+       case QETH_LINK_TYPE_HSTR:
+       case QETH_LINK_TYPE_LANE_TR:
+               return sizeof(struct qeth_hdr) + TR_HLEN;
+       default:
+#ifdef CONFIG_QETH_VLAN
+               return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
+#else
+               return sizeof(struct qeth_hdr) + ETH_HLEN;
+#endif
        }
+#else  /* CONFIG_QETH_IPV6 */
+#ifdef CONFIG_QETH_VLAN
+       return sizeof(struct qeth_hdr) + VLAN_HLEN;
+#else
+       return sizeof(struct qeth_hdr);
+#endif
+#endif /* CONFIG_QETH_IPV6 */
 }
 
-/* max length to be returned: 14 */
-inline static const char *
-qeth_get_cardname_short(int cardtype, __u8 link_type, int is_guest_lan)
+inline static unsigned short
+qeth_get_netdev_flags(int cardtype)
 {
        switch (cardtype) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return "unknown";
-       case QETH_CARD_TYPE_OSAE:
-               if (is_guest_lan)
-                       return "GuestLAN QDIO";
-               switch (link_type) {
-               case QETH_MPC_LINK_TYPE_FAST_ETHERNET:
-                       return "OSD_100";
-               case QETH_MPC_LINK_TYPE_HSTR:
-                       return "HSTR";
-               case QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET:
-                       return "OSD_1000";
-               case QETH_MPC_LINK_TYPE_LANE_ETH100:
-                       return "OSD_FE_LANE";
-               case QETH_MPC_LINK_TYPE_LANE_TR:
-                       return "OSD_TR_LANE";
-               case QETH_MPC_LINK_TYPE_LANE_ETH1000:
-                       return "OSD_GbE_LANE";
-               case QETH_MPC_LINK_TYPE_LANE:
-                       return "OSD_ATM_LANE";
-               default:
-                       return "OSD_Express";
-               }
        case QETH_CARD_TYPE_IQD:
-               return is_guest_lan ? "GuestLAN Hiper" : "HiperSockets";
+               return IFF_NOARP;
+#ifdef CONFIG_QETH_IPV6
        default:
-               return " strange";
-       }
-}
-
-inline static int
-qeth_mtu_is_valid(struct qeth_card * card, int mtu)
-{
-       switch (card->type) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return 1;
-       case QETH_CARD_TYPE_OSAE:
-               return ((mtu >= 576) && (mtu <= 61440));
-       case QETH_CARD_TYPE_IQD:
-               return ((mtu >= 576) && (mtu <= card->max_mtu + 4096 - 32));
+               return 0;
+#else 
        default:
-               return 1;
+               return IFF_NOARP;
+#endif
        }
 }
 
 inline static int
 qeth_get_initial_mtu_for_card(struct qeth_card * card)
 {
-       switch (card->type) {
+       switch (card->info.type) {
        case QETH_CARD_TYPE_UNKNOWN:
                return 1500;
        case QETH_CARD_TYPE_IQD:
-               return card->max_mtu;
+               return card->info.max_mtu;
        case QETH_CARD_TYPE_OSAE:
-               switch (card->link_type) {
-               case QETH_MPC_LINK_TYPE_HSTR:
-               case QETH_MPC_LINK_TYPE_LANE_TR:
+               switch (card->info.link_type) {
+               case QETH_LINK_TYPE_HSTR:
+               case QETH_LINK_TYPE_LANE_TR:
                        return 2000;
                default:
                        return 1492;
@@ -1195,39 +837,50 @@ qeth_get_mtu_outof_framesize(int framesize)
 }
 
 inline static int
-qeth_get_buffersize_for_card(int cardtype)
+qeth_mtu_is_valid(struct qeth_card * card, int mtu)
 {
-       switch (cardtype) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return 65536;
+       switch (card->info.type) {
        case QETH_CARD_TYPE_OSAE:
-               return 65536;
+               return ((mtu >= 576) && (mtu <= 61440));
        case QETH_CARD_TYPE_IQD:
-               return 16384;
+               return ((mtu >= 576) && 
+                       (mtu <= card->info.max_mtu + 4096 - 32));
+       case QETH_CARD_TYPE_UNKNOWN:
        default:
-               return 65536;
+               return 1;
        }
 }
 
 inline static int
-qeth_get_min_number_of_buffers(int cardtype)
+qeth_get_arphdr_type(int cardtype, int linktype)
 {
        switch (cardtype) {
-       case QETH_CARD_TYPE_UNKNOWN:
-               return 32;
        case QETH_CARD_TYPE_OSAE:
-               return 32;
+               switch (linktype) {
+               case QETH_LINK_TYPE_LANE_TR:
+               case QETH_LINK_TYPE_HSTR:
+                       return ARPHRD_IEEE802_TR;
+               default:
+                       return ARPHRD_ETHER;
+               }
        case QETH_CARD_TYPE_IQD:
-               return 64;
        default:
-               return 64;
+               return ARPHRD_ETHER;
        }
 }
 
+#ifdef CONFIG_QETH_PERF_STATS 
 inline static int
-qeth_get_q_format(int cardtype)
+qeth_get_micros(void)
 {
-       switch (cardtype) {
+       return (int) (get_clock() >> 12);
+}
+#endif
+
+static inline int
+qeth_get_qdio_q_format(struct qeth_card *card)
+{
+       switch (card->info.type) {
        case QETH_CARD_TYPE_IQD:
                return 2;
        default:
@@ -1235,100 +888,120 @@ qeth_get_q_format(int cardtype)
        }
 }
 
-inline static int
-qeth_get_device_tx_q_len(int cardtype)
+static inline void
+qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
 {
-       return 100;
+       sprintf(buf, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
 }
 
-inline static int
-qeth_get_max_number_of_buffers(int cardtype)
+static inline int
+qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
 {
-       return 127;
+       const char *start, *end;
+       char abuf[4];
+       char *tmp;
+       int len;
+       int i;
+
+       start = buf;
+       for (i = 0; i < 3; i++) {
+               if (!(end = strchr(start, '.')))
+                       return -EINVAL;
+               len = end - start;
+               memset(abuf, 0, 4);
+               strncpy(abuf, start, len);
+               addr[i] = simple_strtoul(abuf, &tmp, 10);
+               start = end + 1;
+       }
+       memset(abuf, 0, 4);
+       strcpy(abuf, start);
+       addr[3] = simple_strtoul(abuf, &tmp, 10);
+       return 0;
 }
 
-/******************** OUTPUT FACILITIES **************************/
-
-#ifdef PRINT_INFO
-#undef PRINTK_HEADER
-#undef PRINT_STUPID
-#undef PRINT_ALL
-#undef PRINT_INFO
-#undef PRINT_WARN
-#undef PRINT_ERR
-#undef PRINT_CRIT
-#undef PRINT_ALERT
-#undef PRINT_EMERG
-#endif                         /* PRINT_INFO */
+static inline void
+qeth_ipaddr6_to_string(const __u8 *addr, char *buf)
+{
+       sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
+                    ":%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+                    addr[0], addr[1], addr[2], addr[3],
+                    addr[4], addr[5], addr[6], addr[7],
+                    addr[8], addr[9], addr[10], addr[11],
+                    addr[12], addr[13], addr[14], addr[15]);
+}
 
-#define PRINTK_HEADER QETH_NAME ": "
+static inline int
+qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
+{
+       const char *start, *end;
+       u16 *tmp_addr;
+       char abuf[5];
+       char *tmp;
+       int len;
+       int i;
+
+       tmp_addr = (u16 *)addr;
+       start = buf;
+       for (i = 0; i < 7; i++) {
+               if (!(end = strchr(start, ':')))
+                       return -EINVAL;
+               len = end - start;
+               memset(abuf, 0, 5);
+               strncpy(abuf, start, len);
+               tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
+               start = end + 1;
+       }
+       memset(abuf, 0, 5);
+       strcpy(abuf, start);
+       tmp_addr[7] = simple_strtoul(abuf, &tmp, 16);
+       return 0;
+}
 
-#if QETH_VERBOSE_LEVEL>8
-#define PRINT_STUPID(x...) printk( KERN_DEBUG PRINTK_HEADER x)
-#else
-#define PRINT_STUPID(x...)
-#endif
+static inline void
+qeth_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
+                     char *buf)
+{
+       if (proto == QETH_PROT_IPV4)
+               return qeth_ipaddr4_to_string(addr, buf);
+       else if (proto == QETH_PROT_IPV6)
+               return qeth_ipaddr6_to_string(addr, buf);
+}
 
-#if QETH_VERBOSE_LEVEL>7
-#define PRINT_ALL(x...) printk( KERN_DEBUG PRINTK_HEADER x)
-#else
-#define PRINT_ALL(x...)
-#endif
+static inline int
+qeth_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto,
+                     __u8 *addr)
+{
+       if (proto == QETH_PROT_IPV4)
+               return qeth_string_to_ipaddr4(buf, addr);
+       else if (proto == QETH_PROT_IPV6)
+               return qeth_string_to_ipaddr6(buf, addr);
+       else
+               return -EINVAL;
+}
 
-#if QETH_VERBOSE_LEVEL>6
-#define PRINT_INFO(x...) printk( KERN_INFO PRINTK_HEADER x)
-#else
-#define PRINT_INFO(x...)
-#endif
+extern int
+qeth_setrouting_v4(struct qeth_card *);
+extern int
+qeth_setrouting_v6(struct qeth_card *);
 
-#if QETH_VERBOSE_LEVEL>5
-#define PRINT_WARN(x...) printk( KERN_WARNING PRINTK_HEADER x)
-#else
-#define PRINT_WARN(x...)
-#endif
+int
+qeth_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *);
 
-#if QETH_VERBOSE_LEVEL>4
-#define PRINT_ERR(x...) printk( KERN_ERR PRINTK_HEADER x)
-#else
-#define PRINT_ERR(x...)
-#endif
+void
+qeth_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions, u8 *, int);
 
-#if QETH_VERBOSE_LEVEL>3
-#define PRINT_CRIT(x...) printk( KERN_CRIT PRINTK_HEADER x)
-#else
-#define PRINT_CRIT(x...)
-#endif
+int
+qeth_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
 
-#if QETH_VERBOSE_LEVEL>2
-#define PRINT_ALERT(x...) printk( KERN_ALERT PRINTK_HEADER x)
-#else
-#define PRINT_ALERT(x...)
-#endif
+void
+qeth_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
 
-#if QETH_VERBOSE_LEVEL>1
-#define PRINT_EMERG(x...) printk( KERN_EMERG PRINTK_HEADER x)
-#else
-#define PRINT_EMERG(x...)
-#endif
+int
+qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
 
-#define HEXDUMP16(importance,header,ptr) \
-PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
-                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
-                  *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
-                  *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
-                  *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
-                  *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
-                  *(((char*)ptr)+12),*(((char*)ptr)+13), \
-                  *(((char*)ptr)+14),*(((char*)ptr)+15)); \
-PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
-                  "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
-                  *(((char*)ptr)+16),*(((char*)ptr)+17), \
-                  *(((char*)ptr)+18),*(((char*)ptr)+19), \
-                  *(((char*)ptr)+20),*(((char*)ptr)+21), \
-                  *(((char*)ptr)+22),*(((char*)ptr)+23), \
-                  *(((char*)ptr)+24),*(((char*)ptr)+25), \
-                  *(((char*)ptr)+26),*(((char*)ptr)+27), \
-                  *(((char*)ptr)+28),*(((char*)ptr)+29), \
-                  *(((char*)ptr)+30),*(((char*)ptr)+31));
+void
+qeth_del_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
 
+void
+qeth_schedule_recovery(struct qeth_card *);
 #endif /* __QETH_H__ */
diff --git a/drivers/s390/net/qeth_fs.h b/drivers/s390/net/qeth_fs.h
new file mode 100644 (file)
index 0000000..030aa6a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * linux/drivers/s390/net/qeth_fs.h
+ *
+ * Linux on zSeries OSA Express and HiperSockets support.
+ *
+ * This header file contains definitions related to sysfs and procfs.
+ *
+ * Copyright 2000,2003 IBM Corporation
+ * Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ */
+#ifndef __QETH_FS_H__
+#define __QETH_FS_H__
+
+#ifdef CONFIG_PROC_FS
+extern int
+qeth_create_procfs_entries(void);
+
+extern void
+qeth_remove_procfs_entries(void);
+#else
+static inline int
+qeth_create_procfs_entries(void)
+{
+       return 0;
+}
+
+static inline void
+qeth_remove_procfs_entries(void)
+{
+}
+#endif /* CONFIG_PROC_FS */
+
+extern int
+qeth_create_device_attributes(struct device *dev);
+
+extern void
+qeth_remove_device_attributes(struct device *dev);
+
+extern int
+qeth_create_driver_attributes(void);
+
+extern void
+qeth_remove_driver_attributes(void);
+
+/*
+ * utility functions used in qeth_proc.c and qeth_sys.c
+ */
+
+static inline const char *
+qeth_get_checksum_str(struct qeth_card *card)
+{
+       if (card->options.checksum_type == SW_CHECKSUMMING)
+               return "sw";
+       else if (card->options.checksum_type == HW_CHECKSUMMING)
+               return "hw";
+       else
+               return "no";
+}
+
+static inline const char *
+qeth_get_prioq_str(struct qeth_card *card, char *buf)
+{
+       if (card->qdio.do_prio_queueing == QETH_NO_PRIO_QUEUEING)
+               sprintf(buf, "always_q_%i", card->qdio.default_out_queue);
+       else
+               strcpy(buf, (card->qdio.do_prio_queueing ==
+                                       QETH_PRIO_Q_ING_PREC)?
+                               "by_prec." : "by_ToS");
+       return buf;
+}
+
+static inline const char *
+qeth_get_bufsize_str(struct qeth_card *card)
+{
+       if (card->qdio.in_buf_size == 16384)
+               return "16k";
+       else if (card->qdio.in_buf_size == 24576)
+               return "24k";
+       else if (card->qdio.in_buf_size == 32768)
+               return "32k";
+       else if (card->qdio.in_buf_size == 40960)
+               return "40k";
+       else
+               return "64k";
+}
+
+static inline const char *
+qeth_get_cardname(struct qeth_card *card)
+{
+       if (card->info.guestlan) {
+               switch (card->info.type) {
+               case QETH_CARD_TYPE_OSAE:
+                       return " Guest LAN QDIO";
+               case QETH_CARD_TYPE_IQD:
+                       return " Guest LAN Hiper";
+               default:
+                       return " unknown";
+               }
+       } else {
+               switch (card->info.type) {
+               case QETH_CARD_TYPE_OSAE:
+                       return " OSD Express";
+               case QETH_CARD_TYPE_IQD:
+                       return " HiperSockets";
+               default:
+                       return " unknown";
+               }
+       }
+       return " n/a";
+}
+
+/* max length to be returned: 14 */
+static inline const char *
+qeth_get_cardname_short(struct qeth_card *card)
+{
+       if (card->info.guestlan){
+               switch (card->info.type){
+               case QETH_CARD_TYPE_OSAE:
+                       return "GuestLAN QDIO";
+               case QETH_CARD_TYPE_IQD:
+                       return "GuestLAN Hiper";
+               default:
+                       return "unknown";
+               }
+       } else {
+               switch (card->info.type) {
+               case QETH_CARD_TYPE_OSAE:
+                       switch (card->info.link_type) {
+                       case QETH_LINK_TYPE_FAST_ETH:
+                               return "OSD_100";
+                       case QETH_LINK_TYPE_HSTR:
+                               return "HSTR";
+                       case QETH_LINK_TYPE_GBIT_ETH:
+                               return "OSD_1000";
+                       case QETH_LINK_TYPE_LANE_ETH100:
+                               return "OSD_FE_LANE";
+                       case QETH_LINK_TYPE_LANE_TR:
+                               return "OSD_TR_LANE";
+                       case QETH_LINK_TYPE_LANE_ETH1000:
+                               return "OSD_GbE_LANE";
+                       case QETH_LINK_TYPE_LANE:
+                               return "OSD_ATM_LANE";
+                       default:
+                               return "OSD_Express";
+                       }
+               case QETH_CARD_TYPE_IQD:
+                       return "HiperSockets";
+               default:
+                       return "unknown";
+               }
+       }
+       return "n/a";
+}
+
+#endif /* __QETH_FS_H__ */
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
new file mode 100644 (file)
index 0000000..027344d
--- /dev/null
@@ -0,0 +1,6820 @@
+/*
+ * 
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.77 $)
+ *
+ * Linux on zSeries OSA Express and HiperSockets support
+ *
+ * Copyright 2000,2003 IBM Corporation
+ *     
+ *    Author(s): Original Code written by
+ *                       Utz Bacher (utz.bacher@de.ibm.com)
+ *              Rewritten by
+ *                       Frank Pavlic (pavlic@de.ibm.com) and
+ *                       Thomas Spatzier <tspat@de.ibm.com>
+ *
+ *    $Revision: 1.77 $         $Date: 2004/04/06 14:38:19 $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/***
+ * eye catcher; just for debugging purposes
+ */
+void volatile
+qeth_eyecatcher(void)
+{
+       return;
+}
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/ebcdic.h>
+#include <linux/ctype.h>
+#include <asm/semaphore.h>
+#include <asm/timex.h>
+#include <linux/ip.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/tcp.h>
+#include <linux/icmp.h>
+#include <linux/skbuff.h>
+#include <net/route.h>
+#include <net/arp.h>
+#include <linux/in.h>
+#include <linux/igmp.h>
+#include <net/ip.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <asm/qeth.h>
+#include <linux/mii.h>
+
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_fs.h"
+
+#define VERSION_QETH_C "$Revision: 1.77 $"
+static const char *version = "qeth S/390 OSA-Express driver ("
+       VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H
+       QETH_VERSION_IPV6 QETH_VERSION_VLAN ")";
+/**
+ * Debug Facility Stuff
+ */
+static debug_info_t *qeth_dbf_setup = NULL;
+static debug_info_t *qeth_dbf_data = NULL;
+static debug_info_t *qeth_dbf_misc = NULL;
+static debug_info_t *qeth_dbf_control = NULL;
+static debug_info_t *qeth_dbf_trace = NULL;
+static debug_info_t *qeth_dbf_sense = NULL;
+static debug_info_t *qeth_dbf_qerr = NULL;
+static char qeth_dbf_text_buf[255];
+
+/**
+ * some more definitions and declarations
+ */
+static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
+
+/* list of our cards */
+struct qeth_card_list_struct qeth_card_list;
+
+static void qeth_send_control_data_cb(struct qeth_channel *,
+                                     struct qeth_cmd_buffer *); 
+
+static atomic_t qeth_hsi_count;
+
+/**
+ * here we go with function implementation
+ */
+static void
+qeth_init_qdio_info(struct qeth_card *card);
+
+static int
+qeth_init_qdio_queues(struct qeth_card *card);
+
+static int
+qeth_alloc_qdio_buffers(struct qeth_card *card);
+
+static void
+qeth_free_qdio_buffers(struct qeth_card *);
+
+static void
+qeth_clear_qdio_buffers(struct qeth_card *);
+
+static void
+qeth_clear_ip_list(struct qeth_card *, int, int);
+
+static void
+qeth_clear_ipacmd_list(struct qeth_card *);
+
+static int
+qeth_qdio_clear_card(struct qeth_card *, int);
+
+static void
+qeth_clear_working_pool_list(struct qeth_card *);
+
+static void
+qeth_clear_cmd_buffers(struct qeth_channel *);
+
+static int
+qeth_stop(struct net_device *);
+
+static void
+qeth_clear_ipato_list(struct qeth_card *);
+
+static int
+qeth_is_addr_covered_by_ipato(struct qeth_card *, struct qeth_ipaddr *);
+
+static void
+qeth_irq_tasklet(unsigned long);
+
+static int 
+qeth_set_online(struct ccwgroup_device *);
+/**
+ * free channel command buffers
+ */ 
+static void
+qeth_clean_channel(struct qeth_channel *channel)
+{
+       int cnt;
+       
+       QETH_DBF_TEXT(setup, 2, "freech");
+       for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
+               kfree(channel->iob[cnt].data);
+}
+
+/**
+ * free card 
+ */
+static void
+qeth_free_card(struct qeth_card *card) 
+{
+       
+       QETH_DBF_TEXT(setup, 2, "freecrd");
+       QETH_DBF_HEX(setup, 2, &card, sizeof(void *));
+       qeth_clean_channel(&card->read);
+       qeth_clean_channel(&card->write);
+       if (card->dev)
+               free_netdev(card->dev);
+       qeth_clear_ip_list(card, 0, 0);
+       qeth_clear_ipato_list(card);
+       qeth_free_qdio_buffers(card);
+       kfree(card);
+}
+
+/**
+ * alloc memory for command buffer per channel
+ */
+static int
+qeth_setup_channel(struct qeth_channel *channel)
+{
+       int cnt;
+       
+       QETH_DBF_TEXT(setup, 2, "setupch");
+       for (cnt=0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
+               channel->iob[cnt].data = (char *)
+                       kmalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
+               if (channel->iob[cnt].data == NULL)
+                       break;
+               channel->iob[cnt].state = BUF_STATE_FREE;
+               channel->iob[cnt].channel = channel;
+               channel->iob[cnt].callback = qeth_send_control_data_cb;
+               channel->iob[cnt].rc = 0;
+       }
+       if (cnt < QETH_CMD_BUFFER_NO) {
+               while (cnt-- > 0) 
+                       kfree(channel->iob[cnt].data);
+               return -ENOMEM;
+       }
+       channel->buf_no = 0;
+       channel->io_buf_no = 0;
+       atomic_set(&channel->irq_pending, 0);
+       spin_lock_init(&channel->iob_lock);
+
+       init_waitqueue_head(&channel->wait_q);
+       channel->irq_tasklet.data = (unsigned long) channel;
+       channel->irq_tasklet.func = qeth_irq_tasklet;
+       return 0;
+}
+
+/**
+ * alloc memory for card structure
+ */ 
+static struct qeth_card *
+qeth_alloc_card(void)
+{
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(setup, 2, "alloccrd");
+       card = (struct qeth_card *) kmalloc(sizeof(struct qeth_card),
+                                           GFP_DMA|GFP_KERNEL);
+       if (!card)
+               return NULL;
+       QETH_DBF_HEX(setup, 2, &card, sizeof(void *));
+       memset(card, 0, sizeof(struct qeth_card));
+       if (qeth_setup_channel(&card->read)) { 
+               kfree(card);
+               return NULL;
+       }
+       if (qeth_setup_channel(&card->write)) {
+               qeth_clean_channel(&card->read);        
+               kfree(card);
+               return NULL;
+       }
+       return card;
+}
+
+static long
+__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
+{
+       if (!IS_ERR(irb))
+               return 0;
+
+       switch (PTR_ERR(irb)) {
+       case -EIO:
+               PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+               QETH_DBF_TEXT(trace, 2, "ckirberr");
+               QETH_DBF_TEXT_(trace, 2, "  rc%d", -EIO);
+               break;
+       case -ETIMEDOUT:
+               PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+               QETH_DBF_TEXT(trace, 2, "ckirberr");
+               QETH_DBF_TEXT_(trace, 2, "  rc%d", -ETIMEDOUT);
+               break;
+       default:
+               PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
+                          cdev->dev.bus_id);
+               QETH_DBF_TEXT(trace, 2, "ckirberr");
+               QETH_DBF_TEXT(trace, 2, "  rc???");
+       }
+       return PTR_ERR(irb);
+}
+
+static int 
+qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
+{
+       int dstat,cstat;
+       char *sense;
+       
+       sense = (char *) irb->ecw;
+       cstat = irb->scsw.cstat;
+       dstat = irb->scsw.dstat;
+       
+       if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
+                    SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
+                    SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
+               QETH_DBF_TEXT(trace,2, "CGENCHK");
+               PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ",
+                          cdev->dev.bus_id, dstat, cstat);
+               HEXDUMP16(WARN, "irb: ", irb);
+               HEXDUMP16(WARN, "irb: ", ((char *) irb) + 32);
+               return 1;
+       }
+
+       if (dstat & DEV_STAT_UNIT_CHECK) {
+               if (sense[SENSE_RESETTING_EVENT_BYTE] &
+                   SENSE_RESETTING_EVENT_FLAG) {
+                       QETH_DBF_TEXT(trace,2,"REVIND");
+                       return 1;
+               }
+               if (sense[SENSE_COMMAND_REJECT_BYTE] &
+                   SENSE_COMMAND_REJECT_FLAG) {
+                       QETH_DBF_TEXT(trace,2,"CMDREJi");
+                       return 0;
+               }
+               if ((sense[2] == 0xaf) && (sense[3] == 0xfe)) {
+                       QETH_DBF_TEXT(trace,2,"AFFE");
+                       return 1;
+               }
+               if ((!sense[0]) && (!sense[1]) && (!sense[2]) && (!sense[3])) {
+                       QETH_DBF_TEXT(trace,2,"ZEROSEN");
+                       return 0;
+               }
+               QETH_DBF_TEXT(trace,2,"DGENCHK");
+                       return 1;
+       }
+       return 0;
+}
+static int qeth_issue_next_read(struct qeth_card *);
+
+/**
+ * interrupt handler
+ */
+static void
+qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
+{
+       int rc;
+       int cstat,dstat;
+       struct qeth_cmd_buffer *buffer;
+       struct qeth_channel *channel;
+       struct qeth_card *card;
+
+       QETH_DBF_TEXT(trace,5,"irq");
+
+       if (__qeth_check_irb_error(cdev, irb))
+               return;
+       cstat = irb->scsw.cstat;
+       dstat = irb->scsw.dstat;
+
+       card = CARD_FROM_CDEV(cdev);
+       if (!card)
+               return;
+       
+       if (card->read.ccwdev == cdev){
+               channel = &card->read;
+               QETH_DBF_TEXT(trace,5,"read");
+       } else if (card->write.ccwdev == cdev) {
+               channel = &card->write;
+               QETH_DBF_TEXT(trace,5,"write");
+       } else { 
+               channel = &card->data;
+               QETH_DBF_TEXT(trace,5,"data");
+       }
+       atomic_set(&channel->irq_pending, 0);
+       
+       if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC))
+               channel->state = CH_STATE_STOPPED;
+
+       if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC))
+               channel->state = CH_STATE_HALTED;
+
+       /*let's wake up immediately on data channel*/
+       if ((channel == &card->data) && (intparm != 0))
+               goto out;
+
+       if (intparm == QETH_CLEAR_CHANNEL_PARM) {
+               QETH_DBF_TEXT(trace, 6, "clrchpar");
+               /* we don't have to handle this further */
+               intparm = 0;
+       }
+       if (intparm == QETH_HALT_CHANNEL_PARM) {
+               QETH_DBF_TEXT(trace, 6, "hltchpar");
+               /* we don't have to handle this further */
+               intparm = 0;
+       }
+       if ((dstat & DEV_STAT_UNIT_EXCEP) || 
+           (dstat & DEV_STAT_UNIT_CHECK) ||
+           (cstat)) {
+               if (irb->esw.esw0.erw.cons) { 
+                       /* TODO: we should make this s390dbf */
+                       PRINT_WARN("sense data available on channel %s.\n",
+                                  CHANNEL_ID(channel));
+                       PRINT_WARN(" cstat 0x%X\n dstat 0x%X\n", cstat, dstat);
+                       HEXDUMP16(WARN,"irb: ",irb);
+                       HEXDUMP16(WARN,"sense data: ",irb->ecw);
+               }
+               rc = qeth_get_problem(cdev,irb);
+               if (rc) {
+                       qeth_schedule_recovery(card);
+                       goto out;
+               }
+       }
+       
+       if (intparm) {
+               buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
+               buffer->state = BUF_STATE_PROCESSED;
+       }
+       if (channel == &card->data)
+               return;
+
+       if (channel == &card->read &&
+           channel->state == CH_STATE_UP)
+               qeth_issue_next_read(card);
+       
+       tasklet_schedule(&channel->irq_tasklet);
+       return;
+out:
+       wake_up(&card->wait_q);
+}
+
+/**
+ * tasklet function scheduled from irq handler
+ */ 
+static void
+qeth_irq_tasklet(unsigned long data)
+{
+       struct qeth_card *card;
+       struct qeth_channel *channel;
+       struct qeth_cmd_buffer *iob;
+       __u8 index;
+       
+       QETH_DBF_TEXT(trace,5,"irqtlet");
+       channel = (struct qeth_channel *) data;
+       iob = channel->iob;
+       index = channel->buf_no;
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       while (iob[index].state == BUF_STATE_PROCESSED) {
+               if (iob[index].callback !=NULL) {
+                       iob[index].callback(channel,iob + index);
+               }
+               index = (index + 1) % QETH_CMD_BUFFER_NO;
+       }
+       channel->buf_no = index;
+       wake_up(&card->wait_q);
+}
+
+static int qeth_stop_card(struct qeth_card *);
+
+static int 
+qeth_set_offline(struct ccwgroup_device *cgdev) 
+{
+       struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
+       enum qeth_card_states recover_flag;
+       
+       QETH_DBF_TEXT(setup, 3, "setoffl");
+       QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
+
+       recover_flag = card->state;             
+       if (qeth_stop_card(card) == -ERESTARTSYS){
+               PRINT_WARN("Stopping card %s interrupted by user!\n",
+                          CARD_BUS_ID(card));
+               return -ERESTARTSYS;
+       }
+       ccw_device_set_offline(CARD_DDEV(card));
+       ccw_device_set_offline(CARD_WDEV(card));
+       ccw_device_set_offline(CARD_RDEV(card));
+       if ((recover_flag == CARD_STATE_UP_LAN_ONLINE) ||
+           (recover_flag == CARD_STATE_UP_LAN_OFFLINE))
+               card->state = CARD_STATE_RECOVER;
+       return 0;
+}
+
+static void 
+qeth_remove_device(struct ccwgroup_device *cgdev)
+{
+       struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;
+       unsigned long flags;
+       
+       QETH_DBF_TEXT(setup, 3, "rmdev");
+       QETH_DBF_HEX(setup, 3, &card, sizeof(void *));
+       
+       if (!card)
+               return;
+
+       if (cgdev->state == CCWGROUP_ONLINE){
+               card->use_hard_stop = 1;
+               qeth_set_offline(cgdev);
+       }
+       if (card->info.type == QETH_CARD_TYPE_IQD)
+               atomic_dec(&qeth_hsi_count);
+       /* remove form our internal list */
+       write_lock_irqsave(&qeth_card_list.rwlock, flags);
+       list_del(&card->list);
+       write_unlock_irqrestore(&qeth_card_list.rwlock, flags);
+       unregister_netdev(card->dev);
+       qeth_free_card(card);
+       cgdev->dev.driver_data = NULL;
+       put_device(&cgdev->dev);
+}
+
+static int 
+qeth_register_addr_entry(struct qeth_card *, struct qeth_ipaddr *);
+static int 
+qeth_deregister_addr_entry(struct qeth_card *, struct qeth_ipaddr *);
+
+/**
+ * Add/remove address to/from card's ip list, i.e. try to add or remove 
+ * reference to/from an IP address that is already registered on the card.
+ * Returns:
+ *     0  address was on card and its reference count has been adjusted,
+ *        but is still > 0, so nothing has to be done
+ *        also returns 0 if card was not on card and the todo was to delete
+ *        the address -> there is also nothing to be done
+ *     1  address was not on card and the todo is to add it to the card's ip
+ *        list
+ *     -1 address was on card and its reference count has been decremented
+ *        to <= 0 by the todo -> address must be removed from card
+ */
+static int
+__qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
+                     struct qeth_ipaddr **__addr)
+{
+       struct qeth_ipaddr *addr;
+       int found = 0;
+
+       list_for_each_entry(addr, &card->ip_list, entry) {
+               if ((addr->proto     == QETH_PROT_IPV4)  &&
+                   (todo->proto     == QETH_PROT_IPV4)  &&
+                   (addr->type      == todo->type)      &&
+                   (addr->u.a4.addr == todo->u.a4.addr) && 
+                   (addr->u.a4.mask == todo->u.a4.mask)   ){
+                       found = 1;
+                       break;
+               }
+               if ((addr->proto       == QETH_PROT_IPV6)     &&
+                   (todo->proto       == QETH_PROT_IPV6)     &&
+                   (addr->type        == todo->type)         &&
+                   (addr->u.a6.pfxlen == todo->u.a6.pfxlen)  &&
+                   (memcmp(&addr->u.a6.addr, &todo->u.a6.addr,
+                           sizeof(struct in6_addr)) == 0))     {
+                       found = 1;
+                       break;
+               }
+       }
+       if (found){
+               addr->users += todo->users;
+               if (addr->users <= 0){
+                       *__addr = addr;
+                       return -1;
+               } else {
+                       /* for VIPA and RXIP limit refcount to 1 */
+                       if (addr->type != QETH_IP_TYPE_NORMAL)
+                               addr->users = 1;
+                       return 0;
+               }
+       }
+       if (todo->users > 0){
+               /* for VIPA and RXIP limit refcount to 1 */
+               if (todo->type != QETH_IP_TYPE_NORMAL)
+                       addr->users = 1;
+               return 1;
+       } else
+               return 0;
+}
+
+static inline int
+__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
+                             int same_type)
+{
+       struct qeth_ipaddr *tmp;
+
+       list_for_each_entry(tmp, list, entry) {
+               if ((tmp->proto     == QETH_PROT_IPV4)            &&
+                   (addr->proto    == QETH_PROT_IPV4)            &&
+                   ((same_type && (tmp->type == addr->type)) ||
+                    (!same_type && (tmp->type != addr->type))  ) &&
+                   (tmp->u.a4.addr == addr->u.a4.addr)             ){
+                       return 1;
+               }
+               if ((tmp->proto  == QETH_PROT_IPV6)               &&
+                   (addr->proto == QETH_PROT_IPV6)               &&
+                   ((same_type && (tmp->type == addr->type)) ||
+                    (!same_type && (tmp->type != addr->type))  ) &&
+                   (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
+                           sizeof(struct in6_addr)) == 0)          ) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Add IP to be added to todo list. If there is already an "add todo"
+ * in this list we just incremenent the reference count.
+ * Returns 0 if we  just incremented reference count.
+ */
+static int
+__qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
+{
+       struct qeth_ipaddr *tmp, *t;
+       int found = 0;
+
+       list_for_each_entry_safe(tmp, t, &card->ip_tbd_list, entry) {
+               if ((tmp->proto        == QETH_PROT_IPV4)     &&
+                   (addr->proto       == QETH_PROT_IPV4)     &&
+                   (tmp->type         == addr->type)         &&
+                   (tmp->is_multicast == addr->is_multicast) &&
+                   (tmp->u.a4.addr    == addr->u.a4.addr)    && 
+                   (tmp->u.a4.mask    == addr->u.a4.mask)      ){
+                       found = 1;
+                       break;
+               }
+               if ((tmp->proto        == QETH_PROT_IPV6)      &&
+                   (addr->proto       == QETH_PROT_IPV6)      &&
+                   (tmp->type         == addr->type)          &&
+                   (tmp->is_multicast == addr->is_multicast)  &&
+                   (tmp->u.a6.pfxlen  == addr->u.a6.pfxlen)   &&
+                   (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,
+                           sizeof(struct in6_addr)) == 0)        ){
+                       found = 1;
+                       break;
+               }
+       }
+       if (found){
+               if (addr->users != 0)
+                       tmp->users += addr->users;
+               else
+                       tmp->users += add? 1:-1;
+               if (tmp->users == 0){
+                       list_del(&tmp->entry);
+                       kfree(tmp);
+               }
+               return 0;
+       } else {
+               if (addr->users == 0)
+                       addr->users += add? 1:-1;
+               if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&
+                   qeth_is_addr_covered_by_ipato(card, addr)){
+                       QETH_DBF_TEXT(trace, 2, "tkovaddr");
+                       addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;
+               }
+               list_add_tail(&addr->entry, &card->ip_tbd_list);
+               return 1;
+       }
+}
+
+/**
+ * Remove IP address from list
+ */ 
+static int
+qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
+{
+       unsigned long flags;
+       int rc = 0;
+       
+       QETH_DBF_TEXT(trace,4,"delip");
+       if (addr->proto == QETH_PROT_IPV4)
+               QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+       else {
+               QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4);
+               QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4);
+       }
+       spin_lock_irqsave(&card->ip_lock, flags);
+       rc = __qeth_insert_ip_todo(card, addr, 0);
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       return rc;
+}
+
+static int
+qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) 
+{
+       unsigned long flags;
+       int rc = 0;
+       
+       QETH_DBF_TEXT(trace,4,"addip");
+       if (addr->proto == QETH_PROT_IPV4)
+               QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
+       else {
+               QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4);
+               QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4);
+       }
+       spin_lock_irqsave(&card->ip_lock, flags);
+       rc = __qeth_insert_ip_todo(card, addr, 1);
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       return rc;
+}
+
+static void
+qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos)
+{
+       struct qeth_ipaddr *todo, *tmp;
+
+       list_for_each_entry_safe(todo, tmp, todos, entry){
+               list_del_init(&todo->entry);
+               if (todo->users < 0) {
+                       if (!qeth_delete_ip(card, todo))
+                               kfree(todo);
+               } else {
+                       if (!qeth_add_ip(card, todo))
+                               kfree(todo);
+               }
+       }
+}
+
+static void
+qeth_set_ip_addr_list(struct qeth_card *card) 
+{
+       struct list_head failed_todos;
+       struct qeth_ipaddr *todo, *addr, *tmp;
+       unsigned long flags;
+       int rc;
+
+       QETH_DBF_TEXT(trace, 2, "sdiplist");
+       QETH_DBF_HEX(trace, 2, &card, sizeof(void *));
+
+       INIT_LIST_HEAD(&failed_todos);
+
+process_todos:
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry_safe(todo, tmp, &card->ip_tbd_list, entry) {
+               list_del_init(&todo->entry);
+               rc = __qeth_ref_ip_on_card(card, todo, &addr);
+               if (rc == 0) {
+                       /* nothing to be done; only adjusted refcount */
+                       kfree(todo);
+               } else if (rc == 1) {
+                       /* new entry to be added to on-card list */
+                       spin_unlock_irqrestore(&card->ip_lock, flags);
+                       rc = qeth_register_addr_entry(card, todo);
+                       if (!rc){
+                               spin_lock_irqsave(&card->ip_lock, flags);
+                               list_add_tail(&todo->entry, &card->ip_list);
+                               spin_unlock_irqrestore(&card->ip_lock, flags);
+                       } else
+                               list_add_tail(&todo->entry, &failed_todos);
+                       goto process_todos;
+               } else if (rc == -1) {
+                       /* on-card entry to be removed */
+                       list_del_init(&addr->entry);
+                       spin_unlock_irqrestore(&card->ip_lock, flags);
+                       rc = qeth_deregister_addr_entry(card, addr);
+                       if (!rc) {
+                               kfree(addr);
+                               kfree(todo);
+                       } else {
+                               spin_lock_irqsave(&card->ip_lock, flags);
+                               list_add_tail(&addr->entry, &card->ip_list);
+                               list_add_tail(&todo->entry, &failed_todos);
+                               spin_unlock_irqrestore(&card->ip_lock, flags);
+                       }
+                       goto process_todos;
+               }
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       qeth_reinsert_todos(card, &failed_todos);
+}
+
+static void qeth_delete_mc_addresses(struct qeth_card *);
+static void qeth_add_multicast_ipv4(struct qeth_card *);
+#ifdef CONFIG_QETH_IPV6
+static void qeth_add_multicast_ipv6(struct qeth_card *);
+#endif
+
+static void
+qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       card->thread_start_mask |= thread;
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+}
+
+static void
+qeth_clear_thread_start_bit(struct qeth_card *card, unsigned long thread)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       card->thread_start_mask &= ~thread;
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       wake_up(&card->wait_q);
+}
+
+static void
+qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       card->thread_running_mask &= ~thread;
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       wake_up(&card->wait_q);
+}
+
+static inline int
+__qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       if (card->thread_start_mask & thread){
+               if ((card->thread_allowed_mask & thread) &&
+                   !(card->thread_running_mask & thread)){
+                       rc = 1;
+                       card->thread_start_mask &= ~thread;
+                       card->thread_running_mask |= thread;
+               } else
+                       rc = -EPERM;
+       }
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       return rc;
+}
+
+static int
+qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
+{
+       int rc = 0;
+
+       wait_event(card->wait_q,
+                  (rc = __qeth_do_run_thread(card, thread)) >= 0);
+       return rc;
+}
+
+static int
+qeth_register_mc_addresses(void *ptr)
+{
+       struct qeth_card *card;
+
+       card = (struct qeth_card *) ptr;
+       daemonize("getmcaddr");
+       QETH_DBF_TEXT(trace,4,"regmcth1");
+       if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD))
+               return 0;
+       QETH_DBF_TEXT(trace,4,"regmcth2");
+       qeth_delete_mc_addresses(card);
+       qeth_add_multicast_ipv4(card);
+#ifdef CONFIG_QETH_IPV6
+       qeth_add_multicast_ipv6(card);
+#endif
+       qeth_set_ip_addr_list(card);
+       qeth_clear_thread_running_bit(card, QETH_SET_MC_THREAD);
+       return 0;
+}
+
+static int 
+qeth_register_ip_address(void *ptr)
+{
+       struct qeth_card *card;
+
+       card = (struct qeth_card *) ptr;
+       daemonize("regip");
+       QETH_DBF_TEXT(trace,4,"regipth1");
+       if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))
+               return 0;
+       QETH_DBF_TEXT(trace,4,"regipth2");
+       qeth_set_ip_addr_list(card);
+       qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD);
+       return 0;
+}
+
+static int
+qeth_recover(void *ptr)
+{
+       struct qeth_card *card;
+       int rc = 0;
+       
+       card = (struct qeth_card *) ptr;
+       daemonize("recover");
+       QETH_DBF_TEXT(trace,2,"recover1");
+       QETH_DBF_HEX(trace, 2, &card, sizeof(void *));
+       if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
+               return 0;
+       QETH_DBF_TEXT(trace,2,"recover2");
+       PRINT_WARN("Recovery of device %s started ...\n",
+                  CARD_BUS_ID(card));
+       card->use_hard_stop = 1;
+       qeth_set_offline(card->gdev);
+       rc = qeth_set_online(card->gdev);
+       if (!rc)
+               PRINT_INFO("Device %s successfully recovered!\n",
+                          CARD_BUS_ID(card));
+       else
+               PRINT_INFO("Device %s could not be recovered!\n",
+                          CARD_BUS_ID(card));
+       /* don't run another scheduled recovery */
+       qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
+       qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
+       return 0;
+}
+
+void
+qeth_schedule_recovery(struct qeth_card *card)
+{
+       QETH_DBF_TEXT(trace,2,"startrec");
+       
+       qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+
+static int
+qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       QETH_DBF_TEXT_(trace, 4, "  %02x%02x%02x",
+                       (u8) card->thread_start_mask,
+                       (u8) card->thread_allowed_mask,
+                       (u8) card->thread_running_mask);
+       rc = (card->thread_start_mask & thread);
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       return rc;
+}
+
+static void
+qeth_start_kernel_thread(struct qeth_card *card)
+{
+       QETH_DBF_TEXT(trace , 2, "strthrd");
+
+       if (card->read.state != CH_STATE_UP &&
+           card->write.state != CH_STATE_UP)
+               return;
+       
+       if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
+               kernel_thread(qeth_register_ip_address, (void *) card, SIGCHLD);
+       if (qeth_do_start_thread(card, QETH_SET_MC_THREAD))
+               kernel_thread(qeth_register_mc_addresses, (void *)card,SIGCHLD);
+       if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
+               kernel_thread(qeth_recover, (void *) card, SIGCHLD);
+}
+
+
+static void
+qeth_set_intial_options(struct qeth_card *card)
+{
+       card->options.route4.type = NO_ROUTER;
+#ifdef CONFIG_QETH_IPV6
+       card->options.route6.type = NO_ROUTER;
+#endif /* QETH_IPV6 */
+       card->options.checksum_type = QETH_CHECKSUM_DEFAULT;
+       card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
+       card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL;
+       card->options.enable_takeover = 1;
+       card->options.fake_broadcast = 0;
+       card->options.add_hhlen = DEFAULT_ADD_HHLEN;
+       card->options.fake_ll = 0;
+}
+
+/**
+ * initialize channels ,card and all state machines
+ */
+static int
+qeth_setup_card(struct qeth_card *card)
+{
+       
+       QETH_DBF_TEXT(setup, 2, "setupcrd");
+       QETH_DBF_HEX(setup, 2, &card, sizeof(void *));
+
+       card->read.state  = CH_STATE_DOWN;
+       card->write.state = CH_STATE_DOWN;
+       card->data.state  = CH_STATE_DOWN;
+       card->state = CARD_STATE_DOWN;
+       card->lan_online = 0;
+       card->use_hard_stop = 0;
+       card->dev = NULL;
+#ifdef CONFIG_QETH_VLAN
+       spin_lock_init(&card->vlanlock);
+       card->vlangrp = NULL;
+#endif
+       spin_lock_init(&card->ip_lock);
+       spin_lock_init(&card->thread_mask_lock);
+       card->thread_start_mask = 0;
+       card->thread_allowed_mask = 0;
+       card->thread_running_mask = 0;
+       INIT_WORK(&card->kernel_thread_starter,
+                 (void *)qeth_start_kernel_thread,card);
+       INIT_LIST_HEAD(&card->ip_list); 
+       INIT_LIST_HEAD(&card->ip_tbd_list);     
+       INIT_LIST_HEAD(&card->cmd_waiter_list); 
+       init_waitqueue_head(&card->wait_q);
+       /* intial options */
+       qeth_set_intial_options(card);
+       /* IP address takeover */
+       INIT_LIST_HEAD(&card->ipato.entries);
+       card->ipato.enabled = 0;
+       card->ipato.invert4 = 0;
+       card->ipato.invert6 = 0;
+       /* init QDIO stuff */
+       qeth_init_qdio_info(card);
+       return 0;
+}
+
+static int
+qeth_determine_card_type(struct qeth_card *card)
+{
+       int i = 0;
+
+       QETH_DBF_TEXT(setup, 2, "detcdtyp");
+       
+       while (known_devices[i][4]) {
+               if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
+                   (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
+                       card->info.type = known_devices[i][4];
+                       if (card->options.enable_takeover)
+                               card->info.func_level = known_devices[i][6];
+                       else
+                               card->info.func_level = known_devices[i][7];
+                       card->qdio.no_out_queues = known_devices[i][8];
+                       card->info.is_multicast_different = known_devices[i][9];
+                       return 0;
+               }
+               i++;
+       }
+       card->info.type = QETH_CARD_TYPE_UNKNOWN;
+       PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card));
+       return -ENOENT;
+}
+
+static int 
+qeth_probe_device(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card;
+       struct device *dev;
+       unsigned long flags;
+       int rc;
+       
+       QETH_DBF_TEXT(setup, 2, "probedev");
+
+       dev = &gdev->dev;
+       if (!get_device(dev))
+               return -ENODEV;
+
+       card = qeth_alloc_card();
+       if (!card) {
+               put_device(dev);
+               QETH_DBF_TEXT_(setup, 2, "1err%d", -ENOMEM);
+               return -ENOMEM;
+       }
+       if ((rc = qeth_setup_card(card))){
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               put_device(dev);
+               qeth_free_card(card);
+               return rc;
+       }
+       gdev->dev.driver_data = card;
+       card->gdev = gdev;
+       gdev->cdev[0]->handler = qeth_irq;
+       gdev->cdev[1]->handler = qeth_irq;
+       gdev->cdev[2]->handler = qeth_irq;
+
+       rc = qeth_create_device_attributes(dev);
+       if (rc) {
+               put_device(dev);
+               qeth_free_card(card);
+               return rc;
+       }
+       card->read.ccwdev  = gdev->cdev[0];
+       card->write.ccwdev = gdev->cdev[1];
+       card->data.ccwdev  = gdev->cdev[2];
+       if ((rc = qeth_determine_card_type(card))){
+               PRINT_WARN("%s: not a valid card type\n", __func__);
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+               put_device(dev);
+               qeth_free_card(card);
+               return rc;
+       }
+       /* insert into our internal list */
+       write_lock_irqsave(&qeth_card_list.rwlock, flags);
+       list_add_tail(&card->list, &qeth_card_list.list);
+       write_unlock_irqrestore(&qeth_card_list.rwlock, flags);
+       return rc;
+}
+
+
+static int
+qeth_get_unitaddr(struct qeth_card *card)
+{
+       int length;
+       char *prcd;
+       int rc;
+
+       QETH_DBF_TEXT(setup, 2, "getunit");
+       rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length);
+       if (rc) {
+               PRINT_ERR("read_conf_data for device %s returned %i\n",
+                         CARD_DDEV_ID(card), rc);
+               return rc;
+       }
+       card->info.chpid = prcd[30];
+       card->info.unit_addr2 = prcd[31];
+       card->info.cula = prcd[63];
+       card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
+                              (prcd[0x11] == _ascebc['M']));
+       return 0;
+}
+
+static void
+qeth_init_tokens(struct qeth_card *card)
+{
+       card->token.issuer_rm_w = 0x00010103UL;
+       card->token.cm_filter_w = 0x00010108UL;
+       card->token.cm_connection_w = 0x0001010aUL;
+       card->token.ulp_filter_w = 0x0001010bUL;
+       card->token.ulp_connection_w = 0x0001010dUL;
+}
+
+static inline __u16
+raw_devno_from_bus_id(char *id)
+{
+        id += (strlen(id) - 4);
+        return (__u16) simple_strtoul(id, &id, 16);
+}
+/**
+ * setup channel 
+ */
+static void 
+qeth_setup_ccw(struct qeth_channel *channel,unsigned char *iob, __u32 len)
+{
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace, 4, "setupccw");
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       if (channel == &card->read) 
+               memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1));
+       else
+               memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1));
+       channel->ccw.count = len;
+       channel->ccw.cda = (__u32) __pa(iob);
+}
+
+/**
+ * get free buffer for ccws (IDX activation, lancmds,ipassists...)
+ */
+static struct qeth_cmd_buffer *
+__qeth_get_buffer(struct qeth_channel *channel) 
+{
+       __u8 index;
+       
+       QETH_DBF_TEXT(trace, 6, "getbuff");
+       index = channel->io_buf_no;
+       do {
+               if (channel->iob[index].state == BUF_STATE_FREE) {
+                       channel->iob[index].state = BUF_STATE_LOCKED;
+                       channel->io_buf_no = (channel->io_buf_no + 1) %
+                               QETH_CMD_BUFFER_NO;
+                       memset(channel->iob[index].data, 0, QETH_BUFSIZE);
+                       return channel->iob + index;
+               }
+               index = (index + 1) % QETH_CMD_BUFFER_NO;
+       } while(index != channel->io_buf_no);
+
+       return NULL;
+}
+
+/**
+ * release command buffer
+ */ 
+static void
+qeth_release_buffer(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
+{
+       unsigned long flags;
+       
+       QETH_DBF_TEXT(trace, 6, "relbuff");
+       spin_lock_irqsave(&channel->iob_lock, flags);
+       memset(iob->data, 0, QETH_BUFSIZE);
+       iob->state = BUF_STATE_FREE;
+       iob->callback = qeth_send_control_data_cb;
+       iob->rc = 0;
+       spin_unlock_irqrestore(&channel->iob_lock, flags);
+}
+
+static struct qeth_cmd_buffer *
+qeth_get_buffer(struct qeth_channel *channel)
+{
+       struct qeth_cmd_buffer *buffer = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&channel->iob_lock, flags);
+       buffer = __qeth_get_buffer(channel);
+       spin_unlock_irqrestore(&channel->iob_lock, flags);
+       return buffer;
+}
+
+static struct qeth_cmd_buffer *
+qeth_wait_for_buffer(struct qeth_channel *channel) 
+{
+       struct qeth_cmd_buffer *buffer;
+       wait_event(channel->wait_q,
+                  ((buffer = qeth_get_buffer(channel)) != NULL)); 
+       return buffer;
+}
+
+static void
+qeth_clear_cmd_buffers(struct qeth_channel *channel)
+{
+       int cnt = 0;
+       
+       for (cnt=0; cnt < QETH_CMD_BUFFER_NO; cnt++) 
+               qeth_release_buffer(channel,&channel->iob[cnt]);
+       channel->buf_no = 0;
+       channel->io_buf_no = 0;
+}
+
+/**
+ * start IDX for read and write channel
+ */
+static int 
+qeth_idx_activate_get_answer(struct qeth_channel *channel,
+                             void (*idx_reply_cb)(struct qeth_channel *,
+                                                  struct qeth_cmd_buffer *))
+{
+       struct qeth_cmd_buffer *iob;
+       unsigned long flags;
+       int rc;
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(setup, 2, "idxanswr");
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       iob = qeth_get_buffer(channel);
+       iob->callback = idx_reply_cb;
+       memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1));
+       channel->ccw.count = QETH_BUFSIZE;
+       channel->ccw.cda = (__u32) __pa(iob->data);
+       
+       wait_event(card->wait_q,
+                  atomic_compare_and_swap(0,1,&channel->irq_pending) == 0);
+       QETH_DBF_TEXT(setup, 6, "noirqpnd");
+       spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+       rc = ccw_device_start(channel->ccwdev, 
+                             &channel->ccw,(addr_t) iob, 0, 0);
+       spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+       
+       if (rc) {
+               PRINT_ERR("qeth: Error2 in activating channel rc=%d\n",rc);
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               atomic_set(&channel->irq_pending, 0);
+               wake_up(&card->wait_q);
+               return rc;
+       }
+       rc = wait_event_interruptible_timeout(card->wait_q,
+                        channel->state == CH_STATE_UP, QETH_TIMEOUT);
+       if (rc == -ERESTARTSYS)
+               return rc;
+       if (channel->state != CH_STATE_UP){
+               rc = -ETIME;
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+       } else
+               rc = 0;
+       return rc;
+}
+
+static int 
+qeth_idx_activate_channel(struct qeth_channel *channel,
+                          void (*idx_reply_cb)(struct qeth_channel *,
+                                               struct qeth_cmd_buffer *))
+{
+       struct qeth_card *card;
+       struct qeth_cmd_buffer *iob;
+       unsigned long flags;
+       __u16 temp;
+       int rc;
+
+       card = CARD_FROM_CDEV(channel->ccwdev);
+
+       QETH_DBF_TEXT(setup, 2, "idxactch");
+       
+       iob = qeth_get_buffer(channel);
+       iob->callback = idx_reply_cb;
+       memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1));
+       channel->ccw.count = IDX_ACTIVATE_SIZE;
+       channel->ccw.cda = (__u32) __pa(iob->data);
+       if (channel == &card->write) {
+               memcpy(iob->data, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE);
+               memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data),
+                      &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
+               card->seqno.trans_hdr++;
+       } else {
+               memcpy(iob->data, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE);
+               memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data),
+                      &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
+       }
+       memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data),
+              &card->token.issuer_rm_w,QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data),
+              &card->info.func_level,sizeof(__u16));
+       temp = raw_devno_from_bus_id(CARD_DDEV_ID(card));
+       memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp, 2);
+       temp = (card->info.cula << 8) + card->info.unit_addr2;
+       memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2);
+
+       wait_event(card->wait_q,
+                  atomic_compare_and_swap(0,1,&channel->irq_pending) == 0);
+       QETH_DBF_TEXT(setup, 6, "noirqpnd");
+       spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+       rc = ccw_device_start(channel->ccwdev, 
+                             &channel->ccw,(addr_t) iob, 0, 0);
+       spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+       
+       if (rc) {
+               PRINT_ERR("qeth: Error1 in activating channel. rc=%d\n",rc);
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               atomic_set(&channel->irq_pending, 0);
+               wake_up(&card->wait_q);
+               return rc;
+       }
+       rc = wait_event_interruptible_timeout(card->wait_q,
+                       channel->state == CH_STATE_ACTIVATING, QETH_TIMEOUT);
+       if (rc == -ERESTARTSYS)
+               return rc;
+       if (channel->state != CH_STATE_ACTIVATING) {
+               PRINT_WARN("qeth: IDX activate timed out!\n");
+               QETH_DBF_TEXT_(setup, 2, "2err%d", -ETIME);
+               return -ETIME;
+       }
+       return qeth_idx_activate_get_answer(channel,idx_reply_cb);
+}
+
+static int
+qeth_peer_func_level(int level)
+{
+       if ((level & 0xff) == 8)
+               return (level & 0xff) + 0x400;
+       if (((level >> 8) & 3) == 1)
+               return (level & 0xff) + 0x200;
+       return level;
+}
+
+static void 
+qeth_idx_write_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
+{
+       struct qeth_card *card;
+       __u16 temp;
+       
+       QETH_DBF_TEXT(setup ,2, "idxwrcb");
+
+       if (channel->state == CH_STATE_DOWN) {
+               channel->state = CH_STATE_ACTIVATING;
+               goto out;
+       }
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       
+       if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
+               PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative "
+                         "reply\n", CARD_WDEV_ID(card));
+               goto out;
+       }
+       memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
+       if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
+               PRINT_WARN("IDX_ACTIVATE on write channel device %s: "
+                          "function level mismatch "
+                          "(sent: 0x%x, received: 0x%x)\n",
+                          CARD_WDEV_ID(card), card->info.func_level, temp);
+               goto out;
+       }
+       channel->state = CH_STATE_UP;
+out:
+       qeth_release_buffer(channel, iob);
+}
+
+static int
+qeth_check_idx_response(unsigned char *buffer)
+{
+       if (!buffer)
+               return 0;
+
+       QETH_DBF_HEX(control, 2, buffer, QETH_DBF_CONTROL_LEN);
+       if ((buffer[2] & 0xc0) == 0xc0) {
+               PRINT_WARN("received an IDX TERMINATE "
+                          "with cause code 0x%02x%s\n",
+                          buffer[4],
+                          ((buffer[4] == 0x22) ?
+                           " -- try another portname" : ""));
+               QETH_DBF_TEXT(trace, 2, "ckidxres");
+               QETH_DBF_TEXT(trace, 2, " idxterm");
+               QETH_DBF_TEXT_(trace, 2, "  rc%d", -EIO);
+               return -EIO;
+       }
+       return 0;
+}
+
+static void
+qeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob)
+{
+       struct qeth_card *card;
+       __u16 temp;
+
+       QETH_DBF_TEXT(setup , 2, "idxrdcb");
+       if (channel->state == CH_STATE_DOWN) {
+               channel->state = CH_STATE_ACTIVATING;
+               goto out;
+       }
+       
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       if (qeth_check_idx_response(iob->data)) {
+                       goto out;
+       }
+       if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
+               PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative "
+                         "reply\n", CARD_RDEV_ID(card));
+               goto out;
+       }
+
+/**
+ * temporary fix for microcode bug
+ * to revert it,replace OR by AND
+ */            
+       if ( (!QETH_IDX_NO_PORTNAME_REQUIRED(iob->data)) ||
+            (card->info.type == QETH_CARD_TYPE_OSAE) )
+               card->info.portname_required = 1;
+
+       memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
+       if (temp != qeth_peer_func_level(card->info.func_level)) {
+               PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "
+                          "level mismatch (sent: 0x%x, received: 0x%x)\n",
+                          CARD_RDEV_ID(card), card->info.func_level, temp);
+               goto out;       
+       }
+       memcpy(&card->token.issuer_rm_r,
+              QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data),
+              QETH_MPC_TOKEN_LENGTH);
+       memcpy(&card->info.mcl_level[0],
+              QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH);
+       channel->state = CH_STATE_UP;
+out:
+       qeth_release_buffer(channel,iob);
+}
+
+static int
+qeth_issue_next_read(struct qeth_card *card) 
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(trace,5,"issnxrd");
+       if (card->read.state != CH_STATE_UP)
+               return -EIO;
+       iob = qeth_get_buffer(&card->read);
+       if (!iob) {
+               PRINT_WARN("issue_next_read failed: no iob available!\n");
+               return -ENOMEM;
+       }
+       qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);
+       wait_event(card->wait_q,
+                  atomic_compare_and_swap(0,1,&card->read.irq_pending) == 0);
+       QETH_DBF_TEXT(trace, 6, "noirqpnd");
+       rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,
+                             (addr_t) iob, 0, 0);
+       if (rc) {
+               PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc);
+               atomic_set(&card->read.irq_pending, 0);
+               qeth_schedule_recovery(card);
+               wake_up(&card->wait_q);
+       }
+       return rc;
+}
+
+static struct qeth_reply *
+qeth_alloc_reply(struct qeth_card *card)
+{
+       struct qeth_reply *reply;
+
+       reply = kmalloc(sizeof(struct qeth_reply), GFP_KERNEL|GFP_ATOMIC);
+       if (reply){
+               memset(reply, 0, sizeof(struct qeth_reply));
+               atomic_set(&reply->refcnt, 1);
+               reply->card = card;
+       };
+       return reply;
+}
+
+static void
+qeth_get_reply(struct qeth_reply *reply)
+{
+       WARN_ON(atomic_read(&reply->refcnt) <= 0);
+       atomic_inc(&reply->refcnt);
+}
+
+static void
+qeth_put_reply(struct qeth_reply *reply)
+{
+       WARN_ON(atomic_read(&reply->refcnt) <= 0);
+       if (atomic_dec_and_test(&reply->refcnt))
+               kfree(reply);
+}
+
+static void
+qeth_cmd_timeout(unsigned long data)
+{
+       struct qeth_reply *reply, *list_reply, *r;
+       unsigned long flags;
+
+       reply = (struct qeth_reply *) data;
+       spin_lock_irqsave(&reply->card->lock, flags);
+       list_for_each_entry_safe(list_reply, r,
+                                &reply->card->cmd_waiter_list, list) {
+               if (reply == list_reply){
+                       qeth_get_reply(reply);
+                       list_del_init(&reply->list);
+                       spin_unlock_irqrestore(&reply->card->lock, flags);
+                       reply->rc = -ETIME;
+                       reply->received = 1;
+                       wake_up(&reply->wait_q);
+                       qeth_put_reply(reply);
+                       return;
+               }
+       }
+       spin_unlock_irqrestore(&reply->card->lock, flags);
+}
+
+static struct qeth_ipa_cmd * 
+qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
+{
+       struct qeth_ipa_cmd *cmd = NULL;
+       enum qeth_card_states old_state;
+
+       QETH_DBF_TEXT(trace,5,"chkipad");
+       if (IS_IPA(iob->data)){
+               cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
+               if (IS_IPA_REPLY(cmd))
+                       return cmd;
+               else {
+                       switch (cmd->hdr.command) {
+                       case IPA_CMD_STOPLAN:
+                               PRINT_WARN("Link failure on %s (CHPID 0x%X) - "
+                                          "there is a network problem or "
+                                          "someone pulled the cable or "
+                                          "disabled the port. Setting state "
+                                          "of interface to DOWN.\n",
+                                          card->info.if_name,
+                                          card->info.chpid);
+                               card->lan_online = 0;
+                               old_state = card->state;
+                               rtnl_lock();
+                               dev_close(card->dev);
+                               rtnl_unlock();
+                               if ((old_state == CARD_STATE_UP_LAN_ONLINE) ||
+                                   (old_state == CARD_STATE_UP_LAN_OFFLINE))
+                                       card->state = CARD_STATE_UP_LAN_OFFLINE;
+                               return NULL;
+                       case IPA_CMD_STARTLAN:
+                               PRINT_INFO("Link reestablished on %s "
+                                          "(CHPID 0x%X)\n",
+                                          card->info.if_name,
+                                          card->info.chpid);
+                               card->lan_online = 1;
+                               if (card->state == CARD_STATE_UP_LAN_OFFLINE){
+                                       rtnl_lock();
+                                       dev_open(card->dev);
+                                       rtnl_unlock();
+                               }
+                               return NULL;
+                       case IPA_CMD_REGISTER_LOCAL_ADDR:
+                               QETH_DBF_TEXT(trace,3, "irla");
+                               break;
+                       case IPA_CMD_UNREGISTER_LOCAL_ADDR:
+                               PRINT_WARN("probably problem on %s: "
+                                          "received IPA command 0x%X\n",
+                                          card->info.if_name,
+                                          cmd->hdr.command);
+                               break;
+                       default:
+                               PRINT_WARN("Received data is IPA "
+                                          "but not a reply!\n");
+                               break;
+                       }
+               }
+       }
+       return cmd;
+}
+
+/**
+ * wake all waiting ipa commands
+ */ 
+static void
+qeth_clear_ipacmd_list(struct qeth_card *card)
+{
+       struct qeth_reply *reply, *r;
+       unsigned long flags;
+       
+       QETH_DBF_TEXT(trace, 4, "clipalst");
+       
+       spin_lock_irqsave(&card->lock, flags);
+       list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
+               qeth_get_reply(reply);
+               reply->rc = -EIO;
+               reply->received = 1;
+               list_del_init(&reply->list);
+               wake_up(&reply->wait_q);
+               qeth_put_reply(reply);
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void
+qeth_send_control_data_cb(struct qeth_channel *channel,
+                         struct qeth_cmd_buffer *iob)
+{
+       struct qeth_card *card;
+       struct qeth_reply *reply, *r;
+       struct qeth_ipa_cmd *cmd;
+       unsigned long flags;
+       int keep_reply;
+       
+       QETH_DBF_TEXT(trace,4,"sndctlcb");
+
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       if (qeth_check_idx_response(iob->data)) {
+               qeth_clear_ipacmd_list(card);
+               qeth_schedule_recovery(card);
+               goto out;
+       } 
+
+       cmd = qeth_check_ipa_data(card, iob);
+       if ((cmd == NULL) && (card->state != CARD_STATE_DOWN))
+               goto out;
+
+       spin_lock_irqsave(&card->lock, flags);
+       list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {
+               if ((reply->seqno == QETH_IDX_COMMAND_SEQNO) ||
+                   ((cmd) && (reply->seqno == cmd->hdr.seqno))) { 
+                       qeth_get_reply(reply);
+                       list_del_init(&reply->list);
+                       spin_unlock_irqrestore(&card->lock, flags);
+                       keep_reply = 0;
+                       if (reply->callback != NULL) {
+                               if (cmd)
+                                       keep_reply = reply->callback(card,
+                                                       reply,
+                                                       (unsigned long)cmd);
+                               else
+                                       keep_reply = reply->callback(card,
+                                                       reply,
+                                                       (unsigned long)iob);
+                       }
+                       if (cmd)
+                               reply->rc = cmd->hdr.return_code;
+                       else if (iob->rc)
+                               reply->rc = iob->rc;
+                       if (keep_reply) {
+                               spin_lock_irqsave(&card->lock, flags);
+                               list_add_tail(&reply->list,
+                                             &card->cmd_waiter_list);
+                               spin_unlock_irqrestore(&card->lock, flags);
+                       } else {
+                               reply->received = 1;
+                               wake_up(&reply->wait_q);
+                       }
+                       qeth_put_reply(reply);
+                       goto out;
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+out:
+       memcpy(&card->seqno.pdu_hdr_ack,
+               QETH_PDU_HEADER_SEQ_NO(iob->data),
+               QETH_SEQ_NO_LENGTH);
+       qeth_release_buffer(channel,iob);
+}
+
+static int
+qeth_send_control_data(struct qeth_card *card, int len,
+                      struct qeth_cmd_buffer *iob,
+                      int (*reply_cb)
+                      (struct qeth_card *, struct qeth_reply*, unsigned long),
+                      void *reply_param)
+                                           
+{
+       int rc;
+       unsigned long flags;
+       struct qeth_reply *reply;
+       struct timer_list timer;
+
+       QETH_DBF_TEXT(trace, 2, "sendctl");
+
+       qeth_setup_ccw(&card->write,iob->data,len);
+
+       memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data),
+              &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);
+       card->seqno.trans_hdr++;
+
+       memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data),
+              &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH);
+       card->seqno.pdu_hdr++;
+       memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data),
+              &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
+       iob->callback = qeth_release_buffer;
+
+       reply = qeth_alloc_reply(card);
+       if (!reply) {
+               PRINT_WARN("Could no alloc qeth_reply!\n");
+               return -ENOMEM;
+       }
+       reply->callback = reply_cb;
+       reply->param = reply_param;
+       if (card->state == CARD_STATE_DOWN)
+               reply->seqno = QETH_IDX_COMMAND_SEQNO;
+       else
+               reply->seqno = card->seqno.ipa++;
+       init_timer(&timer);
+       timer.function = qeth_cmd_timeout;
+       timer.data = (unsigned long) reply;
+       timer.expires = jiffies + QETH_TIMEOUT;
+       init_waitqueue_head(&reply->wait_q);
+       spin_lock_irqsave(&card->lock, flags);
+       list_add_tail(&reply->list, &card->cmd_waiter_list);
+       spin_unlock_irqrestore(&card->lock, flags);
+       QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);
+       wait_event(card->wait_q,
+                  atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0);
+       QETH_DBF_TEXT(trace, 6, "noirqpnd");
+       spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
+       rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,
+                             (addr_t) iob, 0, 0);
+       spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
+       if (rc){
+               PRINT_WARN("qeth_send_control_data: "
+                          "ccw_device_start rc = %i\n", rc);
+               QETH_DBF_TEXT_(trace, 2, " err%d", rc);
+               spin_lock_irqsave(&card->lock, flags);
+               list_del_init(&reply->list);
+               qeth_put_reply(reply);
+               spin_unlock_irqrestore(&card->lock, flags);
+               qeth_release_buffer(iob->channel, iob);
+               atomic_set(&card->write.irq_pending, 0);
+               wake_up(&card->wait_q);
+               return rc;
+       }
+       add_timer(&timer);
+       wait_event(reply->wait_q, reply->received);
+       del_timer(&timer);
+       rc = reply->rc;
+       qeth_put_reply(reply);
+       return rc;
+}
+
+static int 
+qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, 
+                 int (*reply_cb)
+                 (struct qeth_card *,struct qeth_reply*, unsigned long),
+                 void *reply_param)
+{
+       struct qeth_ipa_cmd *cmd;
+       int rc;
+       
+       QETH_DBF_TEXT(trace,4,"sendipa");
+
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
+       memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
+              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
+
+       rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob,
+                                   reply_cb, reply_param);
+       return rc;
+}
+
+
+static int
+qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
+                 unsigned long data)
+{
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(setup, 2, "cmenblcb");
+
+       iob = (struct qeth_cmd_buffer *) data;
+       memcpy(&card->token.cm_filter_r,
+              QETH_CM_ENABLE_RESP_FILTER_TOKEN(iob->data), 
+              QETH_MPC_TOKEN_LENGTH);
+       QETH_DBF_TEXT_(setup, 2, "  rc%d", iob->rc);
+       return 0;
+}
+
+static int 
+qeth_cm_enable(struct qeth_card *card) 
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT(setup,2,"cmenable");
+
+       iob = qeth_wait_for_buffer(&card->write);
+       memcpy(iob->data, CM_ENABLE, CM_ENABLE_SIZE);
+       memcpy(QETH_CM_ENABLE_ISSUER_RM_TOKEN(iob->data),
+              &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_CM_ENABLE_FILTER_TOKEN(iob->data),
+              &card->token.cm_filter_w, QETH_MPC_TOKEN_LENGTH);
+
+       rc = qeth_send_control_data(card, CM_ENABLE_SIZE, iob,
+                                   qeth_cm_enable_cb, NULL);
+       return rc;
+}
+
+static int 
+qeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
+                unsigned long data)
+{
+       
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT(setup, 2, "cmsetpcb");
+
+       iob = (struct qeth_cmd_buffer *) data;  
+       memcpy(&card->token.cm_connection_r,
+              QETH_CM_SETUP_RESP_DEST_ADDR(iob->data),
+              QETH_MPC_TOKEN_LENGTH);
+       QETH_DBF_TEXT_(setup, 2, "  rc%d", iob->rc);
+       return 0;
+}
+
+static int
+qeth_cm_setup(struct qeth_card *card)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT(setup,2,"cmsetup");
+
+       iob = qeth_wait_for_buffer(&card->write);
+       memcpy(iob->data, CM_SETUP, CM_SETUP_SIZE);
+       memcpy(QETH_CM_SETUP_DEST_ADDR(iob->data),
+              &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_CM_SETUP_CONNECTION_TOKEN(iob->data),
+              &card->token.cm_connection_w, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_CM_SETUP_FILTER_TOKEN(iob->data),
+              &card->token.cm_filter_r, QETH_MPC_TOKEN_LENGTH);
+       rc = qeth_send_control_data(card, CM_SETUP_SIZE, iob,
+                                   qeth_cm_setup_cb, NULL);
+       return rc;
+
+}
+
+static int 
+qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
+                  unsigned long data)
+{
+       
+       __u16 mtu, framesize;
+       __u16 len;
+       __u8 link_type;
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(setup, 2, "ulpenacb");
+       
+       iob = (struct qeth_cmd_buffer *) data;
+       memcpy(&card->token.ulp_filter_r,
+              QETH_ULP_ENABLE_RESP_FILTER_TOKEN(iob->data),
+              QETH_MPC_TOKEN_LENGTH);
+       if (qeth_get_mtu_out_of_mpc(card->info.type)) {
+               memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(iob->data), 2);
+               mtu = qeth_get_mtu_outof_framesize(framesize);
+               if (!mtu) {
+                       iob->rc = -EINVAL;
+                       QETH_DBF_TEXT_(setup, 2, "  rc%d", iob->rc);
+                       return 0;
+               }
+               card->info.max_mtu = mtu;
+               card->info.initial_mtu = mtu;
+               card->qdio.in_buf_size = mtu + 2 * PAGE_SIZE;
+       } else {
+               card->info.initial_mtu = qeth_get_initial_mtu_for_card(card);
+               card->info.max_mtu = qeth_get_max_mtu_for_card(card->info.type);
+               card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT;
+       }
+
+       memcpy(&len, QETH_ULP_ENABLE_RESP_DIFINFO_LEN(iob->data), 2);
+       if (len >= QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE) {
+               memcpy(&link_type, 
+                      QETH_ULP_ENABLE_RESP_LINK_TYPE(iob->data), 1);
+               card->info.link_type = link_type;
+       } else
+               card->info.link_type = 0;
+       QETH_DBF_TEXT_(setup, 2, "  rc%d", iob->rc);
+       return 0;
+}
+
+static int 
+qeth_ulp_enable(struct qeth_card *card)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+
+       /*FIXME: trace view callbacks*/
+       QETH_DBF_TEXT(setup,2,"ulpenabl");
+       
+       iob = qeth_wait_for_buffer(&card->write);
+       memcpy(iob->data, ULP_ENABLE, ULP_ENABLE_SIZE);
+
+       *(QETH_ULP_ENABLE_LINKNUM(iob->data)) =
+               (__u8) card->info.portno;
+
+       memcpy(QETH_ULP_ENABLE_DEST_ADDR(iob->data),
+              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_ULP_ENABLE_FILTER_TOKEN(iob->data),
+              &card->token.ulp_filter_w, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_ULP_ENABLE_PORTNAME_AND_LL(iob->data),
+              card->info.portname, 9);
+       rc = qeth_send_control_data(card, ULP_ENABLE_SIZE, iob,
+                                   qeth_ulp_enable_cb, NULL);
+       return rc;
+
+}
+
+static inline __u16
+__raw_devno_from_bus_id(char *id)
+{
+       id += (strlen(id) - 4);
+       return (__u16) simple_strtoul(id, &id, 16);
+}
+
+static int
+qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
+                 unsigned long data)
+{
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(setup, 2, "ulpstpcb");
+
+       iob = (struct qeth_cmd_buffer *) data;
+       memcpy(&card->token.ulp_connection_r,
+              QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
+              QETH_MPC_TOKEN_LENGTH);
+       QETH_DBF_TEXT_(setup, 2, "  rc%d", iob->rc);
+       return 0;
+}
+
+static int
+qeth_ulp_setup(struct qeth_card *card)
+{
+       int rc;
+       __u16 temp;
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT(setup,2,"ulpsetup");
+       
+       iob = qeth_wait_for_buffer(&card->write);
+       memcpy(iob->data, ULP_SETUP, ULP_SETUP_SIZE);
+
+       memcpy(QETH_ULP_SETUP_DEST_ADDR(iob->data),
+              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_ULP_SETUP_CONNECTION_TOKEN(iob->data),
+              &card->token.ulp_connection_w, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_ULP_SETUP_FILTER_TOKEN(iob->data),
+              &card->token.ulp_filter_r, QETH_MPC_TOKEN_LENGTH);
+
+       temp = __raw_devno_from_bus_id(CARD_DDEV_ID(card));
+       memcpy(QETH_ULP_SETUP_CUA(iob->data), &temp, 2);
+       temp = (card->info.cula << 8) + card->info.unit_addr2;
+       memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2);
+       rc = qeth_send_control_data(card, ULP_SETUP_SIZE, iob,
+                                   qeth_ulp_setup_cb, NULL);
+       return rc;
+}
+
+static inline int
+qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf,
+                            unsigned int qdio_error,
+                            unsigned int siga_error)
+{
+       int rc = 0;
+       
+       if (qdio_error || siga_error) {
+               QETH_DBF_TEXT(trace, 2, "qdinerr");
+               QETH_DBF_TEXT(qerr, 2, "qdinerr");
+               QETH_DBF_TEXT_(qerr, 2, " F15=%02X",
+                              buf->buffer->element[15].flags & 0xff);
+               QETH_DBF_TEXT_(qerr, 2, " F14=%02X",
+                              buf->buffer->element[14].flags & 0xff);
+               QETH_DBF_TEXT_(qerr, 2, " qerr=%X", qdio_error);
+               QETH_DBF_TEXT_(qerr, 2, " serr=%X", siga_error);
+               rc = 1;
+       }
+       return rc;
+}
+
+static void
+qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
+                       unsigned int qdio_err, unsigned int siga_err,
+                       unsigned int queue, int first_element, int count,
+                       unsigned long card_ptr)
+{
+       struct net_device *net_dev;
+       struct qeth_card *card;
+       struct qeth_qdio_buffer *buffer;
+       int i;
+
+       QETH_DBF_TEXT(trace, 6, "qdinput");
+       card = (struct qeth_card *) card_ptr;
+       net_dev = card->dev;
+#ifdef CONFIG_QETH_PERF_STATS
+       card->perf_stats.inbound_start_time = qeth_get_micros();
+#endif
+       if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
+               if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){
+                       QETH_DBF_TEXT(trace, 1,"qdinchk");
+                       QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
+                       QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count);
+                       QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status);
+                       qeth_schedule_recovery(card);
+                       return;
+               }
+       }
+       for (i = first_element; i < (first_element + count); ++i) {
+               buffer = &card->qdio.in_q->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+               if ((status == QDIO_STATUS_LOOK_FOR_ERROR) &&
+                   qeth_check_for_inbound_error(buffer, qdio_err, siga_err))
+                       buffer->state = QETH_QDIO_BUF_ERROR;
+               else
+                       buffer->state = QETH_QDIO_BUF_PRIMED;
+       }
+       
+       tasklet_schedule(&card->qdio.in_tasklet);
+}
+
+static inline struct sk_buff *
+qeth_get_skb(unsigned int length)
+{
+       struct sk_buff* skb;
+#ifdef CONFIG_QETH_VLAN
+       if ((skb = dev_alloc_skb(length + VLAN_HLEN)))
+               skb_reserve(skb, VLAN_HLEN);
+#else
+       skb = dev_alloc_skb(length);
+#endif
+       return skb;
+}
+
+static inline struct sk_buff *
+qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
+                 struct qdio_buffer_element **__element, int *__offset,
+                 struct qeth_hdr **hdr)
+{
+       struct qdio_buffer_element *element = *__element;
+       int offset = *__offset;
+       struct sk_buff *skb = NULL;
+       int skb_len;
+       void *data_ptr;
+       int data_len;
+
+       QETH_DBF_TEXT(trace,6,"nextskb");
+       /* qeth_hdr must not cross element boundaries */
+       if (element->length < offset + sizeof(struct qeth_hdr)){
+               if (qeth_is_last_sbale(element))
+                       return NULL;
+               element++;
+               offset = 0;
+               if (element->length < sizeof(struct qeth_hdr))
+                       return NULL;
+       }
+       *hdr = element->addr + offset;
+
+       offset += sizeof(struct qeth_hdr);
+       skb_len = (*hdr)->length;
+       if (!skb_len)
+               return NULL;
+       if (card->options.fake_ll){
+               if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN)))
+                       goto no_mem;
+               skb_pull(skb, QETH_FAKE_LL_LEN);
+       } else if (!(skb = qeth_get_skb(skb_len)))
+               goto no_mem;
+       data_ptr = element->addr + offset;
+       while (skb_len) {
+               data_len = min(skb_len, (int)(element->length - offset));
+               if (data_len)
+                       memcpy(skb_put(skb, data_len), data_ptr, data_len);
+               skb_len -= data_len;
+               if (skb_len){
+                       if (qeth_is_last_sbale(element)){
+                               QETH_DBF_TEXT(trace,4,"unexeob");
+                               QETH_DBF_TEXT_(trace,4,"%s",CARD_BUS_ID(card));
+                               QETH_DBF_TEXT(qerr,2,"unexeob");
+                               QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card));
+                               QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer));
+                               dev_kfree_skb_irq(skb);
+                               card->stats.rx_errors++;
+                               return NULL;
+                       }
+                       element++;
+                       offset = 0;
+                       data_ptr = element->addr;
+               } else {
+                       offset += data_len;
+               }
+       }
+       *__element = element;
+       *__offset = offset;
+       return skb;
+no_mem:
+       if (net_ratelimit()){
+               PRINT_WARN("No memory for packet received on %s.\n",
+                          card->info.if_name);
+               QETH_DBF_TEXT(trace,2,"noskbmem");
+               QETH_DBF_TEXT_(trace,2,"%s",CARD_BUS_ID(card));
+       }
+       card->stats.rx_dropped++;
+       return NULL;
+}
+
+static inline unsigned short
+qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ethhdr *eth;
+       struct qeth_card *card;
+
+       QETH_DBF_TEXT(trace,5,"typtrans");
+       
+       card = (struct qeth_card *)dev->priv;
+#ifdef CONFIG_TR
+       if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || 
+           (card->info.link_type == QETH_LINK_TYPE_LANE_TR))
+               return tr_type_trans(skb,dev);
+#endif /* CONFIG_TR */
+
+       skb->mac.raw = skb->data;
+       skb_pull(skb, ETH_ALEN * 2 + sizeof (short));
+       eth = skb->mac.ethernet;
+
+       if (*eth->h_dest & 1) {
+               if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+                       skb->pkt_type = PACKET_BROADCAST;
+               else
+                       skb->pkt_type = PACKET_MULTICAST;
+       } else {
+               skb->pkt_type = PACKET_OTHERHOST;
+       }
+       if (ntohs(eth->h_proto) >= 1536)
+               return eth->h_proto;
+       if (*(unsigned short *) (skb->data) == 0xFFFF)
+               return htons(ETH_P_802_3);
+       return htons(ETH_P_802_2);
+}
+
+
+static inline void
+qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
+                        struct qeth_hdr *hdr)
+{
+       struct ethhdr *fake_hdr;
+       struct iphdr *ip_hdr;
+
+       QETH_DBF_TEXT(trace,5,"skbfake");
+       skb->mac.raw = skb->data - QETH_FAKE_LL_LEN;
+       /* this is a fake ethernet header */
+       fake_hdr = (struct ethhdr *) skb->mac.raw;
+
+       /* the destination MAC address */
+       switch (skb->pkt_type){
+       case PACKET_MULTICAST:
+               switch (skb->protocol){
+#ifdef CONFIG_QETH_IPV6
+               case __constant_htons(ETH_P_IPV6):
+                       ndisc_mc_map((struct in6_addr *)
+                                    skb->data + QETH_FAKE_LL_V6_ADDR_POS,
+                                    fake_hdr->h_dest, card->dev, 0);
+                       break;
+#endif /* CONFIG_QETH_IPV6 */
+               case __constant_htons(ETH_P_IP):
+                       ip_hdr = (struct iphdr *)skb->data;
+                       if (card->dev->type == ARPHRD_IEEE802_TR)
+                               ip_tr_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
+                       else
+                               ip_eth_mc_map(ip_hdr->daddr, fake_hdr->h_dest);
+                       break;
+               default:
+                       memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
+               }
+               break;
+       case PACKET_BROADCAST:
+               memset(fake_hdr->h_dest, 0xff, ETH_ALEN);
+               break;
+       default:
+               memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN);
+       }
+       /* the source MAC address */
+       if (hdr->ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+               memcpy(fake_hdr->h_source, &hdr->dest_addr[2], ETH_ALEN);
+       else
+               memset(fake_hdr->h_source, 0, ETH_ALEN);
+       /* the protocol */
+       fake_hdr->h_proto = skb->protocol;
+}
+
+static inline void
+qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
+                     struct qeth_hdr *hdr)
+{
+#ifdef CONFIG_QETH_VLAN
+       u16 *vlan_tag;
+
+       if (hdr->ext_flags & QETH_HDR_EXT_VLAN_FRAME) {
+               vlan_tag = (u16 *) skb_push(skb, VLAN_HLEN);
+               *vlan_tag = hdr->vlan_id;
+               *(vlan_tag + 1) = skb->protocol;
+               skb->protocol = __constant_htons(ETH_P_8021Q);
+       }
+#endif /* CONFIG_QETH_VLAN */
+}
+
+
+static inline void
+qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
+                struct qeth_hdr *hdr)
+{
+#ifdef CONFIG_QETH_IPV6
+       if (hdr->flags & QETH_HDR_PASSTHRU){
+               skb->protocol = qeth_type_trans(skb, card->dev);
+               return;
+       }
+#endif /* CONFIG_QETH_IPV6 */
+       skb->protocol = htons((hdr->flags & QETH_HDR_IPV6)? ETH_P_IPV6 :
+                             ETH_P_IP);
+       switch (hdr->flags & QETH_HDR_CAST_MASK){
+       case QETH_CAST_UNICAST:
+               skb->pkt_type = PACKET_HOST;
+               break;
+       case QETH_CAST_MULTICAST:
+               skb->pkt_type = PACKET_MULTICAST;
+               card->stats.multicast++;
+               break;
+       case QETH_CAST_BROADCAST:
+               skb->pkt_type = PACKET_BROADCAST;
+               card->stats.multicast++;
+               break;
+       case QETH_CAST_ANYCAST:
+       case QETH_CAST_NOCAST:
+       default:
+               skb->pkt_type = PACKET_HOST;
+       }
+       if (card->options.fake_ll)
+               qeth_rebuild_skb_fake_ll(card, skb, hdr);
+       else
+               skb->mac.raw = skb->data;
+       skb->ip_summed = card->options.checksum_type;
+       if (card->options.checksum_type == HW_CHECKSUMMING){
+               if ( (hdr->ext_flags &
+                     (QETH_HDR_EXT_CSUM_HDR_REQ |
+                      QETH_HDR_EXT_CSUM_TRANSP_REQ)) ==
+                    (QETH_HDR_EXT_CSUM_HDR_REQ |
+                     QETH_HDR_EXT_CSUM_TRANSP_REQ) )
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb->ip_summed = SW_CHECKSUMMING;
+       }
+       qeth_rebuild_skb_vlan(card, skb, hdr);
+}
+
+
+static inline struct qeth_buffer_pool_entry *
+qeth_get_buffer_pool_entry(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *entry, *tmp;
+
+       QETH_DBF_TEXT(trace, 6, "gtbfplen");
+       entry = NULL;
+       list_for_each_entry_safe(entry, tmp, 
+                                &card->qdio.in_buf_pool.entry_list, list){
+               list_del_init(&entry->list);
+               break;
+       }
+       return entry;
+}
+
+static inline void
+qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
+{
+       struct qeth_buffer_pool_entry *pool_entry;
+       int i;
+
+       pool_entry = qeth_get_buffer_pool_entry(card);
+       /*
+        * since the buffer is accessed only from the input_tasklet
+        * there shouldn't be a need to synchronize; also, since we use
+        * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run  out off
+        * buffers
+        */
+       BUG_ON(!pool_entry);
+       
+       buf->pool_entry = pool_entry;
+       for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i){
+               buf->buffer->element[i].length = PAGE_SIZE;
+               buf->buffer->element[i].addr =  pool_entry->elements[i];
+               if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1)
+                       buf->buffer->element[i].flags = SBAL_FLAGS_LAST_ENTRY;
+               else
+                       buf->buffer->element[i].flags = 0;
+       }
+       buf->state = QETH_QDIO_BUF_EMPTY;
+}
+
+static void
+qeth_clear_output_buffer(struct qeth_card *card,
+                        struct qeth_qdio_out_buffer *buf)
+{
+       int i;
+       struct sk_buff *skb;
+
+       for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i){
+               buf->buffer->element[i].length = 0;
+               buf->buffer->element[i].addr = NULL;
+               buf->buffer->element[i].flags = 0;
+               while ((skb = skb_dequeue(&buf->skb_list))){
+                       atomic_dec(&skb->users);
+                       dev_kfree_skb_irq(skb);
+               }
+       }
+       buf->next_element_to_fill = 0;
+       buf->state = QETH_QDIO_BUF_EMPTY;
+}
+
+static inline void
+qeth_queue_input_buffer(struct qeth_card *card, int index)
+{
+       struct qeth_qdio_q *queue = card->qdio.in_q;
+       int count;
+       int i;
+       int rc;
+
+       QETH_DBF_TEXT(trace,6,"queinbuf");
+       count = (index < queue->next_buf_to_init)?
+               card->qdio.in_buf_pool.buf_count - 
+               (queue->next_buf_to_init - index) :
+               card->qdio.in_buf_pool.buf_count -
+               (queue->next_buf_to_init + QDIO_MAX_BUFFERS_PER_Q - index);
+       /* only requeue at a certain threshold to avoid SIGAs */
+       if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){
+               for (i = queue->next_buf_to_init;
+                    i < queue->next_buf_to_init + count; ++i)
+                       qeth_init_input_buffer(card,
+                               &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]);
+               /*
+                * according to old code it should be avoided to requeue all
+                * 128 buffers in order to benefit from PCI avoidance.
+                * this function keeps at least one buffer (the buffer at
+                * 'index') un-requeued -> this buffer is the first buffer that
+                * will be requeued the next time
+                */
+               rc = do_QDIO(CARD_DDEV(card),
+                            QDIO_FLAG_SYNC_INPUT,
+                            0, queue->next_buf_to_init, count, NULL);
+               if (rc){
+                       PRINT_WARN("qeth_queue_input_buffer's do_QDIO "
+                                  "return %i (device %s).\n",
+                                  rc, CARD_DDEV_ID(card));
+                       QETH_DBF_TEXT(trace,2,"qinberr");
+                       QETH_DBF_TEXT_(trace,2,"%s",CARD_BUS_ID(card));
+               }
+               queue->next_buf_to_init = (queue->next_buf_to_init + count) %
+                                         QDIO_MAX_BUFFERS_PER_Q;
+       }
+}
+
+static inline void
+qeth_put_buffer_pool_entry(struct qeth_card *card,
+                          struct qeth_buffer_pool_entry *entry)
+{
+       QETH_DBF_TEXT(trace, 6, "ptbfplen");
+       list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
+}
+
+static void
+qeth_qdio_input_tasklet(unsigned long data)
+{
+       struct qeth_card *card = (struct qeth_card *) data;
+       int current_buf = card->qdio.in_q->next_buf_to_process;
+       struct qeth_qdio_buffer *buf;
+       struct qdio_buffer_element *element;
+       int offset;
+       struct sk_buff *skb;
+       struct qeth_hdr *hdr;
+       int rxrc;
+       
+       QETH_DBF_TEXT(trace,6,"qdintlet");
+       buf = &card->qdio.in_q->bufs[current_buf];
+       while((buf->state == QETH_QDIO_BUF_PRIMED) ||
+             (buf->state == QETH_QDIO_BUF_ERROR)){
+               if (buf->state == QETH_QDIO_BUF_ERROR)
+                       goto clear_buffer;
+               if (netif_queue_stopped(card->dev))
+                       goto clear_buffer;
+               /* get first element of current buffer */
+               element = (struct qdio_buffer_element *)
+                       &buf->buffer->element[0];
+               offset = 0;
+#ifdef CONFIG_QETH_PERF_STATS
+               card->perf_stats.bufs_rec++;
+#endif
+               while((skb = qeth_get_next_skb(card, buf->buffer, &element,
+                                              &offset, &hdr))){
+
+                       qeth_rebuild_skb(card, skb, hdr);
+#ifdef CONFIG_QETH_PERF_STATS
+                       card->perf_stats.inbound_time += qeth_get_micros() -
+                               card->perf_stats.inbound_start_time;
+                       card->perf_stats.inbound_cnt++;
+#endif
+                       skb->dev = card->dev;
+                       if (netif_queue_stopped(card->dev)) {
+                               dev_kfree_skb_irq(skb);
+                               card->stats.rx_dropped++;
+                       } else {
+                               rxrc = netif_rx(skb);
+                               card->dev->last_rx = jiffies;
+                               card->stats.rx_packets++;
+                               card->stats.rx_bytes += skb->len;
+                       }
+               }
+clear_buffer:
+               qeth_put_buffer_pool_entry(card, buf->pool_entry);
+               /* give buffer back to hardware */
+               qeth_queue_input_buffer(card, current_buf);
+               current_buf = (current_buf + 1) % QDIO_MAX_BUFFERS_PER_Q;
+               buf = &card->qdio.in_q->bufs[current_buf];
+       }
+       /* set index for next time the tasklet is scheduled */
+       card->qdio.in_q->next_buf_to_process = current_buf;
+}
+
+static inline int
+qeth_handle_send_error(struct qeth_card *card,
+                      struct qeth_qdio_out_buffer *buffer,
+                      int qdio_err, int siga_err)
+{
+       int sbalf15 = buffer->buffer->element[15].flags & 0xff;
+       int cc = siga_err & 3;
+
+       QETH_DBF_TEXT(trace, 6, "hdsnderr");
+       switch (cc) {
+       case 0:
+               if (qdio_err){
+                       QETH_DBF_TEXT(trace, 1,"lnkfail");
+                       QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
+                       QETH_DBF_TEXT_(trace,1,"%04x %02x",
+                                      (u16)qdio_err, (u8)sbalf15);
+                       return QETH_SEND_ERROR_LINK_FAILURE;
+               }
+               return QETH_SEND_ERROR_NONE;
+       case 2:
+               if (siga_err & QDIO_SIGA_ERROR_B_BIT_SET) {
+                       QETH_DBF_TEXT(trace, 1, "SIGAcc2B");
+                       QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
+                       return QETH_SEND_ERROR_KICK_IT;
+               }
+               if ((sbalf15 >= 15) && (sbalf15 <= 31))
+                       return QETH_SEND_ERROR_RETRY;
+               return QETH_SEND_ERROR_LINK_FAILURE;
+               /* look at qdio_error and sbalf 15 */
+       case 1:
+               QETH_DBF_TEXT(trace, 1, "SIGAcc1");
+               QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
+               return QETH_SEND_ERROR_LINK_FAILURE;
+       case 3:
+               QETH_DBF_TEXT(trace, 1, "SIGAcc3");
+               QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
+               return QETH_SEND_ERROR_KICK_IT;
+       }
+       return QETH_SEND_ERROR_LINK_FAILURE;
+}
+
+static inline void
+qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
+                  int index, int count)
+{
+       struct qeth_qdio_out_buffer *buf;
+       int rc;
+       int i;
+
+       QETH_DBF_TEXT(trace, 6, "flushbuf");
+
+       for (i = index; i < index + count; ++i) {
+               buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+               buf->buffer->element[buf->next_element_to_fill - 1].flags |=
+                               SBAL_FLAGS_LAST_ENTRY;
+
+               if (!queue->do_pack){
+                       if ((atomic_read(&queue->used_buffers) >= 
+                               (QETH_HIGH_WATERMARK_PACK -
+                                QETH_WATERMARK_PACK_FUZZ)) &&
+                           !atomic_read(&queue->set_pci_flags_count)){
+                               /* it's likely that we'll go to packing
+                                * mode soon */
+                               atomic_inc(&queue->set_pci_flags_count);
+                               buf->buffer->element[0].flags |= 0x40;
+                       }
+               } else {
+                       if (!atomic_read(&queue->set_pci_flags_count)){
+                               /*
+                                * there's no outstanding PCI any more, so we
+                                * have to request a PCI to be sure the the PCI
+                                * will wake at some time in the future then we
+                                * can flush packed buffers that might still be
+                                * hanging around, which can happen if no
+                                * further send was requested by the stack
+                                */
+                               atomic_inc(&queue->set_pci_flags_count);
+                               buf->buffer->element[0].flags |= 0x40;
+                       }
+#ifdef CONFIG_QETH_PERF_STATS
+                       queue->card->perf_stats.bufs_sent_pack++;
+#endif
+               }
+       }
+
+       queue->card->dev->trans_start = jiffies;
+       if (under_int)
+               rc = do_QDIO(CARD_DDEV(queue->card),
+                            QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
+                            queue->queue_no, index, count, NULL);
+       else
+               rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
+                            queue->queue_no, index, count, NULL);
+       if (rc){
+               QETH_DBF_SPRINTF(trace, 0, "qeth_flush_buffers: do_QDIO "
+                                "returned error (%i) on device %s.",
+                                rc, CARD_DDEV_ID(queue->card));
+               QETH_DBF_TEXT(trace, 2, "flushbuf");
+               QETH_DBF_TEXT_(trace, 2, " err%d", rc);
+               queue->card->stats.tx_errors += count;
+               return;
+       }
+#ifdef CONFIG_QETH_PERF_STATS
+       queue->card->perf_stats.bufs_sent += count;
+       queue->card->perf_stats.outbound_cnt++;
+#endif
+}
+
+/*
+ * switches between PACKING and non-PACKING state if needed.
+ * has to be called holding queue->lock
+ */
+static inline void
+qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
+{
+       struct qeth_qdio_out_buffer *buffer;
+       
+       QETH_DBF_TEXT(trace, 6, "swipack");
+       if (!queue->do_pack) {
+               if (atomic_read(&queue->used_buffers)
+                   >= QETH_HIGH_WATERMARK_PACK){
+                       /* switch non-PACKING -> PACKING */
+                       QETH_DBF_TEXT(trace, 6, "np->pack");
+#ifdef CONFIG_QETH_PERF_STATS
+                       queue->card->perf_stats.sc_dp_p++;
+#endif
+                       queue->do_pack = 1;
+               }
+       } else {
+               if (atomic_read(&queue->used_buffers)
+                   <= QETH_LOW_WATERMARK_PACK) {
+                       /* switch PACKING -> non-PACKING */
+                       QETH_DBF_TEXT(trace, 6, "pack->np");
+#ifdef CONFIG_QETH_PERF_STATS
+                       queue->card->perf_stats.sc_p_dp++;
+#endif
+                       queue->do_pack = 0;
+                       /* flush packing buffers */
+                       buffer = &queue->bufs[queue->next_buf_to_fill];
+                       BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
+                       if (buffer->next_element_to_fill > 0) {
+                               buffer->state = QETH_QDIO_BUF_PRIMED;
+                               atomic_inc(&queue->used_buffers);
+                               queue->next_buf_to_fill = 
+                                       (queue->next_buf_to_fill + 1) % 
+                                       QDIO_MAX_BUFFERS_PER_Q;
+                       }
+               }
+       }
+}
+
+static void
+qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
+                       unsigned int qdio_error, unsigned int siga_error,
+                       unsigned int __queue, int first_element, int count,
+                       unsigned long card_ptr)
+{
+       struct qeth_card *card        = (struct qeth_card *) card_ptr;
+       struct qeth_qdio_out_q *queue = card->qdio.out_qs[__queue];
+       struct qeth_qdio_out_buffer *buffer;
+       int i;
+
+       QETH_DBF_TEXT(trace, 6, "qdouhdl");
+       if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
+               if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){
+                       QETH_DBF_SPRINTF(trace, 2, "On device %s: "
+                                        "received active check "
+                                        "condition (0x%08x).",
+                                        CARD_BUS_ID(card), status);
+                       QETH_DBF_TEXT(trace, 2, "chkcond");
+                       QETH_DBF_TEXT_(trace, 2, "%08x", status);
+                       netif_stop_queue(card->dev);
+                       qeth_schedule_recovery(card);
+                       return;
+               }
+       }
+       
+       for(i = first_element; i < (first_element + count); ++i){
+               buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+               /*we only handle the KICK_IT error by doing a recovery */
+               if (qeth_handle_send_error(card, buffer, qdio_error, siga_error)
+                               == QETH_SEND_ERROR_KICK_IT){
+                       netif_stop_queue(card->dev);
+                       qeth_schedule_recovery(card);
+                       return;
+               }
+               /* is PCI flag set on buffer? */
+               if (buffer->buffer->element[0].flags & 0x40)
+                       atomic_dec(&queue->set_pci_flags_count);
+
+               qeth_clear_output_buffer(card, buffer);
+       }
+       atomic_sub(count, &queue->used_buffers);
+
+       //if (!atomic_read(&queue->set_pci_flags_count))
+               tasklet_schedule(&queue->tasklet);
+       
+       netif_wake_queue(card->dev);
+}
+
+static void
+qeth_qdio_output_tasklet(unsigned long data)
+{
+       struct qeth_qdio_out_q *queue = (struct qeth_qdio_out_q *) data;
+       struct qeth_qdio_out_buffer *buffer;
+       int index;
+       int count;
+       
+       QETH_DBF_TEXT(trace, 6, "outtlet");
+       
+       /* flush all PRIMED buffers */
+       index = queue->next_buf_to_flush;
+       count = 0;
+       while (queue->bufs[index].state == QETH_QDIO_BUF_PRIMED) {
+               count++;
+               index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+       }
+       qeth_flush_buffers(queue, 0, queue->next_buf_to_flush, count);
+       queue->next_buf_to_flush = index;
+
+       /* flush a buffer with data, if no more PCIs are
+        * outstanding */
+       if (!atomic_read(&queue->set_pci_flags_count)){
+               spin_lock(&queue->lock);
+               buffer = &queue->bufs[index];
+               if (buffer->state == QETH_QDIO_BUF_PRIMED){
+                       qeth_flush_buffers(queue, 0, index, 1);
+                       index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+                       queue->next_buf_to_flush = index;
+               } else if (buffer->next_element_to_fill > 0){
+                       /* it's a packing buffer */
+                       BUG_ON(index != queue->next_buf_to_fill);
+                       buffer->state = QETH_QDIO_BUF_PRIMED;
+                       atomic_inc(&queue->used_buffers);
+                       qeth_flush_buffers(queue, 0, index, 1);
+                       index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
+                       queue->next_buf_to_flush = index;
+                       queue->next_buf_to_fill = index;
+               }
+               spin_unlock(&queue->lock);
+       }
+}
+
+static char*
+qeth_create_qib_param_field(struct qeth_card *card)
+{
+       char *param_field;
+
+       param_field = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(char),
+                             GFP_KERNEL);
+       if (!param_field)
+               return NULL;
+       memset(param_field, 0, QDIO_MAX_BUFFERS_PER_Q * sizeof(char));
+
+       param_field[0] = _ascebc['P'];
+       param_field[1] = _ascebc['C'];
+       param_field[2] = _ascebc['I'];
+       param_field[3] = _ascebc['T'];
+       *((unsigned int *) (&param_field[4])) = QETH_PCI_THRESHOLD_A(card);
+       *((unsigned int *) (&param_field[8])) = QETH_PCI_THRESHOLD_B(card);
+       *((unsigned int *) (&param_field[12])) = QETH_PCI_TIMER_VALUE(card);
+
+       return param_field;
+}
+
+static void
+qeth_initialize_working_pool_list(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *entry;
+
+       QETH_DBF_TEXT(trace,5,"inwrklst");
+       
+       list_for_each_entry(entry, 
+                           &card->qdio.init_pool.entry_list, init_list) {
+               qeth_put_buffer_pool_entry(card,entry);
+       }
+}
+
+static void
+qeth_clear_working_pool_list(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *pool_entry, *tmp;
+       
+       QETH_DBF_TEXT(trace,5,"clwrklst");
+       list_for_each_entry_safe(pool_entry, tmp,
+                           &card->qdio.in_buf_pool.entry_list, list){
+                       list_del(&pool_entry->list);
+       }
+}
+
+static void
+qeth_free_buffer_pool(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *pool_entry, *tmp;
+       int i=0;        
+       QETH_DBF_TEXT(trace,5,"freepool");
+       list_for_each_entry_safe(pool_entry, tmp,
+                                &card->qdio.init_pool.entry_list, init_list){
+               for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) 
+                       free_page((unsigned long)pool_entry->elements[i]);
+               list_del(&pool_entry->init_list);
+               kfree(pool_entry);
+       }
+}
+
+static int
+qeth_alloc_buffer_pool(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *pool_entry;
+       void *ptr;
+       int i, j;
+       
+       for (i = 0; i < card->qdio.init_pool.buf_count; ++i){
+               pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
+               if (!pool_entry){
+                       qeth_free_buffer_pool(card);
+                       return -ENOMEM;
+               }
+               for(j = 0; j < QETH_MAX_BUFFER_ELEMENTS(card); ++j){
+                       ptr = (void *) __get_free_page(GFP_KERNEL);
+                       if (!ptr) {
+                               while (j > 0)
+                                       free_page((unsigned long)
+                                                 pool_entry->elements[--j]);
+                               kfree(pool_entry);
+                               qeth_free_buffer_pool(card);
+                               return -ENOMEM;
+                       }
+                       pool_entry->elements[j] = ptr;
+               }
+               list_add(&pool_entry->init_list, 
+                        &card->qdio.init_pool.entry_list);
+               list_add(&pool_entry->list, 
+                        &card->qdio.in_buf_pool.entry_list);
+       }
+       return 0;
+}
+
+static int
+qeth_alloc_qdio_buffers(struct qeth_card *card)
+{
+       int i, j;
+       
+       QETH_DBF_TEXT(setup, 2, "allcqdbf");
+
+       if (card->qdio.state == QETH_QDIO_ALLOCATED) {
+               qeth_initialize_working_pool_list(card);
+               return 0;
+       }
+       card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q), GFP_KERNEL);
+       if (!card->qdio.in_q)
+               return - ENOMEM;
+       QETH_DBF_TEXT(setup, 2, "inq");
+       QETH_DBF_HEX(setup, 2, &card->qdio.in_q, sizeof(void *));
+       memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q));
+       /* give inbound qeth_qdio_buffers their qdio_buffers */
+       for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i)
+               card->qdio.in_q->bufs[i].buffer =
+                       &card->qdio.in_q->qdio_bufs[i];
+       /* inbound buffer pool */
+       if (qeth_alloc_buffer_pool(card)){
+               kfree(card->qdio.in_q);
+               return -ENOMEM;
+       }
+       /* outbound */
+       card->qdio.out_qs =
+               kmalloc(card->qdio.no_out_queues *
+                       sizeof(struct qeth_qdio_out_q *), GFP_KERNEL);
+       if (!card->qdio.out_qs){
+               qeth_free_buffer_pool(card);
+               return -ENOMEM;
+       }
+       for (i = 0; i < card->qdio.no_out_queues; ++i){
+               card->qdio.out_qs[i] = kmalloc(sizeof(struct qeth_qdio_out_q),
+                                              GFP_KERNEL);
+               if (!card->qdio.out_qs[i]){
+                       while (i > 0)
+                               kfree(card->qdio.out_qs[--i]);
+                       kfree(card->qdio.out_qs);
+                       return -ENOMEM;
+               }
+               QETH_DBF_TEXT_(setup, 2, "outq %i", i);
+               QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *));
+               memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q));
+               card->qdio.out_qs[i]->queue_no = i;
+               /* give inbound qeth_qdio_buffers their qdio_buffers */
+               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j){
+                       card->qdio.out_qs[i]->bufs[j].buffer =
+                               &card->qdio.out_qs[i]->qdio_bufs[j];
+                       skb_queue_head_init(&card->qdio.out_qs[i]->bufs[j].
+                                           skb_list);
+               }
+       }
+       card->qdio.state = QETH_QDIO_ALLOCATED;
+       return 0;
+}
+
+static void
+qeth_free_qdio_buffers(struct qeth_card *card)
+{
+       int i, j;
+       
+       QETH_DBF_TEXT(trace, 2, "freeqdbf");
+       if (card->qdio.state == QETH_QDIO_UNINITIALIZED)
+               return;
+       kfree(card->qdio.in_q);
+       /* inbound buffer pool */
+       qeth_free_buffer_pool(card);
+       /* free outbound qdio_qs */
+       for (i = 0; i < card->qdio.no_out_queues; ++i){
+               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+                       qeth_clear_output_buffer(card, &card->qdio.
+                                               out_qs[i]->bufs[j]);
+               kfree(card->qdio.out_qs[i]);
+       }
+       kfree(card->qdio.out_qs);
+       card->qdio.state = QETH_QDIO_UNINITIALIZED;
+}
+
+static void
+qeth_clear_qdio_buffers(struct qeth_card *card)
+{
+       int i, j;
+       
+       QETH_DBF_TEXT(trace, 2, "clearqdbf");
+       /* clear outbound buffers to free skbs */
+       for (i = 0; i < card->qdio.no_out_queues; ++i)
+               if (card->qdio.out_qs[i]){
+                       for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+                               qeth_clear_output_buffer(card, &card->qdio.
+                                               out_qs[i]->bufs[j]);
+               }
+}
+
+static void
+qeth_init_qdio_info(struct qeth_card *card)
+{
+       QETH_DBF_TEXT(setup, 4, "intqdinf");
+       card->qdio.state = QETH_QDIO_UNINITIALIZED;
+       /* inbound */
+       card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT;
+       card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_DEFAULT;
+       card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count;
+       INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list);
+       INIT_LIST_HEAD(&card->qdio.init_pool.entry_list);
+       card->qdio.in_tasklet.data = (unsigned long) card;
+       card->qdio.in_tasklet.func = qeth_qdio_input_tasklet;
+       /* outbound */
+       card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
+       card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+}
+
+static int
+qeth_init_qdio_queues(struct qeth_card *card)
+{
+       int i, j;
+       int rc;
+       
+       QETH_DBF_TEXT(setup, 2, "initqdqs");
+
+       /* inbound queue */
+       memset(card->qdio.in_q->qdio_bufs, 0,
+              QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
+       card->qdio.in_q->next_buf_to_process = 0;
+       card->qdio.in_q->next_buf_to_init = 0;
+       /*give only as many buffers to hardware as we have buffer pool entries*/
+       for (i = 0; i < card->qdio.in_buf_pool.buf_count; ++i)
+               qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]);
+       card->qdio.in_q->next_buf_to_init = card->qdio.in_buf_pool.buf_count;
+       rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0,
+                    card->qdio.in_buf_pool.buf_count, NULL);
+       if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               return rc;
+       }
+       rc = qdio_synchronize(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0);
+       if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               return rc;
+       }
+       /* outbound queue */
+       for (i = 0; i < card->qdio.no_out_queues; ++i){
+               memset(card->qdio.out_qs[i]->qdio_bufs, 0,
+                      QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
+               for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j){
+                       qeth_clear_output_buffer(card, &card->qdio.
+                                                out_qs[i]->bufs[j]);
+               }
+               card->qdio.out_qs[i]->card = card;
+               card->qdio.out_qs[i]->next_buf_to_fill = 0;
+               card->qdio.out_qs[i]->next_buf_to_flush = 0;
+               card->qdio.out_qs[i]->do_pack = 0;
+               atomic_set(&card->qdio.out_qs[i]->used_buffers,0);
+               atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0);
+               card->qdio.out_qs[i]->tasklet.data = 
+                       (unsigned long) card->qdio.out_qs[i];
+               card->qdio.out_qs[i]->tasklet.func = qeth_qdio_output_tasklet;
+               spin_lock_init(&card->qdio.out_qs[i]->lock);
+       }
+       return 0;
+}
+
+static int
+qeth_qdio_establish(struct qeth_card *card)
+{
+       struct qdio_initialize init_data;
+       char *qib_param_field;
+       struct qdio_buffer **in_sbal_ptrs;
+       struct qdio_buffer **out_sbal_ptrs;
+       int i, j, k;
+       int rc;
+
+       QETH_DBF_TEXT(setup, 2, "qdioest");
+       qib_param_field = qeth_create_qib_param_field(card);
+       if (!qib_param_field)
+               return -ENOMEM;
+
+       in_sbal_ptrs = kmalloc(QDIO_MAX_BUFFERS_PER_Q * sizeof(void *),
+                              GFP_KERNEL);
+       if (!in_sbal_ptrs) {
+               kfree(qib_param_field);
+               return -ENOMEM;
+       }
+       for(i = 0; i < QDIO_MAX_BUFFERS_PER_Q; ++i)
+               in_sbal_ptrs[i] = (struct qdio_buffer *)
+                       virt_to_phys(card->qdio.in_q->bufs[i].buffer);
+
+       out_sbal_ptrs =
+               kmalloc(card->qdio.no_out_queues * QDIO_MAX_BUFFERS_PER_Q *
+                       sizeof(void *), GFP_KERNEL);
+       if (!out_sbal_ptrs) {
+               kfree(in_sbal_ptrs);
+               kfree(qib_param_field);
+               return -ENOMEM;
+       }
+       for(i = 0, k = 0; i < card->qdio.no_out_queues; ++i)
+               for(j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j, ++k){
+                       out_sbal_ptrs[k] = (struct qdio_buffer *)
+                               virt_to_phys(card->qdio.out_qs[i]->
+                                            bufs[j].buffer);
+               }
+
+       memset(&init_data, 0, sizeof(struct qdio_initialize));
+       init_data.cdev                   = CARD_DDEV(card);
+       init_data.q_format               = qeth_get_qdio_q_format(card);
+       init_data.qib_param_field_format = 0;
+       init_data.qib_param_field        = qib_param_field;
+       init_data.min_input_threshold    = QETH_MIN_INPUT_THRESHOLD;
+       init_data.max_input_threshold    = QETH_MAX_INPUT_THRESHOLD;
+       init_data.min_output_threshold   = QETH_MIN_OUTPUT_THRESHOLD;
+       init_data.max_output_threshold   = QETH_MAX_OUTPUT_THRESHOLD;
+       init_data.no_input_qs            = 1;
+       init_data.no_output_qs           = card->qdio.no_out_queues;
+       init_data.input_handler          = (qdio_handler_t *)
+                                          qeth_qdio_input_handler;
+       init_data.output_handler         = (qdio_handler_t *)
+                                          qeth_qdio_output_handler;
+       init_data.int_parm               = (unsigned long) card;
+       init_data.flags                  = QDIO_INBOUND_0COPY_SBALS |
+                                          QDIO_OUTBOUND_0COPY_SBALS |
+                                          QDIO_USE_OUTBOUND_PCIS;
+       init_data.input_sbal_addr_array  = (void **) in_sbal_ptrs;
+       init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
+
+       if (!(rc = qdio_initialize(&init_data)))
+               card->qdio.state = QETH_QDIO_ESTABLISHED;
+
+       kfree(out_sbal_ptrs);
+       kfree(in_sbal_ptrs);
+       kfree(qib_param_field);
+       return rc;
+}
+
+static int
+qeth_qdio_activate(struct qeth_card *card) 
+{
+       QETH_DBF_TEXT(setup,3,"qdioact");
+       return qdio_activate(CARD_DDEV(card), 0);
+}
+
+static int
+qeth_clear_channel(struct qeth_channel *channel)
+{
+       unsigned long flags;
+       struct qeth_card *card;
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"clearch");
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+       rc = ccw_device_clear(channel->ccwdev, QETH_CLEAR_CHANNEL_PARM);
+       spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+       
+       if (rc)
+               return rc;
+       rc = wait_event_interruptible_timeout(card->wait_q,
+                       channel->state==CH_STATE_STOPPED, QETH_TIMEOUT);
+       if (rc == -ERESTARTSYS)
+               return rc;
+       if (channel->state != CH_STATE_STOPPED)
+               return -ETIME;
+       channel->state = CH_STATE_DOWN;
+       return 0;
+}
+
+static int 
+qeth_halt_channel(struct qeth_channel *channel)
+{
+       unsigned long flags;
+       struct qeth_card *card;
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"haltch");
+       card = CARD_FROM_CDEV(channel->ccwdev);
+       spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+       rc = ccw_device_halt(channel->ccwdev, QETH_HALT_CHANNEL_PARM);
+       spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+
+       if (rc)
+               return rc;
+       rc = wait_event_interruptible_timeout(card->wait_q,
+                       channel->state==CH_STATE_HALTED, QETH_TIMEOUT);
+       if (rc == -ERESTARTSYS)
+               return rc;
+       if (channel->state != CH_STATE_HALTED)
+               return -ETIME;
+       return 0;
+}
+
+static int 
+qeth_halt_channels(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"haltchs");
+       if ((rc = qeth_halt_channel(&card->read)))
+               return rc;
+       if ((rc = qeth_halt_channel(&card->write)))
+               return rc;
+       return  qeth_halt_channel(&card->data);
+}
+static int
+qeth_clear_channels(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"clearchs");
+       if ((rc = qeth_clear_channel(&card->read)))
+               return rc;
+       if ((rc = qeth_clear_channel(&card->write)))
+               return rc;
+       return  qeth_clear_channel(&card->data);
+}
+
+static int 
+qeth_clear_halt_card(struct qeth_card *card, int halt) 
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"clhacrd");
+       QETH_DBF_HEX(trace, 3, &card, sizeof(void *));
+
+       if (halt)
+               rc = qeth_halt_channels(card);
+       if (rc)
+               return rc;
+       return qeth_clear_channels(card);
+}
+
+static int
+qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
+{
+       int rc = 0;
+       
+       QETH_DBF_TEXT(trace,3,"qdioclr");
+       if (card->qdio.state == QETH_QDIO_ESTABLISHED){
+               qdio_cleanup(CARD_DDEV(card),
+                            (card->info.type == QETH_CARD_TYPE_IQD) ?
+                            QDIO_FLAG_CLEANUP_USING_HALT :
+                            QDIO_FLAG_CLEANUP_USING_CLEAR);
+               card->qdio.state = QETH_QDIO_ALLOCATED;
+       }
+       rc = qeth_clear_halt_card(card, use_halt);
+       card->state = CARD_STATE_DOWN;
+       return rc;
+}
+
+static int
+qeth_dm_act(struct qeth_card *card)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT(setup,2,"dmact");
+       
+       iob = qeth_wait_for_buffer(&card->write);
+       memcpy(iob->data, DM_ACT, DM_ACT_SIZE);
+
+       memcpy(QETH_DM_ACT_DEST_ADDR(iob->data),
+              &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH);
+       memcpy(QETH_DM_ACT_CONNECTION_TOKEN(iob->data),
+              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
+       rc = qeth_send_control_data(card, DM_ACT_SIZE, iob, NULL, NULL);
+       return rc;
+}
+
+static int 
+qeth_mpc_initialize(struct qeth_card *card)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(setup,2,"mpcinit");
+       
+       if ((rc = qeth_issue_next_read(card))){
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_cm_enable(card))){
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_cm_setup(card))){
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_ulp_enable(card))){
+               QETH_DBF_TEXT_(setup, 2, "4err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_ulp_setup(card))){
+               QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_alloc_qdio_buffers(card))){
+               QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
+               return rc;
+       }
+       if ((rc = qeth_qdio_establish(card))){
+               QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
+               qeth_free_qdio_buffers(card);
+               goto out_qdio;
+       }
+       if ((rc = qeth_qdio_activate(card))){
+               QETH_DBF_TEXT_(setup, 2, "7err%d", rc);
+               goto out_qdio;
+       }
+       if ((rc = qeth_dm_act(card))){
+               QETH_DBF_TEXT_(setup, 2, "8err%d", rc);
+               goto out_qdio;
+       }
+       
+       return 0;
+out_qdio:
+       qeth_qdio_clear_card(card, card->info.type==QETH_CARD_TYPE_OSAE);
+       return rc;      
+}
+
+static void
+qeth_set_device_name(struct qeth_card *card)
+{
+       char buf[IF_NAME_LEN];
+
+       memset(buf, 0, IF_NAME_LEN);
+       if (card->info.type == QETH_CARD_TYPE_IQD) {
+               sprintf(buf,"hsi%d", atomic_read(&qeth_hsi_count));
+               atomic_inc(&qeth_hsi_count);
+               memcpy(card->dev->name,buf,IF_NAME_LEN);
+       }
+
+}
+
+static struct net_device *
+qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) 
+{
+       struct net_device *dev = NULL;
+
+       switch (type) {
+       case QETH_CARD_TYPE_OSAE:
+               switch (linktype) {
+               case QETH_LINK_TYPE_LANE_TR:
+               case QETH_LINK_TYPE_HSTR:
+#ifdef CONFIG_TR
+                       dev = alloc_trdev(0);
+#endif /* CONFIG_TR */
+                       break;  
+               default:
+                       dev = alloc_etherdev(0);
+               }
+               break;
+       case QETH_CARD_TYPE_IQD:
+       default:
+               dev = alloc_etherdev(0);
+       }
+       return dev;
+}
+
+static inline int
+qeth_send_packet(struct qeth_card *, struct sk_buff *);
+
+static int
+qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int rc;
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace, 6, "hrdstxmi");
+       card = (struct qeth_card *)dev->priv;
+       if (skb==NULL) {
+               card->stats.tx_dropped++;
+               card->stats.tx_errors++;
+               return -EIO;
+       }
+       if (card->state != CARD_STATE_UP_LAN_ONLINE) {
+               card->stats.tx_dropped++;
+               card->stats.tx_errors++;
+               card->stats.tx_carrier_errors++;
+               return -EIO;
+       }
+       if (netif_queue_stopped(dev) ) {
+               card->stats.tx_dropped++;
+               return -EBUSY;
+       }
+#ifdef CONFIG_QETH_PERF_STATS
+       card->perf_stats.outbound_start_time = qeth_get_micros();
+#endif
+       /*
+        * dev_queue_xmit should ensure that we are called packet
+        * after packet
+        */
+       netif_stop_queue(dev);
+       if (!(rc = qeth_send_packet(card, skb)))
+               netif_wake_queue(dev);
+
+       return rc;
+}
+
+static int
+qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card)
+{
+       int rc = 0;
+#ifdef CONFIG_QETH_VLAN
+       struct vlan_group *vg;
+       int i;
+
+       if (!(vg = card->vlangrp))
+               return rc;
+       
+       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++){
+               if (vg->vlan_devices[i] == dev){
+                       rc = QETH_VLAN_CARD;
+                       break;
+               }
+       }
+#endif
+       return rc;
+}
+
+static int
+qeth_verify_dev(struct net_device *dev)
+{
+       struct qeth_card *card;
+       unsigned long flags;
+       int rc = 0;
+
+       read_lock_irqsave(&qeth_card_list.rwlock, flags);
+       list_for_each_entry(card, &qeth_card_list.list, list){
+               if (card->dev == dev){
+                       rc = QETH_REAL_CARD;
+                       break;
+               }
+               rc = qeth_verify_vlan_dev(dev, card);
+               if (rc)
+                       break;
+       }
+       read_unlock_irqrestore(&qeth_card_list.rwlock, flags);
+
+       return rc;
+}
+
+static struct qeth_card *
+qeth_get_card_from_dev(struct net_device *dev)
+{
+       struct qeth_card *card = NULL;
+       int rc;
+
+       rc = qeth_verify_dev(dev);
+       if (rc == QETH_REAL_CARD)
+               card = (struct qeth_card *)dev->priv;
+       else if (rc == QETH_VLAN_CARD)
+               card = (struct qeth_card *)
+                       VLAN_DEV_INFO(dev)->real_dev->priv;
+
+       QETH_DBF_TEXT_(trace, 4, "%d", rc);
+       return card ;
+}
+
+static void
+qeth_tx_timeout(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       card = (struct qeth_card *) dev->priv;
+       card->stats.tx_errors++;
+       qeth_schedule_recovery(card);
+}
+
+static int
+qeth_open(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       QETH_DBF_TEXT(trace, 4, "qethopen");
+       
+       card = (struct qeth_card *) dev->priv;
+
+       if ((card->state != CARD_STATE_SOFTSETUP) &&
+           (card->state != CARD_STATE_UP_LAN_OFFLINE))
+               return -ENODEV;
+       if (!card->lan_online){
+               card->state = CARD_STATE_UP_LAN_OFFLINE;
+               return -EIO;
+       }
+
+       card->dev->flags |= IFF_UP;
+       netif_start_queue(dev);
+       card->data.state = CH_STATE_UP;
+       card->state = CARD_STATE_UP_LAN_ONLINE; 
+       return 0;               
+}
+
+static int
+qeth_stop(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       QETH_DBF_TEXT(trace, 4, "qethstop");
+       
+       card = (struct qeth_card *) dev->priv;
+
+       netif_stop_queue(dev);
+       card->dev->flags &= ~IFF_UP;
+       if ((card->state == CARD_STATE_UP_LAN_ONLINE) ||
+           (card->state == CARD_STATE_UP_LAN_OFFLINE))
+               card->state = CARD_STATE_SOFTSETUP; 
+       return 0;
+}
+
+static inline int
+qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
+{
+       int cast_type = RTN_UNSPEC;
+
+       if (skb->dst && skb->dst->neighbour){
+               cast_type = skb->dst->neighbour->type;
+               if ((cast_type == RTN_BROADCAST) ||
+                   (cast_type == RTN_MULTICAST) ||
+                   (cast_type == RTN_ANYCAST))
+                       return cast_type;
+               else
+                       return RTN_UNSPEC;
+       }
+       /* try something else */
+       if (skb->protocol == ETH_P_IPV6)
+               return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
+       else if (skb->protocol == ETH_P_IP)
+               return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
+       /* ... */
+       if (!memcmp(skb->nh.raw, skb->dev->broadcast, 6))
+               return RTN_BROADCAST;
+       else {
+               u16 hdr_mac;
+
+               hdr_mac = *((u16 *)skb->nh.raw);
+               /* tr multicast? */
+               switch (card->info.link_type) {
+               case QETH_LINK_TYPE_HSTR:
+               case QETH_LINK_TYPE_LANE_TR:
+                       if ((hdr_mac == QETH_TR_MAC_NC) ||
+                           (hdr_mac == QETH_TR_MAC_C))
+                               return RTN_MULTICAST;
+               /* eth or so multicast? */
+                default:
+                       if ((hdr_mac == QETH_ETH_MAC_V4) ||
+                           (hdr_mac == QETH_ETH_MAC_V6))
+                               return RTN_MULTICAST;
+               }
+        }
+       return cast_type;
+}
+
+static inline int
+qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
+                       int ipv, int cast_type)
+{
+       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSAE))
+               return card->qdio.default_out_queue;
+       switch (card->qdio.no_out_queues) {
+       case 4:
+               if (cast_type && card->info.is_multicast_different)
+                       return card->info.is_multicast_different &
+                               (card->qdio.no_out_queues - 1);
+               if (card->qdio.do_prio_queueing && (ipv == 4)) {
+                       if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_TOS){
+                               if (skb->nh.iph->tos & IP_TOS_NOTIMPORTANT)
+                                       return 3;
+                               if (skb->nh.iph->tos & IP_TOS_HIGHRELIABILITY)
+                                       return 2;
+                               if (skb->nh.iph->tos & IP_TOS_HIGHTHROUGHPUT)
+                                       return 1;
+                               if (skb->nh.iph->tos & IP_TOS_LOWDELAY)
+                                       return 0;
+                       }
+                       if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_PREC)
+                               return 3 - (skb->nh.iph->tos >> 6);
+               } else if (card->qdio.do_prio_queueing && (ipv == 6)) {
+                       /* TODO: IPv6!!! */
+               }
+               return card->qdio.default_out_queue;
+       default:
+               return 0;
+       }
+}
+
+static inline int
+qeth_get_ip_version(struct sk_buff *skb)
+{
+       switch (skb->protocol) {
+       case ETH_P_IPV6:
+               return 6;
+       case ETH_P_IP:
+               return 4;
+       default:
+               return 0;
+       }
+}
+
+static inline int
+qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
+                struct qeth_hdr **hdr, int ipv)
+{
+       struct sk_buff *new_skb;
+#ifdef CONFIG_QETH_VLAN
+       u16 *tag;
+#endif
+
+       QETH_DBF_TEXT(trace, 6, "prepskb");
+       if (skb_headroom(*skb) < sizeof(struct qeth_hdr)){
+               new_skb = skb_realloc_headroom(*skb, sizeof(struct qeth_hdr));
+               if (!new_skb) {
+                       PRINT_ERR("qeth_prepare_skb: could "
+                                 "not realloc headroom for qeth_hdr "
+                                 "on interface %s", card->info.if_name);
+                       return -ENOMEM;
+               }
+               *skb = new_skb;
+       }
+#ifdef CONFIG_QETH_VLAN
+       if (card->vlangrp && vlan_tx_tag_present(*skb) && (ipv == 6)){
+               /*
+                * Move the mac addresses (6 bytes src, 6 bytes dest)
+                * to the beginning of the new header.  We are using three
+                * memcpys instead of one memmove to save cycles.
+                */
+               skb_push(*skb, VLAN_HLEN);
+               memcpy((*skb)->data, (*skb)->data + 4, 4);
+               memcpy((*skb)->data + 4, (*skb)->data + 8, 4);
+               memcpy((*skb)->data + 8, (*skb)->data + 12, 4);
+               tag = (u16 *) (*skb)->data + 12;
+               /*
+                * first two bytes  = ETH_P_8021Q (0x8100)
+                * second two bytes = VLANID
+                */
+               *tag = __constant_htons(ETH_P_8021Q);
+               *(tag + 1) = vlan_tx_tag_get(*skb);
+               *(tag + 1) = htons(*(tag + 1));
+       }
+#endif
+       *hdr = (struct qeth_hdr *) skb_push(*skb, sizeof(struct qeth_hdr));
+       /* 
+        * sanity check, the Linux memory allocation scheme should
+        * never present us cases like this one (the 32bytes header plus
+        * the first 40 bytes of the paket cross a 4k boundary)
+        */
+       if ((((unsigned long) *hdr) & (~(PAGE_SIZE - 1))) !=
+           (((unsigned long) *hdr + sizeof(struct qeth_hdr) +
+             QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
+               PRINT_ERR("qeth_prepare_skb: misaligned "
+                         "packet on interface %s. Discarded.",
+                         card->info.if_name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline u8
+qeth_get_qeth_hdr_flags4(int cast_type)
+{
+       if (cast_type == RTN_MULTICAST)
+               return QETH_CAST_MULTICAST;
+       if (cast_type == RTN_BROADCAST)
+               return QETH_CAST_BROADCAST;
+       return QETH_CAST_UNICAST;
+}
+
+static inline u8
+qeth_get_qeth_hdr_flags6(int cast_type)
+{
+       u8 ct = QETH_HDR_PASSTHRU | QETH_HDR_IPV6;
+       if (cast_type == RTN_MULTICAST)
+               return ct | QETH_CAST_MULTICAST;
+       if (cast_type == RTN_ANYCAST)
+               return ct | QETH_CAST_ANYCAST;
+       if (cast_type == RTN_BROADCAST)
+               return ct | QETH_CAST_BROADCAST;
+       return ct | QETH_CAST_UNICAST;
+}
+
+static inline void
+qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
+               struct sk_buff *skb, int ipv, int cast_type)
+{
+       hdr->id = 1;
+       hdr->ext_flags = 0;
+
+       QETH_DBF_TEXT(trace, 6, "fillhdr");
+#ifdef CONFIG_QETH_VLAN
+       /* 
+        * before we're going to overwrite this location with next hop ip.
+        * v6 uses passthrough, v4 sets the tag in the QDIO header.
+        */
+       if (card->vlangrp && vlan_tx_tag_present(skb)) {
+               hdr->ext_flags = (ipv == 4)? QETH_EXT_HDR_VLAN_FRAME :
+                                            QETH_EXT_HDR_INCLUDE_VLAN_TAG;
+               hdr->vlan_id = vlan_tx_tag_get(skb);
+       }
+#endif /* CONFIG_QETH_VLAN */
+       hdr->length = skb->len - sizeof(struct qeth_hdr);
+       if (ipv == 4) {  /* IPv4 */
+               hdr->flags = qeth_get_qeth_hdr_flags4(cast_type);
+               memset(hdr->dest_addr, 0, 12);
+               if ((skb->dst) && (skb->dst->neighbour)) {
+                       *((u32 *) (&hdr->dest_addr[12])) =
+                           *((u32 *) skb->dst->neighbour->primary_key);
+               } else {
+                       /* fill in destination address used in ip header */
+                       *((u32 *) (&hdr->dest_addr[12])) = skb->nh.iph->daddr;
+               }
+       } else if (ipv == 6) { /* IPv6 or passthru */
+               hdr->flags = qeth_get_qeth_hdr_flags6(cast_type);
+               if ((skb->dst) && (skb->dst->neighbour)) {
+                       memcpy(hdr->dest_addr,
+                              skb->dst->neighbour->primary_key, 16);
+               } else {
+                       /* fill in destination address used in ip header */
+                       memcpy(hdr->dest_addr, &skb->nh.ipv6h->daddr, 16);
+               }
+       } else { /* passthrough */
+               if (!memcmp(skb->data + sizeof(struct qeth_hdr),
+                           skb->dev->broadcast, 6)) {   /* broadcast? */
+                       hdr->flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU;
+               } else {
+                       hdr->flags = (cast_type == RTN_MULTICAST) ?
+                               QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU :
+                               QETH_CAST_UNICAST | QETH_HDR_PASSTHRU;
+               }
+       }
+}
+
+static inline int
+qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf,
+                char *data, struct sk_buff *skb)
+{
+       struct qdio_buffer *buffer;
+       int length = skb->len;
+       int length_here;
+       int element;
+       int first_lap = 1;
+
+       QETH_DBF_TEXT(trace, 6, "qdfillbf");
+
+       buffer = buf->buffer;
+       atomic_inc(&skb->users);
+       skb_queue_tail(&buf->skb_list, skb);
+       element = buf->next_element_to_fill;
+       while (length > 0) {
+               /* length_here is the remaining amount of data in this page */
+               length_here = PAGE_SIZE - ((unsigned long) data % PAGE_SIZE);
+               if (length < length_here)
+                       length_here = length;
+               buffer->element[element].addr = data;
+               buffer->element[element].length = length_here;
+               length -= length_here;
+               if (!length){
+                       if (first_lap)
+                               buffer->element[element].flags = 0;
+                       else
+                               buffer->element[element].flags =
+                                   SBAL_FLAGS_LAST_FRAG;
+               } else {
+                       if (first_lap)
+                               buffer->element[element].flags =
+                                   SBAL_FLAGS_FIRST_FRAG;
+                       else
+                               buffer->element[element].flags =
+                                   SBAL_FLAGS_MIDDLE_FRAG;
+               }
+               data += length_here;
+               element++;
+               first_lap = 0;
+       }
+       buf->next_element_to_fill = element;
+       if (!queue->do_pack) {
+               QETH_DBF_TEXT(trace, 6, "fillbfnp");
+               /* set state to PRIMED -> will be flushed */
+               buf->state = QETH_QDIO_BUF_PRIMED;
+       } else {
+               QETH_DBF_TEXT(trace, 6, "fillbfpa");
+#ifdef CONFIG_QETH_PERF_STATS
+               queue->card->perf_stats.skbs_sent_pack++;
+#endif
+               if (buf->next_element_to_fill >=
+                               QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
+                       /*
+                        * packed buffer if full -> set state PRIMED
+                        * -> will be flushed
+                        */
+                       buf->state = QETH_QDIO_BUF_PRIMED;
+               }
+       }
+       return 0;
+}
+
+static inline int
+qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
+                   struct qeth_qdio_out_q *queue, int ipv,
+                   int cast_type)
+{
+       struct qeth_hdr *hdr;
+       struct qeth_qdio_out_buffer *buffer;
+       int elements_needed;
+       int rc;
+
+       QETH_DBF_TEXT(trace, 6, "dosndpkt");
+
+       if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
+               QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
+               return rc;
+       }
+       qeth_fill_header(card, hdr, skb, ipv, cast_type);
+       elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len)
+                               >> PAGE_SHIFT);
+       if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
+               PRINT_ERR("qeth_do_send_packet: invalid size of "
+                                "IP packet. Discarded.");
+               return -EINVAL;
+       }
+       
+       spin_lock(&queue->lock);
+       /* check if we need to switch packing state of this queue */
+       if (card->info.type != QETH_CARD_TYPE_IQD)
+               qeth_switch_packing_state(queue);
+       buffer = &queue->bufs[queue->next_buf_to_fill];
+       BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
+       if (queue->do_pack){
+               /* does packet fit in current buffer? */
+               if((QETH_MAX_BUFFER_ELEMENTS(card) - buffer->next_element_to_fill)
+                               < elements_needed){
+                       /* ... no -> set state PRIMED */
+                       buffer->state = QETH_QDIO_BUF_PRIMED;
+                       atomic_inc(&queue->used_buffers);
+                       queue->next_buf_to_fill =
+                               (queue->next_buf_to_fill + 1) %
+                               QDIO_MAX_BUFFERS_PER_Q;
+                       buffer = &queue->bufs[queue->next_buf_to_fill];
+               }
+       } 
+       
+       rc = qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
+       if (rc) {
+               PRINT_WARN("qeth_do_send_packet: error during "
+                             "qeth_fill_buffer.");
+               card->stats.tx_dropped++;
+               spin_unlock(&queue->lock);
+               return rc;
+       }
+       if (buffer->state == QETH_QDIO_BUF_PRIMED){
+               /* next time fill the next buffer */
+               atomic_inc(&queue->used_buffers);
+               queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
+                       QDIO_MAX_BUFFERS_PER_Q;
+       }
+       spin_unlock(&queue->lock);
+
+       tasklet_schedule(&queue->tasklet);
+       
+       return rc;
+}
+
+static inline int
+qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
+{
+       int ipv;
+       int cast_type;
+       struct qeth_qdio_out_q *queue;
+       int rc;
+
+       QETH_DBF_TEXT(trace, 6, "sendpkt");
+
+       ipv = qeth_get_ip_version(skb);
+       cast_type = qeth_get_cast_type(card, skb);
+       queue = card->qdio.out_qs
+               [qeth_get_priority_queue(card, skb, ipv, cast_type)];
+       /* do we have empty buffers? */
+       rc = (atomic_read(&queue->used_buffers) >= 
+             QDIO_MAX_BUFFERS_PER_Q - 1) ? -EBUSY : 0;
+       if (rc) {
+               card->stats.tx_dropped++;
+               QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
+               return rc;
+       }
+
+       rc = qeth_do_send_packet(card, skb, queue, ipv, cast_type);
+
+       if (!rc){
+               card->stats.tx_packets++;
+               card->stats.tx_bytes += skb->len;
+#ifdef CONFIG_QETH_PERF_STATS
+               card->perf_stats.outbound_time += qeth_get_micros() -
+                       card->perf_stats.outbound_start_time;
+#endif
+       }
+       return rc;
+}
+
+static int
+qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
+{
+       struct qeth_card *card = (struct qeth_card *) dev->priv;
+       int rc = 0;
+
+       switch(regnum){
+       case MII_BMCR: /* Basic mode control register */
+               rc = BMCR_FULLDPLX;
+               if(card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)
+                       rc |= BMCR_SPEED100;
+               break;
+       case MII_BMSR: /* Basic mode status register */
+               rc = BMSR_ERCAP | BMSR_ANEGCOMPLETE | BMSR_LSTATUS |
+                    BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL |
+                    BMSR_100BASE4;
+               break;
+       case MII_PHYSID1: /* PHYS ID 1 */
+               rc = (dev->dev_addr[0] << 16) | (dev->dev_addr[1] << 8) |
+                    dev->dev_addr[2];
+               rc = (rc >> 5) & 0xFFFF;
+               break;
+       case MII_PHYSID2: /* PHYS ID 2 */
+               rc = (dev->dev_addr[2] << 10) & 0xFFFF;
+               break;
+       case MII_ADVERTISE: /* Advertisement control reg */
+               rc = ADVERTISE_ALL;
+               break;
+       case MII_LPA: /* Link partner ability reg */
+               rc = LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL |
+                    LPA_100BASE4 | LPA_LPACK;
+               break;
+       case MII_EXPANSION: /* Expansion register */
+               break;
+       case MII_DCOUNTER: /* disconnect counter */
+               break;
+       case MII_FCSCOUNTER: /* false carrier counter */
+               break;
+       case MII_NWAYTEST: /* N-way auto-neg test register */
+               break;
+       case MII_RERRCOUNTER: /* rx error counter */
+               rc = card->stats.rx_errors;
+               break;
+       case MII_SREVISION: /* silicon revision */
+               break;
+       case MII_RESV1: /* reserved 1 */
+               break;
+       case MII_LBRERROR: /* loopback, rx, bypass error */
+               break;
+       case MII_PHYADDR: /* physical address */
+               break;
+       case MII_RESV2: /* reserved 2 */
+               break;
+       case MII_TPISTATUS: /* TPI status for 10mbps */
+               break;
+       case MII_NCONFIG: /* network interface config */
+               break;
+       default:
+               rc = 0;
+               break;
+       }
+       return rc;
+}
+
+static void
+qeth_mdio_write(struct net_device *dev, int phy_id, int regnum, int value)
+{
+       switch(regnum){
+       case MII_BMCR: /* Basic mode control register */
+       case MII_BMSR: /* Basic mode status register */
+       case MII_PHYSID1: /* PHYS ID 1 */
+       case MII_PHYSID2: /* PHYS ID 2 */
+       case MII_ADVERTISE: /* Advertisement control reg */
+       case MII_LPA: /* Link partner ability reg */
+       case MII_EXPANSION: /* Expansion register */
+       case MII_DCOUNTER: /* disconnect counter */
+       case MII_FCSCOUNTER: /* false carrier counter */
+       case MII_NWAYTEST: /* N-way auto-neg test register */
+       case MII_RERRCOUNTER: /* rx error counter */
+       case MII_SREVISION: /* silicon revision */
+       case MII_RESV1: /* reserved 1 */
+       case MII_LBRERROR: /* loopback, rx, bypass error */
+       case MII_PHYADDR: /* physical address */
+       case MII_RESV2: /* reserved 2 */
+       case MII_TPISTATUS: /* TPI status for 10mbps */
+       case MII_NCONFIG: /* network interface config */
+       default:
+               break;
+       }
+}
+
+static inline const char *
+qeth_arp_get_error_cause(int *rc)
+{
+       switch (*rc) {
+       case QETH_IPA_ARP_RC_FAILED:
+               *rc = -EIO;
+               return "operation failed";
+       case QETH_IPA_ARP_RC_NOTSUPP:
+               *rc = -EOPNOTSUPP;
+               return "operation not supported";
+       case QETH_IPA_ARP_RC_OUT_OF_RANGE:
+               *rc = -EINVAL;
+               return "argument out of range";
+       case QETH_IPA_ARP_RC_Q_NOTSUPP:
+               *rc = -EOPNOTSUPP;
+               return "query operation not supported";
+       case QETH_IPA_ARP_RC_Q_NO_DATA:
+               *rc = -ENOENT;
+               return "no query data available";
+       default:
+               return "unknown error";
+       }
+}
+
+static int 
+qeth_send_simple_setassparms(struct qeth_card *, enum qeth_ipa_funcs,
+                            __u16, long);
+
+static int
+qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
+{
+       int tmp;
+       int rc;
+               
+       QETH_DBF_TEXT(trace,3,"arpstnoe");
+       
+       /* TODO: really not supported by GuestLAN? */
+       if (card->info.guestlan)
+               return -EOPNOTSUPP;
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
+                                         IPA_CMD_ASS_ARP_SET_NO_ENTRIES,
+                                         no_entries);
+       if (rc) {
+               tmp = rc;
+               PRINT_WARN("Could not set number of ARP entries on %s: "
+                          "%s (0x%x)\n",
+                          card->info.if_name, qeth_arp_get_error_cause(&rc),
+                          tmp);
+       }
+       return rc;
+}
+
+static int
+qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
+                 unsigned long data)
+{
+       struct qeth_ipa_arp_cmd *cmd;
+       struct qeth_arp_query_data *qdata;
+       struct qeth_arp_query_info *qinfo;
+       int entry_size;
+       int i;
+
+       QETH_DBF_TEXT(trace,4,"arpquecb");
+
+       qinfo = (struct qeth_arp_query_info *) reply->param;
+       cmd = (struct qeth_ipa_arp_cmd *) data;
+       if (cmd->ihdr.return_code) {
+               QETH_DBF_TEXT_(trace,4,"qaer1%i", cmd->ihdr.return_code);
+               return 0;
+       }
+       if (cmd->shdr.return_code) {
+               cmd->ihdr.return_code = cmd->shdr.return_code;
+               QETH_DBF_TEXT_(trace,4,"qaer2%i", cmd->ihdr.return_code);
+               return 0;
+       }
+       qdata = &cmd->data.query_arp;
+       switch(qdata->reply_bits){
+       case 5:
+               entry_size = sizeof(struct qeth_arp_qi_entry5);
+               break;
+       case 7:
+               entry_size = sizeof(struct qeth_arp_qi_entry7);
+               break;
+       default:
+               /* tr is the same as eth -> entry7 */
+               entry_size = sizeof(struct qeth_arp_qi_entry7);
+               break;
+       }
+       /* check if there is enough room in userspace */
+       if ((qinfo->udata_len - qinfo->udata_offset) <
+                       qdata->no_entries * entry_size){
+               QETH_DBF_TEXT_(trace, 4, "qaer3%i", -ENOMEM);
+               cmd->ihdr.return_code = -ENOMEM;
+               goto out_error;
+       }       
+       QETH_DBF_TEXT_(trace, 4, "anore%i", cmd->shdr.number_of_replies);
+       QETH_DBF_TEXT_(trace, 4, "aseqn%i", cmd->shdr.seq_no);
+       QETH_DBF_TEXT_(trace, 4, "anoen%i", qdata->no_entries);
+       for (i = 0; i < qdata->no_entries; ++i){
+               memcpy(qinfo->udata + qinfo->udata_offset,
+                      qdata->data + i*entry_size, entry_size);
+               qinfo->no_entries++;
+               qinfo->udata_offset += entry_size;
+       }
+       /* check if all replies received ... */
+       if (cmd->shdr.seq_no < cmd->shdr.number_of_replies)
+               return 1;
+       memcpy(qinfo->udata, &qinfo->no_entries, 4);
+       memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET,&qdata->reply_bits,2);
+       return 0;
+out_error:
+       i = 0;
+       memcpy(qinfo->udata, &i, 4);
+       return 0;
+}
+
+static struct qeth_cmd_buffer *
+qeth_get_ipacmd_buffer(struct qeth_card *, enum qeth_ipa_cmds,
+                      enum qeth_prot_versions);
+
+struct qeth_cmd_buffer *
+qeth_get_ipa_arp_cmd_buffer(struct qeth_card *card, u16 cmd_code,
+                           u32 data_len, enum qeth_prot_versions proto)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_arp_cmd *cmd;
+       u16 s1, s2;
+       
+       QETH_DBF_TEXT(trace,4,"getarpcm");
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, proto);
+
+       memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
+       /* adjust sizes in IPA_PDU_HEADER */
+       s1 = (u32) IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN + data_len;
+       s2 = (u32) QETH_ARP_CMD_BASE_LEN + data_len;
+       memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
+       memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
+       memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
+       memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
+
+       cmd = (struct qeth_ipa_arp_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       cmd->shdr.assist_no = IPA_ARP_PROCESSING;
+       cmd->shdr.length = 8 + data_len;
+       cmd->shdr.command_code = cmd_code;
+       cmd->shdr.return_code = 0;
+       cmd->shdr.seq_no = 0;
+
+       return iob;
+}
+
+static int
+qeth_send_ipa_arp_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
+                     char *data, int data_len,
+                     int (*reply_cb)
+                     (struct qeth_card *,struct qeth_reply*, unsigned long),
+                     void *reply_param)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(trace,4,"sendarp");
+
+       memcpy(QETH_IPA_ARP_DATA_POS(iob->data), data, data_len);
+       memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
+              &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
+
+       rc = qeth_send_control_data(card, IPA_PDU_HEADER_SIZE +
+                                   QETH_ARP_CMD_BASE_LEN + data_len, iob,
+                                   reply_cb, reply_param);
+       return rc;
+}
+
+static int
+qeth_arp_query(struct qeth_card *card, char *udata)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_arp_query_data *qdata;
+       struct qeth_arp_query_info qinfo = {0, };
+       int tmp;
+       int rc;
+       
+       QETH_DBF_TEXT(trace,3,"arpquery");
+
+       /* TODO: really not supported by GuestLAN? */
+       if (card->info.guestlan)
+               return -EOPNOTSUPP;
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       /* get size of userspace mem area */
+       if (copy_from_user(&qinfo.udata_len, udata, 4))
+               return -EFAULT;
+       if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL)))
+               return -ENOMEM;
+       memset(qinfo.udata, 0, qinfo.udata_len);
+       qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
+       /* alloc mem area for the actual query */
+       if (!(qdata = kmalloc(sizeof(struct qeth_arp_query_data),
+                             GFP_KERNEL))){
+               kfree(qinfo.udata);
+               return -ENOMEM;
+       }
+       memset(qdata, 0, sizeof(struct qeth_arp_query_data));
+       iob = qeth_get_ipa_arp_cmd_buffer(card, IPA_CMD_ASS_ARP_QUERY_INFO,
+                                         sizeof(struct qeth_arp_query_data),
+                                         QETH_PROT_IPV4);
+       rc = qeth_send_ipa_arp_cmd(card, iob,
+                                  (char *) qdata,
+                                  sizeof(struct qeth_arp_query_data),
+                                  qeth_arp_query_cb,
+                                  (void *)&qinfo);
+       if (rc) {
+               tmp = rc;
+               PRINT_WARN("Error while querying ARP cache on %s: %s (0x%x)\n",
+                          card->info.if_name, qeth_arp_get_error_cause(&rc),
+                          tmp);
+               copy_to_user(udata, qinfo.udata, 4);
+       } else {
+               copy_to_user(udata, qinfo.udata, qinfo.udata_len);
+       }
+       kfree(qinfo.udata);
+       return rc;
+}
+
+static int
+qeth_default_setassparms_cb(struct qeth_card *, struct qeth_reply *,
+                           unsigned long);
+
+static struct qeth_cmd_buffer * 
+qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
+                        __u16, __u16, enum qeth_prot_versions);
+
+static int
+qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *,
+                     __u16, long,
+                     int (*reply_cb)
+                     (struct qeth_card *, struct qeth_reply *, unsigned long),
+                     void *reply_param);
+
+static int
+qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry)
+{
+       struct qeth_cmd_buffer *iob;
+       char buf[16];
+       int tmp;
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"arpadent");
+
+       /* TODO: really not supported by GuestLAN? */
+       if (card->info.guestlan)
+               return -EOPNOTSUPP;
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       
+       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+                                      IPA_CMD_ASS_ARP_ADD_ENTRY,
+                                      sizeof(struct qeth_arp_cache_entry),
+                                      QETH_PROT_IPV4);
+       rc = qeth_send_setassparms(card, iob,
+                                  sizeof(struct qeth_arp_cache_entry),
+                                  (unsigned long) entry,
+                                  qeth_default_setassparms_cb, NULL);
+       if (rc) {
+               tmp = rc;
+               qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
+               PRINT_WARN("Could not add ARP entry for address %s on %s: "
+                          "%s (0x%x)\n",
+                          buf, card->info.if_name,
+                          qeth_arp_get_error_cause(&rc), tmp);
+       }
+       return rc;
+}
+
+static int
+qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry)
+{
+       struct qeth_cmd_buffer *iob;
+       char buf[16] = {0, };
+       int tmp;
+       int rc;
+       
+       QETH_DBF_TEXT(trace,3,"arprment");
+       
+       /* TODO: really not supported by GuestLAN? */
+       if (card->info.guestlan)
+               return -EOPNOTSUPP;
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       memcpy(buf, entry, 12);
+       iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
+                                      IPA_CMD_ASS_ARP_REMOVE_ENTRY,
+                                      12,
+                                      QETH_PROT_IPV4);
+       rc = qeth_send_setassparms(card, iob,
+                                  12, (unsigned long)buf,
+                                  qeth_default_setassparms_cb, NULL);
+       if (rc) {
+               tmp = rc;
+               memset(buf, 0, 16);
+               qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
+               PRINT_WARN("Could not delete ARP entry for address %s on %s: "
+                          "%s (0x%x)\n",
+                          buf, card->info.if_name,
+                          qeth_arp_get_error_cause(&rc), tmp);
+       }
+       return rc;
+}
+
+static int
+qeth_arp_flush_cache(struct qeth_card *card)
+{
+       int rc;
+       int tmp;
+       
+       QETH_DBF_TEXT(trace,3,"arpflush");
+       
+       /* TODO: really not supported by GuestLAN? */
+       if (card->info.guestlan)
+               return -EOPNOTSUPP;
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
+                                         IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
+       if (rc){
+               tmp = rc;
+               PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x)\n",
+                          card->info.if_name, qeth_arp_get_error_cause(&rc),
+                          tmp);
+       }
+       return rc;
+}
+
+static int
+qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct qeth_card *card = (struct qeth_card *)dev->priv;
+       struct qeth_arp_cache_entry arp_entry;
+       struct mii_ioctl_data *mii_data;
+       int rc = 0;
+       
+       if (!card)
+               return -ENODEV;
+
+       if ((card->state != CARD_STATE_UP_LAN_ONLINE) &&
+           (card->state != CARD_STATE_UP_LAN_OFFLINE))
+               return -ENODEV;
+
+       switch (cmd){
+       case SIOCDEVPRIVATE:
+       case SIOC_QETH_ARP_SET_NO_ENTRIES:
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               rc = qeth_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue);
+               break;
+       case SIOCDEVPRIVATE+1:
+       case SIOC_QETH_ARP_QUERY_INFO:
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               rc = qeth_arp_query(card, rq->ifr_ifru.ifru_data);
+               break;
+       case SIOCDEVPRIVATE+2:
+       case SIOC_QETH_ARP_ADD_ENTRY:
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
+                                  sizeof(struct qeth_arp_cache_entry)))
+                       rc = -EFAULT;
+               else
+                       rc = qeth_arp_add_entry(card, &arp_entry);
+               break;
+       case SIOCDEVPRIVATE+3:
+       case SIOC_QETH_ARP_REMOVE_ENTRY:
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               if (copy_from_user(&arp_entry, rq->ifr_ifru.ifru_data,
+                                  sizeof(struct qeth_arp_cache_entry)))
+                       rc = -EFAULT;
+               else
+                       rc = qeth_arp_remove_entry(card, &arp_entry);
+               break;
+       case SIOCDEVPRIVATE+4:
+       case SIOC_QETH_ARP_FLUSH_CACHE:
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               rc = qeth_arp_flush_cache(card);
+               break;
+       case SIOCDEVPRIVATE+5:
+       case SIOC_QETH_ADP_SET_SNMP_CONTROL:
+               break;
+       case SIOCDEVPRIVATE+6:
+       case SIOC_QETH_GET_CARD_TYPE:
+               break;
+       case SIOCGMIIPHY:
+               mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data;
+               mii_data->phy_id = 0;
+               break;
+       case SIOCGMIIREG:
+               mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data;
+               if (mii_data->phy_id != 0)
+                       rc = -EINVAL;
+               else
+                       mii_data->val_out = qeth_mdio_read(dev,mii_data->phy_id,
+                                                          mii_data->reg_num);
+               break;
+       case SIOCSMIIREG:
+               rc = -EOPNOTSUPP;
+               break;
+               /* TODO: remove return if qeth_mdio_write does something */
+               if (!capable(CAP_NET_ADMIN)){
+                       rc = -EPERM;
+                       break;
+               }
+               mii_data = (struct mii_ioctl_data *) &rq->ifr_ifru.ifru_data;
+               if (mii_data->phy_id != 0)
+                       rc = -EINVAL;
+               else
+                       qeth_mdio_write(dev, mii_data->phy_id, mii_data->reg_num,
+                                       mii_data->val_in);
+               break;
+       default:
+               rc = -EOPNOTSUPP;
+       }
+       return rc;
+}
+
+static struct net_device_stats *
+qeth_get_stats(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       card = (struct qeth_card *) (dev->priv);
+
+       QETH_DBF_TEXT(trace,5,"getstat");
+
+       return &card->stats;
+}
+
+static int
+qeth_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct qeth_card *card;
+       char dbf_text[15];
+
+       card = (struct qeth_card *) (dev->priv);
+
+       QETH_DBF_TEXT(trace,4,"chgmtu");
+       sprintf(dbf_text, "%8x", new_mtu);
+       QETH_DBF_TEXT(trace,4,dbf_text);
+
+       if (new_mtu < 64)
+               return -EINVAL;
+       if (new_mtu > 65535)
+               return -EINVAL;
+       if ((!qeth_is_supported(card,IPA_IP_FRAGMENTATION)) &&
+           (!qeth_mtu_is_valid(card, new_mtu)))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+#ifdef CONFIG_QETH_VLAN
+static void
+qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace,4,"vlanreg");
+       
+       card = (struct qeth_card *) dev->priv;
+       spin_lock_irq(&card->vlanlock);
+       card->vlangrp = grp;
+       spin_unlock_irq(&card->vlanlock);
+}
+
+static void
+qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace,4,"vlkilvid");
+       
+       card = (struct qeth_card *) dev->priv;
+       spin_lock_irq(&card->vlanlock);
+       if (card->vlangrp)
+               card->vlangrp->vlan_devices[vid] = NULL;
+       spin_unlock_irq(&card->vlanlock);
+       /* delete mc addresses for this vlan dev */
+       qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+#endif
+
+static int 
+qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np)
+{
+       return 0;
+}
+
+#ifdef CONFIG_QETH_IPV6
+int
+qeth_ipv6_generate_eui64(u8 * eui, struct net_device *dev)
+{
+       switch (dev->type) {
+       case ARPHRD_ETHER:
+       case ARPHRD_FDDI:
+       case ARPHRD_IEEE802_TR:
+               if (dev->addr_len != ETH_ALEN)
+                       return -1;
+               memcpy(eui, dev->dev_addr, 3);
+               memcpy(eui + 5, dev->dev_addr + 3, 3);
+               eui[3] = (dev->dev_id >> 8) & 0xff;
+               eui[4] = dev->dev_id & 0xff;
+               return 0;
+       }
+       return -1;
+
+}
+#endif
+
+static void
+qeth_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev)
+{
+       if (dev->type == ARPHRD_IEEE802_TR)
+               ip_tr_mc_map(ipm, mac);
+       else
+               ip_eth_mc_map(ipm, mac);
+}
+
+static struct qeth_ipaddr *
+qeth_get_addr_buffer(enum qeth_prot_versions prot)
+{
+       struct qeth_ipaddr *addr;
+       
+       addr = kmalloc(sizeof(struct qeth_ipaddr), GFP_ATOMIC);
+       if (addr == NULL) {
+               PRINT_WARN("Not enough memory to add address\n");
+               return NULL;
+       }
+       memset(addr,0,sizeof(struct qeth_ipaddr));
+       addr->type = QETH_IP_TYPE_NORMAL;
+       addr->proto = prot;
+       addr->is_multicast = 0;
+       addr->users = 0;
+       addr->set_flags = 0;
+       addr->del_flags = 0;
+       return addr;
+}
+
+static void
+qeth_delete_mc_addresses(struct qeth_card *card)
+{
+       struct qeth_ipaddr *ipm, *iptodo;
+       unsigned long flags;
+       
+       QETH_DBF_TEXT(trace,4,"delmc");
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry(ipm, &card->ip_list, entry){
+               if (!ipm->is_multicast)
+                       continue;
+               iptodo = qeth_get_addr_buffer(ipm->proto);
+               memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr));
+               iptodo->users = iptodo->users * -1;
+               if (!__qeth_insert_ip_todo(card, iptodo, 0))
+                       kfree(iptodo);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+}
+
+static inline void
+qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
+{
+       struct qeth_ipaddr *ipm;
+       struct ip_mc_list *im4;
+       char buf[MAX_ADDR_LEN];
+
+       QETH_DBF_TEXT(trace,4,"addmc");
+       for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
+               qeth_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
+               ipm = qeth_get_addr_buffer(QETH_PROT_IPV4);
+               if (!ipm)
+                       continue;
+               ipm->u.a4.addr = im4->multiaddr;
+               memcpy(ipm->mac,buf,OSA_ADDR_LEN);
+               ipm->is_multicast = 1;
+               if (!qeth_add_ip(card,ipm))
+                       kfree(ipm);
+       }
+}
+
+static inline void
+qeth_add_vlan_mc(struct qeth_card *card)
+{
+#ifdef CONFIG_QETH_VLAN
+       struct in_device *in_dev;
+       struct vlan_group *vg;
+       int i;
+
+       QETH_DBF_TEXT(trace,4,"addmcvl");
+       if (!qeth_is_supported(card,IPA_FULL_VLAN) || 
+           (card->vlangrp == NULL))
+               return ;
+       
+       vg = card->vlangrp;
+       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+               if (vg->vlan_devices[i] == NULL ||
+                   !(vg->vlan_devices[i]->flags & IFF_UP))
+                       continue;
+               in_dev = in_dev_get(vg->vlan_devices[i]);
+               if (!in_dev)
+                       continue;
+               read_lock(&in_dev->lock);
+               qeth_add_mc(card,in_dev);
+               read_unlock(&in_dev->lock);
+               in_dev_put(in_dev);
+       }
+#endif
+}
+
+static void
+qeth_add_multicast_ipv4(struct qeth_card *card)
+{
+       struct in_device *in4_dev;
+
+       QETH_DBF_TEXT(trace,4,"chkmcv4");
+       in4_dev = in_dev_get(card->dev);
+       if (in4_dev == NULL)
+               return;
+       read_lock(&in4_dev->lock);
+       qeth_add_mc(card, in4_dev);
+       qeth_add_vlan_mc(card);
+       read_unlock(&in4_dev->lock);
+       in_dev_put(in4_dev);
+}
+
+#ifdef CONFIG_QETH_IPV6
+static inline void
+qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
+{
+       struct qeth_ipaddr *ipm;
+       struct ifmcaddr6 *im6;
+       char buf[MAX_ADDR_LEN];
+
+       QETH_DBF_TEXT(trace,4,"addmc6");
+       for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) {
+               ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0);
+               ipm = qeth_get_addr_buffer(QETH_PROT_IPV6);
+               if (!ipm)
+                       continue;
+               ipm->is_multicast = 1;
+               memcpy(ipm->mac,buf,OSA_ADDR_LEN);
+               memcpy(&ipm->u.a6.addr,&im6->mca_addr.s6_addr, 
+                      sizeof(struct in6_addr));
+               if (!qeth_add_ip(card,ipm))
+                       kfree(ipm);
+       }
+}
+
+static inline void
+qeth_add_vlan_mc6(struct qeth_card *card)
+{
+#ifdef CONFIG_QETH_VLAN
+       struct inet6_dev *in_dev;
+       struct vlan_group *vg;
+       int i;
+
+       QETH_DBF_TEXT(trace,4,"admc6vl");
+       if (!qeth_is_supported(card,IPA_FULL_VLAN) ||
+           (card->vlangrp == NULL))
+               return ;
+       
+       vg = card->vlangrp;
+       for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+               if (vg->vlan_devices[i] == NULL ||
+                   !(vg->vlan_devices[i]->flags & IFF_UP))
+                       continue;
+               in_dev = in6_dev_get(vg->vlan_devices[i]);
+               if (!in_dev)
+                       continue;
+               read_lock(&in_dev->lock);
+               qeth_add_mc6(card,in_dev);
+               read_unlock(&in_dev->lock);
+               in6_dev_put(in_dev);
+       }
+#endif /* CONFIG_QETH_VLAN */
+}
+
+static void
+qeth_add_multicast_ipv6(struct qeth_card *card)
+{
+       struct inet6_dev *in6_dev;
+
+       QETH_DBF_TEXT(trace,4,"chkmcv6");
+       if (!qeth_is_supported(card, IPA_IPV6))
+               return ;
+               
+       in6_dev = in6_dev_get(card->dev);
+       if (in6_dev == NULL) 
+               return;
+       read_lock(&in6_dev->lock);
+       qeth_add_mc6(card, in6_dev);
+       qeth_add_vlan_mc6(card);
+       read_unlock(&in6_dev->lock);
+       in6_dev_put(in6_dev);
+}
+#endif /* CONFIG_QETH_IPV6 */
+
+/**
+ * set multicast address on card 
+ */
+static void
+qeth_set_multicast_list(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       QETH_DBF_TEXT(trace,3,"setmulti");
+       card = (struct qeth_card *) dev->priv;
+       
+       qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+
+static void
+qeth_fill_ipacmd_header(struct qeth_card *card, struct qeth_ipa_cmd *cmd,
+                       __u8 command, enum qeth_prot_versions prot)
+{
+       memset(cmd, 0, sizeof (struct qeth_ipa_cmd));
+       cmd->hdr.command = command;
+       cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
+       cmd->hdr.seqno = card->seqno.ipa;
+       cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
+       cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
+       cmd->hdr.prim_version_no = 1;
+       cmd->hdr.param_count = 1;
+       cmd->hdr.prot_version = prot;
+       cmd->hdr.ipa_supported = 0;
+       cmd->hdr.ipa_enabled = 0;
+}
+
+static struct qeth_cmd_buffer *
+qeth_get_ipacmd_buffer(struct qeth_card *card, enum qeth_ipa_cmds ipacmd,
+                      enum qeth_prot_versions prot)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+
+       iob = qeth_wait_for_buffer(&card->write);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       qeth_fill_ipacmd_header(card, cmd, ipacmd, prot);       
+
+       return iob;
+}
+
+static int 
+qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(trace,4,"setdelmc");
+
+       iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       memcpy(&cmd->data.setdelipm.mac,addr->mac, OSA_ADDR_LEN);
+       if (addr->proto == QETH_PROT_IPV6)
+               memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr,
+                      sizeof(struct in6_addr));
+       else
+               memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr,4);
+       
+       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
+       
+       return rc;
+}
+static inline void
+qeth_fill_netmask(u8 *netmask, unsigned int len)
+{
+       int i,j; 
+       for (i=0;i<16;i++) { 
+               j=(len)-(i*8); 
+               if (j >= 8)
+                       netmask[i] = 0xff;
+               else if (j > 0)
+                       netmask[i] = (u8)(0xFF00>>j);
+               else
+                       netmask[i] = 0;
+       } 
+}
+
+static int
+qeth_send_setdelip(struct qeth_card *card, struct qeth_ipaddr *addr, 
+                  int ipacmd, unsigned int flags)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       __u8 netmask[16];
+       
+       QETH_DBF_TEXT(trace,4,"setdelip");
+       QETH_DBF_TEXT_(trace,4,"flags%02X", flags);
+
+       iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       if (addr->proto == QETH_PROT_IPV6) {
+               memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr,
+                      sizeof(struct in6_addr));
+               qeth_fill_netmask(netmask,addr->u.a6.pfxlen);
+               memcpy(cmd->data.setdelip6.mask, netmask,
+                      sizeof(struct in6_addr));
+               cmd->data.setdelip6.flags = flags;
+       } else {
+               memcpy(cmd->data.setdelip4.ip_addr, &addr->u.a4.addr, 4);
+               memcpy(cmd->data.setdelip4.mask, &addr->u.a4.mask, 4);
+               cmd->data.setdelip4.flags = flags;
+       }
+       
+       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
+
+       return rc;
+}
+
+static int 
+qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
+{
+       //char buf[50];
+       int rc;
+       int cnt = 3;
+       
+       if (addr->proto == QETH_PROT_IPV4) {
+               QETH_DBF_TEXT(trace, 2,"setaddr4");
+               QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, sizeof(int));
+       } else if (addr->proto == QETH_PROT_IPV6) {
+               QETH_DBF_TEXT(trace, 2, "setaddr6");
+               QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4);
+               QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4);
+       } else {
+               QETH_DBF_TEXT(trace, 2, "setaddr?");
+               QETH_DBF_HEX(trace, 4, addr, sizeof(struct qeth_ipaddr));
+       }
+       do {
+               if (addr->is_multicast)
+                       rc =  qeth_send_setdelmc(card, addr, IPA_CMD_SETIPM);
+               else
+                       rc = qeth_send_setdelip(card, addr, IPA_CMD_SETIP,
+                                       addr->set_flags);
+               if (rc)
+                       QETH_DBF_TEXT(trace, 2, "failed");
+       } while ((--cnt > 0) && rc);
+       if (rc){
+               QETH_DBF_TEXT(trace, 2, "FAILED");
+               /* TODO: re-activate this warning as soon as we have a
+                * clean mirco code
+               qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
+               PRINT_WARN("Could not register IP address %s (rc=%x)\n",
+                          buf, rc);
+               */
+       }
+       return rc;
+}
+
+static int
+qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
+{
+       //char buf[50];
+       int rc;
+       
+       if (addr->proto == QETH_PROT_IPV4) {
+               QETH_DBF_TEXT(trace, 2,"deladdr4");
+               QETH_DBF_HEX(trace, 2, &addr->u.a4.addr, sizeof(int));
+       } else if (addr->proto == QETH_PROT_IPV6) {
+               QETH_DBF_TEXT(trace, 2, "deladdr6");
+               QETH_DBF_HEX(trace, 2, &addr->u.a6.addr,
+                            sizeof(struct in6_addr));
+       } else {
+               QETH_DBF_TEXT(trace, 2, "deladdr?");
+               QETH_DBF_HEX(trace, 2, addr, sizeof(struct qeth_ipaddr));
+       }
+       if (addr->is_multicast)
+               rc = qeth_send_setdelmc(card, addr, IPA_CMD_DELIPM);
+       else
+               rc = qeth_send_setdelip(card, addr, IPA_CMD_DELIP,
+                                       addr->del_flags);
+       if (rc) {
+               QETH_DBF_TEXT(trace, 2, "failed");
+               /* TODO: re-activate this warning as soon as we have a
+                * clean mirco code
+               qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf);
+               PRINT_WARN("Could not deregister IP address %s (rc=%x)\n",
+                          buf, rc);
+               */
+       }
+       return rc;
+}
+
+static int
+qeth_netdev_init(struct net_device *dev)
+{
+       struct qeth_card *card;
+
+       card = (struct qeth_card *) dev->priv;
+
+       QETH_DBF_TEXT(trace,3,"initdev");
+
+       dev->tx_timeout = &qeth_tx_timeout; 
+       dev->watchdog_timeo = QETH_TX_TIMEOUT;
+       dev->open = qeth_open;
+       dev->stop = qeth_stop;
+       dev->hard_start_xmit = qeth_hard_start_xmit;
+       dev->do_ioctl = qeth_do_ioctl;
+       dev->get_stats = qeth_get_stats;
+       dev->change_mtu = qeth_change_mtu;
+       dev->neigh_setup = qeth_neigh_setup;
+       dev->set_multicast_list = qeth_set_multicast_list;
+#ifdef CONFIG_QETH_VLAN
+       dev->vlan_rx_register = qeth_vlan_rx_register;
+       dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
+#endif
+       if (qeth_get_netdev_flags(card->info.type) & IFF_NOARP) {
+               dev->rebuild_header = NULL;
+               dev->hard_header = NULL;
+               dev->header_cache_update = NULL;
+               dev->hard_header_cache = NULL;
+       }
+#ifdef CONFIG_QETH_IPV6        
+       /*IPv6 address autoconfiguration stuff*/
+       card->dev->dev_id = card->info.unique_id & 0xffff;
+       if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
+               card->dev->generate_eui64 = qeth_ipv6_generate_eui64;
+
+
+#endif
+       dev->hard_header_parse = NULL;
+       dev->set_mac_address = NULL;
+       dev->flags |= qeth_get_netdev_flags(card->info.type);
+       if ((card->options.fake_broadcast) ||
+           (card->info.broadcast_capable))
+               dev->flags |= IFF_BROADCAST;
+
+       dev->hard_header_len =
+               qeth_get_hlen(card->info.link_type) + card->options.add_hhlen;
+       dev->addr_len = OSA_ADDR_LEN; 
+       dev->mtu = card->info.initial_mtu;
+       
+       SET_MODULE_OWNER(dev);
+       return 0;
+}
+
+/**
+ * hardsetup card, initialize MPC and QDIO stuff 
+ */ 
+static int 
+qeth_hardsetup_card(struct qeth_card *card)
+{
+       int retries = 3;
+       int rc;
+
+       QETH_DBF_TEXT(setup, 2, "hrdsetup");
+       
+retry:
+       if (retries < 3){
+               PRINT_WARN("Retrying to do IDX activates.\n");
+               ccw_device_set_offline(CARD_DDEV(card));
+               ccw_device_set_offline(CARD_WDEV(card));
+               ccw_device_set_offline(CARD_RDEV(card));
+               ccw_device_set_online(CARD_RDEV(card));
+               ccw_device_set_online(CARD_WDEV(card));
+               ccw_device_set_online(CARD_DDEV(card));
+       }
+       rc = qeth_qdio_clear_card(card,card->info.type==QETH_CARD_TYPE_OSAE);
+       if (rc == -ERESTARTSYS) {
+               QETH_DBF_TEXT(setup, 2, "break1");
+               return rc;
+       } else if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               if (--retries < 0)
+                       goto out;
+               else
+                       goto retry;
+       }
+       if ((rc = qeth_get_unitaddr(card))){
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               return rc;
+       }
+       qeth_init_tokens(card);
+       rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
+       if (rc == -ERESTARTSYS) {
+               QETH_DBF_TEXT(setup, 2, "break2");
+               return rc;
+       } else if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+               if (--retries < 0)
+                       goto out;
+               else
+                       goto retry;
+       }
+       rc = qeth_idx_activate_channel(&card->write, qeth_idx_write_cb);
+       if (rc == -ERESTARTSYS) {
+               QETH_DBF_TEXT(setup, 2, "break3");
+               return rc;
+       } else if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "4err%d", rc);
+               if (--retries < 0)
+                       goto out;
+               else
+                       goto retry;
+       }
+       if ((rc = qeth_mpc_initialize(card))){
+               QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
+               goto out;
+       }
+       /* at first set_online allocate netdev */
+       if (!card->dev){        
+               card->dev = qeth_get_netdevice(card->info.type,
+                                              card->info.link_type);
+               if (!card->dev){
+                       qeth_qdio_clear_card(card, card->info.type ==
+                                            QETH_CARD_TYPE_OSAE);
+                       rc = -ENODEV;
+                       QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
+                       goto out;
+               }
+               qeth_set_device_name(card);
+               card->dev->priv = card;
+               card->dev->type = qeth_get_arphdr_type(card->info.type,
+                                                      card->info.link_type);
+               card->dev->init = qeth_netdev_init;
+       }
+       return 0;       
+out:
+       PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc);
+       return rc;
+}
+
+static struct qeth_cmd_buffer *
+qeth_get_adapter_cmd(struct qeth_card *card, __u32 command)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       
+       iob = qeth_get_ipacmd_buffer(card,IPA_CMD_SETADAPTERPARMS,
+                                    QETH_PROT_IPV4);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       cmd->data.setadapterparms.cmdlength = 
+                               sizeof(struct qeth_ipacmd_setadpparms);
+       cmd->data.setadapterparms.command_code = command;
+       cmd->data.setadapterparms.frames_used_total = 1;
+       cmd->data.setadapterparms.frame_seq_no = 1;
+       
+       return iob;
+}
+
+static int
+qeth_default_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply,
+                           unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(trace,4,"defadpcb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       if (cmd->hdr.return_code == 0){
+               cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
+               if (cmd->hdr.prot_version == QETH_PROT_IPV4)
+                       card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
+#ifdef CONFIG_QETH_IPV6
+               if (cmd->hdr.prot_version == QETH_PROT_IPV6)
+                       card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
+#endif
+       }
+       if (cmd->data.setassparms.hdr.assist_no == IPA_INBOUND_CHECKSUM &&
+           cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
+               card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
+               QETH_DBF_TEXT_(trace, 3, "csum:%d", card->info.csum_mask);
+       }
+       return 0;
+}
+
+static int
+qeth_default_setadapterparms_cb(struct qeth_card *card,
+                               struct qeth_reply *reply,
+                               unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(trace,4,"defadpcb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       if (cmd->hdr.return_code == 0)
+               cmd->hdr.return_code = cmd->data.setadapterparms.return_code;
+       return 0;
+}
+
+static int
+qeth_query_setadapterparms_cb(struct qeth_card *card, struct qeth_reply *reply,
+                             unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(trace,3,"quyadpcb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f)
+               card->info.link_type = 
+                     cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
+       card->options.adp.supported_funcs =
+               cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
+       return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
+}
+
+static int 
+qeth_query_setadapterparms(struct qeth_card *card)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(trace,3,"queryadp");
+       iob = qeth_get_adapter_cmd(card,IPA_SETADP_QUERY_COMMANDS_SUPPORTED);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
+       return rc;
+}
+
+static int
+qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
+                                  struct qeth_reply *reply,
+                                  unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(trace,4,"chgmaccb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       memcpy(card->dev->dev_addr, 
+              &cmd->data.setadapterparms.data.change_addr.addr,OSA_ADDR_LEN);
+       qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+       return 0;
+}
+
+static int 
+qeth_setadpparms_change_macaddr(struct qeth_card *card)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(trace,4,"chgmac");
+       
+       iob = qeth_get_adapter_cmd(card,IPA_SETADP_ALTER_MAC_ADDRESS);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC;
+       cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN;
+       memcpy(&cmd->data.setadapterparms.data.change_addr.addr,
+              card->dev->dev_addr, OSA_ADDR_LEN);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_change_macaddr_cb,
+                              NULL);
+       return rc;
+}
+
+static int
+qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(trace,4,"adpmode");
+       
+       iob = qeth_get_adapter_cmd(card, command);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       cmd->data.setadapterparms.data.mode = mode;
+       rc = qeth_send_ipa_cmd(card, iob, qeth_default_setadapterparms_cb,
+                              NULL);
+       return rc;
+}
+
+static inline int 
+qeth_setadapter_hstr(struct qeth_card *card)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(trace,4,"adphstr");
+
+       if (qeth_adp_supported(card,IPA_SETADP_SET_BROADCAST_MODE)) {
+               rc = qeth_send_setadp_mode(card, IPA_SETADP_SET_BROADCAST_MODE,
+                                          card->options.broadcast_mode);
+               if (rc)
+                       PRINT_WARN("couldn't set broadcast mode on "
+                                  "device %s: x%x\n",
+                                  CARD_BUS_ID(card), rc);
+               rc = qeth_send_setadp_mode(card, IPA_SETADP_ALTER_MAC_ADDRESS,
+                                          card->options.macaddr_mode);
+               if (rc)
+                       PRINT_WARN("couldn't set macaddr mode on "
+                                  "device %s: x%x\n", CARD_BUS_ID(card), rc);
+               return rc;
+       }
+       if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL) 
+               PRINT_WARN("set adapter parameters not available "
+                          "to set broadcast mode, using ALLRINGS "
+                          "on device %s:\n", CARD_BUS_ID(card));
+       if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL) 
+               PRINT_WARN("set adapter parameters not available "
+                          "to set macaddr mode, using NONCANONICAL "
+                          "on device %s:\n", CARD_BUS_ID(card));
+       return 0;
+}
+
+static int
+qeth_setadapter_parms(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(setup, 2, "setadprm");
+
+       if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)){
+               PRINT_WARN("set adapter parameters not supported "
+                          "on device %s.\n",
+                          CARD_BUS_ID(card));
+               QETH_DBF_TEXT(setup, 2, " notsupp");
+               return 0;
+       }
+       rc = qeth_query_setadapterparms(card);
+       if (rc) {
+               PRINT_WARN("couldn't set adapter parameters on device %s: "
+                          "x%x\n", CARD_BUS_ID(card), rc);
+               return rc;
+       }
+       if (qeth_adp_supported(card,IPA_SETADP_ALTER_MAC_ADDRESS)) {
+               rc = qeth_setadpparms_change_macaddr(card);
+               if (rc)
+                       PRINT_WARN("couldn't get MAC address on "
+                                  "device %s: x%x\n",
+                                  CARD_BUS_ID(card), rc);
+       }
+       
+       if ((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
+           (card->info.link_type == QETH_LINK_TYPE_LANE_TR))
+               rc = qeth_setadapter_hstr(card);
+       
+       return rc;
+}
+
+
+static int 
+qeth_send_startstoplan(struct qeth_card *card, enum qeth_ipa_cmds ipacmd,
+                      enum qeth_prot_versions prot)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       
+       iob = qeth_get_ipacmd_buffer(card,ipacmd,prot);
+       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);  
+
+       return rc;
+}
+
+static int
+qeth_send_startlan(struct qeth_card *card, enum qeth_prot_versions prot)
+{
+       int rc;
+
+       QETH_DBF_TEXT_(setup, 2, "strtlan%i", prot);
+       
+       rc = qeth_send_startstoplan(card, IPA_CMD_STARTLAN, prot);
+       return rc;
+}
+
+static int
+qeth_send_stoplan(struct qeth_card *card)
+{
+       int rc = 0;
+
+       /*
+        * TODO: according to the IPA format document page 14,
+        * TCP/IP (we!) never issue a STOPLAN
+        * is this right ?!?
+        */
+       QETH_DBF_TEXT(trace, 2, "stoplan");
+       
+       rc = qeth_send_startstoplan(card, IPA_CMD_STOPLAN, QETH_PROT_IPV4);
+       return rc;
+}
+
+static int
+qeth_query_ipassists_cb(struct qeth_card *card, struct qeth_reply *reply,
+                       unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(setup, 2, "qipasscb");
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
+               card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported;
+               card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
+       } else {
+#ifdef CONFIG_QETH_IPV6
+               card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
+               card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
+#endif
+       }
+       return 0;
+}
+
+static int 
+qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot)
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+
+       QETH_DBF_TEXT_(setup, 2, "qipassi%i", prot);
+       
+       iob = qeth_get_ipacmd_buffer(card,IPA_CMD_QIPASSIST,prot);
+       rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL);
+       return rc;
+}
+
+static struct qeth_cmd_buffer * 
+qeth_get_setassparms_cmd(struct qeth_card *card, enum qeth_ipa_funcs ipa_func,
+                        __u16 cmd_code, __u16 len,
+                        enum qeth_prot_versions prot)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(trace,4,"getasscm");
+       iob = qeth_get_ipacmd_buffer(card,IPA_CMD_SETASSPARMS,prot);
+
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       cmd->data.setassparms.hdr.assist_no = ipa_func;
+       cmd->data.setassparms.hdr.length = 8 + len;
+       cmd->data.setassparms.hdr.command_code = cmd_code;
+       cmd->data.setassparms.hdr.return_code = 0;
+       cmd->data.setassparms.hdr.seq_no = 0;
+       
+       return iob;
+}
+
+static int
+qeth_send_setassparms(struct qeth_card *card, struct qeth_cmd_buffer *iob,
+                     __u16 len, long data, 
+                     int (*reply_cb)
+                     (struct qeth_card *,struct qeth_reply *,unsigned long),
+                     void *reply_param)
+{
+       int rc;
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(trace,4,"sendassp");
+       
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       if (len <= sizeof(__u32))
+               cmd->data.setassparms.data.flags_32bit = (__u32) data;
+       else if (len > sizeof(__u32))
+               memcpy(&cmd->data.setassparms.data, (void *) data, len);
+       
+       rc = qeth_send_ipa_cmd(card, iob, reply_cb, reply_param);
+       return rc;      
+}
+
+#ifdef CONFIG_QETH_IPV6
+static int 
+qeth_send_simple_setassparms_ipv6(struct qeth_card *card,
+                                 enum qeth_ipa_funcs ipa_func, __u16 cmd_code)
+                                
+{
+       int rc;
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(trace,4,"simassp6");
+       iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code,
+                                      0, QETH_PROT_IPV6);
+       rc = qeth_send_setassparms(card, iob, 0, 0,
+                                  qeth_default_setassparms_cb, NULL);
+       return rc;
+}
+#endif
+
+static int 
+qeth_send_simple_setassparms(struct qeth_card *card,
+                            enum qeth_ipa_funcs ipa_func,
+                            __u16 cmd_code, long data)
+{
+       int rc;
+       int length = 0; 
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(trace,4,"simassp4");
+       if (data)
+               length = sizeof(__u32);
+       iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code,
+                                      length, QETH_PROT_IPV4);
+       rc = qeth_send_setassparms(card, iob, length, data,
+                                  qeth_default_setassparms_cb, NULL);
+       return rc;
+}
+
+static inline int 
+qeth_start_ipa_arp_processing(struct qeth_card *card)
+{
+       int rc;
+               
+       QETH_DBF_TEXT(trace,3,"ipaarp");
+       
+       if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
+               PRINT_WARN("ARP processing not supported "
+                          "on %s!\n", card->info.if_name);
+               return 0;
+       }
+       rc = qeth_send_simple_setassparms(card,IPA_ARP_PROCESSING,
+                                         IPA_CMD_ASS_START, 0);
+       if (rc) {
+               PRINT_WARN("Could not start ARP processing "
+                          "assist on %s: 0x%x\n",
+                          card->info.if_name, rc);
+       }
+       return rc;
+}
+
+static int 
+qeth_start_ipa_ip_fragmentation(struct qeth_card *card)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(trace,3,"ipaipfrg");
+       
+       if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) {
+               PRINT_INFO("IP fragmentation not supported on %s\n",
+                          card->info.if_name);
+               return  -EOPNOTSUPP;
+       }
+
+       rc = qeth_send_simple_setassparms(card, IPA_IP_FRAGMENTATION,
+                                         IPA_CMD_ASS_START, 0);
+       if (rc) {
+               PRINT_WARN("Could not start IP fragmentation "
+                          "assist on %s: 0x%x\n",
+                          card->info.if_name, rc);
+       } else
+               PRINT_INFO("IP fragmentation enabled \n");
+       return rc;
+}
+
+static int
+qeth_start_ipa_source_mac(struct qeth_card *card)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(trace,3,"stsrcmac");
+
+       if (!card->options.fake_ll) 
+               return -EOPNOTSUPP;
+       
+       if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { 
+               PRINT_INFO("Inbound source address not "
+                          "supported on %s\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+
+       rc = qeth_send_simple_setassparms(card, IPA_SOURCE_MAC,
+                                         IPA_CMD_ASS_START, 0);
+       if (rc) 
+               PRINT_WARN("Could not start inbound source "
+                          "assist on %s: 0x%x\n",
+                          card->info.if_name, rc);
+       return rc;
+}
+
+static int
+qeth_start_ipa_vlan(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"strtvlan");
+
+#ifdef CONFIG_QETH_VLAN
+       if (!qeth_is_supported(card, IPA_FULL_VLAN)) {
+               PRINT_WARN("VLAN not supported on %s\n", card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       
+       rc = qeth_send_simple_setassparms(card, IPA_VLAN_PRIO,
+                                         IPA_CMD_ASS_START,0);
+       if (rc) {
+               PRINT_WARN("Could not start vlan "
+                          "assist on %s: 0x%x\n",
+                          card->info.if_name, rc);
+       } else {
+               PRINT_INFO("VLAN enabled \n");
+               card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+       }
+#endif /* QETH_VLAN */
+       return rc;
+}
+
+static int 
+qeth_start_ipa_multicast(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"stmcast");
+
+       if (!qeth_is_supported(card, IPA_MULTICASTING)) {
+               PRINT_WARN("Multicast not supported on %s\n",
+                          card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       
+       rc = qeth_send_simple_setassparms(card, IPA_MULTICASTING,
+                                         IPA_CMD_ASS_START,0);
+       if (rc) {
+               PRINT_WARN("Could not start multicast "
+                          "assist on %s: rc=%i\n",
+                          card->info.if_name, rc);
+       } else {
+               PRINT_INFO("Multicast enabled\n");
+               card->dev->flags |= IFF_MULTICAST;
+       }
+       return rc;
+}
+
+#ifdef CONFIG_QETH_IPV6
+static int 
+qeth_softsetup_ipv6(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"softipv6");
+
+       netif_stop_queue(card->dev);
+       rc = qeth_send_startlan(card, QETH_PROT_IPV6);
+       if (rc) {
+               PRINT_ERR("IPv6 startlan failed on %s\n",
+                         card->info.if_name);
+               return rc; 
+       }
+       netif_wake_queue(card->dev);
+       rc = qeth_query_ipassists(card,QETH_PROT_IPV6);
+       if (rc) {
+               PRINT_ERR("IPv6 query ipassist failed on %s\n",
+                         card->info.if_name);
+               return rc;
+       }
+       rc = qeth_send_simple_setassparms(card, IPA_IPV6,
+                                         IPA_CMD_ASS_START, 3);
+       if (rc) {
+               PRINT_WARN("IPv6 start assist (version 4) failed "
+                          "on %s: 0x%x\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       rc = qeth_send_simple_setassparms_ipv6(card, IPA_IPV6, 
+                                              IPA_CMD_ASS_START);
+       if (rc) {
+               PRINT_WARN("IPV6 start assist (version 6) failed  "
+                          "on %s: 0x%x\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       rc = qeth_send_simple_setassparms_ipv6(card, IPA_PASSTHRU, 
+                                              IPA_CMD_ASS_START);
+       if (rc) {
+               PRINT_WARN("Could not enable passthrough "
+                          "on %s: 0x%x\n",
+                          card->info.if_name, rc);
+               return rc;
+       } 
+       PRINT_INFO("IPV6 enabled \n");
+       return 0;
+}
+
+#endif
+
+static int
+qeth_start_ipa_ipv6(struct qeth_card *card)
+{
+       int rc = 0;
+#ifdef CONFIG_QETH_IPV6
+       QETH_DBF_TEXT(trace,3,"strtipv6");
+
+       if (!qeth_is_supported(card, IPA_IPV6)) {
+               PRINT_WARN("IPv6 not supported on %s\n",
+                          card->info.if_name);
+               return 0;
+       }
+       rc = qeth_softsetup_ipv6(card); 
+#endif
+       return rc ;
+}
+
+static int
+qeth_start_ipa_broadcast(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"stbrdcst");
+       if (!qeth_is_supported(card, IPA_FILTERING)) {
+               PRINT_WARN("Broadcast not supported on %s\n",
+                          card->info.if_name);
+               return -EOPNOTSUPP;
+       }
+       rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
+                                         IPA_CMD_ASS_START, 0);
+       if (rc) {
+               PRINT_WARN("Could not enable broadcasting "
+                          "on %s: 0x%x\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       
+       rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
+                                         IPA_CMD_ASS_CONFIGURE, 1);
+       if (rc) {
+               PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       PRINT_INFO("Broadcast enabled \n");
+       card->dev->flags |= IFF_BROADCAST;
+       card->info.broadcast_capable = 1;
+       return 0;
+}
+
+static int 
+qeth_send_checksum_command(struct qeth_card *card)
+{
+       int rc;
+
+       rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
+                                         IPA_CMD_ASS_START, 0);
+       if (rc) {
+               PRINT_WARN("Starting Inbound HW Checksumming failed on %s: "
+                          "0x%x,\ncontinuing using Inbound SW Checksumming\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM,
+                                         IPA_CMD_ASS_ENABLE,
+                                         card->info.csum_mask);
+       if (rc) {
+               PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: "
+                          "0x%x,\ncontinuing using Inbound SW Checksumming\n",
+                          card->info.if_name, rc);
+               return rc;
+       }
+       return 0;       
+}
+
+static int
+qeth_start_ipa_checksum(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"strtcsum");
+       
+       if (card->options.checksum_type == NO_CHECKSUMMING) {
+               PRINT_WARN("Using no checksumming on %s.\n",
+                          card->info.if_name);
+               return 0;
+       }
+       if (card->options.checksum_type == SW_CHECKSUMMING) {
+               PRINT_WARN("Using SW checksumming on %s.\n",
+                          card->info.if_name);
+               return 0;
+       }
+       if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) {
+               PRINT_WARN("Inbound HW Checksumming not "
+                          "supported on %s,\ncontinuing "
+                          "using Inbound SW Checksumming\n",
+                          card->info.if_name);
+               card->options.checksum_type = SW_CHECKSUMMING;
+               return 0;
+       }
+       rc = qeth_send_checksum_command(card);
+       if (!rc) {
+               PRINT_INFO("HW Checksumming (inbound) enabled \n");
+       }
+       return rc;
+}
+
+/*
+static inline void
+qeth_print_ipassist_status(struct qeth_card *card)
+{
+       char buf[255];
+       int offset = 0;
+
+       offset += sprintf(buf, "IPAssist options of %s: ", card->info.if_name);
+       if (qeth_is_enabled(card, IPA_ARP_PROCESSING))
+               offset += sprintf(buf+offset, "ARP ");
+       if (qeth_is_enabled(card, IPA_IP_FRAGMENTATION))
+               offset += sprintf(buf+offset, "IP_FRAG");
+       if (qeth_is_enabled(card, IPA_SOURCE_MAC))
+               offset += sprintf(buf+offset, "SRC_MAC");
+       if (qeth_is_enabled(card, IPA_FULL_VLAN))
+               offset += sprintf(buf+offset, "VLAN");
+       if (qeth_is_enabled(card, IPA_VLAN_PRIO))
+               offset += sprintf(buf+offset, "VLAN_PRIO");
+}
+*/
+
+static int 
+qeth_start_ipassists(struct qeth_card *card) 
+{
+       QETH_DBF_TEXT(trace,3,"strtipas");
+       qeth_start_ipa_arp_processing(card);    /* go on*/
+       qeth_start_ipa_ip_fragmentation(card);  /* go on*/
+       qeth_start_ipa_source_mac(card);        /* go on*/
+       qeth_start_ipa_vlan(card);              /* go on*/
+       qeth_start_ipa_multicast(card);         /* go on*/
+       qeth_start_ipa_ipv6(card);              /* go on*/
+       qeth_start_ipa_broadcast(card);         /* go on*/
+       qeth_start_ipa_checksum(card);          /* go on*/
+       return 0;
+}
+
+static int 
+qeth_send_setrouting(struct qeth_card *card, enum qeth_routing_types type, 
+                    enum qeth_prot_versions prot)
+{
+       int rc;
+       struct qeth_ipa_cmd *cmd;
+       struct qeth_cmd_buffer *iob;
+       
+       QETH_DBF_TEXT(trace,4,"setroutg");
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       cmd->data.setrtg.type = (type);
+       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
+
+       return rc;
+       
+}
+
+int 
+qeth_setrouting_v4(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(trace,3,"setrtg4");
+
+       if (card->options.route4.type == NO_ROUTER)
+               return 0;
+
+       rc = qeth_send_setrouting(card, card->options.route4.type,
+                                 QETH_PROT_IPV4);
+       if (rc) {
+               card->options.route4.type = NO_ROUTER; 
+               PRINT_WARN("Error (0x%04x) while setting routing type on %s. "
+                          "Type set to 'no router'.\n",
+                          rc, card->info.if_name);
+       }
+       return rc;
+}
+
+int 
+qeth_setrouting_v6(struct qeth_card *card)
+{
+       int rc = 0;
+
+       QETH_DBF_TEXT(trace,3,"setrtg6");
+#ifdef CONFIG_QETH_IPV6
+       
+       if ((card->options.route6.type == NO_ROUTER) ||
+           ((card->info.type == QETH_CARD_TYPE_OSAE) &&
+            (card->options.route6.type == MULTICAST_ROUTER) &&
+            !qeth_is_supported6(card,IPA_OSA_MC_ROUTER)))
+               return 0;
+       rc = qeth_send_setrouting(card, card->options.route6.type,
+                                 QETH_PROT_IPV6);
+       if (rc) {
+               card->options.route6.type = NO_ROUTER; 
+               PRINT_WARN("Error (0x%04x) while setting routing type on %s. "
+                          "Type set to 'no router'.\n",
+                          rc, card->info.if_name);
+       }
+#endif
+       return rc;      
+}
+
+/*
+ * softsetup card: init IPA stuff
+ */
+static int
+qeth_softsetup_card(struct qeth_card *card)
+{
+       int rc;
+
+       QETH_DBF_TEXT(setup, 2, "softsetp");
+
+       if ((rc = qeth_send_startlan(card, QETH_PROT_IPV4))){
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               if (rc == 0xe080){
+                       PRINT_WARN("LAN on card %s if offline! "
+                                  "Continuing softsetup.\n",
+                                  CARD_BUS_ID(card));
+                       card->lan_online = 0;
+               } else
+                       return rc;
+       } else
+               card->lan_online = 1;
+       if ((rc = qeth_setadapter_parms(card)))
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+       if ((rc = qeth_start_ipassists(card)))
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+       if ((rc = qeth_setrouting_v4(card)))
+               QETH_DBF_TEXT_(setup, 2, "4err%d", rc);
+       if ((rc = qeth_setrouting_v6(card)))
+               QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
+       netif_stop_queue(card->dev);
+       return 0;
+}
+
+#ifdef CONFIG_QETH_IPV6
+static int
+qeth_get_unique_id_cb(struct qeth_card *card, struct qeth_reply *reply,
+                     unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd;
+
+       cmd = (struct qeth_ipa_cmd *) data;
+       if (cmd->hdr.return_code == 0)
+               card->info.unique_id = *((__u16 *)
+                               &cmd->data.create_destroy_addr.unique_id[6]);
+       else {
+               card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
+                                       UNIQUE_ID_NOT_BY_CARD;
+               PRINT_WARN("couldn't get a unique id from the card on device "
+                          "%s (result=x%x), using default id. ipv6 "
+                          "autoconfig on other lpars may lead to duplicate "
+                          "ip addresses. please use manually "
+                          "configured ones.\n",
+                          CARD_BUS_ID(card), cmd->hdr.return_code);
+       }
+       return 0;
+}
+#endif
+
+static int
+qeth_put_unique_id(struct qeth_card *card)
+{
+
+       int rc = 0;
+#ifdef CONFIG_QETH_IPV6
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       
+       QETH_DBF_TEXT(trace,2,"puniqeid");
+
+       if ((card->info.unique_id & UNIQUE_ID_NOT_BY_CARD) ==
+               UNIQUE_ID_NOT_BY_CARD)
+               return -1;
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_DESTROY_ADDR,
+                                    QETH_PROT_IPV6);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
+                           card->info.unique_id;
+       memcpy(&cmd->data.create_destroy_addr.unique_id[0], 
+              card->dev->dev_addr, OSA_ADDR_LEN);
+       rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
+#else  
+       card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
+                               UNIQUE_ID_NOT_BY_CARD;
+#endif
+       return rc;
+}
+
+/**
+ * Clear IP List
+ */ 
+static void
+qeth_clear_ip_list(struct qeth_card *card, int clean, int recover)
+{
+       struct qeth_ipaddr *addr, *tmp;
+       int first_run = 1;
+       unsigned long flags;
+
+       QETH_DBF_TEXT(trace,4,"clearip");
+       spin_lock_irqsave(&card->ip_lock, flags);
+       /* clear todo list */
+       list_for_each_entry_safe(addr, tmp, &card->ip_tbd_list, entry){
+               list_del(&addr->entry);
+               kfree(addr);
+       }
+again:
+       if (first_run)
+               first_run = 0;
+       else
+               spin_lock_irqsave(&card->ip_lock, flags);
+       
+       list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
+               list_del_init(&addr->entry);
+               if (clean){
+                       spin_unlock_irqrestore(&card->ip_lock, flags);
+                       qeth_deregister_addr_entry(card, addr);
+               }
+               if (!recover || addr->is_multicast)
+                       kfree(addr);
+               else {
+                       if (clean)
+                               spin_lock_irqsave(&card->ip_lock, flags);
+                       list_add_tail(&addr->entry, &card->ip_tbd_list);
+                       if (clean) {
+                               spin_unlock_irqrestore(&card->ip_lock, flags);
+                               goto again;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+}
+
+static void
+qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
+                        int clear_start_mask)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       card->thread_allowed_mask = threads;
+       if (clear_start_mask)
+               card->thread_start_mask &= threads;
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       wake_up(&card->wait_q);
+}
+
+static inline int
+qeth_threads_running(struct qeth_card *card, unsigned long threads)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       spin_lock_irqsave(&card->thread_mask_lock, flags);
+       rc = (card->thread_running_mask & threads);
+       spin_unlock_irqrestore(&card->thread_mask_lock, flags);
+       return rc;
+}
+
+static int
+qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
+{
+       return wait_event_interruptible(card->wait_q,
+                       qeth_threads_running(card, threads) == 0);
+}
+
+static int 
+qeth_stop_card(struct qeth_card *card)
+{
+       int recover_flag = 0;
+       int rc = 0;
+
+       QETH_DBF_TEXT(setup ,2,"stopcard");
+       QETH_DBF_HEX(setup, 2, &card, sizeof(void *));
+        
+       qeth_set_allowed_threads(card, 0, 1);
+       if (qeth_wait_for_threads(card, ~QETH_RECOVER_THREAD))
+               return -ERESTARTSYS;
+       if (card->read.state == CH_STATE_UP &&
+           card->write.state == CH_STATE_UP &&
+           ((card->state == CARD_STATE_UP_LAN_ONLINE) ||
+            (card->state == CARD_STATE_UP_LAN_OFFLINE))) {
+               recover_flag = 1;
+               rtnl_lock();
+               dev_close(card->dev);
+               rtnl_unlock();
+               if (!card->use_hard_stop)
+                       if ((rc = qeth_send_stoplan(card)))
+                               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               card->state = CARD_STATE_SOFTSETUP;
+       }
+       if (card->state == CARD_STATE_SOFTSETUP) {
+               qeth_clear_ip_list(card, !card->use_hard_stop, recover_flag);
+               qeth_clear_ipacmd_list(card);
+               card->state = CARD_STATE_HARDSETUP;
+       }
+       if (card->state == CARD_STATE_HARDSETUP) {
+               if (!card->use_hard_stop)
+                       if ((rc = qeth_put_unique_id(card)))
+                               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               qeth_qdio_clear_card(card, 0);
+               qeth_clear_qdio_buffers(card);
+               qeth_clear_working_pool_list(card);
+               card->state = CARD_STATE_DOWN;
+       }
+       if (card->state == CARD_STATE_DOWN) {
+               qeth_clear_cmd_buffers(&card->read);
+               qeth_clear_cmd_buffers(&card->write);
+       }
+       card->use_hard_stop = 0;
+       return rc;
+}
+
+             
+static int
+qeth_get_unique_id(struct qeth_card *card)
+{
+       int rc = 0;
+#ifdef CONFIG_QETH_IPV6
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+
+       QETH_DBF_TEXT(setup, 2, "guniqeid");
+
+       if (!qeth_is_supported(card,IPA_IPV6)) {
+               card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
+                                       UNIQUE_ID_NOT_BY_CARD;
+               return 0;
+       }
+
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
+                                    QETH_PROT_IPV6);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); 
+       *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
+                           card->info.unique_id;
+       
+       rc = qeth_send_ipa_cmd(card, iob, qeth_get_unique_id_cb, NULL);
+#else  
+       card->info.unique_id =  UNIQUE_ID_IF_CREATE_ADDR_FAILED |
+                               UNIQUE_ID_NOT_BY_CARD;
+#endif
+       return rc;
+}
+static void
+qeth_print_status_with_portname(struct qeth_card *card)
+{
+       char dbf_text[15];
+       int i;
+       
+       sprintf(dbf_text, "%s", card->info.portname + 1);
+       for (i = 0; i < 8; i++)
+               dbf_text[i] =
+                       (char) _ebcasc[(__u8) dbf_text[i]];
+       dbf_text[8] = 0;
+       printk("qeth: Device %s/%s/%s is a%s card%s%s%s\n"
+              "with link type %s (portname: %s)\n",
+              CARD_RDEV_ID(card),
+              CARD_WDEV_ID(card),
+              CARD_DDEV_ID(card),
+              qeth_get_cardname(card),
+              (card->info.mcl_level[0]) ? " (level: " : "",
+              (card->info.mcl_level[0]) ? card->info.mcl_level : "",
+              (card->info.mcl_level[0]) ? ")" : "",
+              qeth_get_cardname_short(card),
+              dbf_text);
+
+}
+
+static void
+qeth_print_status_no_portname(struct qeth_card *card)
+{
+       if (card->info.portname[0])
+               printk("qeth: Device %s/%s/%s is a%s "
+                      "card%s%s%s\nwith link type %s "
+                      "(no portname needed by interface).\n",
+                      CARD_RDEV_ID(card),
+                      CARD_WDEV_ID(card),
+                      CARD_DDEV_ID(card),
+                      qeth_get_cardname(card),
+                      (card->info.mcl_level[0]) ? " (level: " : "",
+                      (card->info.mcl_level[0]) ? card->info.mcl_level : "",
+                      (card->info.mcl_level[0]) ? ")" : "",
+                      qeth_get_cardname_short(card));
+       else
+               printk("qeth: Device %s/%s/%s is a%s "
+                      "card%s%s%s\nwith link type %s.\n",
+                      CARD_RDEV_ID(card),
+                      CARD_WDEV_ID(card),
+                      CARD_DDEV_ID(card),
+                      qeth_get_cardname(card),
+                      (card->info.mcl_level[0]) ? " (level: " : "",
+                      (card->info.mcl_level[0]) ? card->info.mcl_level : "",
+                      (card->info.mcl_level[0]) ? ")" : "",
+                      qeth_get_cardname_short(card));
+}
+
+static void
+qeth_print_status_message(struct qeth_card *card)
+{
+       switch (card->info.type) {
+       case QETH_CARD_TYPE_OSAE:
+               /* VM will use a non-zero first character 
+                * to indicate a HiperSockets like reporting
+                * of the level OSA sets the first character to zero
+                * */
+               if (!card->info.mcl_level[0]) {
+                       sprintf(card->info.mcl_level,"%02x%02x",
+                               card->info.mcl_level[2],
+                               card->info.mcl_level[3]);
+                          
+                       card->info.mcl_level[QETH_MCL_LENGTH] = 0;
+                       break;
+               }
+               /* fallthrough */
+       case QETH_CARD_TYPE_IQD:
+               card->info.mcl_level[0] = (char) _ebcasc[(__u8) 
+                       card->info.mcl_level[0]];
+               card->info.mcl_level[1] = (char) _ebcasc[(__u8) 
+                       card->info.mcl_level[1]];
+               card->info.mcl_level[2] = (char) _ebcasc[(__u8) 
+                       card->info.mcl_level[2]];
+               card->info.mcl_level[3] = (char) _ebcasc[(__u8) 
+                       card->info.mcl_level[3]];
+               card->info.mcl_level[QETH_MCL_LENGTH] = 0;
+               break;
+       default:
+               memset(&card->info.mcl_level[0], 0, QETH_MCL_LENGTH + 1);
+       }
+       if (card->info.portname_required)
+               qeth_print_status_with_portname(card);
+       else
+               qeth_print_status_no_portname(card);
+}
+
+static int 
+qeth_register_netdev(struct qeth_card *card)
+{
+       int rc;
+       
+       QETH_DBF_TEXT(setup, 3, "regnetd");
+       if (card->dev->reg_state != NETREG_UNINITIALIZED)
+               return 0;
+       /* sysfs magic */
+       SET_NETDEV_DEV(card->dev, &card->gdev->dev);
+       rc = register_netdev(card->dev);
+       if (!rc)
+               strcpy(card->info.if_name, card->dev->name);
+       
+       return rc;      
+}
+
+static void
+qeth_start_again(struct qeth_card *card)
+{
+       QETH_DBF_TEXT(setup ,2, "startag");
+
+       rtnl_lock();
+       dev_open(card->dev);
+       rtnl_unlock();
+       qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+
+static int 
+qeth_set_online(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = gdev->dev.driver_data;
+       int rc = 0;
+       enum qeth_card_states recover_flag;
+
+       BUG_ON(!card);
+       QETH_DBF_TEXT(setup ,2, "setonlin");
+       QETH_DBF_HEX(setup, 2, &card, sizeof(void *));
+       
+       qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 1);
+       if (qeth_wait_for_threads(card, ~QETH_RECOVER_THREAD)){
+               PRINT_WARN("set_online of card %s interrupted by user!\n",
+                          CARD_BUS_ID(card));
+               return -ERESTARTSYS;
+       }
+       
+       recover_flag = card->state;
+       if (ccw_device_set_online(CARD_RDEV(card)) ||
+           ccw_device_set_online(CARD_WDEV(card)) ||
+           ccw_device_set_online(CARD_DDEV(card))){
+               QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
+               return -EIO;
+       }
+               
+       if ((rc = qeth_hardsetup_card(card))){
+               QETH_DBF_TEXT_(setup, 2, "2err%d", rc);
+               goto out_remove;
+       }
+       card->state = CARD_STATE_HARDSETUP;
+       
+       if ((rc = qeth_query_ipassists(card,QETH_PROT_IPV4))){
+               QETH_DBF_TEXT_(setup, 2, "3err%d", rc);
+               /*TODO: rc !=0*/
+       } else
+               rc = qeth_get_unique_id(card);
+       
+       if (rc) {
+               QETH_DBF_TEXT_(setup, 2, "4err%d", rc);
+               goto out_remove;
+       }
+       qeth_print_status_message(card);        
+       if ((rc = qeth_register_netdev(card))){
+               QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
+               goto out_remove;
+       }
+       if ((rc = qeth_softsetup_card(card))){
+               QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
+               goto out_remove;
+       }
+       card->state = CARD_STATE_SOFTSETUP;
+       
+       if ((rc = qeth_init_qdio_queues(card))){
+               QETH_DBF_TEXT_(setup, 2, "7err%d", rc);
+               goto out_remove;
+       }
+/*maybe it was set offline without ifconfig down
+ * we can also use this state for recovery purposes*/
+       qeth_set_allowed_threads(card, 0xffffffff, 0);
+       if (recover_flag == CARD_STATE_RECOVER)
+               qeth_start_again(card);
+
+       return 0;
+out_remove:
+       card->use_hard_stop = 1;
+       qeth_stop_card(card);
+       ccw_device_set_offline(CARD_DDEV(card));
+       ccw_device_set_offline(CARD_WDEV(card));
+       ccw_device_set_offline(CARD_RDEV(card));
+       if (recover_flag == CARD_STATE_RECOVER)
+               card->state = CARD_STATE_RECOVER;
+       else
+               card->state = CARD_STATE_DOWN;
+       return -ENODEV;
+}
+
+static struct ccw_device_id qeth_ids[] = {
+       {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
+       {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
+       {},
+};
+MODULE_DEVICE_TABLE(ccw, qeth_ids);
+
+struct device *qeth_root_dev = NULL;
+
+struct ccwgroup_driver qeth_ccwgroup_driver = {
+       .owner = THIS_MODULE,
+       .name = "qeth",
+       .driver_id = 0xD8C5E3C8,
+       .probe = qeth_probe_device,
+       .remove = qeth_remove_device,
+       .set_online = qeth_set_online,
+       .set_offline = qeth_set_offline,
+};
+
+struct ccw_driver qeth_ccw_driver = {
+       .name = "qeth",
+       .ids = qeth_ids,
+       .probe = ccwgroup_probe_ccwdev,
+       .remove = ccwgroup_remove_ccwdev,
+};
+
+
+static void
+qeth_unregister_dbf_views(void)
+{
+       if (qeth_dbf_setup)
+               debug_unregister(qeth_dbf_setup);
+       if (qeth_dbf_qerr)
+               debug_unregister(qeth_dbf_qerr);
+       if (qeth_dbf_sense)
+               debug_unregister(qeth_dbf_sense);
+       if (qeth_dbf_misc)
+               debug_unregister(qeth_dbf_misc);
+       if (qeth_dbf_data)
+               debug_unregister(qeth_dbf_data);
+       if (qeth_dbf_control)
+               debug_unregister(qeth_dbf_control);
+       if (qeth_dbf_trace)
+               debug_unregister(qeth_dbf_trace);
+}
+static int
+qeth_register_dbf_views(void)
+{
+       qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME,
+                                       QETH_DBF_SETUP_INDEX,
+                                       QETH_DBF_SETUP_NR_AREAS,
+                                       QETH_DBF_SETUP_LEN);
+       qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME,
+                                      QETH_DBF_MISC_INDEX,
+                                      QETH_DBF_MISC_NR_AREAS,
+                                      QETH_DBF_MISC_LEN);
+       qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME,
+                                      QETH_DBF_DATA_INDEX,
+                                      QETH_DBF_DATA_NR_AREAS,
+                                      QETH_DBF_DATA_LEN);
+       qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME,
+                                         QETH_DBF_CONTROL_INDEX,
+                                         QETH_DBF_CONTROL_NR_AREAS,
+                                         QETH_DBF_CONTROL_LEN);
+       qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME,
+                                       QETH_DBF_SENSE_INDEX,
+                                       QETH_DBF_SENSE_NR_AREAS,
+                                       QETH_DBF_SENSE_LEN);
+       qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME,
+                                      QETH_DBF_QERR_INDEX,
+                                      QETH_DBF_QERR_NR_AREAS,
+                                      QETH_DBF_QERR_LEN);
+       qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME,
+                                       QETH_DBF_TRACE_INDEX,
+                                       QETH_DBF_TRACE_NR_AREAS,
+                                       QETH_DBF_TRACE_LEN);
+       
+       if ((qeth_dbf_setup == NULL) || (qeth_dbf_misc == NULL)    ||
+           (qeth_dbf_data == NULL)  || (qeth_dbf_control == NULL) ||
+           (qeth_dbf_sense == NULL) || (qeth_dbf_qerr == NULL)    ||
+           (qeth_dbf_trace == NULL)) {
+               qeth_unregister_dbf_views();
+               return -ENOMEM;
+       }
+       debug_register_view(qeth_dbf_setup, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_setup, QETH_DBF_SETUP_LEVEL);
+
+       debug_register_view(qeth_dbf_misc, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_misc, QETH_DBF_MISC_LEVEL);
+
+       debug_register_view(qeth_dbf_data, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_data, QETH_DBF_DATA_LEVEL);
+
+       debug_register_view(qeth_dbf_control, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_control, QETH_DBF_CONTROL_LEVEL);
+
+       debug_register_view(qeth_dbf_sense, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_sense, QETH_DBF_SENSE_LEVEL);
+
+       debug_register_view(qeth_dbf_qerr, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_qerr, QETH_DBF_QERR_LEVEL);
+
+       debug_register_view(qeth_dbf_trace, &debug_hex_ascii_view);
+       debug_set_level(qeth_dbf_trace, QETH_DBF_TRACE_LEVEL);
+
+       return 0;
+}
+
+#ifdef CONFIG_QETH_IPV6
+extern struct neigh_table arp_tbl; 
+static struct neigh_ops *arp_direct_ops;
+static int (*qeth_old_arp_constructor) (struct neighbour *); 
+
+static struct neigh_ops arp_direct_ops_template = {
+       .family = AF_INET,
+       .destructor = NULL,
+       .solicit = NULL,
+       .error_report = NULL,
+       .output = dev_queue_xmit,
+       .connected_output = dev_queue_xmit,
+       .hh_output = dev_queue_xmit,
+       .queue_xmit = dev_queue_xmit
+};
+
+static int
+qeth_arp_constructor(struct neighbour *neigh)
+{
+       struct net_device *dev = neigh->dev;
+       struct in_device *in_dev = in_dev_get(dev);
+
+       if (in_dev == NULL)
+               return -EINVAL;
+       if (!qeth_verify_dev(dev)) {
+               in_dev_put(in_dev);
+               return qeth_old_arp_constructor(neigh);
+       }
+
+       neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
+       if (in_dev->arp_parms)
+               neigh->parms = in_dev->arp_parms;
+       in_dev_put(in_dev);
+       neigh->nud_state = NUD_NOARP;
+       neigh->ops = arp_direct_ops;
+       neigh->output = neigh->ops->queue_xmit;
+       return 0;
+}
+#endif  /*CONFIG_QETH_IPV6*/
+
+/*
+ * IP address takeover related functions
+ */
+static void
+qeth_clear_ipato_list(struct qeth_card *card)
+{
+       struct qeth_ipato_entry *ipatoe, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry) {
+               list_del(&ipatoe->entry);
+               kfree(ipatoe);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+}
+
+int
+qeth_add_ipato_entry(struct qeth_card *card, struct qeth_ipato_entry *new)
+{
+       struct qeth_ipato_entry *ipatoe;
+       unsigned long flags;
+       int rc = 0;     
+
+       QETH_DBF_TEXT(trace, 2, "addipato");
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry(ipatoe, &card->ipato.entries, entry){
+               if (ipatoe->proto != new->proto)
+                       continue;
+               if (!memcmp(ipatoe->addr, new->addr,
+                           (ipatoe->proto == QETH_PROT_IPV4)? 4:16) &&
+                   (ipatoe->mask_bits == new->mask_bits)){
+                       PRINT_WARN("ipato entry already exists!\n");
+                       rc = -EEXIST;
+                       break;
+               }
+       }
+       if (!rc) {
+               list_add_tail(&new->entry, &card->ipato.entries);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       return rc;
+}
+
+void
+qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto,
+                    u8 *addr, int mask_bits)
+{
+       struct qeth_ipato_entry *ipatoe, *tmp;
+       unsigned long flags;
+
+       QETH_DBF_TEXT(trace, 2, "delipato");
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry_safe(ipatoe, tmp, &card->ipato.entries, entry){
+               if (ipatoe->proto != proto)
+                       continue;
+               if (!memcmp(ipatoe->addr, addr,
+                           (proto == QETH_PROT_IPV4)? 4:16) &&
+                   (ipatoe->mask_bits == mask_bits)){
+                       list_del(&ipatoe->entry);
+                       kfree(ipatoe);
+               }
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+}
+
+static inline void
+qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
+{
+       int i, j;
+       u8 octet;
+
+       for (i = 0; i < len; ++i){
+               octet = addr[i];
+               for (j = 7; j >= 0; --j){
+                       bits[i*8 + j] = octet & 1;
+                       octet >>= 1;
+               }
+       }
+}
+
+static int
+qeth_is_addr_covered_by_ipato(struct qeth_card *card, struct qeth_ipaddr *addr)
+{
+       struct qeth_ipato_entry *ipatoe;
+       u8 addr_bits[128] = {0, };
+       u8 ipatoe_bits[128] = {0, };
+       int rc = 0;
+
+       if (!card->ipato.enabled)
+               return 0;
+       
+       qeth_convert_addr_to_bits((u8 *) &addr->u, addr_bits,
+                                 (addr->proto == QETH_PROT_IPV4)? 4:16);
+       list_for_each_entry(ipatoe, &card->ipato.entries, entry){
+               if (addr->proto != ipatoe->proto)
+                       continue;
+               qeth_convert_addr_to_bits(ipatoe->addr, ipatoe_bits,
+                                         (ipatoe->proto==QETH_PROT_IPV4) ?
+                                         4:16);
+               if (addr->proto == QETH_PROT_IPV4)
+                       rc = !memcmp(addr_bits, ipatoe_bits,
+                                    min(32, ipatoe->mask_bits));
+               else
+                       rc = !memcmp(addr_bits, ipatoe_bits,
+                                    min(128, ipatoe->mask_bits));
+               if (rc)
+                       break;
+       }
+       /* invert? */
+       if ((addr->proto == QETH_PROT_IPV4) && card->ipato.invert4)
+               rc = !rc;
+       else if ((addr->proto == QETH_PROT_IPV6) && card->ipato.invert6)
+               rc = !rc;
+
+       return rc;
+}
+
+/*
+ * VIPA related functions
+ */
+int
+qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
+             const u8 *addr)
+{
+       struct qeth_ipaddr *ipaddr;
+       unsigned long flags;
+       int rc = 0;
+
+       ipaddr = qeth_get_addr_buffer(proto);
+       if (ipaddr){
+               if (proto == QETH_PROT_IPV4){
+                       QETH_DBF_TEXT(trace, 2, "addvipa4");
+                       memcpy(&ipaddr->u.a4.addr, addr, 4);
+                       ipaddr->u.a4.mask = 0;
+#ifdef CONFIG_QETH_IPV6
+               } else if (proto == QETH_PROT_IPV6){
+                       QETH_DBF_TEXT(trace, 2, "addvipa6");
+                       memcpy(&ipaddr->u.a6.addr, addr, 16);
+                       ipaddr->u.a6.pfxlen = 0;
+#endif
+               }
+               ipaddr->type = QETH_IP_TYPE_VIPA;
+               ipaddr->set_flags = QETH_IPA_SETIP_VIPA_FLAG;
+               ipaddr->del_flags = QETH_IPA_DELIP_VIPA_FLAG;
+       } else
+               return -ENOMEM;
+       spin_lock_irqsave(&card->ip_lock, flags);
+       if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
+           __qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0))
+               rc = -EEXIST;
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       if (rc){
+               PRINT_WARN("Cannot add VIPA. Address already exists!\n");
+               return rc;
+       }
+       if (!qeth_add_ip(card, ipaddr))
+               kfree(ipaddr);
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+       return rc;
+}
+
+void
+qeth_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
+             const u8 *addr)
+{
+       struct qeth_ipaddr *ipaddr;
+
+       ipaddr = qeth_get_addr_buffer(proto);
+       if (ipaddr){
+               if (proto == QETH_PROT_IPV4){
+                       QETH_DBF_TEXT(trace, 2, "delvipa4");
+                       memcpy(&ipaddr->u.a4.addr, addr, 4);
+                       ipaddr->u.a4.mask = 0;
+#ifdef CONFIG_QETH_IPV6
+               } else if (proto == QETH_PROT_IPV6){
+                       QETH_DBF_TEXT(trace, 2, "delvipa6");
+                       memcpy(&ipaddr->u.a6.addr, addr, 16);
+                       ipaddr->u.a6.pfxlen = 0;
+#endif
+               }
+               ipaddr->type = QETH_IP_TYPE_VIPA;
+       } else
+               return;
+       if (!qeth_delete_ip(card, ipaddr))
+               kfree(ipaddr);
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+
+/*
+ * proxy ARP related functions
+ */
+int
+qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
+             const u8 *addr)
+{
+       struct qeth_ipaddr *ipaddr;
+       unsigned long flags;
+       int rc = 0;
+
+       ipaddr = qeth_get_addr_buffer(proto);
+       if (ipaddr){
+               if (proto == QETH_PROT_IPV4){
+                       QETH_DBF_TEXT(trace, 2, "addrxip4");
+                       memcpy(&ipaddr->u.a4.addr, addr, 4);
+                       ipaddr->u.a4.mask = 0;
+#ifdef CONFIG_QETH_IPV6
+               } else if (proto == QETH_PROT_IPV6){
+                       QETH_DBF_TEXT(trace, 2, "addrxip6");
+                       memcpy(&ipaddr->u.a6.addr, addr, 16);
+                       ipaddr->u.a6.pfxlen = 0;
+#endif
+               }
+               ipaddr->type = QETH_IP_TYPE_RXIP;
+               ipaddr->set_flags = QETH_IPA_SETIP_TAKEOVER_FLAG;
+               ipaddr->del_flags = 0;
+       } else
+               return -ENOMEM;
+       spin_lock_irqsave(&card->ip_lock, flags);
+       if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
+           __qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0))
+               rc = -EEXIST;
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       if (rc){
+               PRINT_WARN("Cannot add RXIP. Address already exists!\n");
+               return rc;
+       }
+       if (!qeth_add_ip(card, ipaddr))
+               kfree(ipaddr);
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+       return 0;
+}
+
+void
+qeth_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
+             const u8 *addr)
+{
+       struct qeth_ipaddr *ipaddr;
+
+       ipaddr = qeth_get_addr_buffer(proto);
+       if (ipaddr){
+               if (proto == QETH_PROT_IPV4){
+                       QETH_DBF_TEXT(trace, 2, "addrxip4");
+                       memcpy(&ipaddr->u.a4.addr, addr, 4);
+                       ipaddr->u.a4.mask = 0;
+#ifdef CONFIG_QETH_IPV6
+               } else if (proto == QETH_PROT_IPV6){
+                       QETH_DBF_TEXT(trace, 2, "addrxip6");
+                       memcpy(&ipaddr->u.a6.addr, addr, 16);
+                       ipaddr->u.a6.pfxlen = 0;
+#endif
+               }
+               ipaddr->type = QETH_IP_TYPE_RXIP;
+       } else
+               return;
+       if (!qeth_delete_ip(card, ipaddr))
+               kfree(ipaddr);
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+}
+
+/**
+ * IP event handler
+ */ 
+static int 
+qeth_ip_event(struct notifier_block *this,
+             unsigned long event,void *ptr)
+{
+       struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+       struct net_device *dev =(struct net_device *) ifa->ifa_dev->dev;
+       struct qeth_ipaddr *addr;
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace,3,"ipevent");
+       card = qeth_get_card_from_dev(dev);
+       if (!card)
+               return NOTIFY_DONE;
+
+       addr = qeth_get_addr_buffer(QETH_PROT_IPV4);
+       if (addr != NULL) {
+               addr->u.a4.addr = ifa->ifa_address;
+               addr->u.a4.mask = ifa->ifa_mask;
+               addr->type = QETH_IP_TYPE_NORMAL;
+       }
+       switch(event) {
+       case NETDEV_UP:
+               if (addr) {
+                       if (!qeth_add_ip(card, addr))
+                               kfree(addr);
+               }
+               break;
+       case NETDEV_DOWN:
+               if (addr) {
+                       if (!qeth_delete_ip(card, addr))
+                               kfree(addr);
+               }
+               break;
+       default:
+               break;
+       }
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+       
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block qeth_ip_notifier = {
+       qeth_ip_event,
+       0
+};
+
+#ifdef CONFIG_QETH_IPV6
+/**
+ * IPv6 event handler
+ */ 
+static int 
+qeth_ip6_event(struct notifier_block *this,
+             unsigned long event,void *ptr)
+{
+
+       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; 
+       struct net_device *dev = (struct net_device *)ifa->idev->dev;
+       struct qeth_ipaddr *addr;
+       struct qeth_card *card;
+       
+       QETH_DBF_TEXT(trace,3,"ip6event");
+       
+       card = qeth_get_card_from_dev(dev);
+       if (!card)
+               return NOTIFY_DONE;
+       if (!qeth_is_supported(card, IPA_IPV6))
+               return NOTIFY_DONE;
+       
+       addr = qeth_get_addr_buffer(QETH_PROT_IPV6);
+       if (addr != NULL) {
+               memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr));
+               addr->u.a6.pfxlen = ifa->prefix_len;
+               addr->type = QETH_IP_TYPE_NORMAL;
+       }
+       switch(event) {
+       case NETDEV_UP:
+               if (addr){
+                       if (!qeth_add_ip(card, addr))
+                               kfree(addr);
+               }
+               break;
+       case NETDEV_DOWN:
+               if (addr){
+                       if (!qeth_delete_ip(card, addr))
+                               kfree(addr);
+               }
+               break;
+       default:
+               break;
+       }
+       qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
+       schedule_work(&card->kernel_thread_starter);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block qeth_ip6_notifier = {
+       qeth_ip6_event,
+       0
+};
+#endif
+
+static int
+qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+
+       struct device *entry;
+       struct qeth_card *card;
+
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+              list_for_each_entry(entry, &qeth_ccwgroup_driver.driver.devices,
+                                  driver_list) {
+                      card = (struct qeth_card *) entry->driver_data;
+                      qeth_clear_ip_list(card, 0, 0);
+                      qeth_qdio_clear_card(card, 0);                  
+              }
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       return NOTIFY_DONE;
+}
+
+
+static struct notifier_block qeth_reboot_notifier = {
+       qeth_reboot_event,
+       0
+};
+
+static int 
+qeth_register_notifiers(void)
+{
+        int r;
+
+       QETH_DBF_TEXT(trace,5,"regnotif");
+       if ((r = register_reboot_notifier(&qeth_reboot_notifier)))
+               return r;
+       if ((r = register_inetaddr_notifier(&qeth_ip_notifier)))
+               goto out_reboot;
+#ifdef CONFIG_QETH_IPV6
+       if ((r = register_inet6addr_notifier(&qeth_ip6_notifier)))
+               goto out_ipv4;
+#endif 
+       return 0;
+       
+#ifdef CONFIG_QETH_IPV6
+out_ipv4:
+       unregister_inetaddr_notifier(&qeth_ip_notifier);
+#endif
+out_reboot:
+       unregister_reboot_notifier(&qeth_reboot_notifier);
+       return r;
+}
+
+/**
+ * unregister all event notifiers
+ */ 
+static void
+qeth_unregister_notifiers(void)
+{
+
+       QETH_DBF_TEXT(trace,5,"unregnot");
+       BUG_ON(unregister_reboot_notifier(&qeth_reboot_notifier));
+       BUG_ON(unregister_inetaddr_notifier(&qeth_ip_notifier));
+#ifdef CONFIG_QETH_IPV6
+       BUG_ON(unregister_inet6addr_notifier(&qeth_ip6_notifier));
+#endif /* QETH_IPV6 */
+
+}
+
+#ifdef CONFIG_QETH_IPV6
+static int
+qeth_ipv6_init(void)
+{
+       qeth_old_arp_constructor = arp_tbl.constructor;
+       write_lock(&arp_tbl.lock);
+       arp_tbl.constructor = qeth_arp_constructor;
+       write_unlock(&arp_tbl.lock);
+
+       arp_direct_ops = (struct neigh_ops*)
+               kmalloc(sizeof(struct neigh_ops), GFP_KERNEL);
+       if (!arp_direct_ops)
+               return -ENOMEM;
+
+       memcpy(arp_direct_ops, &arp_direct_ops_template,
+              sizeof(struct neigh_ops));
+
+       return 0;
+}
+
+static void
+qeth_ipv6_uninit(void)
+{
+       write_lock(&arp_tbl.lock);
+       arp_tbl.constructor = qeth_old_arp_constructor;
+       write_unlock(&arp_tbl.lock);
+       kfree(arp_direct_ops);
+}
+#endif /* CONFIG_QETH_IPV6 */
+
+static void 
+qeth_sysfs_unregister(void)
+{
+       qeth_remove_driver_attributes();
+       ccw_driver_unregister(&qeth_ccw_driver);
+       ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
+       s390_root_dev_unregister(qeth_root_dev);
+}
+/**
+ * register qeth at sysfs
+ */ 
+static int 
+qeth_sysfs_register(void)
+{
+       int rc=0;
+
+       rc = ccwgroup_driver_register(&qeth_ccwgroup_driver);
+       if (rc) 
+               return rc;
+       rc = ccw_driver_register(&qeth_ccw_driver);     
+       if (rc) 
+               return rc;      
+       rc = qeth_create_driver_attributes();
+       if (rc)
+               return rc;
+       qeth_root_dev = s390_root_dev_register("qeth");
+       if (IS_ERR(qeth_root_dev)) {
+               rc = PTR_ERR(qeth_root_dev);
+               return rc;
+       }
+       return 0;
+}
+
+/***
+ * init function
+ */
+static int __init
+qeth_init(void)
+{
+       int rc=0;
+       
+       qeth_eyecatcher();
+       printk(KERN_INFO "qeth: loading %s\n",version);
+
+       INIT_LIST_HEAD(&qeth_card_list.list);
+       rwlock_init(&qeth_card_list.rwlock);
+
+       atomic_set(&qeth_hsi_count, 0);
+       if (qeth_register_dbf_views())
+               goto out_err;
+       if (qeth_sysfs_register())
+               goto out_sysfs;
+
+#ifdef CONFIG_QETH_IPV6
+       if (qeth_ipv6_init()) {
+               PRINT_ERR("Out of memory during ipv6 init.\n");
+               goto out_sysfs;
+       }
+#endif /* QETH_IPV6 */
+       if (qeth_register_notifiers())
+               goto out_ipv6;
+       if (qeth_create_procfs_entries())
+               goto out_notifiers;
+
+       return rc;
+
+out_notifiers:
+       qeth_unregister_notifiers();
+out_ipv6:
+#ifdef CONFIG_QETH_IPV6
+       qeth_ipv6_uninit();
+#endif /* QETH_IPV6 */
+out_sysfs:
+       qeth_sysfs_unregister();
+       qeth_unregister_dbf_views();
+out_err:
+       PRINT_ERR("Initialization failed");
+       return rc;
+}
+
+static void 
+__exit qeth_exit(void)
+{
+       struct qeth_card *card, *tmp;
+       unsigned long flags;
+
+       QETH_DBF_TEXT(trace,1, "cleanup.");
+       
+       /*
+        * Weed would not need to clean up our devices here, because the
+        * common device layer calls qeth_remove_device for each device
+        * as soon as we unregister our driver (done in qeth_sysfs_unregister).
+        * But we do cleanup here so we can do a "soft" shutdown of our cards.
+        * qeth_remove_device called by the common device layer would otherwise
+        * do a "hard" shutdown (card->use_hard_stop is set to one in
+        * qeth_remove_device).
+        */
+again:
+       read_lock_irqsave(&qeth_card_list.rwlock, flags);
+       list_for_each_entry_safe(card, tmp, &qeth_card_list.list, list){
+               read_unlock_irqrestore(&qeth_card_list.rwlock, flags);
+               qeth_set_offline(card->gdev);
+               qeth_remove_device(card->gdev);
+               goto again;
+       }
+       read_unlock_irqrestore(&qeth_card_list.rwlock, flags);
+#ifdef CONFIG_QETH_IPV6
+       qeth_ipv6_uninit();
+#endif 
+       qeth_unregister_notifiers();
+       qeth_remove_procfs_entries();
+       qeth_sysfs_unregister();
+       qeth_unregister_dbf_views();
+       printk("qeth: removed\n");
+}
+
+EXPORT_SYMBOL(qeth_eyecatcher);
+module_init(qeth_init);
+module_exit(qeth_exit);
+MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>");
+MODULE_DESCRIPTION("Linux on zSeries OSA Express and HiperSockets support\n" \
+                                     "Copyright 2000,2003 IBM Corporation\n");
+
+MODULE_LICENSE("GPL");
index 7adce02..1221afa 100644 (file)
@@ -4,7 +4,8 @@
  * Linux on zSeries OSA Express and HiperSockets support
  *
  * Copyright 2000,2003 IBM Corporation
- * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
+ * Author(s): Frank Pavlic <pavlic@de.ibm.com>
+ *           Thomas Spatzier <tspat@de.ibm.com>                
  *
  */
 #include <asm/cio.h>
@@ -126,16 +127,22 @@ unsigned char DM_ACT[]={
 unsigned char IPA_PDU_HEADER[]={
        0x00,0xe0,0x00,0x00, 0x77,0x77,0x77,0x77,
        0x00,0x00,0x00,0x14, 0x00,0x00,
-               (IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd))/256,
-               (IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd))%256,
+               (IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))/256,
+               (IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))%256,
        0x10,0x00,0x00,0x01,
        0x00,0x00,0x00,0x00,
        0xc1,0x03,0x00,0x01, 0x00,0x00,0x00,0x00,
-       0x00,0x00,0x00,0x00, 0x00,0x24,0x00,sizeof(struct ipa_cmd),
-       0x00,0x00,sizeof(struct ipa_cmd),0x05, 0x77,0x77,0x77,0x77,
+       0x00,0x00,0x00,0x00, 0x00,0x24,
+               sizeof(struct qeth_ipa_cmd)/256,
+               sizeof(struct qeth_ipa_cmd)%256,
+       0x00,
+               sizeof(struct qeth_ipa_cmd)/256,
+               sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77,
        0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
-       0x01,0x00,sizeof(struct ipa_cmd)/256,sizeof(struct ipa_cmd)%256,
-                               0x00,0x00,0x00,0x40,
+       0x01,0x00,
+               sizeof(struct qeth_ipa_cmd)/256,
+               sizeof(struct qeth_ipa_cmd)%256,
+       0x00,0x00,0x00,0x40,
 };
 
 unsigned char WRITE_CCW[]={
@@ -158,4 +165,3 @@ unsigned char READ_CCW[]={
 
 
 
-
index 5998604..9b0d97f 100644 (file)
  *
  * Copyright 2000,2003 IBM Corporation
  * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
+ *            Thomas Spatzier <tspat@de.ibm.com>
+ *            Frank Pavlic <pavlic@de.ibm.com>
  *
  */
 #ifndef __QETH_MPC_H__
 #define __QETH_MPC_H__
 
-#define VERSION_QETH_MPC_H "$Revision: 1.18 $"
+#include <asm/qeth.h>
 
-#define QETH_IPA_TIMEOUT (card->ipa_timeout)
-#define QETH_MPC_TIMEOUT 2000
-#define QETH_ADDR_TIMEOUT 1000
+#define VERSION_QETH_MPC_H "$Revision: 1.27 $"
 
-#define QETH_SETIP_RETRIES 2
-
-#define IDX_ACTIVATE_SIZE 0x22
-#define CM_ENABLE_SIZE 0x63
-#define CM_SETUP_SIZE 0x64
-#define ULP_ENABLE_SIZE 0x6b
-#define ULP_SETUP_SIZE 0x6c
-#define DM_ACT_SIZE 0x55
+#define IPA_PDU_HEADER_SIZE    0x40
+#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
+#define QETH_IPA_PDU_LEN_PDU1(buffer) (buffer+0x26)
+#define QETH_IPA_PDU_LEN_PDU2(buffer) (buffer+0x2a)
+#define QETH_IPA_PDU_LEN_PDU3(buffer) (buffer+0x3a)
 
-#define QETH_MPC_TOKEN_LENGTH 4
-#define QETH_SEQ_NO_LENGTH 4
-#define QETH_IPA_SEQ_NO_LENGTH 2
+extern unsigned char IPA_PDU_HEADER[];
+#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
 
-#define QETH_TRANSPORT_HEADER_SEQ_NO(buffer) (buffer+4)
-#define QETH_PDU_HEADER_SEQ_NO(buffer) (buffer+0x1c)
-#define QETH_PDU_HEADER_ACK_SEQ_NO(buffer) (buffer+0x20)
+#define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
 
-extern unsigned char IDX_ACTIVATE_READ[];
+#define QETH_SEQ_NO_LENGTH     4
+#define QETH_MPC_TOKEN_LENGTH  4
+#define QETH_MCL_LENGTH                4
+#define OSA_ADDR_LEN           6
 
-extern unsigned char IDX_ACTIVATE_WRITE[];
+#define QETH_TIMEOUT           (10 * HZ)       
+#define QETH_IDX_COMMAND_SEQNO         -1
+#define SR_INFO_LEN            16
 
-#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
-#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
-#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
-#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer+0x16)
-#define QETH_IDX_ACT_QDIO_DEV_CUA(buffer) (buffer+0x1e)
-#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
+#define QETH_CLEAR_CHANNEL_PARM        -10
+#define QETH_HALT_CHANNEL_PARM -11
 
-#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
+/*****************************************************************************/
+/* IP Assist related definitions                                             */
+/*****************************************************************************/
+#define IPA_CMD_INITIATOR_HOST  0x00
+#define IPA_CMD_INITIATOR_HYDRA 0x01
+#define IPA_CMD_PRIM_VERSION_NO 0x01
 
-#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
-#define QETH_MCL_LENGTH 4
+enum qeth_card_types {
+       QETH_CARD_TYPE_UNKNOWN = 0,
+       QETH_CARD_TYPE_OSAE    = 10,
+       QETH_CARD_TYPE_IQD     = 1234,
+};
 
-extern unsigned char CM_ENABLE[];
+#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
+/* only the first two bytes are looked at in qeth_get_cardname_short */
+enum qeth_link_types {
+       QETH_LINK_TYPE_FAST_ETH     = 0x01,
+       QETH_LINK_TYPE_HSTR         = 0x02,
+       QETH_LINK_TYPE_GBIT_ETH     = 0x03,
+       QETH_LINK_TYPE_10GBIT_ETH   = 0x10,
+       QETH_LINK_TYPE_LANE_ETH100  = 0x81,
+       QETH_LINK_TYPE_LANE_TR      = 0x82,
+       QETH_LINK_TYPE_LANE_ETH1000 = 0x83,
+       QETH_LINK_TYPE_LANE         = 0x88,
+       QETH_LINK_TYPE_ATM_NATIVE   = 0x90,
+};
 
-#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer+0x2c)
-#define QETH_CM_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
-#define QETH_CM_ENABLE_USER_DATA(buffer) (buffer+0x5b)
+enum qeth_tr_macaddr_modes {
+       QETH_TR_MACADDR_NONCANONICAL = 0,
+       QETH_TR_MACADDR_CANONICAL    = 1,
+};
 
-#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
-                                                 0x13)
+enum qeth_tr_broadcast_modes {
+       QETH_TR_BROADCAST_ALLRINGS = 0,
+       QETH_TR_BROADCAST_LOCAL    = 1,
+};
 
-extern unsigned char CM_SETUP[];
+/* these values match CHECKSUM_* in include/linux/skbuff.h */
+enum qeth_checksum_types {
+       SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */
+       HW_CHECKSUMMING = 1,
+       NO_CHECKSUMMING = 2,
+};
+#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING
 
-#define QETH_CM_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
-#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
+/*
+ * Routing stuff
+ */
+#define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */
+enum qeth_routing_types {
+       NO_ROUTER           = 0, /* TODO: set to bit flag used in IPA Command */
+       PRIMARY_ROUTER      = 1,
+       SECONDARY_ROUTER    = 2,
+       MULTICAST_ROUTER    = 3,
+       PRIMARY_CONNECTOR   = 4,
+       SECONDARY_CONNECTOR = 5,
+};
 
-#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) (PDU_ENCAPSULATION(buffer)+ \
-                                             0x1a)
 
-extern unsigned char ULP_ENABLE[];
+/* IPA Commands */
+enum qeth_ipa_cmds {
+       IPA_CMD_STARTLAN              = 0x01,
+       IPA_CMD_STOPLAN               = 0x02,
+       IPA_CMD_SETIP                 = 0xb1,
+       IPA_CMD_DELIP                 = 0xb7,
+       IPA_CMD_QIPASSIST             = 0xb2,
+       IPA_CMD_SETASSPARMS           = 0xb3,
+       IPA_CMD_SETIPM                = 0xb4,
+       IPA_CMD_DELIPM                = 0xb5,
+       IPA_CMD_SETRTG                = 0xb6,
+       IPA_CMD_SETADAPTERPARMS       = 0xb8,
+       IPA_CMD_IPFRAME               = 0xb9,
+       IPA_CMD_ADD_ADDR_ENTRY        = 0xc1,
+       IPA_CMD_DELETE_ADDR_ENTRY     = 0xc2,
+       IPA_CMD_CREATE_ADDR           = 0xc3,
+       IPA_CMD_DESTROY_ADDR          = 0xc4,
+       IPA_CMD_REGISTER_LOCAL_ADDR   = 0xd1,
+       IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
+};
 
-#define QETH_ULP_ENABLE_LINKNUM(buffer) (buffer+0x61)
-#define QETH_ULP_ENABLE_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_ULP_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
-#define QETH_ULP_ENABLE_PORTNAME_AND_LL(buffer) (buffer+0x62)
+enum qeth_ip_ass_cmds {
+       IPA_CMD_ASS_START       = 0x0001,
+       IPA_CMD_ASS_STOP        = 0x0002,
+       IPA_CMD_ASS_CONFIGURE   = 0x0003,
+       IPA_CMD_ASS_ENABLE      = 0x0004,
+};
 
-#define QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
-                                                  0x13)
-#define QETH_ULP_ENABLE_RESP_MAX_MTU(buffer) (PDU_ENCAPSULATION(buffer)+ 0x1f)
-#define QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
-                                                 0x17)
-#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) (PDU_ENCAPSULATION(buffer)+ \
-                                               0x2b)
+enum qeth_arp_process_subcmds {
+       IPA_CMD_ASS_ARP_SET_NO_ENTRIES  = 0x0003,
+       IPA_CMD_ASS_ARP_QUERY_CACHE     = 0x0004,
+       IPA_CMD_ASS_ARP_ADD_ENTRY       = 0x0005,
+       IPA_CMD_ASS_ARP_REMOVE_ENTRY    = 0x0006,
+       IPA_CMD_ASS_ARP_FLUSH_CACHE     = 0x0007,
+       IPA_CMD_ASS_ARP_QUERY_INFO      = 0x0104,
+       IPA_CMD_ASS_ARP_QUERY_STATS     = 0x0204,
+};
 
-extern unsigned char ULP_SETUP[];
+/* Return Codes for IPA Commands */
+enum qeth_ipa_return_codes {
+       IPA_RC_SUCCESS             = 0x0000,
+       IPA_RC_NOTSUPP             = 0x0001,
+       IPA_RC_NO_ACCESS           = 0x0002,
+       IPA_RC_FAILED              = 0x0003,
+       IPA_RC_DATA_MISMATCH       = 0xe001,
+       IPA_RC_INVALID_LAN_TYPE    = 0xe003,
+       IPA_RC_INVALID_LAN_NO      = 0xe004,
+       IPA_RC_IPADDR_ALREADY_REG  = 0xe005,
+       IPA_RC_IPADDR_TABLE_FULL   = 0xe006,
+       IPA_RC_IPADDR_ALREADY_USED = 0xe00a,
+       IPA_RC_ASSNO_NOT_SUPP      = 0xe00d,
+       IPA_RC_ASSCMD_START_FAILED = 0xe00e,
+       IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f,
+       IPA_RC_IPADDR_NOT_DEFINED  = 0xe010,
+       IPA_RC_LAN_OFFLINE         = 0xe080,
+};
 
-#define QETH_ULP_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_ULP_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
-#define QETH_ULP_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
-#define QETH_ULP_SETUP_CUA(buffer) (buffer+0x68)
-#define QETH_ULP_SETUP_REAL_DEVADDR(buffer) (buffer+0x6a)
+/* IPA function flags; each flag marks availability of respective function */
+enum qeth_ipa_funcs {
+       IPA_ARP_PROCESSING      = 0x00000001L,
+       IPA_INBOUND_CHECKSUM    = 0x00000002L,
+       IPA_OUTBOUND_CHECKSUM   = 0x00000004L,
+       IPA_IP_FRAGMENTATION    = 0x00000008L,
+       IPA_FILTERING           = 0x00000010L,
+       IPA_IPV6                = 0x00000020L,
+       IPA_MULTICASTING        = 0x00000040L,
+       IPA_IP_REASSEMBLY       = 0x00000080L,
+       IPA_QUERY_ARP_COUNTERS  = 0x00000100L,
+       IPA_QUERY_ARP_ADDR_INFO = 0x00000200L,
+       IPA_SETADAPTERPARMS     = 0x00000400L,
+       IPA_VLAN_PRIO           = 0x00000800L,
+       IPA_PASSTHRU            = 0x00001000L,
+       IPA_FULL_VLAN           = 0x00004000L,
+       IPA_SOURCE_MAC          = 0x00010000L,
+       IPA_OSA_MC_ROUTER       = 0x00020000L,
+};
 
-#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) (PDU_ENCAPSULATION \
-                                                     (buffer)+0x1a)
+/* SETIP/DELIP IPA Command: ***************************************************/
+enum qeth_ipa_setdelip_flags {
+       QETH_IPA_SETDELIP_DEFAULT          = 0x00L, /* default */
+       QETH_IPA_SETIP_VIPA_FLAG           = 0x01L, /* no grat. ARP */
+       QETH_IPA_SETIP_TAKEOVER_FLAG       = 0x02L, /* nofail on grat. ARP */
+       QETH_IPA_DELIP_ADDR_2_B_TAKEN_OVER = 0x20L,
+       QETH_IPA_DELIP_VIPA_FLAG           = 0x40L,
+       QETH_IPA_DELIP_ADDR_NEEDS_SETIP    = 0x80L,
+};
 
-extern unsigned char DM_ACT[];
+/* SETADAPTER IPA Command: ****************************************************/
+enum qeth_ipa_setadp_cmd {
+       IPA_SETADP_QUERY_COMMANDS_SUPPORTED     = 0x01,
+       IPA_SETADP_ALTER_MAC_ADDRESS            = 0x02,
+       IPA_SETADP_ADD_DELETE_GROUP_ADDRESS     = 0x04,
+       IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR   = 0x08,
+       IPA_SETADP_SET_ADDRESSING_MODE          = 0x10,
+       IPA_SETADP_SET_CONFIG_PARMS             = 0x20,
+       IPA_SETADP_SET_CONFIG_PARMS_EXTENDED    = 0x40,
+       IPA_SETADP_SET_BROADCAST_MODE           = 0x80,
+       IPA_SETADP_SEND_OSA_MESSAGE             = 0x0100,
+       IPA_SETADP_SET_SNMP_CONTROL             = 0x0200,
+       IPA_SETADP_READ_SNMP_PARMS              = 0x0400,
+       IPA_SETADP_WRITE_SNMP_PARMS             = 0x0800,
+       IPA_SETADP_QUERY_CARD_INFO              = 0x1000,
+};
+enum qeth_ipa_mac_ops {
+       CHANGE_ADDR_READ_MAC            = 0,
+       CHANGE_ADDR_REPLACE_MAC         = 1,
+       CHANGE_ADDR_ADD_MAC             = 2,
+       CHANGE_ADDR_DEL_MAC             = 4,
+       CHANGE_ADDR_RESET_MAC           = 8,
+};
+enum qeth_ipa_addr_ops {
+       CHANGE_ADDR_READ_ADDR           = 0,
+       CHANGE_ADDR_ADD_ADDR            = 1,
+       CHANGE_ADDR_DEL_ADDR            = 2,
+       CHANGE_ADDR_FLUSH_ADDR_TABLE    = 4,
 
-#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
 
-#define IPA_CMD_STARTLAN 0x01
-#define IPA_CMD_STOPLAN 0x02
-#define IPA_CMD_SETIP 0xb1
-#define IPA_CMD_DELIP 0xb7
-#define IPA_CMD_QIPASSIST 0xb2
-#define IPA_CMD_SETASSPARMS 0xb3
-#define IPA_CMD_SETIPM 0xb4
-#define IPA_CMD_DELIPM 0xb5
-#define IPA_CMD_SETRTG 0xb6
-#define IPA_CMD_SETADAPTERPARMS 0xb8
-#define IPA_CMD_ADD_ADDR_ENTRY 0xc1
-#define IPA_CMD_DELETE_ADDR_ENTRY 0xc2
-#define IPA_CMD_CREATE_ADDR 0xc3
-#define IPA_CMD_DESTROY_ADDR 0xc4
-#define IPA_CMD_REGISTER_LOCAL_ADDR 0xd1
-#define IPA_CMD_UNREGISTER_LOCAL_ADDR 0xd2
-
-#define INITIATOR_HOST 0
-#define INITIATOR_HYDRA 1
-
-#define PRIM_VERSION_IPA 1
-
-#define PROT_VERSION_SNA 1 /* hahaha */
-#define PROT_VERSION_IPv4 4
-#define PROT_VERSION_IPv6 6
-
-#define OSA_ADDR_LEN 6
-#define IPA_SETADAPTERPARMS_IP_VERSION PROT_VERSION_IPv4
-#define SR_INFO_LEN 16
-
-#define IPA_ARP_PROCESSING 0x00000001L
-#define IPA_INBOUND_CHECKSUM 0x00000002L
-#define IPA_OUTBOUND_CHECKSUM 0x00000004L
-#define IPA_IP_FRAGMENTATION 0x00000008L
-#define IPA_FILTERING 0x00000010L
-#define IPA_IPv6 0x00000020L
-#define IPA_MULTICASTING 0x00000040L
-#define IPA_IP_REASSEMBLY 0x00000080L
-#define IPA_QUERY_ARP_COUNTERS 0x00000100L
-#define IPA_QUERY_ARP_ADDR_INFO 0x00000200L
-#define IPA_SETADAPTERPARMS 0x00000400L
-#define IPA_VLAN_PRIO 0x00000800L
-#define IPA_PASSTHRU 0x00001000L
-#define IPA_FULL_VLAN 0x00004000L
-#define IPA_SOURCE_MAC_AVAIL 0x00010000L
-#define IPA_OSA_MC_ROUTER_AVAIL 0x00020000L
-
-#define IPA_SETADP_QUERY_COMMANDS_SUPPORTED 0x01
-#define IPA_SETADP_ALTER_MAC_ADDRESS 0x02
-#define IPA_SETADP_ADD_DELETE_GROUP_ADDRESS 0x04
-#define IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR 0x08
-#define IPA_SETADP_SET_ADDRESSING_MODE 0x10
-#define IPA_SETADP_SET_CONFIG_PARMS 0x20
-#define IPA_SETADP_SET_CONFIG_PARMS_EXTENDED 0x40
-#define IPA_SETADP_SET_BROADCAST_MODE 0x80
-#define IPA_SETADP_SEND_OSA_MESSAGE 0x0100
-#define IPA_SETADP_SET_SNMP_CONTROL 0x0200
-#define IPA_SETADP_READ_SNMP_PARMS 0x0400
-#define IPA_SETADP_WRITE_SNMP_PARMS 0x0800
-#define IPA_SETADP_QUERY_CARD_INFO 0x1000
-
-#define CHANGE_ADDR_READ_MAC 0
-#define CHANGE_ADDR_REPLACE_MAC 1
-#define CHANGE_ADDR_ADD_MAC 2
-#define CHANGE_ADDR_DEL_MAC 4
-#define CHANGE_ADDR_RESET_MAC 8
-#define CHANGE_ADDR_READ_ADDR 0
-#define CHANGE_ADDR_ADD_ADDR 1
-#define CHANGE_ADDR_DEL_ADDR 2
-#define CHANGE_ADDR_FLUSH_ADDR_TABLE 4
-/* we assumed, that the card is named card */
-#define qeth_is_supported(str) (card->ipa_supported&str)
-#define qeth_is_supported6(str) (card->ipa6_supported&str)
-#define qeth_is_adp_supported(str) (card->adp_supported&str)
-
-/* the same for all assist parms: */
-#define IPA_CMD_ASS_START 0x0001
-#define IPA_CMD_ASS_STOP 0x0002
-
-#define IPA_CMD_ASS_CONFIGURE 0x0003
-#define IPA_CMD_ASS_ENABLE 0x0004
-
-#define IPA_CMD_ASS_ARP_SET_NO_ENTRIES 0x0003
-#define IPA_CMD_ASS_ARP_QUERY_CACHE 0x0004
-#define IPA_CMD_ASS_ARP_ADD_ENTRY 0x0005
-#define IPA_CMD_ASS_ARP_REMOVE_ENTRY 0x0006
-#define IPA_CMD_ASS_ARP_FLUSH_CACHE 0x0007
-#define IPA_CMD_ASS_ARP_QUERY_INFO 0x0104
-#define IPA_CMD_ASS_ARP_QUERY_STATS 0x0204
-
-#define IPA_CHECKSUM_DEFAULT_ENABLE_MASK 0x001a
-
-#define IPA_CMD_ASS_FILTER_SET_TYPES 0x0003
-
-#define IPA_CMD_ASS_IPv6_SET_FUNCTIONS 0x0003
-
-#define IPA_REPLY_SUCCESS 0
-#define IPA_REPLY_FAILED 1
-#define IPA_REPLY_OPNOTSUPP 2
-#define IPA_REPLY_OPNOTSUPP2 4
-#define IPA_REPLY_NOINFO 8
-
-#define IPA_SETIP_FLAGS 0
-#define IPA_SETIP_VIPA_FLAGS 1
-#define IPA_SETIP_TAKEOVER_FLAGS 2
-
-#define VIPA_2_B_ADDED 0
-#define VIPA_ESTABLISHED 1
-#define VIPA_2_B_REMOVED 2
-
-#define IPA_DELIP_FLAGS 0
-
-#define IPA_SETADP_CMDSIZE 40
-
-struct ipa_setadp_cmd {
-       __u32 supp_hw_cmds;
-       __u32 reserved1;
-       __u16 cmdlength;
-       __u16 reserved2;
-       __u32 command_code;
+};
+/* (SET)DELIP(M) IPA stuff ***************************************************/
+struct qeth_ipacmd_setdelip4 {
+       __u8   ip_addr[4];
+       __u8   mask[4];
+       __u32  flags;
+} __attribute__ ((packed));
+       
+struct qeth_ipacmd_setdelip6 {
+       __u8   ip_addr[16];
+       __u8   mask[16];
+       __u32  flags;
+} __attribute__ ((packed));
+
+struct qeth_ipacmd_setdelipm {
+       __u8 mac[6];
+       __u8 padding[2];
+       __u8 ip6[12];
+       __u8 ip4[4];
+} __attribute__ ((packed));
+
+struct qeth_ipacmd_setassparms_hdr {
+       __u32 assist_no;
+       __u16 length;
+       __u16 command_code;
        __u16 return_code;
-       __u8 frames_used_total;
-       __u8 frame_seq_no;
-       __u32 reserved3;
+       __u8 number_of_replies;
+       __u8 seq_no;
+} __attribute__((packed));
+
+/* SETASSPARMS IPA Command: */
+struct qeth_ipacmd_setassparms {
+       struct qeth_ipacmd_setassparms_hdr hdr;
        union {
-               struct {
-                       __u32 no_lantypes_supp;
-                       __u8 lan_type;
-                       __u8 reserved1[3];
-                       __u32 supported_cmds;
-                       __u8 reserved2[8];
-               } query_cmds_supp;
-               struct {
-                       __u32 cmd;
-                       __u32 addr_size;
-                       __u32 no_macs;
-                       __u8 addr[OSA_ADDR_LEN];
-               } change_addr;
-               __u32 mode;
+               __u32 flags_32bit;
+               struct qeth_arp_cache_entry add_arp_entry; 
+               __u8 ip[16];
        } data;
+} __attribute__ ((packed));
+
+
+/* SETRTG IPA Command:    ****************************************************/
+struct qeth_set_routing {
+       __u8 type;
 };
 
-struct ipa_cmd{
-       __u8 command;
-       __u8 initiator;
-       __u16 seq_no;
-       __u16 return_code;
-       __u8 adapter_type;
-       __u8 rel_adapter_no;
-       __u8 prim_version_no;
-       __u8 param_count;
-       __u16 prot_version;
-       __u32 ipa_supported;
-       __u32 ipa_enabled;
-       union {
-               struct {
-                       __u8 ip[4];
-                       __u8 netmask[4];
-                       __u32 flags;
-               } setdelip4;
-               struct {
-                       __u8 ip[16];
-                       __u8 netmask[16];
-                       __u32 flags;
-               } setdelip6;
-               struct {
-                       __u32 assist_no;
-                       __u16 length;
-                       __u16 command_code;
-                       __u16 return_code;
-                       __u8 number_of_replies;
-                       __u8 seq_no;
-                       union {
-                               __u32 flags_32bit;
-                               struct {
-                                       __u8 mac[6];
-                                       __u8 reserved[2];
-                                       __u8 ip[16];
-                                       __u8 reserved2[32];
-                               } add_arp_entry;
-                               __u8 ip[16];
-                       } data;
-               } setassparms;
-               struct {
-                       __u8 mac[6];
-                       __u8 padding[2];
-                       __u8 ip6[12];
-                       __u8 ip4_6[4];
-               } setdelipm;
-               struct {
-                       __u8 type;
-               } setrtg;
-               struct ipa_setadp_cmd setadapterparms;
-               struct {
-                       __u32 command;
-#define ADDR_FRAME_TYPE_DIX 1
-#define ADDR_FRAME_TYPE_802_3 2
-#define ADDR_FRAME_TYPE_TR_WITHOUT_SR 0x10
-#define ADDR_FRAME_TYPE_TR_WITH_SR 0x20
-                       __u32 frame_type;
-                       __u32 cmd_flags;
-                       __u8 ip_addr[16];
-                       __u32 tag_field;
-                       __u8 mac_addr[6];
-                       __u8 reserved[10];
-                       __u32 sr_len;
-                       __u8 sr_info[SR_INFO_LEN];
-               } add_addr_entry;
-               struct {
-                       __u32 command;
-                       __u32 cmd_flags;
-                       __u8 ip_addr[16];
-                       __u32 tag_field;
-               } delete_addr_entry;
-               struct {
-                       __u8 unique_id[8];
-               } create_destroy_addr;
-       } data;
-}__attribute__ ((packed));
-
-#define QETH_IOC_MAGIC 0x22
-/* these don't really have 'unsigned long' arguments but were defined that way */
-#define QETH_IOCPROC_OSAEINTERFACES _IOWR(QETH_IOC_MAGIC, 1, unsigned long)
-#define QETH_IOCPROC_INTERFACECHANGES _IOWR(QETH_IOC_MAGIC, 2, unsigned long)
-
-#define SNMP_QUERY_CARD_INFO 0x00000002L
-#define SNMP_REGISETER_MIB   0x00000004L
-#define SNMP_GET_OID         0x00000010L
-#define SNMP_SET_OID         0x00000011L
-#define SNMP_GET_NEXT_OID    0x00000012L
-#define SNMP_QUERY_ALERTS    0x00000020L
-#define SNMP_SET_TRAP        0x00000021L
-
-
-#define ARP_DATA_SIZE 3968
-#define ARP_FLUSH -3
-#define ARP_RETURNCODE_NOARPDATA -2
-#define ARP_RETURNCODE_ERROR -1
-#define ARP_RETURNCODE_SUCCESS 0
-#define ARP_RETURNCODE_LASTREPLY 1
-
-#define SNMP_BASE_CMDLENGTH 44
-#define SNMP_SETADP_CMDLENGTH 16
-#define SNMP_REQUEST_DATA_OFFSET 16
-
-struct snmp_ipa_setadp_cmd {
+/* SETADAPTERPARMS IPA Command:    *******************************************/
+struct qeth_query_cmds_supp {
+       __u32 no_lantypes_supp;
+       __u8 lan_type;
+       __u8 reserved1[3];
+       __u32 supported_cmds;
+       __u8 reserved2[8];
+} __attribute__ ((packed));
+
+struct qeth_change_addr {
+       __u32 cmd;
+       __u32 addr_size;
+       __u32 no_macs;
+       __u8 addr[OSA_ADDR_LEN];
+} __attribute__ ((packed));
+
+struct qeth_ipacmd_setadpparms {
        __u32 supp_hw_cmds;
        __u32 reserved1;
        __u16 cmdlength;
@@ -354,91 +287,198 @@ struct snmp_ipa_setadp_cmd {
        __u8 frames_used_total;
        __u8 frame_seq_no;
        __u32 reserved3;
-       __u8 snmp_token[16];
        union {
-               struct {
-                       __u32 snmp_request;
-                       __u32 snmp_interface;
-                       __u32 snmp_returncode;
-                       __u32 snmp_firmwarelevel;
-                       __u32 snmp_seqno;
-                       __u8 snmp_data[ARP_DATA_SIZE];
-               } snmp_subcommand;
+               struct qeth_query_cmds_supp query_cmds_supp;
+               struct qeth_change_addr change_addr;
+               __u32 mode;
        } data;
-}__attribute__ ((packed));
-
-
-struct arp_cmd {
-       __u8 command;
-       __u8 initiator;
-       __u16 seq_no;
-       __u16 return_code;
-       __u8 adapter_type;
-       __u8 rel_adapter_no;
-       __u8 prim_version_no;
-       __u8 param_count;
-       __u16 prot_version;
-       __u32 ipa_supported;
-       __u32 ipa_enabled;
+} __attribute__ ((packed));
+
+/* IPFRAME IPA Command:    ***************************************************/
+/* TODO: define in analogy to commands define above */
+
+/* ADD_ADDR_ENTRY IPA Command:    ********************************************/
+/* TODO: define in analogy to commands define above */
+
+/* DELETE_ADDR_ENTRY IPA Command:    *****************************************/
+/* TODO: define in analogy to commands define above */
+
+/* CREATE_ADDR IPA Command:    ***********************************************/
+struct qeth_create_destroy_address {
+       __u8 unique_id[8];
+} __attribute__ ((packed));
+
+/* REGISTER_LOCAL_ADDR IPA Command:    ***************************************/
+/* TODO: define in analogy to commands define above */
+
+/* UNREGISTER_LOCAL_ADDR IPA Command:    *************************************/
+/* TODO: define in analogy to commands define above */
+
+/* Header for each IPA command */
+struct qeth_ipacmd_hdr {
+       __u8   command;
+       __u8   initiator;
+       __u16  seqno;
+       __u16  return_code;
+       __u8   adapter_type;
+       __u8   rel_adapter_no;
+       __u8   prim_version_no;
+       __u8   param_count;
+       __u16  prot_version;
+       __u32  ipa_supported;
+       __u32  ipa_enabled;
+} __attribute__ ((packed));
+
+/* The IPA command itself */
+struct qeth_ipa_cmd {
+       struct qeth_ipacmd_hdr hdr;
        union {
-               struct {
-                       __u32 assist_no;
-                       __u16 length;
-                       __u16 command_code;
-                       __u16 return_code;
-                       __u8 number_of_replies;
-                       __u8 seq_no;
-                       union {
-                               struct {
-                                       __u16 tcpip_requestbitmask;
-                                       __u16 osa_setbitmask;
-                                       __u32 number_of_entries;
-                                       __u8 arp_data[ARP_DATA_SIZE];
-                               } queryarp_data;
-                       } data;
-               } setassparms;
-                struct snmp_ipa_setadp_cmd setadapterparms; 
+               struct qeth_ipacmd_setdelip4    setdelip4;
+               struct qeth_ipacmd_setdelip6    setdelip6;
+               struct qeth_ipacmd_setdelipm    setdelipm;
+               struct qeth_ipacmd_setassparms  setassparms;
+               struct qeth_create_destroy_address create_destroy_addr;
+               struct qeth_ipacmd_setadpparms  setadapterparms;
+               struct qeth_set_routing setrtg;
        } data;
-}__attribute__ ((packed));
+} __attribute__ ((packed));
 
+/* 
+ * special command for ARP processing.
+ * this is not included in setassparms command before, because we get
+ * problem with the size of struct qeth_ipacmd_setassparms otherwise
+ */
+enum qeth_ipa_arp_return_codes {
+       QETH_IPA_ARP_RC_SUCCESS      = 0x0000,
+       QETH_IPA_ARP_RC_FAILED       = 0x0001,
+       QETH_IPA_ARP_RC_NOTSUPP      = 0x0002,
+       QETH_IPA_ARP_RC_OUT_OF_RANGE = 0x0003,
+       QETH_IPA_ARP_RC_Q_NOTSUPP    = 0x0004,
+       QETH_IPA_ARP_RC_Q_NO_DATA    = 0x0008,
+};
 
+#define QETH_QARP_DATA_SIZE 3968
+struct qeth_arp_query_data {
+       __u16 request_bits;
+       __u16 reply_bits;
+       __u32 no_entries;
+       char data[QETH_QARP_DATA_SIZE];
+} __attribute__((packed));
+
+/* used as parameter for arp_query reply */
+struct qeth_arp_query_info {
+       __u32 udata_len;
+       __u32 udata_offset;
+       __u32 no_entries;
+       char *udata;
+};
 
-#define IPA_PDU_HEADER_SIZE 0x40
-#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
-#define QETH_IPA_PDU_LEN_PDU1(buffer) (buffer+0x26)
-#define QETH_IPA_PDU_LEN_PDU2(buffer) (buffer+0x2a)
-#define QETH_IPA_PDU_LEN_PDU3(buffer) (buffer+0x3a)
+#define IPA_ARP_CMD_LEN (IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_arp_cmd))
+#define QETH_ARP_CMD_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
+                              sizeof(struct qeth_ipacmd_setassparms_hdr))
+#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
+                                      QETH_ARP_CMD_BASE_LEN)
+struct qeth_ipa_arp_cmd {
+       struct qeth_ipacmd_hdr ihdr;
+       struct qeth_ipacmd_setassparms_hdr shdr;
+       union {
+               struct qeth_arp_query_data query_arp;   
+       } data;
+} __attribute__((packed));
 
-extern unsigned char IPA_PDU_HEADER[];
 
-#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
+/* Helper functions */
+#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST)
 
-#define PDU_ENCAPSULATION(buffer) \
-       (buffer+ \
-        *(buffer+ (*(buffer+0x0b))+ *(buffer+*(buffer+0x0b)+0x11) +0x07))
+/*****************************************************************************/
+/* END OF   IP Assist related definitions                                    */
+/*****************************************************************************/
 
-#define IS_IPA(buffer) ((buffer) && ( *(buffer+ ((*(buffer+0x0b))+4) )==0xc1) )
 
-#define IS_IPA_REPLY(buffer) ( (buffer) && ( (*(PDU_ENCAPSULATION(buffer)+1))==INITIATOR_HOST ) )
+extern unsigned char WRITE_CCW[];
+extern unsigned char READ_CCW[];
+
+extern unsigned char CM_ENABLE[];
+#define CM_ENABLE_SIZE 0x63
+#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer+0x2c)
+#define QETH_CM_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
+#define QETH_CM_ENABLE_USER_DATA(buffer) (buffer+0x5b)
 
-#define CCW_NOP_CMD 0x03
-#define CCW_NOP_COUNT 1
+#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) \
+               (PDU_ENCAPSULATION(buffer)+ 0x13)
 
-extern unsigned char WRITE_CCW[];
 
-extern unsigned char READ_CCW[];
+extern unsigned char CM_SETUP[];
+#define CM_SETUP_SIZE 0x64
+#define QETH_CM_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
+#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
+#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
 
-#endif /* __QETH_MPC_H__ */
+#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) \
+               (PDU_ENCAPSULATION(buffer) + 0x1a)
 
+extern unsigned char ULP_ENABLE[];
+#define ULP_ENABLE_SIZE 0x6b
+#define QETH_ULP_ENABLE_LINKNUM(buffer) (buffer+0x61)
+#define QETH_ULP_ENABLE_DEST_ADDR(buffer) (buffer+0x2c)
+#define QETH_ULP_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
+#define QETH_ULP_ENABLE_PORTNAME_AND_LL(buffer) (buffer+0x62)
+#define QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer) \
+               (PDU_ENCAPSULATION(buffer) + 0x13)
+#define QETH_ULP_ENABLE_RESP_MAX_MTU(buffer) \
+               (PDU_ENCAPSULATION(buffer)+ 0x1f)
+#define QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer) \
+               (PDU_ENCAPSULATION(buffer) + 0x17)
+#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \
+               (PDU_ENCAPSULATION(buffer)+ 0x2b)
 
+extern unsigned char ULP_SETUP[];
+#define ULP_SETUP_SIZE 0x6c
+#define QETH_ULP_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
+#define QETH_ULP_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
+#define QETH_ULP_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
+#define QETH_ULP_SETUP_CUA(buffer) (buffer+0x68)
+#define QETH_ULP_SETUP_REAL_DEVADDR(buffer) (buffer+0x6a)
 
+#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) \
+               (PDU_ENCAPSULATION(buffer)+0x1a)
 
+       
+extern unsigned char DM_ACT[];
+#define DM_ACT_SIZE 0x55
+#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
+#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
 
 
 
+#define QETH_TRANSPORT_HEADER_SEQ_NO(buffer) (buffer+4)
+#define QETH_PDU_HEADER_SEQ_NO(buffer) (buffer+0x1c)
+#define QETH_PDU_HEADER_ACK_SEQ_NO(buffer) (buffer+0x20)
 
+extern unsigned char IDX_ACTIVATE_READ[];
+extern unsigned char IDX_ACTIVATE_WRITE[];
 
+#define IDX_ACTIVATE_SIZE      0x22
+#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
+#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
+#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
+#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer+0x16)
+#define QETH_IDX_ACT_QDIO_DEV_CUA(buffer) (buffer+0x1e)
+#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
+#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
+#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
 
+#define PDU_ENCAPSULATION(buffer) \
+       (buffer + *(buffer + (*(buffer+0x0b)) + \
+        *(buffer + *(buffer+0x0b)+0x11) +0x07))
 
+#define IS_IPA(buffer) \
+       ((buffer) && \
+        ( *(buffer + ((*(buffer+0x0b))+4) )==0xc1) )
 
+#define ADDR_FRAME_TYPE_DIX 1
+#define ADDR_FRAME_TYPE_802_3 2
+#define ADDR_FRAME_TYPE_TR_WITHOUT_SR 0x10
+#define ADDR_FRAME_TYPE_TR_WITH_SR 0x20
 
+#endif
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
new file mode 100644 (file)
index 0000000..3a9d90a
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ *
+ * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.5 $)
+ *
+ * Linux on zSeries OSA Express and HiperSockets support
+ * This file contains code related to procfs.
+ *
+ * Copyright 2000,2003 IBM Corporation
+ *
+ * Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
+#include <linux/rwsem.h>
+
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_fs.h"
+
+/***** /proc/qeth *****/
+#define QETH_PROCFILE_NAME "qeth"
+static struct proc_dir_entry *qeth_procfile;
+
+static void *
+qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
+{
+       struct list_head *next_card = NULL;
+       int i = 0;
+
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       
+       if (*offset == 0)
+               return SEQ_START_TOKEN;
+
+       /* get card at pos *offset */
+       list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices)
+               if (++i == *offset)
+                       return next_card;
+       
+       return NULL;
+}
+
+static void
+qeth_procfile_seq_stop(struct seq_file *s, void* it)
+{
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+}
+
+static void *
+qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
+{
+       struct list_head *next_card = NULL;
+       struct list_head *current_card;
+       
+       if (it == SEQ_START_TOKEN) {
+               next_card = qeth_ccwgroup_driver.driver.devices.next;
+               if (next_card->next == next_card) /* list empty */
+                       return NULL;
+               (*offset)++;
+       } else {
+               current_card = (struct list_head *)it;
+               if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
+                       return NULL; /* end of list reached */
+               next_card = current_card->next;
+               (*offset)++;
+       }
+       
+       return next_card;
+}
+
+static inline const char *
+qeth_get_router_str(struct qeth_card *card, int ipv)
+{
+       int routing_type = 0;
+
+       if (ipv == 4){
+               routing_type = card->options.route4.type;
+       } else {
+#ifdef CONFIG_QETH_IPV6
+               routing_type = card->options.route6.type;
+#else
+               return "n/a";
+#endif /* CONFIG_QETH_IPV6 */
+       }
+       
+       if (routing_type == PRIMARY_ROUTER)
+               return "pri";
+       else if (routing_type == SECONDARY_ROUTER)
+               return "sec";
+       else if (routing_type == MULTICAST_ROUTER)
+               return "mc";
+       else if (routing_type == PRIMARY_CONNECTOR)
+               return "p.c";
+       else if (routing_type == SECONDARY_CONNECTOR)
+               return "s.c";
+       else if (routing_type == NO_ROUTER)
+               return "no";
+       else
+               return "unk";
+}
+
+static int
+qeth_procfile_seq_show(struct seq_file *s, void *it)
+{
+       struct device *device;
+       struct qeth_card *card;
+       char tmp[12]; /* for qeth_get_prioq_str */
+       
+       if (it == SEQ_START_TOKEN){
+               seq_printf(s, "devices                    CHPID interface  "
+                             "cardtype       port chksum prio-q'ing rtr4 "
+                             "rtr6 fsz   cnt\n");
+               seq_printf(s, "-------------------------- ----- ---------- "
+                             "-------------- ---- ------ ---------- ---- "
+                             "---- ----- -----\n");
+       } else {
+               device = list_entry(it, struct device, driver_list);
+               card = device->driver_data;
+               seq_printf(s, "%s/%s/%s x%02X   %-10s %-14s %-4i ", 
+                               CARD_RDEV_ID(card),
+                               CARD_WDEV_ID(card),
+                               CARD_DDEV_ID(card),
+                               card->info.chpid,
+                               card->info.if_name,
+                               qeth_get_cardname_short(card),
+                               card->info.portno);
+               if (card->lan_online)
+                       seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n", 
+                                       qeth_get_checksum_str(card),
+                                       qeth_get_prioq_str(card, tmp),
+                                       qeth_get_router_str(card, 4),
+                                       qeth_get_router_str(card, 6),
+                                       qeth_get_bufsize_str(card),
+                                       card->qdio.in_buf_pool.buf_count);
+               else
+                       seq_printf(s, "  +++ LAN OFFLINE +++\n");
+       }
+       return 0;
+}
+
+static struct seq_operations qeth_procfile_seq_ops = {
+       .start = qeth_procfile_seq_start,
+       .stop  = qeth_procfile_seq_stop,
+       .next  = qeth_procfile_seq_next,
+       .show  = qeth_procfile_seq_show,
+};
+
+static int
+qeth_procfile_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &qeth_procfile_seq_ops);
+}
+
+static struct file_operations qeth_procfile_fops = {
+       .owner   = THIS_MODULE,
+       .open    = qeth_procfile_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+/***** /proc/qeth_perf *****/
+#define QETH_PERF_PROCFILE_NAME "qeth_perf"
+static struct proc_dir_entry *qeth_perf_procfile;
+
+#ifdef CONFIG_QETH_PERF_STATS
+
+static void *
+qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
+{
+       struct list_head *next_card = NULL;
+       int i = 0;
+       
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       /* get card at pos *offset */
+       list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
+               if (i == *offset)
+                       return next_card;
+               i++;
+       }
+       return NULL;
+}
+
+static void
+qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
+{
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+}
+
+static void *
+qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
+{
+       struct list_head *current_card = (struct list_head *)it;
+       
+       if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
+               return NULL; /* end of list reached */
+       (*offset)++;
+       return current_card->next;
+}
+
+static int
+qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
+{
+       struct device *device;
+       struct qeth_card *card;
+       
+       device = list_entry(it, struct device, driver_list);
+       card = device->driver_data;
+       seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
+                       CARD_RDEV_ID(card),
+                       CARD_WDEV_ID(card),
+                       CARD_DDEV_ID(card),
+                       card->info.if_name
+                 );
+       seq_printf(s, "  Skb's/buffers received                 : %li/%i\n"
+                     "  Skb's/buffers sent                     : %li/%i\n\n",
+                       card->stats.rx_packets, card->perf_stats.bufs_rec,
+                       card->stats.tx_packets, card->perf_stats.bufs_sent
+                 );
+       seq_printf(s, "  Skb's/buffers sent without packing     : %li/%i\n"
+                     "  Skb's/buffers sent with packing        : %i/%i\n\n",
+                  card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
+                  card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
+                  card->perf_stats.skbs_sent_pack,
+                  card->perf_stats.bufs_sent_pack
+                 );
+       seq_printf(s, "  Packing state changes no pkg.->packing : %i/%i\n"
+                     "  Current buffer usage (outbound q's)    : "
+                     "%i/%i/%i/%i\n\n",
+                       card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
+                       atomic_read(&card->qdio.out_qs[0]->used_buffers),
+                       (card->qdio.no_out_queues > 1)?
+                               atomic_read(&card->qdio.out_qs[1]->used_buffers)
+                               : 0,
+                       (card->qdio.no_out_queues > 2)?
+                               atomic_read(&card->qdio.out_qs[2]->used_buffers)
+                               : 0,
+                       (card->qdio.no_out_queues > 3)?
+                               atomic_read(&card->qdio.out_qs[3]->used_buffers)
+                               : 0
+                 );
+       seq_printf(s, "  Inbound time (in us)                   : %i\n"
+                     "  Inbound cnt                            : %i\n"
+                     "  Outbound time (in us, incl QDIO)       : %i\n"
+                     "  Outbound cnt                           : %i\n"
+                     "  Watermarks L/H                         : %i/%i\n\n",
+                       card->perf_stats.inbound_time,
+                       card->perf_stats.inbound_cnt,
+                       card->perf_stats.outbound_time,
+                       card->perf_stats.outbound_cnt,
+                       QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK
+                 );
+
+       return 0;
+}
+
+static struct seq_operations qeth_perf_procfile_seq_ops = {
+       .start = qeth_perf_procfile_seq_start,
+       .stop  = qeth_perf_procfile_seq_stop,
+       .next  = qeth_perf_procfile_seq_next,
+       .show  = qeth_perf_procfile_seq_show,
+};
+
+static int
+qeth_perf_procfile_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &qeth_perf_procfile_seq_ops);
+}
+
+static struct file_operations qeth_perf_procfile_fops = {
+       .owner   = THIS_MODULE,
+       .open    = qeth_perf_procfile_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+#define qeth_perf_procfile_created qeth_perf_procfile
+#else
+#define qeth_perf_procfile_created 1
+#endif /* CONFIG_QETH_PERF_STATS */
+
+/***** /proc/qeth_ipa_takeover *****/
+#define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
+static struct proc_dir_entry *qeth_ipato_procfile;
+
+static void *
+qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
+{
+       struct list_head *next_card = NULL;
+       int i = 0;
+       
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       /* TODO: finish this */
+       /*
+        * maybe SEQ_SATRT_TOKEN can be returned for offset 0
+        * output driver settings then;
+        * else output setting for respective card
+        */
+       /* get card at pos *offset */
+       list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
+               if (i == *offset)
+                       return next_card;
+               i++;
+       }
+       return NULL;
+}
+
+static void
+qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
+{
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+}
+
+static void *
+qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
+{
+       struct list_head *current_card = (struct list_head *)it;
+       
+       /* TODO: finish this */
+       /*
+        * maybe SEQ_SATRT_TOKEN can be returned for offset 0
+        * output driver settings then;
+        * else output setting for respective card
+        */
+       if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
+               return NULL; /* end of list reached */
+       (*offset)++;
+       return current_card->next;
+}
+
+static int
+qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
+{
+       struct device *device;
+       struct qeth_card *card;
+       
+       /* TODO: finish this */
+       /*
+        * maybe SEQ_SATRT_TOKEN can be returned for offset 0
+        * output driver settings then;
+        * else output setting for respective card
+        */
+       device = list_entry(it, struct device, driver_list);
+       card = device->driver_data;
+
+       return 0;
+}
+
+static struct seq_operations qeth_ipato_procfile_seq_ops = {
+       .start = qeth_ipato_procfile_seq_start,
+       .stop  = qeth_ipato_procfile_seq_stop,
+       .next  = qeth_ipato_procfile_seq_next,
+       .show  = qeth_ipato_procfile_seq_show,
+};
+
+static int
+qeth_ipato_procfile_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &qeth_ipato_procfile_seq_ops);
+}
+
+static struct file_operations qeth_ipato_procfile_fops = {
+       .owner   = THIS_MODULE,
+       .open    = qeth_ipato_procfile_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+int __init
+qeth_create_procfs_entries(void)
+{
+       qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
+                                          S_IFREG | 0444, NULL);
+       if (qeth_procfile)
+               qeth_procfile->proc_fops = &qeth_procfile_fops;
+
+#ifdef CONFIG_QETH_PERF_STATS
+       qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
+                                          S_IFREG | 0444, NULL);
+       if (qeth_perf_procfile)
+               qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
+#endif /* CONFIG_QETH_PERF_STATS */
+
+       qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
+                                          S_IFREG | 0444, NULL);
+       if (qeth_ipato_procfile)
+               qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
+
+       if (qeth_procfile &&
+           qeth_ipato_procfile &&
+           qeth_perf_procfile_created)
+               return 0;
+       else
+               return -ENOMEM;
+}
+
+void __exit
+qeth_remove_procfs_entries(void)
+{
+       if (qeth_procfile)
+               remove_proc_entry(QETH_PROCFILE_NAME, NULL);
+       if (qeth_perf_procfile)
+               remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
+       if (qeth_ipato_procfile)
+               remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
+}
+
+
+/* ONLY FOR DEVELOPMENT! -> make it as module */
+/*
+static void
+qeth_create_sysfs_entries(void)
+{
+       struct device *dev;
+       
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       
+       list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
+                       driver_list)
+               qeth_create_device_attributes(dev);
+       
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+}
+
+static void
+qeth_remove_sysfs_entries(void)
+{
+       struct device *dev;
+       
+       down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+       
+       list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
+                       driver_list)
+               qeth_remove_device_attributes(dev);
+       
+       up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
+}
+
+static int __init
+qeth_fs_init(void)
+{
+       printk(KERN_INFO "qeth_fs_init\n");
+       qeth_create_procfs_entries();
+       qeth_create_sysfs_entries();
+
+       return 0;
+}
+
+static void __exit
+qeth_fs_exit(void)
+{
+       printk(KERN_INFO "qeth_fs_exit\n");
+       qeth_remove_procfs_entries();
+       qeth_remove_sysfs_entries();
+}
+
+
+module_init(qeth_fs_init);
+module_exit(qeth_fs_exit);
+
+MODULE_LICENSE("GPL");
+*/
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
new file mode 100644 (file)
index 0000000..c4a0e77
--- /dev/null
@@ -0,0 +1,1479 @@
+/*
+ *
+ * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.19 $)
+ *
+ * Linux on zSeries OSA Express and HiperSockets support
+ * This file contains code related to sysfs.
+ *
+ * Copyright 2000,2003 IBM Corporation
+ *
+ * Author(s): Thomas Spatzier <tspat@de.ibm.com>
+ *           Frank Pavlic <pavlic@de.ibm.com>  
+ *
+ */
+#include <linux/list.h>
+#include <linux/rwsem.h>
+
+#include <asm/ebcdic.h>
+
+#include "qeth.h"
+#include "qeth_mpc.h"
+#include "qeth_fs.h"
+
+/*****************************************************************************/
+/*                                                                           */
+/*          /sys-fs stuff UNDER DEVELOPMENT !!!                              */
+/*                                                                           */
+/*****************************************************************************/
+//low/high watermark
+
+static ssize_t
+qeth_dev_state_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       if (!card)
+               return -EINVAL;
+       
+       switch (card->state) {
+       case CARD_STATE_DOWN:
+               return sprintf(buf, "DOWN\n");
+       case CARD_STATE_HARDSETUP:
+               return sprintf(buf, "HARDSETUP\n");
+       case CARD_STATE_SOFTSETUP:
+               return sprintf(buf, "SOFTSETUP\n");
+       case CARD_STATE_UP_LAN_OFFLINE:
+               return sprintf(buf, "UP (LAN OFFLINE)\n");
+       case CARD_STATE_UP_LAN_ONLINE:
+               return sprintf(buf, "UP (LAN ONLINE)\n");
+       case CARD_STATE_RECOVER:
+               return sprintf(buf, "RECOVER\n");
+       default:
+               return sprintf(buf, "UNKNOWN\n");
+       }
+}
+
+static DEVICE_ATTR(state, 0444, qeth_dev_state_show, NULL);
+
+static ssize_t
+qeth_dev_chpid_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%02X\n", card->info.chpid);
+}
+
+static DEVICE_ATTR(chpid, 0444, qeth_dev_chpid_show, NULL);
+
+static ssize_t
+qeth_dev_if_name_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%s\n", card->info.if_name);
+}
+
+static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL);
+
+static ssize_t
+qeth_dev_card_type_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%s\n", qeth_get_cardname_short(card));
+}
+
+static DEVICE_ATTR(card_type, 0444, qeth_dev_card_type_show, NULL);
+
+static ssize_t
+qeth_dev_portno_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%i\n", card->info.portno);
+}
+
+static ssize_t
+qeth_dev_portno_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       unsigned int portno;
+       
+       if (!card)
+               return -EINVAL;
+       
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+       
+       portno = simple_strtoul(buf, &tmp, 16);
+       if ((portno < 0) || (portno > MAX_PORTNO)){
+               PRINT_WARN("portno 0x%X is out of range\n", portno);
+               return -EINVAL;
+       }
+       
+       card->info.portno = portno;
+       return count;
+}
+
+static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store);
+
+static ssize_t
+qeth_dev_portname_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+       char portname[9] = {0, };
+
+       if (!card)
+               return -EINVAL;
+       
+       if (card->info.portname_required) {
+               memcpy(portname, card->info.portname + 1, 8);
+               EBCASC(portname, 8);
+               return sprintf(buf, "%s\n", portname);
+       } else
+               return sprintf(buf, "no portname required\n");
+}
+
+static ssize_t
+qeth_dev_portname_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+       
+       if (!card)
+               return -EINVAL;
+       
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+       
+       tmp = strsep((char **) &buf, "\n");
+       if ((strlen(tmp) > 8) || (strlen(tmp) < 2))
+               return -EINVAL;
+
+       card->info.portname[0] = strlen(tmp);
+       /* for beauty reasons */
+       for (i = 1; i < 9; i++)
+               card->info.portname[i] = ' ';
+       strcpy(card->info.portname + 1, tmp);
+       ASCEBC(card->info.portname + 1, 8);
+
+       return count;
+}
+
+static DEVICE_ATTR(portname, 0644, qeth_dev_portname_show,
+               qeth_dev_portname_store);
+
+static ssize_t
+qeth_dev_checksum_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%s checksumming\n", qeth_get_checksum_str(card));
+}
+
+static ssize_t
+qeth_dev_checksum_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       
+       if (!card)
+               return -EINVAL;
+       
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+       
+       tmp = strsep((char **) &buf, "\n");
+       if (!strcmp(tmp, "sw_checksumming"))
+               card->options.checksum_type = SW_CHECKSUMMING;
+       else if (!strcmp(tmp, "hw_checksumming"))
+               card->options.checksum_type = HW_CHECKSUMMING;
+       else if (!strcmp(tmp, "no_checksumming"))
+               card->options.checksum_type = NO_CHECKSUMMING;
+       else {
+               PRINT_WARN("Unknown checksumming type '%s'\n", tmp);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(checksumming, 0644, qeth_dev_checksum_show,
+               qeth_dev_checksum_store);
+
+static ssize_t
+qeth_dev_prioqing_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       switch (card->qdio.do_prio_queueing) {
+       case QETH_PRIO_Q_ING_PREC:
+               return sprintf(buf, "%s\n", "by precedence");
+       case QETH_PRIO_Q_ING_TOS:
+               return sprintf(buf, "%s\n", "by type of service");
+       default:
+               return sprintf(buf, "always queue %i\n",
+                              card->qdio.default_out_queue);
+       }
+}
+
+static ssize_t
+qeth_dev_prioqing_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       
+       if (!card)
+               return -EINVAL;
+       
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+       
+       tmp = strsep((char **) &buf, "\n");
+       if (!strcmp(tmp, "prio_queueing_prec"))
+               card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
+       else if (!strcmp(tmp, "prio_queueing_tos"))
+               card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS;
+       else if (!strcmp(tmp, "no_prio_queueing:0")) {
+               card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
+               card->qdio.default_out_queue = 0;
+       } else if (!strcmp(tmp, "no_prio_queueing:1")) {
+               card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
+               card->qdio.default_out_queue = 1;
+       } else if (!strcmp(tmp, "no_prio_queueing:2")) {
+               card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
+               card->qdio.default_out_queue = 2;
+       } else if (!strcmp(tmp, "no_prio_queueing:3")) {
+               card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
+               card->qdio.default_out_queue = 3;
+       } else if (!strcmp(tmp, "no_prio_queueing")) {
+               card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
+               card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
+       } else {
+               PRINT_WARN("Unknown queueing type '%s'\n", tmp);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(priority_queueing, 0644, qeth_dev_prioqing_show,
+               qeth_dev_prioqing_store);
+
+static ssize_t
+qeth_dev_bufcnt_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count);
+}
+
+static ssize_t
+qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       unsigned int cnt;
+       
+       if (!card)
+               return -EINVAL;
+       
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+       
+       cnt = simple_strtoul(buf, &tmp, 16);
+       cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
+               ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
+       card->qdio.in_buf_pool.buf_count = cnt;
+       /* TODO: steel/add buffers from/to a running card's buffer pool (?) */
+
+       return count;
+}
+
+static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
+               qeth_dev_bufcnt_store);
+
+static inline ssize_t
+qeth_dev_route_show(struct qeth_routing_info *route, char *buf)
+{
+       switch (route->type) {
+       case PRIMARY_ROUTER:
+               return sprintf(buf, "%s\n", "primary router");
+       case SECONDARY_ROUTER:
+               return sprintf(buf, "%s\n", "secondary router");
+       case MULTICAST_ROUTER:
+               return sprintf(buf, "%s\n", "multicast router");
+       case PRIMARY_CONNECTOR:
+               return sprintf(buf, "%s\n", "primary connector");
+       case SECONDARY_CONNECTOR:
+               return sprintf(buf, "%s\n", "secondary connector");
+       default:
+               return sprintf(buf, "%s\n", "no");
+       }
+}
+
+static ssize_t
+qeth_dev_route4_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_route_show(&card->options.route4, buf);
+}
+
+static inline ssize_t
+qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
+               enum qeth_prot_versions prot, const char *buf, size_t count)
+{
+       enum qeth_routing_types old_route_type = route->type;
+       char *tmp;
+       int rc;
+
+       tmp = strsep((char **) &buf, "\n");
+
+       if (!strcmp(tmp, "no_router")){
+               route->type = NO_ROUTER;
+               goto check_reset;
+       }
+
+       if (card->info.type == QETH_CARD_TYPE_IQD) {
+               if (!strcmp(tmp, "primary_connector")) {
+                       route->type = PRIMARY_CONNECTOR;
+               } else if (!strcmp(tmp, "secondary_connector")) {
+                       route->type = SECONDARY_CONNECTOR;
+               } else if (!strcmp(tmp, "multicast_router")) {
+                       route->type = MULTICAST_ROUTER;
+               } else
+                       goto out_inval;
+       } else {
+               if (!strcmp(tmp, "primary_router")) {
+                       route->type = PRIMARY_ROUTER;
+               } else if (!strcmp(tmp, "secondary_router")) {
+                       route->type = SECONDARY_ROUTER;
+               } else if (!strcmp(tmp, "multicast_router")) {
+                       if (qeth_is_ipafunc_supported(card, prot,
+                                                     IPA_OSA_MC_ROUTER))
+                               route->type = MULTICAST_ROUTER;
+                       else
+                               goto out_inval;
+               } else
+                       goto out_inval;
+       }               
+check_reset:
+       if (old_route_type != route->type){
+               if (prot == QETH_PROT_IPV4)
+                       rc = qeth_setrouting_v4(card);
+               else if (prot == QETH_PROT_IPV6)
+                       rc = qeth_setrouting_v6(card);
+       }
+       return count;
+out_inval:
+       PRINT_WARN("Routing type '%s' not supported for interface %s.\n"
+                  "Router status not changed.\n",
+                  tmp, card->info.if_name);
+       return -EINVAL;
+}
+
+static ssize_t
+qeth_dev_route4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_route_store(card, &card->options.route4,
+                                   QETH_PROT_IPV4, buf, count);
+}
+
+static DEVICE_ATTR(route4, 0644, qeth_dev_route4_show, qeth_dev_route4_store);
+
+#ifdef CONFIG_QETH_IPV6
+static ssize_t
+qeth_dev_route6_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       if (!qeth_is_supported(card, IPA_IPV6))
+               return sprintf(buf, "%s\n", "n/a");
+
+       return qeth_dev_route_show(&card->options.route6, buf);
+}
+
+static ssize_t
+qeth_dev_route6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       if (!qeth_is_supported(card, IPA_IPV6)){
+               PRINT_WARN("IPv6 not supported for interface %s.\n"
+                          "Routing status no changed.\n",
+                          card->info.if_name);
+               return -ENOTSUPP;
+       }
+
+       return qeth_dev_route_store(card, &card->options.route6,
+                                   QETH_PROT_IPV6, buf, count);
+}
+
+static DEVICE_ATTR(route6, 0644, qeth_dev_route6_show, qeth_dev_route6_store);
+#endif
+
+static ssize_t
+qeth_dev_add_hhlen_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%i\n", card->options.add_hhlen);
+}
+
+static ssize_t
+qeth_dev_add_hhlen_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if ((i < 0) || (i > MAX_ADD_HHLEN)) {
+               PRINT_WARN("add_hhlen out of range\n");
+               return -EINVAL;
+       }
+       card->options.add_hhlen = i;
+
+       return count;
+}
+
+static DEVICE_ATTR(add_hhlen, 0644, qeth_dev_add_hhlen_show,
+                  qeth_dev_add_hhlen_store);
+
+static ssize_t
+qeth_dev_fake_ll_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return sprintf(buf, "%i\n", card->options.fake_ll? 1:0);
+}
+
+static ssize_t
+qeth_dev_fake_ll_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if ((i == 0) || (i == 1))
+               card->options.fake_ll = i;
+       else {
+               PRINT_WARN("fake_ll: write 0 or 1 to this file!\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(fake_ll, 0644, qeth_dev_fake_ll_show,
+                  qeth_dev_fake_ll_store);
+
+static ssize_t
+qeth_dev_fake_broadcast_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
+}
+
+static ssize_t
+qeth_dev_fake_broadcast_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if ((i == 0) || (i == 1))
+               card->options.fake_broadcast = i;
+       else {
+               PRINT_WARN("fake_broadcast: write 0 or 1 to this file!\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(fake_broadcast, 0644, qeth_dev_fake_broadcast_show,
+                  qeth_dev_fake_broadcast_store);
+
+static ssize_t
+qeth_dev_recover_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_UP_LAN_ONLINE) &&
+           (card->state != CARD_STATE_UP_LAN_OFFLINE))
+               return -EPERM;
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if (i == 1)
+               qeth_schedule_recovery(card);
+
+       return count;
+}
+
+static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
+
+/* TODO */
+static ssize_t
+qeth_dev_broadcast_mode_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
+             (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
+               return sprintf(buf, "n/a\n");
+
+       return sprintf(buf, "%s\n", (card->options.broadcast_mode ==
+                                    QETH_TR_BROADCAST_ALLRINGS)?
+                      "all rings":"local");
+}
+
+/* TODO */
+static ssize_t
+qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
+             (card->info.link_type == QETH_LINK_TYPE_LANE_TR))){
+               PRINT_WARN("Device is not a tokenring device!\n");
+               return -EINVAL;
+       }
+
+       tmp = strsep((char **) &buf, "\n");
+
+       if (!strcmp(tmp, "local")){
+               card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
+               return count;
+       } else if (!strcmp(tmp, "all_rings")) {
+               card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
+               return count;
+       } else {
+               PRINT_WARN("broadcast_mode: invalid mode %s!\n",
+                          tmp);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(broadcast_mode, 0644, qeth_dev_broadcast_mode_show,
+                  qeth_dev_broadcast_mode_store);
+
+/* TODO */
+static ssize_t
+qeth_dev_canonical_macaddr_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
+             (card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
+               return sprintf(buf, "n/a\n");
+
+       return sprintf(buf, "%i\n", (card->options.macaddr_mode ==
+                                    QETH_TR_MACADDR_CANONICAL)? 1:0);
+}
+
+/* TODO */
+static ssize_t
+qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf,
+                                 size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+       int i;
+
+       if (!card)
+               return -EINVAL;
+
+       if ((card->state != CARD_STATE_DOWN) &&
+           (card->state != CARD_STATE_RECOVER))
+               return -EPERM;
+
+       if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
+             (card->info.link_type == QETH_LINK_TYPE_LANE_TR))){
+               PRINT_WARN("Device is not a tokenring device!\n");
+               return -EINVAL;
+       }
+
+       i = simple_strtoul(buf, &tmp, 16);
+       if ((i == 0) || (i == 1))
+               card->options.macaddr_mode = i?
+                       QETH_TR_MACADDR_CANONICAL :
+                       QETH_TR_MACADDR_NONCANONICAL;
+       else {
+               PRINT_WARN("canonical_macaddr: write 0 or 1 to this file!\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(canonical_macaddr, 0644, qeth_dev_canonical_macaddr_show,
+                  qeth_dev_canonical_macaddr_store);
+
+static struct device_attribute * qeth_device_attrs[] = {
+       &dev_attr_state,
+       &dev_attr_chpid,
+       &dev_attr_if_name,
+       &dev_attr_card_type,
+       &dev_attr_portno,
+       &dev_attr_portname,
+       &dev_attr_checksumming,
+       &dev_attr_priority_queueing,
+       &dev_attr_buffer_count,
+       &dev_attr_route4,
+#ifdef CONFIG_QETH_IPV6
+       &dev_attr_route6,
+#endif
+       &dev_attr_add_hhlen,
+       &dev_attr_fake_ll,
+       &dev_attr_fake_broadcast,
+       &dev_attr_recover,
+       &dev_attr_broadcast_mode,
+       &dev_attr_canonical_macaddr,
+       NULL,
+};
+
+static struct attribute_group qeth_device_attr_group = {
+       .attrs = (struct attribute **)qeth_device_attrs,
+};
+
+
+#define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store)                      \
+struct device_attribute dev_attr_##_id = {                                  \
+       .attr = {.name=__stringify(_name), .mode=_mode, .owner=THIS_MODULE },\
+       .show   = _show,                                                     \
+       .store  = _store,                                                    \
+};
+
+static ssize_t
+qeth_dev_ipato_enable_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
+}
+
+static ssize_t
+qeth_dev_ipato_enable_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+
+       if (!card)
+               return -EINVAL;
+
+       tmp = strsep((char **) &buf, "\n");
+       if (!strcmp(tmp, "toggle")){
+               card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
+       } else if (!strcmp(tmp, "1")){
+               card->ipato.enabled = 1;
+       } else if (!strcmp(tmp, "0")){
+               card->ipato.enabled = 0;
+       } else {
+               PRINT_WARN("ipato_enable: write 0, 1 or 'toggle' to "
+                          "this file\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
+                       qeth_dev_ipato_enable_show,
+                       qeth_dev_ipato_enable_store);
+
+static ssize_t
+qeth_dev_ipato_invert4_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
+}
+
+static ssize_t
+qeth_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+
+       if (!card)
+               return -EINVAL;
+
+       tmp = strsep((char **) &buf, "\n");
+       if (!strcmp(tmp, "toggle")){
+               card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
+       } else if (!strcmp(tmp, "1")){
+               card->ipato.invert4 = 1;
+       } else if (!strcmp(tmp, "0")){
+               card->ipato.invert4 = 0;
+       } else {
+               PRINT_WARN("ipato_invert4: write 0, 1 or 'toggle' to "
+                          "this file\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
+                       qeth_dev_ipato_invert4_show,
+                       qeth_dev_ipato_invert4_store);
+
+static inline ssize_t
+qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
+                       enum qeth_prot_versions proto)
+{
+       struct qeth_ipato_entry *ipatoe;
+       unsigned long flags;
+       char addr_str[49];
+       int i = 0;
+
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry(ipatoe, &card->ipato.entries, entry){
+               if (ipatoe->proto != proto)
+                       continue;
+               qeth_ipaddr_to_string(proto, ipatoe->addr, addr_str);
+               i += sprintf(buf + i, "%s/%i\n", addr_str, ipatoe->mask_bits);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       i += sprintf(buf + i, "\n");
+       
+       return i;
+}
+
+static ssize_t
+qeth_dev_ipato_add4_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
+}
+
+static inline int
+qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
+                 u8 *addr, int *mask_bits)
+{
+       const char *start, *end;
+       char *tmp;
+       char buffer[49] = {0, };
+
+       start = buf;
+       /* get address string */
+       end = strchr(start, '/');
+       if (!end){
+               PRINT_WARN("Invalid format for ipato_addx/delx. "
+                          "Use <ip addr>/<mask bits>\n");
+               return -EINVAL;
+       }
+       strncpy(buffer, start, end - start);
+       if (qeth_string_to_ipaddr(buffer, proto, addr)){
+               PRINT_WARN("Invalid IP address format!\n");
+               return -EINVAL;
+       }
+       start = end + 1;
+       *mask_bits = simple_strtoul(start, &tmp, 10);
+       
+       return 0;
+}
+
+static inline ssize_t
+qeth_dev_ipato_add_store(const char *buf, size_t count,
+                        struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       struct qeth_ipato_entry *ipatoe;
+       u8 addr[16];
+       int mask_bits;
+       int rc;
+
+       if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits)))
+               return rc;
+
+       if (!(ipatoe = kmalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL))){
+               PRINT_WARN("No memory to allocate ipato entry\n");
+               return -ENOMEM;
+       }
+       memset(ipatoe, 0, sizeof(struct qeth_ipato_entry));
+       ipatoe->proto = proto;
+       memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
+       ipatoe->mask_bits = mask_bits;
+
+       if ((rc = qeth_add_ipato_entry(card, ipatoe))){
+               kfree(ipatoe);
+               return rc;
+       }
+       
+       return count;
+}
+
+static ssize_t
+qeth_dev_ipato_add4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
+                       qeth_dev_ipato_add4_show,
+                       qeth_dev_ipato_add4_store);
+
+static inline ssize_t
+qeth_dev_ipato_del_store(const char *buf, size_t count,
+                        struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       u8 addr[16];
+       int mask_bits;
+       int rc;
+
+       if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits)))
+               return rc;
+
+       qeth_del_ipato_entry(card, proto, addr, mask_bits);
+       
+       return count;
+}
+
+static ssize_t
+qeth_dev_ipato_del4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
+                       qeth_dev_ipato_del4_store);
+
+#ifdef CONFIG_QETH_IPV6
+static ssize_t
+qeth_dev_ipato_invert6_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
+}
+
+static ssize_t
+qeth_dev_ipato_invert6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       char *tmp;
+
+       if (!card)
+               return -EINVAL;
+
+       tmp = strsep((char **) &buf, "\n");
+       if (!strcmp(tmp, "toggle")){
+               card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
+       } else if (!strcmp(tmp, "1")){
+               card->ipato.invert6 = 1;
+       } else if (!strcmp(tmp, "0")){
+               card->ipato.invert6 = 0;
+       } else {
+               PRINT_WARN("ipato_invert6: write 0, 1 or 'toggle' to "
+                          "this file\n");
+               return -EINVAL;
+       }
+       return count;
+}
+
+static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
+                       qeth_dev_ipato_invert6_show,
+                       qeth_dev_ipato_invert6_store);
+
+
+static ssize_t
+qeth_dev_ipato_add6_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
+}
+
+static ssize_t
+qeth_dev_ipato_add6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
+                       qeth_dev_ipato_add6_show,
+                       qeth_dev_ipato_add6_store);
+
+static ssize_t
+qeth_dev_ipato_del6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
+                       qeth_dev_ipato_del6_store);
+#endif /* CONFIG_QETH_IPV6 */
+
+static struct device_attribute * qeth_ipato_device_attrs[] = {
+       &dev_attr_ipato_enable,
+       &dev_attr_ipato_invert4,
+       &dev_attr_ipato_add4,
+       &dev_attr_ipato_del4,
+#ifdef CONFIG_QETH_IPV6
+       &dev_attr_ipato_invert6,
+       &dev_attr_ipato_add6,
+       &dev_attr_ipato_del6,
+#endif
+       NULL,
+};
+
+static struct attribute_group qeth_device_ipato_group = {
+       .name = "ipa_takeover",
+       .attrs = (struct attribute **)qeth_ipato_device_attrs,
+};
+
+static inline ssize_t
+qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
+                       enum qeth_prot_versions proto)
+{
+       struct qeth_ipaddr *ipaddr;
+       char addr_str[49];
+       unsigned long flags;
+       int i = 0;
+
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry(ipaddr, &card->ip_list, entry){
+               if (ipaddr->proto != proto)
+                       continue;
+               if (ipaddr->type != QETH_IP_TYPE_VIPA)
+                       continue;
+               qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str);
+               i += sprintf(buf + i, "%s\n", addr_str);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       i += sprintf(buf + i, "\n");
+       
+       return i;
+}
+
+static ssize_t
+qeth_dev_vipa_add4_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
+}
+
+static inline int
+qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
+                u8 *addr)
+{
+       if (qeth_string_to_ipaddr(buf, proto, addr)){
+               PRINT_WARN("Invalid IP address format!\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline ssize_t
+qeth_dev_vipa_add_store(const char *buf, size_t count,
+                        struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       u8 addr[16] = {0, };
+       int rc;
+
+       if ((rc = qeth_parse_vipae(buf, proto, addr)))
+               return rc;
+
+       if ((rc = qeth_add_vipa(card, proto, addr)))
+               return rc;
+
+       return count;
+}
+
+static ssize_t
+qeth_dev_vipa_add4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
+                       qeth_dev_vipa_add4_show,
+                       qeth_dev_vipa_add4_store);
+
+static inline ssize_t
+qeth_dev_vipa_del_store(const char *buf, size_t count,
+                        struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       u8 addr[16];
+       int rc;
+
+       if ((rc = qeth_parse_vipae(buf, proto, addr)))
+               return rc;
+
+       qeth_del_vipa(card, proto, addr);
+
+       return count;
+}
+
+static ssize_t
+qeth_dev_vipa_del4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
+                       qeth_dev_vipa_del4_store);
+
+#ifdef CONFIG_QETH_IPV6
+static ssize_t
+qeth_dev_vipa_add6_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
+}
+
+static ssize_t
+qeth_dev_vipa_add6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
+                       qeth_dev_vipa_add6_show,
+                       qeth_dev_vipa_add6_store);
+
+static ssize_t
+qeth_dev_vipa_del6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
+                       qeth_dev_vipa_del6_store);
+#endif /* CONFIG_QETH_IPV6 */
+
+static struct device_attribute * qeth_vipa_device_attrs[] = {
+       &dev_attr_vipa_add4,
+       &dev_attr_vipa_del4,
+#ifdef CONFIG_QETH_IPV6
+       &dev_attr_vipa_add6,
+       &dev_attr_vipa_del6,
+#endif
+       NULL,
+};
+
+static struct attribute_group qeth_device_vipa_group = {
+       .name = "vipa",
+       .attrs = (struct attribute **)qeth_vipa_device_attrs,
+};
+
+static inline ssize_t
+qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
+                      enum qeth_prot_versions proto)
+{
+       struct qeth_ipaddr *ipaddr;
+       char addr_str[49];
+       unsigned long flags;
+       int i = 0;
+
+       spin_lock_irqsave(&card->ip_lock, flags);
+       list_for_each_entry(ipaddr, &card->ip_list, entry){
+               if (ipaddr->proto != proto)
+                       continue;
+               if (ipaddr->type != QETH_IP_TYPE_RXIP)
+                       continue;
+               qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str);
+               i += sprintf(buf + i, "%s\n", addr_str);
+       }
+       spin_unlock_irqrestore(&card->ip_lock, flags);
+       i += sprintf(buf + i, "\n");
+       
+       return i;
+}
+
+static ssize_t
+qeth_dev_rxip_add4_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
+}
+
+static inline int
+qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
+                u8 *addr)
+{
+       if (qeth_string_to_ipaddr(buf, proto, addr)){
+               PRINT_WARN("Invalid IP address format!\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline ssize_t
+qeth_dev_rxip_add_store(const char *buf, size_t count,
+                       struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       u8 addr[16] = {0, };
+       int rc;
+
+       if ((rc = qeth_parse_rxipe(buf, proto, addr)))
+               return rc;
+
+       if ((rc = qeth_add_rxip(card, proto, addr)))
+               return rc;
+
+       return count;
+}
+
+static ssize_t
+qeth_dev_rxip_add4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+       
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
+                       qeth_dev_rxip_add4_show,
+                       qeth_dev_rxip_add4_store);
+
+static inline ssize_t
+qeth_dev_rxip_del_store(const char *buf, size_t count,
+                       struct qeth_card *card, enum qeth_prot_versions proto)
+{
+       u8 addr[16];
+       int rc;
+
+       if ((rc = qeth_parse_rxipe(buf, proto, addr)))
+               return rc;
+
+       qeth_del_rxip(card, proto, addr);
+
+       return count;
+}
+
+static ssize_t
+qeth_dev_rxip_del4_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
+}
+
+static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
+                       qeth_dev_rxip_del4_store);
+
+#ifdef CONFIG_QETH_IPV6
+static ssize_t
+qeth_dev_rxip_add6_show(struct device *dev, char *buf)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+       
+       return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
+}
+
+static ssize_t
+qeth_dev_rxip_add6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
+                       qeth_dev_rxip_add6_show,
+                       qeth_dev_rxip_add6_store);
+
+static ssize_t
+qeth_dev_rxip_del6_store(struct device *dev, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev->driver_data;
+
+       if (!card)
+               return -EINVAL;
+
+       return qeth_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
+}
+
+static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
+                       qeth_dev_rxip_del6_store);
+#endif /* CONFIG_QETH_IPV6 */
+
+static struct device_attribute * qeth_rxip_device_attrs[] = {
+       &dev_attr_rxip_add4,
+       &dev_attr_rxip_del4,
+#ifdef CONFIG_QETH_IPV6
+       &dev_attr_rxip_add6,
+       &dev_attr_rxip_del6,
+#endif
+       NULL,
+};
+
+static struct attribute_group qeth_device_rxip_group = {
+       .name = "rxip",
+       .attrs = (struct attribute **)qeth_rxip_device_attrs,
+};
+
+int
+qeth_create_device_attributes(struct device *dev)
+{
+       int ret;
+       
+       if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group)))
+               return ret;
+       if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){
+               sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
+               return ret;
+       }
+       if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group))){
+               sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
+               sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
+               return ret;
+       }
+       if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group))){
+               sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
+               sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
+               sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
+       }
+
+       return ret;
+}
+
+void
+qeth_remove_device_attributes(struct device *dev)
+{
+       sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
+       sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
+       sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
+       sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
+}
+
+/**********************/
+/* DRIVER ATTRIBUTES  */
+/**********************/
+static ssize_t 
+qeth_driver_group_store(struct device_driver *ddrv, const char *buf,
+                       size_t count)
+{
+       const char *start, *end;
+       char bus_ids[3][BUS_ID_SIZE], *argv[3];
+       int i;
+       int err;
+
+       start = buf;
+       for (i = 0; i < 3; i++) {
+               static const char delim[] = { ',', ',', '\n' };
+               int len;
+
+               if (!(end = strchr(start, delim[i])))
+                       return -EINVAL;
+               len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
+               strncpy(bus_ids[i], start, len);
+               bus_ids[i][len] = '\0';
+               start = end + 1;
+               argv[i] = bus_ids[i];
+       }
+       err = ccwgroup_create(qeth_root_dev, qeth_ccwgroup_driver.driver_id,
+                       &qeth_ccw_driver, 3, argv);
+       if (err)
+               return err;
+       else
+               return count;
+}
+
+
+static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
+
+static ssize_t
+qeth_driver_snmp_register_show(struct device_driver *ddrv, char *buf)
+{
+       /* TODO */
+       return 0;
+}
+
+static ssize_t
+qeth_driver_snmp_register_store(struct device_driver *ddrv, const char *buf,
+                               size_t count)
+{
+       /* TODO */
+       return count;
+}
+
+static DRIVER_ATTR(snmp_register, 0644, qeth_driver_snmp_register_show,
+                  qeth_driver_snmp_register_store);
+
+int
+qeth_create_driver_attributes(void)
+{
+       int rc;
+       
+       if ((rc = driver_create_file(&qeth_ccwgroup_driver.driver,
+                                    &driver_attr_group)))
+               return rc;
+       return driver_create_file(&qeth_ccwgroup_driver.driver,
+                                 &driver_attr_snmp_register);
+}
+
+void
+qeth_remove_driver_attributes(void)
+{
+       driver_remove_file(&qeth_ccwgroup_driver.driver,
+                       &driver_attr_group);
+       driver_remove_file(&qeth_ccwgroup_driver.driver,
+                       &driver_attr_snmp_register);
+}
index 5be3dd3..55f1f5b 100644 (file)
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_AUX_REVISION "$Revision: 1.101 $"
-
-/********************** INCLUDES *********************************************/
-
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/workqueue.h>
-#include <linux/syscalls.h>
+#define ZFCP_AUX_REVISION "$Revision: 1.105 $"
 
 #include "zfcp_ext.h"
 
-#include <asm/semaphore.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/ebcdic.h>
-#include <asm/cpcmd.h>         /* Debugging only */
-#include <asm/processor.h>     /* Debugging only */
-
-#include <linux/miscdevice.h>
-#include <linux/major.h>
-
 /* accumulated log level (module parameter) */
 static u32 loglevel = ZFCP_LOG_LEVEL_DEFAULTS;
 static char *device;
@@ -272,7 +239,6 @@ void
 zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
                       void *add_data, int add_length)
 {
-#ifdef ZFCP_DEBUG_COMMANDS
        struct zfcp_adapter *adapter = fsf_req->adapter;
        struct scsi_cmnd *scsi_cmnd;
        int level = 3;
@@ -299,7 +265,6 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
                                    min(ZFCP_CMD_DBF_LENGTH, add_length - i));
        }
        write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);
-#endif
 }
 
 /* XXX additionally log unit if available */
@@ -307,7 +272,6 @@ zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req,
 void
 zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
 {
-#ifdef ZFCP_DEBUG_COMMANDS
        struct zfcp_adapter *adapter;
        union zfcp_req_data *req_data;
        struct zfcp_fsf_req *fsf_req;
@@ -335,14 +299,12 @@ zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd)
                debug_text_event(adapter->cmd_dbf, level, "");
        }
        write_unlock_irqrestore(&adapter->cmd_dbf_lock, flags);
-#endif
 }
 
 void
 zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
                      struct fsf_status_read_buffer *status_buffer, int length)
 {
-#ifdef ZFCP_DEBUG_INCOMING_ELS
        int level = 1;
        int i;
 
@@ -353,7 +315,6 @@ zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text,
                            level,
                            (char *) status_buffer->payload + i,
                            min(ZFCP_IN_ELS_DBF_LENGTH, length - i));
-#endif
 }
 
 /**
@@ -748,7 +709,7 @@ static inline int
 zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
 {
        struct scatterlist *sg;
-       int i;
+       unsigned int i;
        int retval = 0;
 
        sg_list->count = size >> PAGE_SHIFT;
@@ -790,7 +751,7 @@ static inline int
 zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
 {
        struct scatterlist *sg;
-       int i;
+       unsigned int i;
        int retval = 0;
 
        BUG_ON((sg_list->sg == NULL) || (sg_list == NULL));
@@ -1123,6 +1084,91 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter)
                mempool_destroy(adapter->pool.data_gid_pn);
 }
 
+/**
+ * zfcp_adapter_debug_register - registers debug feature for an adapter
+ * @adapter: pointer to adapter for which debug features should be registered
+ * return: -ENOMEM on error, 0 otherwise
+ */
+int
+zfcp_adapter_debug_register(struct zfcp_adapter *adapter)
+{
+       char dbf_name[20];
+
+       /* debug feature area which records fsf request sequence numbers */
+       sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s",
+               zfcp_get_busid_by_adapter(adapter));
+       adapter->req_dbf = debug_register(dbf_name,
+                                         ZFCP_REQ_DBF_INDEX,
+                                         ZFCP_REQ_DBF_AREAS,
+                                         ZFCP_REQ_DBF_LENGTH);
+       debug_register_view(adapter->req_dbf, &debug_hex_ascii_view);
+       debug_set_level(adapter->req_dbf, ZFCP_REQ_DBF_LEVEL);
+       debug_text_event(adapter->req_dbf, 1, "zzz");
+
+       /* debug feature area which records SCSI command failures (hostbyte) */
+       rwlock_init(&adapter->cmd_dbf_lock);
+       sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s",
+               zfcp_get_busid_by_adapter(adapter));
+       adapter->cmd_dbf = debug_register(dbf_name,
+                                         ZFCP_CMD_DBF_INDEX,
+                                         ZFCP_CMD_DBF_AREAS,
+                                         ZFCP_CMD_DBF_LENGTH);
+       debug_register_view(adapter->cmd_dbf, &debug_hex_ascii_view);
+       debug_set_level(adapter->cmd_dbf, ZFCP_CMD_DBF_LEVEL);
+
+       /* debug feature area which records SCSI command aborts */
+       sprintf(dbf_name, ZFCP_ABORT_DBF_NAME "%s",
+               zfcp_get_busid_by_adapter(adapter));
+       adapter->abort_dbf = debug_register(dbf_name,
+                                           ZFCP_ABORT_DBF_INDEX,
+                                           ZFCP_ABORT_DBF_AREAS,
+                                           ZFCP_ABORT_DBF_LENGTH);
+       debug_register_view(adapter->abort_dbf, &debug_hex_ascii_view);
+       debug_set_level(adapter->abort_dbf, ZFCP_ABORT_DBF_LEVEL);
+
+       /* debug feature area which records SCSI command aborts */
+       sprintf(dbf_name, ZFCP_IN_ELS_DBF_NAME "%s",
+               zfcp_get_busid_by_adapter(adapter));
+       adapter->in_els_dbf = debug_register(dbf_name,
+                                            ZFCP_IN_ELS_DBF_INDEX,
+                                            ZFCP_IN_ELS_DBF_AREAS,
+                                            ZFCP_IN_ELS_DBF_LENGTH);
+       debug_register_view(adapter->in_els_dbf, &debug_hex_ascii_view);
+       debug_set_level(adapter->in_els_dbf, ZFCP_IN_ELS_DBF_LEVEL);
+
+
+       /* debug feature area which records erp events */
+       sprintf(dbf_name, ZFCP_ERP_DBF_NAME "%s",
+               zfcp_get_busid_by_adapter(adapter));
+       adapter->erp_dbf = debug_register(dbf_name,
+                                         ZFCP_ERP_DBF_INDEX,
+                                         ZFCP_ERP_DBF_AREAS,
+                                         ZFCP_ERP_DBF_LENGTH);
+       debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
+       debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
+
+       if (adapter->req_dbf && adapter->cmd_dbf && adapter->abort_dbf &&
+           adapter->in_els_dbf && adapter->erp_dbf)
+               return 0;
+
+       zfcp_adapter_debug_unregister(adapter);
+       return -ENOMEM;
+}
+
+/**
+ * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter
+ * @adapter: pointer to adapter for which debug features should be unregistered
+ */
+void
+zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter)
+{
+       debug_unregister(adapter->erp_dbf);
+       debug_unregister(adapter->req_dbf);
+       debug_unregister(adapter->cmd_dbf);
+       debug_unregister(adapter->abort_dbf);
+       debug_unregister(adapter->in_els_dbf);
+}
+
 /*
  * Enqueues an adapter at the end of the adapter list in the driver data.
  * All adapter internal structures are set up.
@@ -1138,7 +1184,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 {
        int retval = 0;
        struct zfcp_adapter *adapter;
-       char dbf_name[20];
 
        /*
         * Note: It is safe to release the list_lock, as any list changes 
@@ -1215,95 +1260,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
        if (zfcp_sysfs_adapter_create_files(&ccw_device->dev))
                goto sysfs_failed;
 
-#ifdef ZFCP_DEBUG_REQUESTS
-       /* debug feature area which records fsf request sequence numbers */
-       sprintf(dbf_name, ZFCP_REQ_DBF_NAME "%s",
-               zfcp_get_busid_by_adapter(adapter));
-       adapter->req_dbf = debug_register(dbf_name,
-                                         ZFCP_REQ_DBF_INDEX,
-                                         ZFCP_REQ_DBF_AREAS,
-                                         ZFCP_REQ_DBF_LENGTH);
-       if (!adapter->req_dbf) {
-               ZFCP_LOG_INFO("registration of dbf for adapter %s failed\n",
-                             zfcp_get_busid_by_adapter(adapter));
-               retval = -ENOMEM;
-               goto failed_req_dbf;
-       }
-       debug_register_view(adapter->req_dbf, &debug_hex_ascii_view);
-       debug_set_level(adapter->req_dbf, ZFCP_REQ_DBF_LEVEL);
-       debug_text_event(adapter->req_dbf, 1, "zzz");
-#endif                         /* ZFCP_DEBUG_REQUESTS */
-
-#ifdef ZFCP_DEBUG_COMMANDS
-       /* debug feature area which records SCSI command failures (hostbyte) */
-       rwlock_init(&adapter->cmd_dbf_lock);
-       sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s",
-               zfcp_get_busid_by_adapter(adapter));
-       adapter->cmd_dbf = debug_register(dbf_name,
-                                         ZFCP_CMD_DBF_INDEX,
-                                         ZFCP_CMD_DBF_AREAS,
-                                         ZFCP_CMD_DBF_LENGTH);
-       if (!adapter->cmd_dbf) {
-               ZFCP_LOG_INFO("registration of dbf for adapter %s failed\n",
-                             zfcp_get_busid_by_adapter(adapter));
-               retval = -ENOMEM;
-               goto failed_cmd_dbf;
-       }
-       debug_register_view(adapter->cmd_dbf, &debug_hex_ascii_view);
-       debug_set_level(adapter->cmd_dbf, ZFCP_CMD_DBF_LEVEL);
-#endif                         /* ZFCP_DEBUG_COMMANDS */
-
-#ifdef ZFCP_DEBUG_ABORTS
-       /* debug feature area which records SCSI command aborts */
-       sprintf(dbf_name, ZFCP_ABORT_DBF_NAME "%s",
-               zfcp_get_busid_by_adapter(adapter));
-       adapter->abort_dbf = debug_register(dbf_name,
-                                           ZFCP_ABORT_DBF_INDEX,
-                                           ZFCP_ABORT_DBF_AREAS,
-                                           ZFCP_ABORT_DBF_LENGTH);
-       if (!adapter->abort_dbf) {
-               ZFCP_LOG_INFO("registration of dbf for adapter %s failed\n",
-                             zfcp_get_busid_by_adapter(adapter));
-               retval = -ENOMEM;
-               goto failed_abort_dbf;
-       }
-       debug_register_view(adapter->abort_dbf, &debug_hex_ascii_view);
-       debug_set_level(adapter->abort_dbf, ZFCP_ABORT_DBF_LEVEL);
-#endif                         /* ZFCP_DEBUG_ABORTS */
-
-#ifdef ZFCP_DEBUG_INCOMING_ELS
-       /* debug feature area which records SCSI command aborts */
-       sprintf(dbf_name, ZFCP_IN_ELS_DBF_NAME "%s",
-               zfcp_get_busid_by_adapter(adapter));
-       adapter->in_els_dbf = debug_register(dbf_name,
-                                            ZFCP_IN_ELS_DBF_INDEX,
-                                            ZFCP_IN_ELS_DBF_AREAS,
-                                            ZFCP_IN_ELS_DBF_LENGTH);
-       if (!adapter->in_els_dbf) {
-               ZFCP_LOG_INFO("registration of dbf for adapter %s failed\n",
-                             zfcp_get_busid_by_adapter(adapter));
-               retval = -ENOMEM;
-               goto failed_in_els_dbf;
-       }
-       debug_register_view(adapter->in_els_dbf, &debug_hex_ascii_view);
-       debug_set_level(adapter->in_els_dbf, ZFCP_IN_ELS_DBF_LEVEL);
-#endif                         /* ZFCP_DEBUG_INCOMING_ELS */
-
-       sprintf(dbf_name, ZFCP_ERP_DBF_NAME "%s",
-               zfcp_get_busid_by_adapter(adapter));
-       adapter->erp_dbf = debug_register(dbf_name,
-                                         ZFCP_ERP_DBF_INDEX,
-                                         ZFCP_ERP_DBF_AREAS,
-                                         ZFCP_ERP_DBF_LENGTH);
-       if (!adapter->erp_dbf) {
-               ZFCP_LOG_INFO("registration of dbf for adapter %s failed\n",
-                             zfcp_get_busid_by_adapter(adapter));
-               retval = -ENOMEM;
-               goto failed_erp_dbf;
-       }
-       debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view);
-       debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL);
-
        /* put allocated adapter at list tail */
        write_lock_irq(&zfcp_data.config_lock);
        atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
@@ -1314,27 +1270,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 
        goto out;
 
- failed_erp_dbf:
-#ifdef ZFCP_DEBUG_INCOMING_ELS
-       debug_unregister(adapter->in_els_dbf);
- failed_in_els_dbf:
-#endif
-
-#ifdef ZFCP_DEBUG_ABORTS
-       debug_unregister(adapter->abort_dbf);
- failed_abort_dbf:
-#endif
-
-#ifdef ZFCP_DEBUG_COMMANDS
-       debug_unregister(adapter->cmd_dbf);
- failed_cmd_dbf:
-#endif
-
-#ifdef ZFCP_DEBUG_REQUESTS
-       debug_unregister(adapter->req_dbf);
- failed_req_dbf:
-#endif
-       zfcp_sysfs_adapter_remove_files(&ccw_device->dev);
  sysfs_failed:
        dev_set_drvdata(&ccw_device->dev, NULL);
  failed_low_mem_buffers:
@@ -1398,23 +1333,6 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
                ZFCP_LOG_NORMAL("bug: qdio_free for adapter %s failed\n",
                                zfcp_get_busid_by_adapter(adapter));
 
-       debug_unregister(adapter->erp_dbf);
-
-#ifdef ZFCP_DEBUG_REQUESTS
-       debug_unregister(adapter->req_dbf);
-#endif
-
-#ifdef ZFCP_DEBUG_COMMANDS
-       debug_unregister(adapter->cmd_dbf);
-#endif
-#ifdef ZFCP_DEBUG_ABORTS
-       debug_unregister(adapter->abort_dbf);
-#endif
-
-#ifdef ZFCP_DEBUG_INCOMING_ELS
-       debug_unregister(adapter->in_els_dbf);
-#endif
-
        zfcp_free_low_mem_buffers(adapter);
        /* free memory of adapter data structure and queues */
        zfcp_qdio_free_queues(adapter);
index 341e8e9..f25020c 100644 (file)
@@ -26,7 +26,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_CCW_C_REVISION "$Revision: 1.51 $"
+#define ZFCP_CCW_C_REVISION "$Revision: 1.52 $"
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -159,12 +159,15 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
        down(&zfcp_data.config_sema);
        adapter = dev_get_drvdata(&ccw_device->dev);
 
+       retval = zfcp_adapter_debug_register(adapter);
+       if (retval)
+               goto out;
        retval = zfcp_erp_thread_setup(adapter); 
        if (retval) {
                ZFCP_LOG_INFO("error: start of error recovery thread for "
                              "adapter %s failed\n",
                              zfcp_get_busid_by_adapter(adapter));
-               goto out;
+               goto out_erp_thread;
        }
 
        retval = zfcp_adapter_scsi_register(adapter);
@@ -178,6 +181,8 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
 
  out_scsi_register:
        zfcp_erp_thread_kill(adapter);
+ out_erp_thread:
+       zfcp_adapter_debug_unregister(adapter);
  out:
        up(&zfcp_data.config_sema);
        return retval;
@@ -203,6 +208,7 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
        zfcp_erp_wait(adapter);
        zfcp_adapter_scsi_unregister(adapter);
        zfcp_erp_thread_kill(adapter);
+       zfcp_adapter_debug_unregister(adapter);
        up(&zfcp_data.config_sema);
        return 0;
 }
index 8f3ab2d..00de5d6 100644 (file)
 #define ZFCP_DEF_H
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_DEF_REVISION "$Revision: 1.66 $"
+#define ZFCP_DEF_REVISION "$Revision: 1.71 $"
 
 /*************************** INCLUDES *****************************************/
 
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
-#include "../../scsi/scsi.h"
 #include "../../fc4/fc.h"
-#include "zfcp_fsf.h"                  /* FSF SW Interface */
+#include "zfcp_fsf.h"
 #include <asm/ccwdev.h>
 #include <asm/qdio.h>
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
 #include <linux/reboot.h>
 #include <linux/mempool.h>
+#include <linux/syscalls.h>
 #include <linux/ioctl.h>
 #ifdef CONFIG_S390_SUPPORT
 #include <linux/ioctl32.h>
 /************************ DEBUG FLAGS *****************************************/
 
 #define        ZFCP_PRINT_FLAGS
-#define        ZFCP_DEBUG_REQUESTS     /* fsf_req tracing */
-#define ZFCP_DEBUG_COMMANDS     /* host_byte tracing */
-#define ZFCP_DEBUG_ABORTS       /* scsi_cmnd abort tracing */
-#define ZFCP_DEBUG_INCOMING_ELS /* incoming ELS tracing */
 #define        ZFCP_STAT_REQSIZES
 #define        ZFCP_STAT_QUEUES
 
@@ -723,11 +723,6 @@ struct zfcp_cfdc_sense_data {
 
 #define ZFCP_CFDC_MAX_CONTROL_FILE_SIZE                127 * 1024
 
-static const char zfcp_act_subtable_type[5][8] = {
-       {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
-};
-
-
 /************************* STRUCTURE DEFINITIONS *****************************/
 
 struct zfcp_fsf_req;
@@ -1037,7 +1032,6 @@ struct zfcp_unit {
                                                  refcount drop to zero */
        struct zfcp_port       *port;          /* remote port of unit */
        atomic_t               status;         /* status of this logical unit */
-       u32                    lun_access;     /* access flags for this unit */
        scsi_lun_t             scsi_lun;       /* own SCSI LUN */
        fcp_lun_t              fcp_lun;        /* own FCP_LUN */
        u32                    handle;         /* handle assigned by FSF */
index edbfd22..ccac73e 100644 (file)
@@ -31,7 +31,7 @@
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_ERP
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_ERP_REVISION "$Revision: 1.45 $"
+#define ZFCP_ERP_REVISION "$Revision: 1.49 $"
 
 #include "zfcp_ext.h"
 
@@ -1137,7 +1137,7 @@ zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
  * returns:    0 - there was an action to handle
  *             !0 - otherwise
  */
-static int
+int
 zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
                       unsigned long set_mask)
 {
@@ -1153,28 +1153,6 @@ zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
 }
 
 /*
- * purpose:    is called for finished FSF requests related to erp,
- *             moves concerned erp action to 'ready' queue and
- *             signals erp thread to process it,
- *             besides it cancels a timeout
- */
-void
-zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *fsf_req)
-{
-       struct zfcp_erp_action *erp_action = fsf_req->erp_action;
-       struct zfcp_adapter *adapter = fsf_req->adapter;
-
-       debug_text_event(adapter->erp_dbf, 3, "a_frh");
-       debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int));
-
-       if (erp_action) {
-               debug_event(adapter->erp_dbf, 3, &erp_action->action,
-                           sizeof (int));
-               zfcp_erp_async_handler(erp_action, 0);
-       }
-}
-
-/*
  * purpose:    is called for erp_action which was slept waiting for
  *             memory becoming avaliable,
  *             will trigger that this action will be continued
@@ -1817,7 +1795,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
                                "unit 0x%016Lx on port 0x%016Lx on "
                                "adapter %s\n", unit->fcp_lun, unit->port->wwpn,
                                zfcp_get_busid_by_unit(unit));
-               atomic_set(&p->unit->scsi_add_work, 0);
+               atomic_set(&unit->scsi_add_work, 0);
                return -ENOMEM;
        }
 
@@ -2419,10 +2397,8 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
                ZFCP_LOG_NORMAL("bug: shutdown of QDIO queues failed "
                                "(retval=%d)\n", retval_cleanup);
        }
-#ifdef ZFCP_DEBUG_REQUESTS
        else
                debug_text_event(adapter->req_dbf, 1, "q_clean");
-#endif                         /* ZFCP_DEBUG_REQUESTS */
 
  failed_qdio_establish:
        atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
@@ -2494,9 +2470,7 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
                                zfcp_get_busid_by_adapter(adapter));
        } else {
                ZFCP_LOG_DEBUG("queues cleaned up\n");
-#ifdef ZFCP_DEBUG_REQUESTS
                debug_text_event(adapter->req_dbf, 1, "q_clean");
-#endif                         /* ZFCP_DEBUG_REQUESTS */
        }
 
        /*
index d6911fe..5c44ee5 100644 (file)
@@ -31,7 +31,7 @@
 #ifndef ZFCP_EXT_H
 #define ZFCP_EXT_H
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_EXT_REVISION "$Revision: 1.47 $"
+#define ZFCP_EXT_REVISION "$Revision: 1.49 $"
 
 #include "zfcp_def.h"
 
@@ -53,7 +53,9 @@ extern struct zfcp_unit *zfcp_get_unit_by_lun(struct zfcp_port *,
 extern struct zfcp_port *zfcp_get_port_by_wwpn(struct zfcp_adapter *,
                                               wwn_t wwpn);
 extern struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *);
+extern int    zfcp_adapter_debug_register(struct zfcp_adapter *);
 extern void   zfcp_adapter_dequeue(struct zfcp_adapter *);
+extern void   zfcp_adapter_debug_unregister(struct zfcp_adapter *);
 extern struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *, wwn_t, u32);
 extern void   zfcp_port_dequeue(struct zfcp_port *);
 extern struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *, fcp_lun_t);
@@ -155,7 +157,7 @@ extern void zfcp_erp_unit_failed(struct zfcp_unit *);
 extern int  zfcp_erp_thread_setup(struct zfcp_adapter *);
 extern int  zfcp_erp_thread_kill(struct zfcp_adapter *);
 extern int  zfcp_erp_wait(struct zfcp_adapter *);
-extern void zfcp_erp_fsf_req_handler(struct zfcp_fsf_req *);
+extern int  zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long);
 
 extern int  zfcp_test_link(struct zfcp_port *);
 
index fb3f8ec..c4faf9e 100644 (file)
@@ -29,7 +29,7 @@
  */
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_FSF_C_REVISION "$Revision: 1.36 $"
+#define ZFCP_FSF_C_REVISION "$Revision: 1.43 $"
 
 #include "zfcp_ext.h"
 
@@ -78,6 +78,11 @@ static u32 fsf_qtcb_type[] = {
        [FSF_QTCB_UPLOAD_CONTROL_FILE] =  FSF_SUPPORT_COMMAND
 };
 
+static const char zfcp_act_subtable_type[5][8] = {
+       {"unknown"}, {"OS"}, {"WWPN"}, {"DID"}, {"LUN"}
+};
+
+
 /****************************************************************/
 /*************** FSF related Functions  *************************/
 /****************************************************************/
@@ -318,7 +323,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
                             sizeof(struct fsf_qtcb));
                        goto forget_log;
                }
-               if ((fsf_req->qtcb->header.log_start +
+               if ((size_t) (fsf_req->qtcb->header.log_start +
                     fsf_req->qtcb->header.log_length)
                    > sizeof(struct fsf_qtcb)) {
                        ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
@@ -374,7 +379,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
                                zfcp_get_busid_by_adapter(adapter),
                                fsf_req->qtcb->prefix.prot_status_qual.
                                sequence_error.exp_req_seq_no);
-#ifdef ZFCP_DEBUG_REQUESTS
                debug_text_event(adapter->req_dbf, 1, "exp_seq!");
                debug_event(adapter->req_dbf, 1,
                            &fsf_req->qtcb->prefix.prot_status_qual.
@@ -382,7 +386,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
                debug_text_event(adapter->req_dbf, 1, "qtcb_seq!");
                debug_exception(adapter->req_dbf, 1,
                                &fsf_req->qtcb->prefix.req_seq_no, 4);
-#endif                         /* ZFCP_DEBUG_REQUESTS */
                debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err");
                /* restart operation on this adapter */
                zfcp_erp_adapter_reopen(adapter, 0);
@@ -733,6 +736,8 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req)
 static int
 zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
 {
+       struct zfcp_erp_action *erp_action = fsf_req->erp_action;
+       struct zfcp_adapter *adapter = fsf_req->adapter;
        int retval = 0;
 
        if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
@@ -819,7 +824,13 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
                             fsf_req->qtcb->header.fsf_command);
        }
 
-        zfcp_erp_fsf_req_handler(fsf_req);
+       if (!erp_action)
+               return retval;
+
+       debug_text_event(adapter->erp_dbf, 3, "a_frh");
+       debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int));
+       zfcp_erp_async_handler(erp_action, 0);
+
        return retval;
 }
 
@@ -880,9 +891,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
 
        ZFCP_LOG_TRACE("Status Read request initiated (adapter%s)\n",
                       zfcp_get_busid_by_adapter(adapter));
-#ifdef ZFCP_DEBUG_REQUESTS
        debug_text_event(adapter->req_dbf, 1, "unso");
-#endif
        goto out;
 
  failed_req_send:
@@ -1000,8 +1009,12 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_STATUS_READ_LINK_DOWN:
                ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_LINK_DOWN\n");
-
-               /* Unneccessary, ignoring.... */
+               debug_text_event(adapter->erp_dbf, 0, "unsol_link_down:");
+               ZFCP_LOG_INFO("Local link to adapter %s is down\n",
+                             zfcp_get_busid_by_adapter(adapter));
+               atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+                               &adapter->status);
+               zfcp_erp_adapter_failed(adapter);
                break;
 
        case FSF_STATUS_READ_LINK_UP:
@@ -1020,27 +1033,6 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
 
                break;
 
-       case FSF_STATUS_READ_NOTIFICATION_LOST:
-               ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_NOTIFICATION_LOST\n");
-               debug_text_event(adapter->erp_dbf, 2, "unsol_not_lost:");
-               switch (status_buffer->status_subtype) {
-               case FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED:
-                       ZFCP_LOG_NORMAL(
-                               "The unsolicited status information about "
-                               "CFDC update on the adapter %s is lost "
-                               "due to the lack of internal resources\n",
-                               zfcp_get_busid_by_adapter(adapter));
-                       break;
-               case FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED:
-                       ZFCP_LOG_NORMAL(
-                               "The unsolicited status information about "
-                               "CFDC harden on the adapter %s is lost "
-                               "due to the lack of internal resources\n",
-                               zfcp_get_busid_by_adapter(adapter));
-                       break;
-               }
-               break;
-
        case FSF_STATUS_READ_CFDC_UPDATED:
                ZFCP_LOG_FLAGS(1, "FSF_STATUS_READ_CFDC_UPDATED\n");
                debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:");
@@ -1285,16 +1277,10 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
        case FSF_FCP_COMMAND_DOES_NOT_EXIST:
                ZFCP_LOG_FLAGS(2, "FSF_FCP_COMMAND_DOES_NOT_EXIST\n");
                retval = 0;
-#ifdef ZFCP_DEBUG_REQUESTS
-               /*
-                * debug feature area which records
-                * fsf request sequence numbers
-                */
                debug_text_event(new_fsf_req->adapter->req_dbf, 3, "no_exist");
                debug_event(new_fsf_req->adapter->req_dbf, 3,
                            &new_fsf_req->qtcb->bottom.support.req_handle,
                            sizeof (unsigned long));
-#endif                         /* ZFCP_DEBUG_REQUESTS */
                debug_text_event(new_fsf_req->adapter->erp_dbf, 3,
                                 "fsf_s_no_exist");
                new_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED;
@@ -2062,6 +2048,84 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
        return retval;
 }
 
+/**
+ * zfcp_fsf_exchange_config_evaluate
+ * @fsf_req: fsf_req which belongs to xchg config data request
+ * @xchg_ok: specifies if xchg config data was incomplete or complete (0/1)
+ *
+ * returns: -EIO on error, 0 otherwise
+ */
+static int
+zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
+{
+       struct fsf_qtcb_bottom_config *bottom;
+       struct zfcp_adapter *adapter = fsf_req->adapter;
+
+       bottom = &fsf_req->qtcb->bottom.config;
+       ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n",
+                      bottom->low_qtcb_version, bottom->high_qtcb_version);
+       adapter->fsf_lic_version = bottom->lic_version;
+       adapter->supported_features = bottom->supported_features;
+
+       if (xchg_ok) {
+               adapter->wwnn = bottom->nport_serv_param.wwnn;
+               adapter->wwpn = bottom->nport_serv_param.wwpn;
+               adapter->s_id = bottom->s_id & ZFCP_DID_MASK;
+               adapter->fc_topology = bottom->fc_topology;
+               adapter->fc_link_speed = bottom->fc_link_speed;
+               adapter->hydra_version = bottom->adapter_type;
+       } else {
+               adapter->wwnn = 0;
+               adapter->wwpn = 0;
+               adapter->s_id = 0;
+               adapter->fc_topology = 0;
+               adapter->fc_link_speed = 0;
+               adapter->hydra_version = 0;
+       }
+
+       if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
+               adapter->hardware_version = bottom->hardware_version;
+               memcpy(adapter->serial_number, bottom->serial_number, 17);
+               EBCASC(adapter->serial_number, sizeof(adapter->serial_number));
+       }
+
+       ZFCP_LOG_INFO("The adapter %s reported the following characteristics:\n"
+                     "WWNN 0x%016Lx, "
+                     "WWPN 0x%016Lx, "
+                     "S_ID 0x%08x,\n"
+                     "adapter version 0x%x, "
+                     "LIC version 0x%x, "
+                     "FC link speed %d Gb/s\n",
+                     zfcp_get_busid_by_adapter(adapter),
+                     adapter->wwnn,
+                     adapter->wwpn,
+                     (unsigned int) adapter->s_id,
+                     adapter->hydra_version,
+                     adapter->fsf_lic_version,
+                     adapter->fc_link_speed);
+       if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
+               ZFCP_LOG_NORMAL("error: the adapter %s "
+                               "only supports newer control block "
+                               "versions in comparison to this device "
+                               "driver (try updated device driver)\n",
+                               zfcp_get_busid_by_adapter(adapter));
+               debug_text_event(adapter->erp_dbf, 0, "low_qtcb_ver");
+               zfcp_erp_adapter_shutdown(adapter, 0);
+               return -EIO;
+       }
+       if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
+               ZFCP_LOG_NORMAL("error: the adapter %s "
+                               "only supports older control block "
+                               "versions than this device driver uses"
+                               "(consider a microcode upgrade)\n",
+                               zfcp_get_busid_by_adapter(adapter));
+               debug_text_event(adapter->erp_dbf, 0, "high_qtcb_ver");
+               zfcp_erp_adapter_shutdown(adapter, 0);
+               return -EIO;
+       }
+       return 0;
+}
+
 /*
  * function:    zfcp_fsf_exchange_config_data_handler
  *
@@ -2072,81 +2136,20 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
 static int
 zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
 {
-       int retval = -EIO;
        struct fsf_qtcb_bottom_config *bottom;
        struct zfcp_adapter *adapter = fsf_req->adapter;
 
-       if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
-               /* don't set any value, stay with the old (unitialized) ones */
-               goto skip_fsfstatus;
-       }
+       if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)
+               return -EIO;
 
-       /* evaluate FSF status in QTCB */
        switch (fsf_req->qtcb->header.fsf_status) {
 
        case FSF_GOOD:
                ZFCP_LOG_FLAGS(2, "FSF_GOOD\n");
-               bottom = &fsf_req->qtcb->bottom.config;
-               /* only log QTCB versions for now */
-               ZFCP_LOG_DEBUG("low QTCB version 0x%x of FSF, "
-                              "high QTCB version 0x%x of FSF, \n",
-                              bottom->low_qtcb_version,
-                              bottom->high_qtcb_version);
-               adapter->wwnn = bottom->nport_serv_param.wwnn;
-               adapter->wwpn = bottom->nport_serv_param.wwpn;
-               adapter->s_id = bottom->s_id & ZFCP_DID_MASK;
-               adapter->hydra_version = bottom->adapter_type;
-               adapter->fsf_lic_version = bottom->lic_version;
-               adapter->fc_topology = bottom->fc_topology;
-               adapter->fc_link_speed = bottom->fc_link_speed;
-                adapter->supported_features = bottom->supported_features;
-
-               if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){
-                       adapter->hardware_version = bottom->hardware_version;
-                        /* copy just first 17 bytes */
-                        memcpy(adapter->serial_number,
-                               bottom->serial_number, 17);
-                        EBCASC(adapter->serial_number,
-                               sizeof(adapter->serial_number));
-               }
 
-               ZFCP_LOG_INFO("The adapter %s reported "
-                             "the following characteristics:\n"
-                             "WWNN 0x%016Lx, "
-                             "WWPN 0x%016Lx, "
-                             "S_ID 0x%08x,\n"
-                             "adapter version 0x%x, "
-                             "LIC version 0x%x, "
-                             "FC link speed %d Gb/s\n",
-                             zfcp_get_busid_by_adapter(adapter),
-                             adapter->wwnn,
-                             adapter->wwpn,
-                             (unsigned int) adapter->s_id,
-                             adapter->hydra_version,
-                             adapter->fsf_lic_version,
-                             adapter->fc_link_speed);
-               if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) {
-                       ZFCP_LOG_NORMAL("error: the adapter %s "
-                                       "only supports newer control block "
-                                       "versions in comparison to this device "
-                                       "driver (try updated device driver)\n",
-                                       zfcp_get_busid_by_adapter(adapter));
-                       debug_text_event(fsf_req->adapter->erp_dbf, 0,
-                                        "low_qtcb_ver");
-                       zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
-               }
-               if (ZFCP_QTCB_VERSION > bottom->high_qtcb_version) {
-                       ZFCP_LOG_NORMAL("error: the adapter %s "
-                                       "only supports older control block "
-                                       "versions than this device driver uses"
-                                       "(consider a microcode upgrade)\n",
-                                       zfcp_get_busid_by_adapter(adapter));
-                       debug_text_event(fsf_req->adapter->erp_dbf, 0,
-                                        "high_qtcb_ver");
-                       zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
-               }
+               if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
+                       return -EIO;
+
                switch (adapter->fc_topology) {
                case FSF_TOPO_P2P:
                        ZFCP_LOG_FLAGS(1, "FSF_TOPO_P2P\n");
@@ -2157,7 +2160,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        debug_text_event(fsf_req->adapter->erp_dbf, 0,
                                         "top-p-to-p");
                        zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
+                       return -EIO;
                case FSF_TOPO_AL:
                        ZFCP_LOG_FLAGS(1, "FSF_TOPO_AL\n");
                        ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
@@ -2167,7 +2170,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        debug_text_event(fsf_req->adapter->erp_dbf, 0,
                                         "top-al");
                        zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
+                       return -EIO;
                case FSF_TOPO_FABRIC:
                        ZFCP_LOG_FLAGS(1, "FSF_TOPO_FABRIC\n");
                        ZFCP_LOG_INFO("Switched fabric fibrechannel "
@@ -2185,8 +2188,9 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        debug_text_exception(fsf_req->adapter->erp_dbf, 0,
                                             "unknown-topo");
                        zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
+                       return -EIO;
                }
+               bottom = &fsf_req->qtcb->bottom.config;
                if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) {
                        ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) "
                                        "allowed by the adapter %s "
@@ -2200,22 +2204,32 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        debug_event(fsf_req->adapter->erp_dbf, 0,
                                    &bottom->max_qtcb_size, sizeof (u32));
                        zfcp_erp_adapter_shutdown(adapter, 0);
-                       goto skip_fsfstatus;
+                       return -EIO;
                }
                atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
                                &adapter->status);
-               retval = 0;
-
                break;
+       case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
+               debug_text_event(adapter->erp_dbf, 0, "xchg-inco");
+
+               if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
+                       return -EIO;
 
+               ZFCP_LOG_INFO("Local link to adapter %s is down\n",
+                             zfcp_get_busid_by_adapter(adapter));
+               atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
+                               ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED,
+                               &adapter->status);
+               zfcp_erp_adapter_failed(adapter);
+               break;
        default:
-               /* retval is -EIO by default */
                debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
                debug_event(fsf_req->adapter->erp_dbf, 0,
                            &fsf_req->qtcb->header.fsf_status, sizeof (u32));
+               zfcp_erp_adapter_shutdown(adapter, 0);
+               return -EIO;
        }
- skip_fsfstatus:
-       return retval;
+       return 0;
 }
 
 /*
@@ -2855,8 +2869,6 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
        atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
        erp_action->fsf_req->data.open_unit.unit = erp_action->unit;
        erp_action->fsf_req->erp_action = erp_action;
-//     erp_action->fsf_req->qtcb->bottom.support.option =
-//             FSF_OPEN_LUN_UNSOLICITED_SENSE_DATA;
 
        /* start QDIO request for this FSF request */
        retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
@@ -2976,23 +2988,26 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
 
        case FSF_LUN_SHARING_VIOLATION :
                ZFCP_LOG_FLAGS(2, "FSF_LUN_SHARING_VIOLATION\n");
-               subtable = header->fsf_status_qual.halfword[4];
-               rule = header->fsf_status_qual.halfword[5];
-               if (rule == 0xFFFF) {
+               if (header->fsf_status_qual.word[0] != 0) {
                        ZFCP_LOG_NORMAL("FCP-LUN 0x%Lx at the remote port "
-                                       "with WWPN 0x%Lx connected to the "
-                                       "adapter %s is already in use\n",
+                                       "with WWPN 0x%Lx "
+                                       "connected to the adapter %s "
+                                       "is already in use in LPAR%d\n",
                                        unit->fcp_lun,
                                        unit->port->wwpn,
-                                       zfcp_get_busid_by_unit(unit));
+                                       zfcp_get_busid_by_unit(unit),
+                                       header->fsf_status_qual.fsf_queue_designator.hla);
                } else {
+                       subtable = header->fsf_status_qual.halfword[4];
+                       rule = header->fsf_status_qual.halfword[5];
                        switch (subtable) {
                        case FSF_SQ_CFDC_SUBTABLE_OS:
                        case FSF_SQ_CFDC_SUBTABLE_PORT_WWPN:
                        case FSF_SQ_CFDC_SUBTABLE_PORT_DID:
                        case FSF_SQ_CFDC_SUBTABLE_LUN:
-                               ZFCP_LOG_NORMAL("Access to unit 0x%016Lx on "
-                                               "port 0x%016Lx on adapter %s "
+                               ZFCP_LOG_NORMAL("Access to FCP-LUN 0x%Lx at the "
+                                               "remote port with WWPN 0x%Lx "
+                                               "connected to the adapter %s "
                                                "is denied (%s rule %d)\n",
                                                unit->fcp_lun,
                                                unit->port->wwpn,
@@ -3003,7 +3018,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
                        }
                }
                ZFCP_LOG_DEBUG("status qualifier:\n");
-               ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
+               ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
                              (char *) &header->fsf_status_qual,
                              sizeof (union fsf_status_qual));
                debug_text_event(adapter->erp_dbf, 2,
@@ -3075,17 +3090,13 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
                /* save LUN handle assigned by FSF */
                unit->handle = header->lun_handle;
                ZFCP_LOG_TRACE("unit 0x%016Lx on remote port 0x%016Lx on "
-                              "adapter %s opened, port handle 0x%x, "
-                              "access flag 0x%02x\n",
+                              "adapter %s opened, port handle 0x%x\n",
                               unit->fcp_lun,
                               unit->port->wwpn,
                               zfcp_get_busid_by_unit(unit),
-                              unit->handle,
-                              bottom->lun_access);
+                              unit->handle);
                /* mark unit as open */
                atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status);
-               if (adapter->supported_features & FSF_FEATURE_CFDC)
-                       unit->lun_access = bottom->lun_access;
                retval = 0;
                break;
 
@@ -3362,15 +3373,11 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
         * (need this for look up on normal command completion)
         */
        fsf_req->data.send_fcp_command_task.scsi_cmnd = scsi_cmnd;
-#ifdef ZFCP_DEBUG_REQUESTS
        debug_text_event(adapter->req_dbf, 3, "fsf/sc");
        debug_event(adapter->req_dbf, 3, &fsf_req, sizeof (unsigned long));
        debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long));
-#endif                         /* ZFCP_DEBUG_REQUESTS */
-#ifdef ZFCP_DEBUG_ABORTS
-       fsf_req->data.send_fcp_command_task.start_jiffies = jiffies;
-#endif
 
+       fsf_req->data.send_fcp_command_task.start_jiffies = jiffies;
        fsf_req->data.send_fcp_command_task.unit = unit;
        ZFCP_LOG_DEBUG("unit=%p, fcp_lun=0x%016Lx\n", unit, unit->fcp_lun);
 
@@ -3511,10 +3518,8 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
  no_fit:
  failed_scsi_cmnd:
        /* dequeue new FSF request previously enqueued */
-#ifdef ZFCP_DEBUG_REQUESTS
        debug_text_event(adapter->req_dbf, 3, "fail_sc");
        debug_event(adapter->req_dbf, 3, &scsi_cmnd, sizeof (unsigned long));
-#endif                         /* ZFCP_DEBUG_REQUESTS */
 
        zfcp_fsf_req_free(fsf_req);
        fsf_req = NULL;
@@ -4262,7 +4267,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
         * the new eh
         */
        /* always call back */
-#ifdef ZFCP_DEBUG_REQUESTS
        debug_text_event(fsf_req->adapter->req_dbf, 2, "ok_done:");
        debug_event(fsf_req->adapter->req_dbf, 2, &scpnt,
                    sizeof (unsigned long));
@@ -4270,7 +4274,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
                    sizeof (unsigned long));
        debug_event(fsf_req->adapter->req_dbf, 2, &fsf_req,
                    sizeof (unsigned long));
-#endif /* ZFCP_DEBUG_REQUESTS */
        (scpnt->scsi_done) (scpnt);
        /*
         * We must hold this lock until scsi_done has been called.
@@ -4951,7 +4954,6 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
                         "to request queue.\n");
        } else {
                req_queue->distance_from_int = new_distance_from_int;
-#ifdef ZFCP_DEBUG_REQUESTS
                debug_text_event(adapter->req_dbf, 1, "o:a/seq");
                debug_event(adapter->req_dbf, 1, &fsf_req,
                            sizeof (unsigned long));
@@ -4961,7 +4963,6 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
                } else {
                        debug_text_event(adapter->req_dbf, 1, "nocb");
                }
-#endif                         /* ZFCP_DEBUG_REQUESTS */
                /*
                 * increase FSF sequence counter -
                 * this must only be done for request successfully enqueued to
index e6f3859..8793138 100644 (file)
 #define FSF_CONFLICTS_OVERRULED                        0x00000058
 #define FSF_PORT_BOXED                         0x00000059
 #define FSF_LUN_BOXED                          0x0000005A
+#define FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE    0x0000005B
 #define FSF_PAYLOAD_SIZE_MISMATCH              0x00000060
 #define FSF_REQUEST_SIZE_TOO_LARGE             0x00000061
 #define FSF_RESPONSE_SIZE_TOO_LARGE            0x00000062
 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD    0x00000004
 #define FSF_STATUS_READ_LINK_DOWN              0x00000005 /* FIXME: really? */
 #define FSF_STATUS_READ_LINK_UP                0x00000006
-#define FSF_STATUS_READ_NOTIFICATION_LOST      0x00000009
 #define FSF_STATUS_READ_CFDC_UPDATED           0x0000000A
 #define FSF_STATUS_READ_CFDC_HARDENED          0x0000000B
 
 #define FSF_STATUS_READ_SUB_ERROR_PORT         0x00000002
 
 /* status subtypes for CFDC */
-#define FSF_STATUS_READ_SUB_LOST_CFDC_UPDATED  0x00000020
-#define FSF_STATUS_READ_SUB_LOST_CFDC_HARDENED 0x00000040
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE        0x00000002
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
 
 
 /* option */
 #define FSF_OPEN_LUN_SUPPRESS_BOXING           0x00000001
-#define FSF_OPEN_LUN_UNSOLICITED_SENSE_DATA    0x00000002
 
 /* adapter types */
 #define FSF_ADAPTER_TYPE_FICON                  0x00000001
 #define FSF_ADAPTER_TYPE_FICON_EXPRESS          0x00000002
 
-/* flags */
-#define FSF_CFDC_OPEN_LUN_ALLOWED              0x01
-#define FSF_CFDC_EXCLUSIVE_ACCESS              0x02
-#define FSF_CFDC_OUTBOUND_TRANSFER_ALLOWED     0x10
-
 /* port types */
 #define FSF_HBA_PORTTYPE_UNKNOWN               0x00000001
 #define FSF_HBA_PORTTYPE_NOTPRESENT            0x00000003
@@ -329,18 +321,7 @@ union fsf_status_qual {
        u8  byte[FSF_STATUS_QUALIFIER_SIZE];
        u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)];
        u32 word[FSF_STATUS_QUALIFIER_SIZE / sizeof (u32)];
-       struct {
-               u32 this_cmd;
-               u32 aborted_cmd;
-       } port_handle;
-       struct {
-               u32 this_cmd;
-               u32 aborted_cmd;
-       } lun_handle;
-       struct {
-               u64 found;
-               u64 expected;
-       } fcp_lun;
+       struct fsf_queue_designator fsf_queue_designator;
 } __attribute__ ((packed));
 
 struct fsf_qtcb_header {
@@ -400,8 +381,7 @@ struct fsf_qtcb_bottom_support {
        u32 service_class;
        u8  res3[3];
        u8  timeout;
-       u32 lun_access;
-       u8  res4[180];
+       u8  res4[184];
        u32 els1_length;
        u32 els2_length;
        u32 req_buf_length;
index c1c7dce..e34e771 100644 (file)
@@ -28,7 +28,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_QDIO_C_REVISION "$Revision: 1.15 $"
+#define ZFCP_QDIO_C_REVISION "$Revision: 1.16 $"
 
 #include "zfcp_ext.h"
 
@@ -485,11 +485,9 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
        struct zfcp_fsf_req *fsf_req;
        int retval = 0;
 
-#ifdef ZFCP_DEBUG_REQUESTS
        /* Note: seq is entered later */
        debug_text_event(adapter->req_dbf, 1, "i:a/seq");
        debug_event(adapter->req_dbf, 1, &sbale_addr, sizeof (unsigned long));
-#endif                         /* ZFCP_DEBUG_REQUESTS */
 
        /* invalid (per convention used in this driver) */
        if (unlikely(!sbale_addr)) {
@@ -508,13 +506,11 @@ zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
                retval = -EINVAL;
                goto out;
        }
-#ifdef ZFCP_DEBUG_REQUESTS
        /* debug feature stuff (test for QTCB: remember new unsol. status!) */
        if (likely(fsf_req->qtcb)) {
                debug_event(adapter->req_dbf, 1,
                            &fsf_req->qtcb->prefix.req_seq_no, sizeof (u32));
        }
-#endif                         /* ZFCP_DEBUG_REQUESTS */
 
        ZFCP_LOG_TRACE("fsf_req at %p, QTCB at %p\n", fsf_req, fsf_req->qtcb);
        if (likely(fsf_req->qtcb)) {
index 6d00a14..071007e 100644 (file)
@@ -31,7 +31,7 @@
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_SCSI
 
 /* this drivers version (do not edit !!! generated and updated by cvs) */
-#define ZFCP_SCSI_REVISION "$Revision: 1.57 $"
+#define ZFCP_SCSI_REVISION "$Revision: 1.59 $"
 
 #include <linux/blkdev.h>
 
@@ -48,7 +48,8 @@ static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
 static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
 static int zfcp_task_management_function(struct zfcp_unit *, u8);
 
-static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, int, int);
+static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
+                                         scsi_lun_t);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
 
@@ -297,12 +298,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
                ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n");
                retval = SCSI_MLQUEUE_HOST_BUSY;
        } else {
-
-#ifdef ZFCP_DEBUG_REQUESTS
                debug_text_event(adapter->req_dbf, 3, "q_scpnt");
                debug_event(adapter->req_dbf, 3, &scpnt,
                            sizeof (unsigned long));
-#endif                         /* ZFCP_DEBUG_REQUESTS */
        }
 
 out:
@@ -374,7 +372,8 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
  * context:    
  */
 static struct zfcp_unit *
-zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, int id, int lun)
+zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id,
+                scsi_lun_t lun)
 {
        struct zfcp_port *port;
        struct zfcp_unit *unit, *retval = NULL;
@@ -424,8 +423,6 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        unsigned long flags;
        u32 status = 0;
 
-
-#ifdef ZFCP_DEBUG_ABORTS
        /* the components of a abort_dbf record (fixed size record) */
        u64 dbf_scsi_cmnd = (unsigned long) scpnt;
        char dbf_opcode[ZFCP_ABORT_DBF_LENGTH];
@@ -443,7 +440,6 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        memcpy(dbf_opcode,
               scpnt->cmnd,
               min(scpnt->cmd_len, (unsigned char) ZFCP_ABORT_DBF_LENGTH));
-#endif
 
        ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n",
                      scpnt, zfcp_get_busid_by_adapter(adapter));
@@ -483,11 +479,11 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 
        /* Figure out which fsf_req needs to be aborted. */
        old_fsf_req = req_data->send_fcp_command_task.fsf_req;
-#ifdef ZFCP_DEBUG_ABORTS
+
        dbf_fsf_req = (unsigned long) old_fsf_req;
        dbf_timeout =
            (jiffies - req_data->send_fcp_command_task.start_jiffies) / HZ;
-#endif
+
        ZFCP_LOG_DEBUG("old_fsf_req=%p\n", old_fsf_req);
        if (!old_fsf_req) {
                write_unlock_irqrestore(&adapter->abort_lock, flags);
@@ -541,7 +537,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 
        /* wait for completion of abort */
        ZFCP_LOG_DEBUG("waiting for cleanup...\n");
-#ifdef ZFCP_DEBUG_ABORTS
+#if 1
        /*
         * FIXME:
         * copying zfcp_fsf_req_wait_and_cleanup code is not really nice
@@ -577,8 +573,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
                strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH);
        }
 
-      out:
-#ifdef ZFCP_DEBUG_ABORTS
+ out:
        debug_event(adapter->abort_dbf, 1, &dbf_scsi_cmnd, sizeof (u64));
        debug_event(adapter->abort_dbf, 1, &dbf_opcode, ZFCP_ABORT_DBF_LENGTH);
        debug_event(adapter->abort_dbf, 1, &dbf_wwn, sizeof (wwn_t));
@@ -591,7 +586,7 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[0], sizeof (u64));
        debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[1], sizeof (u64));
        debug_text_event(adapter->abort_dbf, 1, dbf_result);
-#endif
+
        spin_lock_irq(scsi_host->host_lock);
        return retval;
 }
index d2abe3a..5ac2f3c 100644 (file)
@@ -26,7 +26,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.13 $"
+#define ZFCP_SYSFS_DRIVER_C_REVISION "$Revision: 1.13.2.1 $"
 
 #include <asm/ccwdev.h>
 #include "zfcp_ext.h"
index fa9e371..dbe2584 100644 (file)
@@ -15,5 +15,4 @@
 #define L1_CACHE_SHIFT     8
 #define L1_CACHE_SHIFT_MAX 8   /* largest L1 which this arch supports */
 
-#define __ARCH_FORCE_KMALLOCALIGN 8
 #endif
index ec34d58..9030813 100644 (file)
@@ -139,7 +139,10 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
 static inline struct page *
 pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
-       return virt_to_page(pte_alloc_one_kernel(mm, vmaddr));
+       pte_t *pte = pte_alloc_one_kernel(mm, vmaddr);
+       if (pte)
+               return virt_to_page(pte);
+       return 0;
 }
 
 static inline void pte_free_kernel(pte_t *pte)
diff --git a/include/asm-s390/qeth.h b/include/asm-s390/qeth.h
new file mode 100644 (file)
index 0000000..8868027
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * include/asm-s390/qeth.h
+ *
+ * ioctl definitions for qeth driver
+ *
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Author(s):  Thomas Spatzier <tspat@de.ibm.com>
+ *
+ */
+#ifndef __ASM_S390_IOCTL_H__
+#define __ASM_S390_IOCTL_H__
+#include <linux/ioctl.h>
+
+#define QETH_IOCTL_LETTER 'Q'
+
+#define SIOC_QETH_ARP_SET_NO_ENTRIES   _IOWR(QETH_IOCTL_LETTER, 1, int)
+#define SIOC_QETH_ARP_QUERY_INFO       _IOWR(QETH_IOCTL_LETTER, 2, int)
+#define SIOC_QETH_ARP_ADD_ENTRY                _IOWR(QETH_IOCTL_LETTER, 3, int)
+#define SIOC_QETH_ARP_REMOVE_ENTRY     _IOWR(QETH_IOCTL_LETTER, 4, int)
+#define SIOC_QETH_ARP_FLUSH_CACHE      _IOWR(QETH_IOCTL_LETTER, 5, int)
+#define SIOC_QETH_ADP_SET_SNMP_CONTROL _IOWR(QETH_IOCTL_LETTER, 6, int)
+#define SIOC_QETH_GET_CARD_TYPE                _IOWR(QETH_IOCTL_LETTER, 7, int)
+
+struct qeth_arp_cache_entry {
+       __u8  macaddr[6];
+       __u8  reserved1[2];
+       __u8  ipaddr[16]; /* for both  IPv4 and IPv6 */
+       __u8  reserved2[32];
+} __attribute__ ((packed));
+
+struct qeth_arp_qi_entry7 {
+       __u8 media_specific[32];
+       __u8 macaddr_type;
+       __u8 ipaddr_type;
+       __u8 macaddr[6];
+       __u8 ipaddr[4];
+} __attribute__((packed));
+
+struct qeth_arp_qi_entry5 {
+       __u8 media_specific[32];
+       __u8 macaddr_type;
+       __u8 ipaddr_type;
+       __u8 ipaddr[4];
+} __attribute__((packed));
+
+/* data sent to user space as result of query arp ioctl */
+#define QETH_QARP_USER_DATA_SIZE 20000
+#define QETH_QARP_MASK_OFFSET    4
+#define QETH_QARP_ENTRIES_OFFSET 6
+struct qeth_arp_query_user_data {
+       union {
+               __u32 data_len;         /* set by user space program */
+               __u32 no_entries;       /* set by kernel */
+       } u;
+       __u16 mask_bits;
+       char *entries;
+} __attribute__((packed));
+
+#endif /* __ASM_S390_IOCTL_H__ */
index 12da8b0..4c3b6aa 100644 (file)
@@ -70,11 +70,9 @@ extern inline void _raw_spin_lock(spinlock_t *lp)
 
 extern inline int _raw_spin_trylock(spinlock_t *lp)
 {
-#ifndef __s390x__
-       unsigned long result, reg;
-#else /* __s390x__ */
-       unsigned int result, reg;
-#endif /* __s390x__ */
+       unsigned long reg;
+       unsigned int result;
+
        __asm__ __volatile("    basr  %1,0\n"
                           "0:  cs    %0,%1,0(%3)"
                           : "=d" (result), "=&d" (reg), "=m" (lp->lock)
@@ -226,7 +224,7 @@ extern inline int _raw_write_trylock(rwlock_t *rw)
                             "0: csg %0,%1,0(%3)\n"
 #endif /* __s390x__ */
                             : "=d" (result), "=&d" (reg), "=m" (rw->lock)
-                            : "a" (&rw->lock), "m" (rw->lock), "0" (0)
+                            : "a" (&rw->lock), "m" (rw->lock), "0" (0UL)
                             : "cc", "memory" );
        return result == 0;
 }
index 483ce61..d43fdbb 100644 (file)
@@ -456,13 +456,13 @@ struct net_device
                                                     unsigned char *haddr);
        int                     (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
        int                     (*accept_fastpath)(struct net_device *, struct dst_entry*);
+       int                     (*generate_eui64)(u8 *eui, struct net_device *dev);
 #ifdef CONFIG_NETPOLL_RX
        int                     netpoll_rx;
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*poll_controller)(struct net_device *dev);
 #endif
-       int                     (*generate_eui64)(u8 *eui, struct net_device *dev);
 
        /* bridge stuff */
        struct net_bridge_port  *br_port;
index 58048ab..11f5aea 100644 (file)
@@ -121,6 +121,29 @@ static inline int rcu_pending(int cpu)
                return 0;
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+extern cpumask_t idle_cpu_mask;
+#endif
+
+/* 
+ * RCU is build for ticking systems. Without the HZ timer 
+ * we have not enought state changes which may result in a 
+ * never finished RCU request.
+ * In a tickless system we don't want to wake idle CPUs just 
+ * to finish the RCU request. That is possible because the 
+ * idle CPUs satisfy the quiescilant RCU condition anyway.          
+ */
+static inline void rcu_set_active_cpu_map(cpumask_t *mask) 
+{
+#ifdef CONFIG_NO_IDLE_HZ
+       cpumask_t active = idle_cpu_mask;
+       cpus_complement(active);
+       cpus_and(*mask, cpu_online_map, active);
+#else
+       *mask = cpu_online_map;
+#endif
+}
+
 #define rcu_read_lock()                preempt_disable()
 #define rcu_read_unlock()      preempt_enable()
 
index b9a312b..f4d54ec 100644 (file)
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 
-#ifdef CONFIG_NO_IDLE_HZ
-extern cpumask_t idle_cpu_mask;
-#endif
-
 /* Definition for rcupdate control block. */
 struct rcu_ctrlblk rcu_ctrlblk = 
        { .mutex = SPIN_LOCK_UNLOCKED, .curbatch = 1, 
@@ -114,22 +110,8 @@ static void rcu_start_batch(long newbatch)
            !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
                return;
        }
-
-#ifdef CONFIG_NO_IDLE_HZ
-       /* 
-        * RCU is build for ticking systems. Without the HZ timer 
-        * we have not enought state changes which may result in a 
-        * never finished RCU request.
-        * In a tickless system we don't want to wake idle CPUs just 
-        * to finish the RCU request. That is possible because the 
-        * idle CPUs satisfy the quiescilant RCU condition anyway.          
-        * FIXME: Is this correct? 
-        */
-       rcu_ctrlblk.rcu_cpu_mask = cpu_online_map & ~idle_cpu_mask;
-#else
        /* Can't change, since spin lock held. */
-       rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
-#endif
+       rcu_set_active_cpu_map(&rcu_ctrlblk.rcu_cpu_mask);
 }
 
 /*
index e35a5ae..fb16561 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 #include       <asm/cacheflush.h>
 #include       <asm/tlbflush.h>
 
-#ifdef __ARCH_FORCE_KMALLOCALIGN
-#define KMALLOC_ALIGN  __ARCH_FORCE_KMALLOCALIGN
-#else
-#define KMALLOC_ALIGN  0
-#endif
-
 /*
  * DEBUG       - 1 for kmem_cache_create() to honour; SLAB_DEBUG_INITIAL,
  *               SLAB_RED_ZONE & SLAB_POISON.
@@ -274,7 +268,6 @@ struct kmem_cache_s {
        unsigned int            colour_off;     /* colour offset */
        unsigned int            colour_next;    /* cache colouring */
        kmem_cache_t            *slabp_cache;
-       unsigned int            slab_size;
        unsigned int            dflags;         /* dynamic flags */
 
        /* constructor func */
@@ -497,11 +490,8 @@ static kmem_cache_t cache_cache = {
        .objsize        = sizeof(kmem_cache_t),
        .flags          = SLAB_NO_REAP,
        .spinlock       = SPIN_LOCK_UNLOCKED,
-       .colour_off     = SMP_CACHE_BYTES,
+       .colour_off     = L1_CACHE_BYTES,
        .name           = "kmem_cache",
-#if DEBUG
-       .reallen        = sizeof(kmem_cache_t),
-#endif
 };
 
 /* Guard access to the cache-chain. */
@@ -545,7 +535,7 @@ static inline struct array_cache *ac_data(kmem_cache_t *cachep)
 }
 
 /* Cal the num objs, wastage, and bytes left over for a given slab size. */
-static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
+static void cache_estimate (unsigned long gfporder, size_t size,
                 int flags, size_t *left_over, unsigned int *num)
 {
        int i;
@@ -558,7 +548,7 @@ static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
                extra = sizeof(kmem_bufctl_t);
        }
        i = 0;
-       while (i*size + ALIGN(base+i*extra, align) <= wastage)
+       while (i*size + L1_CACHE_ALIGN(base+i*extra) <= wastage)
                i++;
        if (i > 0)
                i--;
@@ -568,7 +558,7 @@ static void cache_estimate (unsigned long gfporder, size_t size, size_t align,
 
        *num = i;
        wastage -= i*size;
-       wastage -= ALIGN(base+i*extra, align);
+       wastage -= L1_CACHE_ALIGN(base+i*extra);
        *left_over = wastage;
 }
 
@@ -717,15 +707,14 @@ void __init kmem_cache_init(void)
        list_add(&cache_cache.next, &cache_chain);
        cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
 
-       cache_estimate(0, cache_cache.objsize, SMP_CACHE_BYTES, 0,
-                       &left_over, &cache_cache.num);
+       cache_estimate(0, cache_cache.objsize, 0,
+                       &left_over, &cache_cache.num);
        if (!cache_cache.num)
                BUG();
 
        cache_cache.colour = left_over/cache_cache.colour_off;
        cache_cache.colour_next = 0;
-       cache_cache.slab_size = ALIGN(cache_cache.num*sizeof(kmem_bufctl_t) + sizeof(struct slab),
-                                       SMP_CACHE_BYTES);
+
 
        /* 2+3) create the kmalloc caches */
        sizes = malloc_sizes;
@@ -739,7 +728,7 @@ void __init kmem_cache_init(void)
                 * allow tighter packing of the smaller caches. */
                sizes->cs_cachep = kmem_cache_create(
                        names->name, sizes->cs_size,
-                       KMALLOC_ALIGN, 0, NULL, NULL);
+                       0, SLAB_HWCACHE_ALIGN, NULL, NULL);
                if (!sizes->cs_cachep)
                        BUG();
 
@@ -751,7 +740,7 @@ void __init kmem_cache_init(void)
 
                sizes->cs_dmacachep = kmem_cache_create(
                        names->name_dma, sizes->cs_size,
-                       KMALLOC_ALIGN, SLAB_CACHE_DMA, NULL, NULL);
+                       0, SLAB_CACHE_DMA|SLAB_HWCACHE_ALIGN, NULL, NULL);
                if (!sizes->cs_dmacachep)
                        BUG();
 
@@ -1067,7 +1056,7 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
  * kmem_cache_create - Create a cache.
  * @name: A string which is used in /proc/slabinfo to identify this cache.
  * @size: The size of objects to be created in this cache.
- * @align: The required alignment for the objects.
+ * @offset: The offset to use within the page.
  * @flags: SLAB flags
  * @ctor: A constructor for the objects.
  * @dtor: A destructor for the objects.
@@ -1092,14 +1081,16 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
  * %SLAB_NO_REAP - Don't automatically reap this cache when we're under
  * memory pressure.
  *
- * %SLAB_HWCACHE_ALIGN - This flag has no effect and will be removed soon.
+ * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
+ * cacheline.  This can be beneficial if you're counting cycles as closely
+ * as davem.
  */
 kmem_cache_t *
-kmem_cache_create (const char *name, size_t size, size_t align,
+kmem_cache_create (const char *name, size_t size, size_t offset,
        unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
        void (*dtor)(void*, kmem_cache_t *, unsigned long))
 {
-       size_t left_over, slab_size;
+       size_t left_over, align, slab_size;
        kmem_cache_t *cachep = NULL;
 
        /*
@@ -1110,11 +1101,11 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                (size < BYTES_PER_WORD) ||
                (size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
                (dtor && !ctor) ||
-               (align < 0)) {
+               (offset < 0 || offset > size)) {
                        printk(KERN_ERR "%s: Early error in slab %s\n",
                                        __FUNCTION__, name);
                        BUG();
-       }
+               }
 
 #if DEBUG
        WARN_ON(strchr(name, ' '));     /* It confuses parsers */
@@ -1127,16 +1118,22 @@ kmem_cache_create (const char *name, size_t size, size_t align,
 
 #if FORCED_DEBUG
        /*
-        * Enable redzoning and last user accounting, except for caches with
-        * large objects, if the increased size would increase the object size
-        * above the next power of two: caches with object sizes just above a
-        * power of two have a significant amount of internal fragmentation.
+        * Enable redzoning and last user accounting, except
+        * - for caches with forced alignment: redzoning would violate the
+        *   alignment
+        * - for caches with large objects, if the increased size would
+        *   increase the object size above the next power of two: caches
+        *   with object sizes just above a power of two have a significant
+        *   amount of internal fragmentation
         */
-       if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD)))
+       if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD))
+                       && !(flags & SLAB_MUST_HWCACHE_ALIGN)) {
                flags |= SLAB_RED_ZONE|SLAB_STORE_USER;
+       }
        flags |= SLAB_POISON;
 #endif
 #endif
+
        /*
         * Always checks flags, a caller might be expecting debug
         * support which isn't available.
@@ -1144,23 +1141,15 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        if (flags & ~CREATE_MASK)
                BUG();
 
-       if (align) {
-               /* minimum supported alignment: */
-               if (align < BYTES_PER_WORD)
-                       align = BYTES_PER_WORD;
-
-               /* combinations of forced alignment and advanced debugging is
-                * not yet implemented.
-                */
-               flags &= ~(SLAB_RED_ZONE|SLAB_STORE_USER);
-       }
-
        /* Get cache's description obj. */
        cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);
        if (!cachep)
                goto opps;
        memset(cachep, 0, sizeof(kmem_cache_t));
 
+#if DEBUG
+       cachep->reallen = size;
+#endif
        /* Check that size is in terms of words.  This is needed to avoid
         * unaligned accesses for some archs when redzoning is used, and makes
         * sure any on-slab bufctl's are also correctly aligned.
@@ -1171,25 +1160,20 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        }
        
 #if DEBUG
-       cachep->reallen = size;
-
        if (flags & SLAB_RED_ZONE) {
-               /* redzoning only works with word aligned caches */
-               align = BYTES_PER_WORD;
-
+               /*
+                * There is no point trying to honour cache alignment
+                * when redzoning.
+                */
+               flags &= ~SLAB_HWCACHE_ALIGN;
                /* add space for red zone words */
                cachep->dbghead += BYTES_PER_WORD;
                size += 2*BYTES_PER_WORD;
        }
        if (flags & SLAB_STORE_USER) {
-               /* user store requires word alignment and
-                * one word storage behind the end of the real
-                * object.
-                */
-               align = BYTES_PER_WORD;
-               size += BYTES_PER_WORD;
+               flags &= ~SLAB_HWCACHE_ALIGN;
+               size += BYTES_PER_WORD; /* add space */
        }
-
 #if FORCED_DEBUG && defined(CONFIG_DEBUG_PAGEALLOC)
        if (size > 128 && cachep->reallen > L1_CACHE_BYTES && size < PAGE_SIZE) {
                cachep->dbghead += PAGE_SIZE - size;
@@ -1197,6 +1181,9 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        }
 #endif
 #endif
+       align = BYTES_PER_WORD;
+       if (flags & SLAB_HWCACHE_ALIGN)
+               align = L1_CACHE_BYTES;
 
        /* Determine if the slab management is 'on' or 'off' slab. */
        if (size >= (PAGE_SIZE>>3))
@@ -1206,16 +1193,13 @@ kmem_cache_create (const char *name, size_t size, size_t align,
                 */
                flags |= CFLGS_OFF_SLAB;
 
-       if (!align) {
-               /* Default alignment: compile time specified l1 cache size.
-                * But if an object is really small, then squeeze multiple
-                * into one cacheline.
-                */
-               align = L1_CACHE_BYTES;
+       if (flags & SLAB_HWCACHE_ALIGN) {
+               /* Need to adjust size so that objs are cache aligned. */
+               /* Small obj size, can get at least two per cache line. */
                while (size <= align/2)
                        align /= 2;
+               size = (size+align-1)&(~(align-1));
        }
-       size = ALIGN(size, align);
 
        /* Cal size (in pages) of slabs, and the num of objs per slab.
         * This could be made much more intelligent.  For now, try to avoid
@@ -1225,7 +1209,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
        do {
                unsigned int break_flag = 0;
 cal_wastage:
-               cache_estimate(cachep->gfporder, size, align, flags,
+               cache_estimate(cachep->gfporder, size, flags,
                                                &left_over, &cachep->num);
                if (break_flag)
                        break;
@@ -1259,7 +1243,7 @@ next:
                cachep = NULL;
                goto opps;
        }
-       slab_size = ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab),align);
+       slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab));
 
        /*
         * If the slab has been placed off-slab, and we have enough space then
@@ -1270,17 +1254,14 @@ next:
                left_over -= slab_size;
        }
 
-       if (flags & CFLGS_OFF_SLAB) {
-               /* really off slab. No need for manual alignment */
-               slab_size = cachep->num*sizeof(kmem_bufctl_t)+sizeof(struct slab);
-       }
-       cachep->colour_off = L1_CACHE_BYTES;
        /* Offset must be a multiple of the alignment. */
-       if (cachep->colour_off < align)
-               cachep->colour_off = align;
-       cachep->colour = left_over/cachep->colour_off;
-       cachep->slab_size = slab_size;
+       offset += (align-1);
+       offset &= ~(align-1);
+       if (!offset)
+               offset = L1_CACHE_BYTES;
+       cachep->colour_off = offset;
+       cachep->colour = left_over/offset;
+
        cachep->flags = flags;
        cachep->gfpflags = 0;
        if (flags & SLAB_CACHE_DMA)
@@ -1562,7 +1543,8 @@ static inline struct slab* alloc_slabmgmt (kmem_cache_t *cachep,
                        return NULL;
        } else {
                slabp = objp+colour_off;
-               colour_off += cachep->slab_size;
+               colour_off += L1_CACHE_ALIGN(cachep->num *
+                               sizeof(kmem_bufctl_t) + sizeof(struct slab));
        }
        slabp->inuse = 0;
        slabp->colouroff = colour_off;
index 28f7c3a..59e82d2 100644 (file)
@@ -1567,6 +1567,10 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
        case NETDEV_UNREGISTER:
                fib6_run_gc(0);
                break;
+       case NETDEV_DOWN:
+               neigh_ifdown(&nd_tbl, dev);
+               fib6_run_gc(0);
+               break;
        default:
                break;
        }