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

 - ctc/iucv: Add module author/description/license to fsm.c
 - ctc/lcs/iucv/qeth: Remove dst_link_failure calls because they can
   trigger a BUG in icmp.c.
 - ctc/iucv/qeth: Use s390_root_dev_{register,unregister} to fix reference
   counting for the group device sysfs root object.
 - ctc/lcs/qeth: Fix ccwgroup behaviour, remove should not imply offline.
 - ctc: Adapt to notify api change in cio.
 - ctc: Remove duplicate put_user.
 - iucv: Fix oops with empty netiucv peer name.
 - iucv: Use GFP_ATOMIC for kmalloc from tasklet.
 - iucv: Fix removal of attritubes.
 - qeth: Use correct length in clearing of MAC address.
 - qeth: Queue multicast and broadcast packets into the last
   queue on HiperSocket.
 - qeth: Reenable send control data after i/o error.
 - qeth: Find correct recbuf in qeth_send_control_data.
 - qeth: Handle VM startlan disabled.
 - qeth: Set flags for vipa entries.
 - qeth: Correct netmask on vipa setting.
 - qeth: Fix spinlock problems ("scheduling while atomic").
 - qeth: Avoid setting multicast IP addresses several times.
 - qeth: Fix /proc/qeth format.
 - qeth: Fix race on device removal.



---

 25-akpm/drivers/s390/net/ctcmain.c  |   18 +-
 25-akpm/drivers/s390/net/ctctty.c   |    3 
 25-akpm/drivers/s390/net/cu3088.c   |   25 +--
 25-akpm/drivers/s390/net/fsm.c      |    6 
 25-akpm/drivers/s390/net/iucv.c     |   37 +++--
 25-akpm/drivers/s390/net/iucv.h     |    2 
 25-akpm/drivers/s390/net/lcs.c      |   17 +-
 25-akpm/drivers/s390/net/netiucv.c  |   16 +-
 25-akpm/drivers/s390/net/qeth.c     |  226 ++++++++++++++++++++++--------------
 25-akpm/drivers/s390/net/qeth.h     |   12 +
 25-akpm/drivers/s390/net/qeth_mpc.h |    8 -
 11 files changed, 217 insertions(+), 153 deletions(-)

diff -puN drivers/s390/net/ctcmain.c~s390-06-network-drivers drivers/s390/net/ctcmain.c
--- 25/drivers/s390/net/ctcmain.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/ctcmain.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.47 2003/09/22 13:40:51 cohuck Exp $
+ * $Id: ctcmain.c,v 1.50 2003/12/02 15:18:50 cohuck Exp $
  *
  * CTC / ESCON network driver
  *
@@ -36,7 +36,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.47 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.50 $
  *
  */
 
