]> git.hungrycats.org Git - linux/commitdiff
[PATCH] s390: network drivers
authorAndrew Morton <akpm@osdl.org>
Mon, 19 Jan 2004 02:41:35 +0000 (18:41 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Mon, 19 Jan 2004 02:41:35 +0000 (18:41 -0800)
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.

drivers/s390/net/ctcmain.c
drivers/s390/net/ctctty.c
drivers/s390/net/cu3088.c
drivers/s390/net/fsm.c
drivers/s390/net/iucv.c
drivers/s390/net/iucv.h
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth.c
drivers/s390/net/qeth.h
drivers/s390/net/qeth_mpc.h

index 1753099c579ff4fee77113319d1c0875d2a66376..19892aa07f4ef95a05a2e53b7d385f2ded4611c6 100644 (file)
@@ -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 $
  *
  */
 \f
@@ -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_device * dev)
 
        /**
         * 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_device *cgdev)
 
 }
 
-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 = {
index 659894f2697a8e5ce6028f8523a5ba2d7f80dee0..4c9aae83fb818cd2490442a141b94dc3dad1d743 100644 (file)
@@ -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, struct file *file,
                        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
index e8872b50490aff4d405572400b0fdf2bff2d062b..b79d08b42cff88d09217ff53f4f35166e06b9477 100644 (file)
@@ -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 @@
 \f
 #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, const char *buf, size_t count)
                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);
index d2519b01a987f11aa55c4ccfe6134af882a1675e..fa09440d82e549e59f0700ca09da9fed7fb31543 100644 (file)
@@ -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
  *
 #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)
index 555c6dd31da9055855036ffddf34c0c498198ec1..7a6e4eaf34e1d855cb3795481632b56c06e7bf54 100644 (file)
@@ -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 $
  *
  */
 \f
 #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, struct device_driver *drv)
        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__);
index 7bd3617fa03b143eb5935249ab1d16c5a11fde27..49f84e20308f36cdc5f61728dd7296fb7a055279 100644 (file)
@@ -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-    */
 /*                                                                
index 629c50496e145610cafb7f0ee09d12be9e7da357..e0e220e969d3719f601bdc3b7ffecab4580fc3ea 100644 (file)
@@ -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, struct sk_buff *skb,
                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_device *ccwgdev)
 /**
  * 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 *ccwgdev)
        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;
 }
 
 /**
index 61198556d46504d9b87e12dc295fc9168b30451e..da672160ed34baf6c3ddf51f310634933aaa4ffb 100644 (file)
@@ -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 $
  *
  */
 \f
@@ -1177,12 +1177,10 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
 
        /**
         * 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_device *ndev, int ifno)
 
        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_driver = {
 static void
 netiucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.26 $";
+       char vbuf[] = "$Revision: 1.30 $";
        char *version = vbuf;
 
        if ((version = strchr(version, ':'))) {
index 4c9dc2c02e5fc1d47f92d677be353b2907918122..a01fb0c89c18fbceccf9aa0ad20388e1f95f5106 100644 (file)
@@ -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 number of pre-allocated spare buffers "
                 "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 *card, spinlock_t * lock)
        }
 }
 
+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_buff *skb, int version)
                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_card *card, struct sk_buff *skb,
                       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, int queue, int bufno,
                        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, struct net_device *dev)
 
        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, struct net_device *dev)
        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 *card, __u8 * ip, __u8 * mac,
                          (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, int set_only)
                                                           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, int set_only)
                         * 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, int set_only)
                                    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, int set_only)
                        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 *card, int use_setipm_retries)
        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 *card, int use_setipm_retries)
                                  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_card *card, struct inet6_dev *in6_dev)
                        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 *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_card *card, struct in_device *in4_dev)
                        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 *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_card *card, int do_a_startlan6)
                        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 qeth_card *card)
                                   "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_card *card)
        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 *card, int wait_for_lock)
        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 *card, int in_recovery)
        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 *card, int in_recovery)
        }
 
 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 qeth_card *card)
                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 qeth_card *card)
                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, struct file *file)
 
        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, struct file *file,
 {
 
        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 *drv, const char *buf, size_t count)
        }
        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;
 }
@@ -10674,19 +10729,6 @@ out:
        return -ENODEV;
 }
 
-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)
 {
@@ -10723,6 +10765,21 @@ qeth_set_offline(struct ccwgroup_device *gdev)
        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;
index c038d68e9ef66dfceeb7f6e202d911a23255d683..dd77adb561223eb8cce991a4e1ece98f07e36195 100644 (file)
@@ -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
 #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->priv */
        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;
index 27064fac3dfd79b6b05b19e8766a69b225b04689..5998604695b66bd72264858a1699d51c87f7a559 100644 (file)
@@ -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