From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The rewritten qeth network driver.


---

 /dev/null                            |10872 -----------------------------------
 25-akpm/drivers/s390/net/Kconfig     |    2 
 25-akpm/drivers/s390/net/Makefile    |    6 
 25-akpm/drivers/s390/net/qeth.h      | 1823 ++---
 25-akpm/drivers/s390/net/qeth_fs.h   |  156 
 25-akpm/drivers/s390/net/qeth_main.c | 6820 +++++++++++++++++++++
 25-akpm/drivers/s390/net/qeth_mpc.c  |   22 
 25-akpm/drivers/s390/net/qeth_mpc.h  |  766 +-
 25-akpm/drivers/s390/net/qeth_proc.c |  468 +
 25-akpm/drivers/s390/net/qeth_sys.c  | 1479 ++++
 25-akpm/include/asm-s390/qeth.h      |   60 
 11 files changed, 10152 insertions(+), 12322 deletions(-)

diff -puN drivers/s390/net/Kconfig~s390-12-12-rewritten-qeth-driver drivers/s390/net/Kconfig
--- 25/drivers/s390/net/Kconfig~s390-12-12-rewritten-qeth-driver	2004-04-08 13:55:46.658930936 -0700
+++ 25-akpm/drivers/s390/net/Kconfig	2004-04-08 13:55:46.672928808 -0700
@@ -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"
diff -puN drivers/s390/net/Makefile~s390-12-12-rewritten-qeth-driver drivers/s390/net/Makefile
--- 25/drivers/s390/net/Makefile~s390-12-12-rewritten-qeth-driver	2004-04-08 13:55:46.659930784 -0700
+++ 25-akpm/drivers/s390/net/Makefile	2004-04-08 13:55:46.672928808 -0700
@@ -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
diff -L drivers/s390/net/qeth.c -puN drivers/s390/net/qeth.c~s390-12-12-rewritten-qeth-driver /dev/null
--- 25/drivers/s390/net/qeth.c
+++ /dev/null	2003-09-15 06:40:47.000000000 -0700
@@ -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);
diff -puN /dev/null drivers/s390/net/qeth_fs.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/s390/net/qeth_fs.h	2004-04-08 13:55:46.731919840 -0700
@@ -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 -puN drivers/s390/net/qeth.h~s390-12-12-rewritten-qeth-driver drivers/s390/net/qeth.h
--- 25/drivers/s390/net/qeth.h~s390-12-12-rewritten-qeth-driver	2004-04-08 13:55:46.664930024 -0700
+++ 25-akpm/drivers/s390/net/qeth.h	2004-04-08 13:55:46.730919992 -0700
@@ -1,1147 +1,789 @@
-/*
- * 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>
+
+#include <net/ipv6.h>
+#include <linux/in6.h>
+#include <net/if_inet6.h>
+#include <net/addrconf.h>
 
-#define QETH_NAME " qeth"
 
-#define VERSION_QETH_H "$Revision: 1.60 $"
+#include <asm/bitops.h>
+#include <asm/debug.h>
+#include <asm/qdio.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+
+#include "qeth_mpc.h"
 
-/******************** CONFIG STUFF ***********************/
-//#define QETH_DBF_LIKE_HELL
+#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 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 PRINTK_HEADER 	"qeth: "
 
-#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;
 
-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 */
+	for (i = 0; i < len; i++) {
+		if (i && !(i % 16))
+			printk("\n");
+		printk("%02x ", *(buf + i));
 	}
+	printk("\n");
 }
 
-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
+#define SENSE_COMMAND_REJECT_BYTE 0
+#define SENSE_COMMAND_REJECT_FLAG 0x80
+#define SENSE_RESETTING_EVENT_BYTE 1
+#define SENSE_RESETTING_EVENT_FLAG 0x80
 
-#endif /* QETH_IPV6 */
-}
+/*
+ * Common IO related definitions
+ */
+extern struct device *qeth_root_dev;
+extern struct ccw_driver qeth_ccw_driver;
+extern struct ccwgroup_driver qeth_ccwgroup_driver;
+
+#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
 
-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;
-	}
-}
+#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
+		((struct ccwgroup_device *)cdev->dev.driver_data)\
+		->dev.driver_data;
 