@@ -272,7 +272,7 @@ static void
 print_banner(void)
 {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.47 $";
+	char vbuf[] = "$Revision: 1.50 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -2441,14 +2441,12 @@ ctc_tx(struct sk_buff *skb, struct net_d
 
 	/**
 	 * If channels are not running, try to restart them
-	 * notify anybody about a link failure and throw
-	 * away packet. 
+	 * and throw away packet. 
 	 */
 	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
 		fsm_event(privptr->fsm, DEV_EVENT_START, dev);
 		if (privptr->protocol == CTC_PROTO_LINUX_TTY)
 			return -EBUSY;
-		dst_link_failure(skb);
 		dev_kfree_skb(skb);
 		privptr->stats.tx_dropped++;
 		privptr->stats.tx_errors++;
@@ -2994,20 +2992,20 @@ ctc_shutdown_device(struct ccwgroup_devi
 
 }
 
-static int
+static void
 ctc_remove_device(struct ccwgroup_device *cgdev)
 {
 	struct ctc_priv *priv;
 
 	priv = cgdev->dev.driver_data;
 	if (!priv)
-		return 0;
-
+		return;
+	if (cgdev->state == CCWGROUP_ONLINE)
+		ctc_shutdown_device(cgdev);
 	ctc_remove_files(&cgdev->dev);
 	cgdev->dev.driver_data = NULL;
 	kfree(priv);
 	put_device(&cgdev->dev);
-	return 0;
 }
 
 static struct ccwgroup_driver ctc_group_driver = {
diff -puN drivers/s390/net/ctctty.c~s390-06-network-drivers drivers/s390/net/ctctty.c
--- 25/drivers/s390/net/ctctty.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/ctctty.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.13 2003/09/26 14:48:36 mschwide Exp $
+ * $Id: ctctty.c,v 1.14 2003/10/06 11:33:33 mschwide Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -761,7 +761,6 @@ ctc_tty_ioctl(struct tty_struct *tty, st
 			error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
 			if (error)
 				return error;
-			put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
 			return 0;
 		case TIOCSSOFTCAR:
 #ifdef CTC_DEBUG_MODEM_IOCTL
diff -puN drivers/s390/net/cu3088.c~s390-06-network-drivers drivers/s390/net/cu3088.c
--- 25/drivers/s390/net/cu3088.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/cu3088.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: cu3088.c,v 1.31 2003/09/29 15:24:27 cohuck Exp $
+ * $Id: cu3088.c,v 1.33 2003/10/14 12:10:19 cohuck Exp $
  *
  * CTC / LCS ccw_device driver
  *
@@ -25,6 +25,7 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <asm/ccwdev.h>
 #include <asm/ccwgroup.h>
@@ -55,15 +56,7 @@ static struct ccw_device_id cu3088_ids[]
 
 static struct ccw_driver cu3088_driver;
 
-static void
-cu3088_root_dev_release (struct device *dev)
-{
-}
-
-struct device cu3088_root_dev = {
-	.bus_id = "cu3088",
-	.release = cu3088_root_dev_release,
-};
+struct device *cu3088_root_dev;
 
 static ssize_t
 group_write(struct device_driver *drv, const char *buf, size_t count)
@@ -90,7 +83,7 @@ group_write(struct device_driver *drv, c
 		start = end + 1;
 	}
 
-	ret = ccwgroup_create(&cu3088_root_dev, cdrv->driver_id,
+	ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
 			      &cu3088_driver, 2, argv);
 
 	return (ret == 0) ? count : ret;
@@ -144,12 +137,12 @@ cu3088_init (void)
 {
 	int rc;
 	
-	rc = device_register(&cu3088_root_dev);
-	if (rc)
-		return rc;
+	cu3088_root_dev = s390_root_dev_register("cu3088");
+	if (IS_ERR(cu3088_root_dev))
+		return PTR_ERR(cu3088_root_dev);
 	rc = ccw_driver_register(&cu3088_driver);
 	if (rc)
-		device_unregister(&cu3088_root_dev);
+		s390_root_dev_unregister(cu3088_root_dev);
 
 	return rc;
 }
@@ -158,7 +151,7 @@ static void __exit
 cu3088_exit (void)
 {
 	ccw_driver_unregister(&cu3088_driver);
-	device_unregister(&cu3088_root_dev);
+	s390_root_dev_unregister(cu3088_root_dev);
 }
 
 MODULE_DEVICE_TABLE(ccw,cu3088_ids);
diff -puN drivers/s390/net/fsm.c~s390-06-network-drivers drivers/s390/net/fsm.c
--- 25/drivers/s390/net/fsm.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/fsm.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /**
- * $Id: fsm.c,v 1.4 2003/03/28 08:54:40 mschwide Exp $
+ * $Id: fsm.c,v 1.6 2003/10/15 11:37:29 mschwide Exp $
  *
  * A generic FSM based on fsm used in isdn4linux
  *
@@ -10,6 +10,10 @@
 #include <linux/module.h>
 #include <linux/timer.h>
 
+MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
+MODULE_DESCRIPTION("Finite state machine helper functions");
+MODULE_LICENSE("GPL");
+
 fsm_instance *
 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
 		int nr_events, const fsm_node *tmpl, int tmpl_len, int order)
diff -puN drivers/s390/net/iucv.c~s390-06-network-drivers drivers/s390/net/iucv.c
--- 25/drivers/s390/net/iucv.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/iucv.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /* 
- * $Id: iucv.c,v 1.15 2003/10/01 09:25:15 mschwide Exp $
+ * $Id: iucv.c,v 1.19 2003/12/18 15:28:49 braunu Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.15 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.19 $
  *
  */
 
@@ -44,12 +44,14 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/device.h>
 #include <asm/atomic.h>
 #include "iucv.h"
 #include <asm/io.h>
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
+#include <asm/ccwdev.h> //for root device stuff
 
 #define DEBUG
 
@@ -79,20 +81,12 @@ iucv_bus_match (struct device *dev, stru
 	return 0;
 }
 
-static void
-iucv_root_release (struct device *dev)
-{
-}
-
 struct bus_type iucv_bus = {
 	.name = "iucv",
 	.match = iucv_bus_match,
 };	
 
-struct device iucv_root = {
-	.bus_id = "iucv",
-	.release = iucv_root_release,
-};
+struct device *iucv_root;
 
 /* General IUCV interrupt structure */
 typedef struct {
@@ -355,7 +349,7 @@ do { \
 static void
 iucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.15 $";
+	char vbuf[] = "$Revision: 1.19 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
@@ -378,6 +372,11 @@ iucv_init(void)
 {
 	int ret;
 
+	if (!MACHINE_IS_VM) {
+		printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
+		return -EPROTONOSUPPORT;
+	}
+
 	if (iucv_external_int_buffer)
 		return 0;
 
@@ -387,11 +386,11 @@ iucv_init(void)
 		return ret;
 	}
 
-	ret = device_register(&iucv_root);
-	if (ret != 0) {
+	iucv_root = s390_root_dev_register("iucv");
+	if (IS_ERR(iucv_root)) {
 		printk(KERN_ERR "IUCV: failed to register iucv root.\n");
 		bus_unregister(&iucv_bus);
-		return ret;
+		return PTR_ERR(iucv_root);
 	}
 
 	/* Note: GFP_DMA used used to get memory below 2G */
@@ -401,6 +400,7 @@ iucv_init(void)
 		printk(KERN_WARNING
 		       "%s: Could not allocate external interrupt buffer\n",
 		       __FUNCTION__);
+		s390_root_dev_unregister(iucv_root);
 		return -ENOMEM;
 	}
 	memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt));
@@ -413,6 +413,7 @@ iucv_init(void)
 		       __FUNCTION__);
 		kfree(iucv_external_int_buffer);
 		iucv_external_int_buffer = NULL;
+		s390_root_dev_unregister(iucv_root);
 		return -ENOMEM;
 	}
 	memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE);