-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;
-	}
-}
+/**
+ * card stuff
+ */
+#ifdef CONFIG_QETH_PERF_STATS
+struct qeth_perf_stats {
+	unsigned int bufs_rec;
+	unsigned int bufs_sent;
 
-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;
-	}
-}
+	unsigned int skbs_sent_pack;
+	unsigned int bufs_sent_pack;
 
-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;
-	}
-}
+	unsigned int sc_dp_p;
+	unsigned int sc_p_dp;
 
-static unsigned short
-qeth_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-	struct ethhdr *eth;
+	__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 */
 
-	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);
-}
+/* Routing stuff */
+struct qeth_routing_info {
+	enum qeth_routing_types type;
+};
 
-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 */
+/* IPA stuff */
+struct qeth_ipa_info {
+	__u32 supported_funcs;
+	__u32 enabled_funcs;
+};
 
-inline static const char *
-qeth_get_link_type_name(int cardtype, __u8 linktype)
+static inline int
+qeth_is_ipa_supported(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
 {
-	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";
-	}
+	return (ipa->supported_funcs & func);
 }
 
-inline static const char *
-qeth_get_dev_basename(int cardtype, __u8 link_type)
+static inline int
+qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
 {
-	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";
-	}
+	return (ipa->supported_funcs & ipa->enabled_funcs & func);
 }
 
-/* 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: */
+#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)
 
-inline static int
-qeth_sbal_packing_on_card(int cardtype)
-{
-	switch (cardtype) {
-	case QETH_CARD_TYPE_IQD:
-		return 0;
-	default:
-		return 1;
-	}
-}
 
-/* 
- * 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
+#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
 
-static inline int
-qeth_sbalf15_in_retrieable_range(int sbalf15)
-{
-	return ((sbalf15 >= 15) && (sbalf15 <= 31));
-}
+#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
 
-#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 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
+/**
+ * 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
 
-#define DEV_NAME_LEN 16
-#define IOCTL_MAX_TRANSFER_SIZE 65535
+/*IPv6 address autoconfiguration stuff*/
+#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe
+#define UNIQUE_ID_NOT_BY_CARD 		0x10000
+
+/*****************************************************************************/
+/* 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
-
-#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
+/* Packing */
+#define QETH_LOW_WATERMARK_PACK  2
+#define QETH_HIGH_WATERMARK_PACK 5
+#define QETH_WATERMARK_PACK_FUZZ 1
 
-typedef int (*reg_notifier_t) (struct notifier_block *);
+#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
 
-struct ipato_entry {
-	int version;
-	__u8 addr[16];
-	int mask_bits;
-	char dev_name[DEV_NAME_LEN];
-	struct ipato_entry *next;
-};
+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 qeth_vipa_entry {
-	int version;
-	__u8 ip[16];
-	int flag;
-	volatile int state;
-	struct qeth_vipa_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,
+};
+
+/* 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,
+};
+
+enum qeth_qdio_info_states {
+	QETH_QDIO_UNINITIALIZED,
+	QETH_QDIO_ALLOCATED,
+	QETH_QDIO_ESTABLISHED,
+};
+
+struct qeth_buffer_pool_entry {
+	struct list_head list;
+	struct list_head init_list;
+	void *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
+};
+
+struct qeth_qdio_buffer_pool {
+	struct list_head entry_list;
+	int buf_count;
+};
+
+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_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;
 };
 
-struct ip_mc_state {
-	struct qeth_ipm_mac *ipm_ifa;
-	struct qeth_ipm_mac *ipm6_ifa;
-};
+struct qeth_card;
 
-struct addr_request {
-	struct addr_request *next;
-	int request_type;
-	__u8 mac[ETH_ALEN];
-	__u8 ip[16];
-};
+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;
 
-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;
+	/* priority queueing */
 	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;
+	int default_out_queue;
 };
 
-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];
+enum qeth_send_errors {
+	QETH_SEND_ERROR_NONE,
+	QETH_SEND_ERROR_LINK_FAILURE,
+	QETH_SEND_ERROR_RETRY,
+	QETH_SEND_ERROR_KICK_IT,
 };
 
-struct qeth_ringbuffer_element {
-	struct sk_buff_head skb_list;
-	int next_element_to_fill;
-} __attribute__ ((packed));
+#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 */
 