@@ -439,7 +440,7 @@ iucv_exit(void)
 		kfree(iucv_external_int_buffer);
 	if (iucv_param_pool)
 		kfree(iucv_param_pool);
-	device_unregister(&iucv_root);
+	s390_root_dev_unregister(iucv_root);
 	bus_unregister(&iucv_bus);
 	printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
 }
@@ -772,7 +773,7 @@ iucv_register_program (__u8 pgmname[16],
 	}
 
 	/* Allocate handler entry */
-	new_handler = (handler *)kmalloc(sizeof(handler), GFP_KERNEL);
+	new_handler = (handler *)kmalloc(sizeof(handler), GFP_ATOMIC);
 	if (new_handler == NULL) {
 		printk(KERN_WARNING "%s: storage allocation for new handler "
 		       "failed.\n", __FUNCTION__);
@@ -787,7 +788,7 @@ iucv_register_program (__u8 pgmname[16],
 
 		max_connections = iucv_query_maxconn();
 		iucv_pathid_table = kmalloc(max_connections * sizeof(handler *),
-				       GFP_KERNEL);
+				       GFP_ATOMIC);
 		if (iucv_pathid_table == NULL) {
 			printk(KERN_WARNING "%s: iucv_pathid_table storage "
 			       "allocation failed\n", __FUNCTION__);
diff -puN drivers/s390/net/iucv.h~s390-06-network-drivers drivers/s390/net/iucv.h
--- 25/drivers/s390/net/iucv.h~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/iucv.h	Thu Jan  8 14:11:32 2004
@@ -203,7 +203,7 @@ typedef struct {
 } iucv_array_t __attribute__ ((aligned (8)));
 
 extern struct bus_type iucv_bus;
-extern struct device iucv_root;
+extern struct device *iucv_root;
 
 /*   -prototypes-    */
 /*                                                                
diff -puN drivers/s390/net/lcs.c~s390-06-network-drivers drivers/s390/net/lcs.c
--- 25/drivers/s390/net/lcs.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/lcs.c	Thu Jan  8 14:11:32 2004
@@ -11,7 +11,7 @@
  *			  Frank Pavlic (pavlic@de.ibm.com) and
  *		 	  Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.58 $	 $Date: 2003/09/22 13:33:56 $
+ *    $Revision: 1.61 $	 $Date: 2003/12/02 15:18:50 $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -58,7 +58,7 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.58 $"
+#define VERSION_LCS_C  "$Revision: 1.61 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
 
@@ -1168,7 +1168,6 @@ __lcs_start_xmit(struct lcs_card *card, 
 		return -EIO;
 	}
 	if (card->state != DEV_STATE_UP) {
-		dst_link_failure(skb);
 		dev_kfree_skb(skb);
 		card->stats.tx_dropped++;
 		card->stats.tx_errors++;
@@ -1891,7 +1890,7 @@ lcs_shutdown_device(struct ccwgroup_devi
 /**
  * lcs_remove_device, free buffers and card
  */
-static int
+static void
 lcs_remove_device(struct ccwgroup_device *ccwgdev)
 {
 	struct lcs_card *card;
@@ -1899,12 +1898,18 @@ lcs_remove_device(struct ccwgroup_device
 	LCS_DBF_TEXT(3, setup, "remdev");
 	card = (struct lcs_card *)ccwgdev->dev.driver_data;
 	if (!card)
-		return 0;
+		return;
+	if (ccwgdev->state == CCWGROUP_ONLINE) {
+		lcs_stop_device(card->dev); /* Ignore rc. */
+		sysfs_remove_link(&card->dev->class_dev.kobj,
+				  ccwgdev->dev.bus_id);
+		sysfs_remove_link(&ccwgdev->dev.kobj, card->dev->name);
+		unregister_netdev(card->dev);
+	}
 	sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);
 	lcs_cleanup_card(card);
 	lcs_free_card(card);
 	put_device(&ccwgdev->dev);
-	return 0;
 }
 
 /**
diff -puN drivers/s390/net/netiucv.c~s390-06-network-drivers drivers/s390/net/netiucv.c
--- 25/drivers/s390/net/netiucv.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/netiucv.c	Thu Jan  8 14:11:32 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.26 2003/09/23 16:48:17 mschwide Exp $
+ * $Id: netiucv.c,v 1.30 2003/12/02 12:29:32 braunu Exp $
  *
  * IUCV network driver
  *
@@ -30,7 +30,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.26 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.30 $
  *
  */
 
@@ -1177,12 +1177,10 @@ static int netiucv_tx(struct sk_buff *sk
 
 	/**
 	 * If connection is not running, try to restart it
-	 * notify anybody about a link failure and throw
-	 * away packet. 
+	 * and throw away packet. 
 	 */
 	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
 		fsm_event(privptr->fsm, DEV_EVENT_START, dev);
-		dst_link_failure(skb);
 		dev_kfree_skb(skb);
 		privptr->stats.tx_dropped++;
 		privptr->stats.tx_errors++;
@@ -1464,7 +1462,7 @@ netiucv_add_files(struct device *dev)
 		return ret;
 	ret = sysfs_create_group(&dev->kobj, &netiucv_stat_attr_group);
 	if (ret)
-		sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
+		sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
 	return ret;
 }
 
@@ -1472,7 +1470,7 @@ static inline void
 netiucv_remove_files(struct device *dev)
 {
 	sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
-	sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group);
+	sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
 }
 
 static int
@@ -1485,7 +1483,7 @@ netiucv_register_device(struct net_devic
 
 	snprintf(dev->bus_id, BUS_ID_SIZE, "%s%x", str, ifno);
 	dev->bus = &iucv_bus;
-	dev->parent = &iucv_root;
+	dev->parent = iucv_root;
 
 	ret = device_register(dev);
 
@@ -1731,7 +1729,7 @@ static struct device_driver netiucv_driv
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.26 $";
+	char vbuf[] = "$Revision: 1.30 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff -puN drivers/s390/net/qeth.c~s390-06-network-drivers drivers/s390/net/qeth.c
--- 25/drivers/s390/net/qeth.c~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/qeth.c	Thu Jan  8 14:11:32 2004
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth.c ($Revision: 1.160 $)
+ * linux/drivers/s390/net/qeth.c ($Revision: 1.177 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -11,6 +11,7 @@
  *                                               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
@@ -165,7 +166,7 @@ MODULE_PARM_DESC(qeth_sparebufs, "the nu
 		 "reserved for low memory situations");
 
 /****************** MODULE STUFF **********************************/
-#define VERSION_QETH_C "$Revision: 1.160 $"
+#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 ")";
@@ -314,6 +315,21 @@ my_spin_lock_nonbusy(struct qeth_card *c
 	}
 }
 
+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 */
@@ -612,6 +628,10 @@ 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) ||
@@ -622,20 +642,38 @@ qeth_is_multicast_skb_at_all(struct sk_b
 		return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
 	} else if (version == 6) {
 		return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
-	} else {
-		PRINT_STUPID("QETH_IP_VERSION is %x\n", version);
-		PRINT_STUPID("skb->protocol=x%x=%i\n",
-			     skb->protocol, skb->protocol);
-		HEXDUMP16(STUPID, "skb:", skb->data);
 	}
-	return 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)
+	if (!version && (card->type == QETH_CARD_TYPE_OSAE))
 		return QETH_DEFAULT_QUEUE;
 	switch (card->no_queues) {
 	case 1:
@@ -1327,7 +1365,7 @@ __qeth_rebuild_skb_fake_ll(struct qeth_c
 		       QETH_FAKE_LL_ADDR_LEN);
 	} else {
 		/* clear source MAC for security reasons */
-		memset(skb->mac.raw + QETH_FAKE_LL_DEST_MAC_POS,
+		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,
@@ -1947,7 +1985,6 @@ qeth_free_buffer(struct qeth_card *card,
 			case ERROR_LINK_FAILURE:
 			case ERROR_KICK_THAT_PUPPY:
 				QETH_DBF_TEXT4(0, trace, "endeglnd");
-				dst_link_failure(skb);
 				atomic_dec(&skb->users);
 				dev_kfree_skb_irq(skb);
 				break;
@@ -2425,7 +2462,6 @@ qeth_hard_start_xmit(struct sk_buff *skb
 
 	if (!card) {
 		QETH_DBF_TEXT2(0, trace, "XMNSNOCD");
-		dst_link_failure(skb);
 		dev_kfree_skb_irq(skb);
 		return 0;
 	}
@@ -2436,7 +2472,6 @@ qeth_hard_start_xmit(struct sk_buff *skb
 	if (!atomic_read(&card->is_startlaned)) {
 		card->stats->tx_carrier_errors++;
 		QETH_DBF_CARD2(0, trace, "XMNS", card);
-		dst_link_failure(skb);
 		dev_kfree_skb_irq(skb);
 		return 0;
 	}
@@ -2548,7 +2583,8 @@ static void
 qeth_wakeup_procfile(void)
 {
 	QETH_DBF_TEXT5(0, trace, "procwkup");
-	if (atomic_read(&qeth_procfile_ioctl_sem.count) <
+	/* is this if statement correct? */
+	if (atomic_read(&qeth_procfile_ioctl_sem.count) <=
 	    PROCFILE_SLEEP_SEM_MAX_VALUE)
 		up(&qeth_procfile_ioctl_sem);
 }
@@ -2558,7 +2594,6 @@ qeth_sleepon_procfile(void)
 {
 	QETH_DBF_TEXT5(0, trace, "procslp");
 	if (down_interruptible(&qeth_procfile_ioctl_sem)) {
-		up(&qeth_procfile_ioctl_sem);
 		return -ERESTARTSYS;
 	}
 	return 0;
@@ -2634,6 +2669,8 @@ again:
 		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;
 	}
 
@@ -2644,7 +2681,7 @@ again:
 			atomic_set(&card->write_busy, 0);
 			return NULL;
 		}
-		rec_buf = card->ipa_buf;
+		rec_buf = card->dma_stuff->recbuf;
 		QETH_DBF_CARD2(0, trace, "scro", card);
 	} else {
 		if (qeth_sleepon(card, (setip) ? QETH_IPA_TIMEOUT :
@@ -3350,6 +3387,11 @@ qeth_send_setdelipm(struct qeth_card *ca
 			  (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")
 
@@ -3392,7 +3434,8 @@ retry:
 		QETH_DBF_TEXT2(0, trace, dbf_text);
 	}
 
-	if (((result == -1) || (result == 0xe080)) && (retries--)) {
+	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);
@@ -3557,8 +3600,8 @@ qeth_set_vipas(struct qeth_card *card, i
 							   le is last entry */
 	char dbf_text[15];
 	int result;
-	__u8 netmask[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+	__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;
@@ -3576,9 +3619,10 @@ qeth_set_vipas(struct qeth_card *card, i
 			 * so we clone the entry */
 			ne = (struct qeth_vipa_entry *)
 			    kmalloc(sizeof (struct qeth_vipa_entry),
-				    GFP_KERNEL);
+				    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;
@@ -3613,6 +3657,7 @@ qeth_set_vipas(struct qeth_card *card, i
 				    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;
@@ -3645,7 +3690,7 @@ qeth_set_vipas(struct qeth_card *card, i
 			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 %08x"
+				PRINT_ERR("going to leave vipa/rxip x%08x"
 					  "unset...\n",
 					  *((__u32 *) & priv_add_list->ip[0]));
 				sprintf(dbf_text, "%08x",
@@ -4085,6 +4130,9 @@ __qeth_setipms_ipv6(struct qeth_card *ca
 	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;
 		}
@@ -4118,8 +4166,13 @@ __qeth_setipms_ipv6(struct qeth_card *ca
 				  CARD_BUS_ID(card), result);
  			sprintf(dbf_text, "sms6%4x", result);
  			QETH_DBF_TEXT3(0, trace, dbf_text);
-			qeth_remove_mc_ifa_from_list
-				(&card->ip_mc_current_state.ipm6_ifa, addr);
+		} 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;
 	}
@@ -4555,7 +4608,7 @@ __qeth_takeover_ip_ipms6_mc(struct qeth_
 			ndisc_mc_map(&im6->mca_addr, buf, card->dev, 0);
 			ipmanew =
 			    (struct qeth_ipm_mac *)
-			    kmalloc(sizeof (struct qeth_ipm_mac), GFP_KERNEL);
+			    kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
 			if (!ipmanew) {
 				PRINT_WARN("No memory for IPM address "
 					   "handling. Multicast IP "
@@ -4630,7 +4683,7 @@ qeth_takeover_ip_ipms6(struct qeth_card 
 
 		while (ifa) {
 			ifanew =
-			    kmalloc(sizeof (struct inet6_ifaddr), GFP_KERNEL);
+			    kmalloc(sizeof (struct inet6_ifaddr), GFP_ATOMIC);
 			if (!ifanew) {
 				PRINT_WARN("No memory for IP address "
 					   "handling. Some of the IPs "
@@ -4864,7 +4917,7 @@ __qeth_takeover_ip_ipms_mc(struct qeth_c
 			qeth_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
 			ipmanew =
 			    (struct qeth_ipm_mac *)
-			    kmalloc(sizeof (struct qeth_ipm_mac), GFP_KERNEL);
+			    kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
 			if (!ipmanew) {
 				PRINT_WARN("No memory for IPM address "
 					   "handling. Multicast IP %08x"
@@ -4930,7 +4983,7 @@ qeth_takeover_ip_ipms(struct qeth_card *
 		ifa = ((struct in_device *) card->dev->ip_ptr)->ifa_list;
 
 		while (ifa) {
-			ifanew = kmalloc(sizeof (struct in_ifaddr), GFP_KERNEL);
+			ifanew = kmalloc(sizeof (struct in_ifaddr), GFP_ATOMIC);
 			if (!ifanew) {
 				PRINT_WARN("No memory for IP address "
 					   "handling. Some of the IPs "
@@ -5212,7 +5265,7 @@ __qeth_softsetup_enable_ipv6(struct qeth
 			QETH_DBF_TEXT2(0, trace, dbf_text);
 			atomic_set(&card->is_softsetup, 0);
 			/* do not return an error */
-			if (result == 0xe080)
+			if ((result == 0xe080) || (result == 0xf080))
 				result = 0;
 			return result;
 		}
@@ -5300,13 +5353,17 @@ __qeth_softsetup_start_assists(struct qe
 				   "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) {
+			if ((result == 0xe080) || (result == 0xf080)) {
 				result = 0;
 			}
 			return result;
@@ -5527,7 +5584,10 @@ __qeth_softsetup_routingv6(struct qeth_c
 	if (!atomic_read(&card->enable_routing_attempts6))
 		return;
 
-	if (!card->options.routing_type6) {
+	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;
@@ -5580,9 +5640,9 @@ qeth_softsetup_card(struct qeth_card *ca
 	int use_setip_retries = 1;
 
 	if (wait_for_lock == QETH_WAIT_FOR_LOCK) {
-		spin_lock(&card->softsetup_lock);
+		down(&card->softsetup_sema);
 	} else if (wait_for_lock == QETH_DONT_WAIT_FOR_LOCK) {
-		if (!spin_trylock(&card->softsetup_lock)) {
+		if (!down_trylock(&card->softsetup_sema)) {
 			return -EAGAIN;
 		}
 	} else if (wait_for_lock == QETH_LOCK_ALREADY_HELD) {
@@ -5634,7 +5694,7 @@ out:
 		netif_wake_queue(card->dev);
 	}
 	if (wait_for_lock != QETH_LOCK_ALREADY_HELD)
-		spin_unlock(&card->softsetup_lock);
+		up(&card->softsetup_sema);
 	return result;
 }
 
@@ -7835,7 +7895,7 @@ qeth_hardsetup_card(struct qeth_card *ca
 	cleanup_qdio = in_recovery;	/* if we are in recovery, we clean
 					   the qdio stuff up */
 
-	spin_lock(&card->hardsetup_lock);
+	down(&card->hardsetup_sema);
 	atomic_set(&card->write_busy, 0);
 
 	do {
@@ -8146,7 +8206,7 @@ qeth_hardsetup_card(struct qeth_card *ca
 	}
 
 exit:
-	spin_unlock(&card->hardsetup_lock);
+	up(&card->hardsetup_sema);
 	return result;
 }
 
@@ -8198,13 +8258,13 @@ qeth_reinit_thread(void *param)
 
 		atomic_set(&card->escape_softsetup, 1);
 
-		if (-1 == my_spin_lock_nonbusy(card, &card->softsetup_lock)) {
+		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)) {
-			spin_unlock(&card->softsetup_lock);
+			up(&card->softsetup_sema);
 			goto out_wakeup;
 		}
 		if (!qeth_verify_card(card))
@@ -8248,7 +8308,7 @@ qeth_reinit_thread(void *param)
 		} else {
 			QETH_DBF_TEXT1(0, trace, "ri-sftst");
 			qeth_softsetup_card(card, QETH_LOCK_ALREADY_HELD);
-			spin_unlock(&card->softsetup_lock);
+			up(&card->softsetup_sema);
 
 			if (!already_registered) {
 				QETH_DBF_TEXT1(0, trace, "ri-regcd");
@@ -8374,8 +8434,8 @@ qeth_alloc_card(void)
 
 	qeth_fill_qeth_card_options(card);
 
-	spin_lock_init(&card->softsetup_lock);
-	spin_lock_init(&card->hardsetup_lock);
+	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);
@@ -8571,7 +8631,8 @@ __qeth_correct_routing_status_v4(struct 
 		card->options.do_prio_queueing = NO_PRIO_QUEUEING;
 	} else {
 		/* if it's a mc router, it's no router */
-		if ((card->options.routing_type4 == MULTICAST_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 "
@@ -8599,7 +8660,8 @@ __qeth_correct_routing_status_v6(struct 
 		card->options.do_prio_queueing = NO_PRIO_QUEUEING;
 	} else {
 		/* if it's a mc router, it's no router */
-		if ((card->options.routing_type6 == MULTICAST_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 "
@@ -8851,11 +8913,11 @@ qeth_procfile_open(struct inode *inode, 
 
 	QETH_DBF_TEXT2(0, trace, "procread");
 	length += sprintf(buffer + length,
-			  "devices            CHPID     "
+			  "devices                  CHPID     "
 			  "device     cardtype port chksum prio-q'ing "
 			  "rtr fsz cnt\n");
 	length += sprintf(buffer + length,
-			  "-------------------- --- ----"
+			  "-------------------------- --- ----"
 			  "------ -------------- --     -- ---------- "
 			  "--- --- ---\n");
 	card = firstcard;
@@ -9509,19 +9571,20 @@ qeth_procfile_ioctl(struct inode *inode,
 {
 
 	int result;
-	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);
+	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;
 };
 
@@ -9779,15 +9842,7 @@ static struct ccw_driver qeth_ccw_driver
 	.remove = ccwgroup_remove_ccwdev,
 };
 
-static void
-qeth_root_dev_release (struct device *dev)
-{
-}
-
-static struct device qeth_root_dev = {
-	.bus_id = "qeth",
-	.release = qeth_root_dev_release,
-};
+static struct device *qeth_root_dev;
 
 static struct ccwgroup_driver qeth_ccwgroup_driver;
 static ssize_t
@@ -9813,7 +9868,7 @@ qeth_group_store(struct device_driver *d
 	}
 	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,
+	ccwgroup_create(qeth_root_dev, qeth_ccwgroup_driver.driver_id,
 			&qeth_ccw_driver, 3, argv);
 	return count;
 }
@@ -10675,19 +10730,6 @@ out:
 }
 
 static int
-qeth_remove_device(struct ccwgroup_device *gdev)
-{
-	struct qeth_card *card = gdev->dev.driver_data;
-
-	__qeth_remove_attributes(&gdev->dev);
-	gdev->dev.driver_data = NULL;
-	if (card)
-		qeth_free_card(card);
-	put_device(&gdev->dev);
-	return 0;
-}
-
-static int
 qeth_set_online(struct ccwgroup_device *gdev)
 {
 	int rc;
@@ -10723,6 +10765,21 @@ qeth_set_offline(struct ccwgroup_device 
 	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 = {
 	.name = "qeth",
 	.driver_id = 0xD8C5E3C8,
@@ -10773,10 +10830,11 @@ qeth_init(void)
 	if (result)
 		goto out_cdrv;
 
-	result = device_register(&qeth_root_dev);
-	if (result)
+	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();
 
@@ -10815,7 +10873,7 @@ qeth_exit(void)
 	driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group);
 	ccw_driver_unregister(&qeth_ccw_driver);
 	ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
-	device_unregister(&qeth_root_dev);
+	s390_root_dev_unregister(qeth_root_dev);
 
 	while (firstcard) {
 		struct qeth_card *card = firstcard;
diff -puN drivers/s390/net/qeth.h~s390-06-network-drivers drivers/s390/net/qeth.h
--- 25/drivers/s390/net/qeth.h~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/qeth.h	Thu Jan  8 14:11:32 2004
@@ -14,7 +14,7 @@
 
 #define QETH_NAME " qeth"
 
-#define VERSION_QETH_H "$Revision: 1.58 $"
+#define VERSION_QETH_H "$Revision: 1.60 $"
 
 /******************** CONFIG STUFF ***********************/
 //#define QETH_DBF_LIKE_HELL
@@ -288,6 +288,12 @@
 #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
@@ -888,8 +894,8 @@ struct qeth_card {	/* pointed to by dev-
 	atomic_t is_open;	/* card is in use */
 
 	/* prevents deadlocks :-O */
-	spinlock_t softsetup_lock;
-	spinlock_t hardsetup_lock;
+	struct semaphore softsetup_sema;
+	struct semaphore hardsetup_sema;
 	spinlock_t ioctl_lock;
 	atomic_t softsetup_thread_is_running;
 	struct semaphore softsetup_thread_sem;
diff -puN drivers/s390/net/qeth_mpc.h~s390-06-network-drivers drivers/s390/net/qeth_mpc.h
--- 25/drivers/s390/net/qeth_mpc.h~s390-06-network-drivers	Thu Jan  8 14:11:32 2004
+++ 25-akpm/drivers/s390/net/qeth_mpc.h	Thu Jan  8 14:11:32 2004
@@ -10,7 +10,7 @@
 #ifndef __QETH_MPC_H__
 #define __QETH_MPC_H__
 
-#define VERSION_QETH_MPC_H "$Revision: 1.16 $"
+#define VERSION_QETH_MPC_H "$Revision: 1.18 $"
 
 #define QETH_IPA_TIMEOUT (card->ipa_timeout)
 #define QETH_MPC_TIMEOUT 2000
@@ -143,6 +143,7 @@ extern unsigned char DM_ACT[];
 #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
@@ -319,8 +320,9 @@ struct ipa_cmd{
 }__attribute__ ((packed));
 
 #define QETH_IOC_MAGIC 0x22
-#define QETH_IOCPROC_OSAEINTERFACES _IOWR(QETH_IOC_MAGIC, 1, arg)
-#define QETH_IOCPROC_INTERFACECHANGES _IOWR(QETH_IOC_MAGIC, 2, arg)
+/* 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

_