-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)));
+#define DEFAULT_ADD_HHLEN 0
+#define MAX_ADD_HHLEN 1024
 
-struct qeth_perf_stats {
-	unsigned int skbs_rec;
-	unsigned int bufs_rec;
+/**
+ * buffer stuff for read channel
+ */
+#define QETH_CMD_BUFFER_NO	8
 
-	unsigned int skbs_sent;
-	unsigned int bufs_sent;
+/**
+ *  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,
+};
 
-	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;
+/**
+ * Protocol versions
+ */
+enum qeth_prot_versions {
+	QETH_PROT_SNA  = 0x0001,
+	QETH_PROT_IPV4 = 0x0004,
+	QETH_PROT_IPV6 = 0x0006,
+};
 
-	unsigned int sc_dp_p;
-	unsigned int sc_p_dp;
+enum qeth_ip_types {
+	QETH_IP_TYPE_NORMAL,
+	QETH_IP_TYPE_VIPA,
+	QETH_IP_TYPE_RXIP,
+};
 
-	__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_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;
+};
+
+struct qeth_ipato_entry {
+	struct list_head entry;
+	enum qeth_prot_versions proto;
+	char addr[16];
+	int mask_bits;
 };
 
-/* ugly. I know. */
-struct qeth_card {	/* pointed to by dev->priv */
+struct qeth_ipato {
+	int enabled;
+	int invert4;
+	int invert6;
+	struct list_head entries;
+};
 
-	/* pointer to options (defaults + parameters) */
-	struct qeth_card_options options;
+struct qeth_channel;
 
-	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 */
+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 *);
+};
 
-#ifdef QETH_VLAN
-	struct vlan_group *vlangrp;
-	spinlock_t vlan_lock;
-#endif
 
-	char dev_name[DEV_NAME_LEN];	/* pointed to by dev->name */
-	struct net_device *dev;
-	struct net_device_stats *stats;
+/**
+ * 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;
+};
 
-	int no_queues;
+/**
+ *  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;
+};
+
+struct qeth_seqno {
+	__u32 trans_hdr;
+	__u32 pdu_hdr;
+	__u32 pdu_hdr_ack;
+	__u32 ipa;
+};
 
-#ifdef QETH_PERFORMANCE_STATS
-	struct qeth_perf_stats perf_stats;
-#endif /* QETH_PERFORMANCE_STATS */
+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;
+};
 
-	/* 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;
+struct qeth_card_info {
 
-	/* this is card-related */
-	int type;
+	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 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 broadcast_capable;
 	int unique_id;
+	__u32 csum_mask;
+};
 
-	/* device and I/O data */
-	struct ccwgroup_device *gdev;
-	unsigned short unit_addr2;
-	unsigned short cula;
-	unsigned short chpid;
-
-	unsigned char ipa_buf[QETH_BUFSIZE];
-	unsigned char send_buf[QETH_BUFSIZE];
-
-/* IOCTL Stuff */
-	unsigned char *ioctl_data_buffer;
-	unsigned char *ioctl_buffer_pointer;
-	int ioctl_returncode;
-	int ioctl_buffersize;
-	int number_of_entries;
-
-	atomic_t ioctl_data_has_arrived;
-	wait_queue_head_t ioctl_wait_q;
+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;
+};
 
-/* stuff under 2 gb */
-	struct qeth_dma_stuff *dma_stuff;
+/*
+ * thread bits for qeth_card thread masks
+ */
+enum qeth_threads {
+	QETH_SET_IP_THREAD  = 1,
+	QETH_SET_MC_THREAD  = 2,
+	QETH_RECOVER_THREAD = 4,
+};
 
-	unsigned int ipa_timeout;
+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;
 
-	atomic_t write_busy;
+	struct net_device *dev;
+	struct net_device_stats stats;
 
-	/* vipa stuff */
-	rwlock_t vipa_list_lock;
-	struct qeth_vipa_entry *vipa_list;
+	struct qeth_card_info info;
+	struct qeth_token token;
+	struct qeth_seqno seqno;
+	struct qeth_card_options options;
 
-	/* state information when doing I/O */
-	atomic_t shutdown_phase;
-	atomic_t data_has_arrived;
 	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;
+};
 
-	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;
-
-	int broadcast_capable;
-	int portname_required;
-
-	int realloc_message;
-
-	char level[QETH_MCL_LENGTH + 1];
-
-	volatile int saved_dev_flags;
-
-	/* 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 framesi
 }
 
 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;
+}
+
+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]);
 }
 
-/******************** 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 */
-
-#define PRINTK_HEADER QETH_NAME ": "
-
-#if QETH_VERBOSE_LEVEL>8
-#define PRINT_STUPID(x...) printk( KERN_DEBUG PRINTK_HEADER x)
-#else
-#define PRINT_STUPID(x...)
-#endif
+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;
+}
+
+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 -puN /dev/null drivers/s390/net/qeth_main.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/s390/net/qeth_main.c	2004-04-08 13:55:46.761915280 -0700
@@ -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");
diff -puN drivers/s390/net/qeth_mpc.c~s390-12-12-rewritten-qeth-driver drivers/s390/net/qeth_mpc.c
--- 25/drivers/s390/net/qeth_mpc.c~s390-12-12-rewritten-qeth-driver	2004-04-08 13:55:46.665929872 -0700
+++ 25-akpm/drivers/s390/net/qeth_mpc.c	2004-04-08 13:55:46.762915128 -0700
@@ -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[]={
 
 
 
-
diff -puN drivers/s390/net/qeth_mpc.h~s390-12-12-rewritten-qeth-driver drivers/s390/net/qeth_mpc.h
--- 25/drivers/s390/net/qeth_mpc.h~s390-12-12-rewritten-qeth-driver	2004-04-08 13:55:46.667929568 -0700
+++ 25-akpm/drivers/s390/net/qeth_mpc.h	2004-04-08 13:55:46.767914368 -0700
@@ -5,215 +5,279 @@
  *
  * 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 QETH_MPC_TOKEN_LENGTH 4
-#define QETH_SEQ_NO_LENGTH 4
-#define QETH_IPA_SEQ_NO_LENGTH 2
-
-#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[];
+#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)
 
-extern unsigned char IDX_ACTIVATE_WRITE[];
+extern unsigned char IPA_PDU_HEADER[];
+#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
 
-#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 IPA_CMD_LENGTH	(IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
 
-#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
+#define QETH_SEQ_NO_LENGTH 	4
+#define QETH_MPC_TOKEN_LENGTH 	4
+#define QETH_MCL_LENGTH		4
+#define OSA_ADDR_LEN		6
+
+#define QETH_TIMEOUT 		(10 * HZ)
+#define QETH_IDX_COMMAND_SEQNO 	-1
+#define SR_INFO_LEN		16
+
+#define QETH_CLEAR_CHANNEL_PARM	-10
+#define QETH_HALT_CHANNEL_PARM	-11
+
+/*****************************************************************************/
+/* IP Assist related definitions                                             */
+/*****************************************************************************/
+#define IPA_CMD_INITIATOR_HOST  0x00
+#define IPA_CMD_INITIATOR_HYDRA 0x01
+#define IPA_CMD_PRIM_VERSION_NO 0x01
+
+enum qeth_card_types {
+	QETH_CARD_TYPE_UNKNOWN = 0,
+	QETH_CARD_TYPE_OSAE    = 10,
+	QETH_CARD_TYPE_IQD     = 1234,
+};
 
-#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
-#define QETH_MCL_LENGTH 4
+#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,
+};
 
-extern unsigned char CM_ENABLE[];
+enum qeth_tr_macaddr_modes {
+	QETH_TR_MACADDR_NONCANONICAL = 0,
+	QETH_TR_MACADDR_CANONICAL    = 1,
+};
 
-#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_broadcast_modes {
+	QETH_TR_BROADCAST_ALLRINGS = 0,
+	QETH_TR_BROADCAST_LOCAL    = 1,
+};
 
-#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
-						  0x13)
+/* 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
 
-extern unsigned char CM_SETUP[];
+/*
+ * 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_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
-#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
 
-#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) (PDU_ENCAPSULATION(buffer)+ \
-					      0x1a)
+/* 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,
+};
 
-extern unsigned char ULP_ENABLE[];
+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_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_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,
+};
 
-#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)
+/* 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,
+};
 
-extern unsigned char ULP_SETUP[];
+/* 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_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)
+/* 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,
+};
 
-#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) (PDU_ENCAPSULATION \
-						      (buffer)+0x1a)
+/* 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,
 
-extern unsigned char DM_ACT[];
 
-#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
-#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
+};
+/* (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 number_of_replies;
+	__u8 seq_no;
+} __attribute__((packed));
+
+/* SETASSPARMS IPA Command: */
+struct qeth_ipacmd_setassparms {
+	struct qeth_ipacmd_setassparms_hdr hdr;
+	union {
+		__u32 flags_32bit;
+		struct qeth_arp_cache_entry add_arp_entry;
+		__u8 ip[16];
+	} data;
+} __attribute__ ((packed));
 
-#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
+/* SETRTG IPA Command:    ****************************************************/
+struct qeth_set_routing {
+	__u8 type;
+};
 
-#define IPA_SETADP_CMDSIZE 40
+/* 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 ipa_setadp_cmd {
+struct qeth_ipacmd_setadpparms {
 	__u32 supp_hw_cmds;
 	__u32 reserved1;
 	__u16 cmdlength;
@@ -224,221 +288,197 @@ struct ipa_setadp_cmd {
 	__u8 frame_seq_no;
 	__u32 reserved3;
 	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;
+		struct qeth_query_cmds_supp query_cmds_supp;
+		struct qeth_change_addr change_addr;
 		__u32 mode;
 	} data;
-};
+} __attribute__ ((packed));
 
-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));
+/* IPFRAME IPA Command:    ***************************************************/
+/* TODO: define in analogy to commands define above */
 
-#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
+/* ADD_ADDR_ENTRY IPA Command:    ********************************************/
+/* TODO: define in analogy to commands define above */
 
-struct snmp_ipa_setadp_cmd {
-	__u32 supp_hw_cmds;
-	__u32 reserved1;
-	__u16 cmdlength;
-	__u16 reserved2;
-	__u32 command_code;
-	__u16 return_code;
-	__u8 frames_used_total;
-	__u8 frame_seq_no;
-	__u32 reserved3;
-	__u8 snmp_token[16];
+/* 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 snmp_request;
-			__u32 snmp_interface;
-			__u32 snmp_returncode;
-			__u32 snmp_firmwarelevel;
-			__u32 snmp_seqno;
-			__u8 snmp_data[ARP_DATA_SIZE];
-		} snmp_subcommand;
+		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,
+};
 
-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;
+#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_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 {
-			__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_arp_query_data query_arp;
 	} data;
-}__attribute__ ((packed));
+} __attribute__((packed));
 
 
+/* Helper functions */
+#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST)
 
-#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)
+/*****************************************************************************/
+/* END OF   IP Assist related definitions                                    */
+/*****************************************************************************/
 
-extern unsigned char IPA_PDU_HEADER[];
-
-#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
 
-#define PDU_ENCAPSULATION(buffer) \
-	(buffer+ \
-	 *(buffer+ (*(buffer+0x0b))+ *(buffer+*(buffer+0x0b)+0x11) +0x07))
+extern unsigned char WRITE_CCW[];
+extern unsigned char READ_CCW[];
 
-#define IS_IPA(buffer) ((buffer) && ( *(buffer+ ((*(buffer+0x0b))+4) )==0xc1) )
+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 IS_IPA_REPLY(buffer) ( (buffer) && ( (*(PDU_ENCAPSULATION(buffer)+1))==INITIATOR_HOST ) )
+#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) \
+		(PDU_ENCAPSULATION(buffer)+ 0x13)
 
-#define CCW_NOP_CMD 0x03
-#define CCW_NOP_COUNT 1
 
-extern unsigned char WRITE_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)
 
-extern unsigned char READ_CCW[];
+#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) \
+		(PDU_ENCAPSULATION(buffer) + 0x1a)
 
-#endif /* __QETH_MPC_H__ */
+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 -puN /dev/null drivers/s390/net/qeth_proc.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/s390/net/qeth_proc.c	2004-04-08 13:55:46.769914064 -0700
@@ -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 -puN /dev/null drivers/s390/net/qeth_sys.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/drivers/s390/net/qeth_sys.c	2004-04-08 13:55:46.775913152 -0700
@@ -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);
+}
diff -puN /dev/null include/asm-s390/qeth.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ 25-akpm/include/asm-s390/qeth.h	2004-04-08 13:55:46.775913152 -0700
@@ -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__ */

_