From: Martin Schwidefsky - 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 | 18 +-- drivers/s390/net/ctctty.c | 3 drivers/s390/net/cu3088.c | 25 +--- drivers/s390/net/fsm.c | 6 - drivers/s390/net/iucv.c | 37 +++---- drivers/s390/net/iucv.h | 2 drivers/s390/net/lcs.c | 17 ++- drivers/s390/net/netiucv.c | 16 +-- drivers/s390/net/qeth.c | 226 +++++++++++++++++++++++++++----------------- drivers/s390/net/qeth.h | 12 +- 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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/ctcmain.c 2004-01-14 02:10:26.000000000 -0800 @@ -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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/ctctty.c 2004-01-14 02:10:26.000000000 -0800 @@ -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. * @@ -746,7 +746,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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/cu3088.c 2004-01-14 02:10:26.000000000 -0800 @@ -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 #include +#include #include #include @@ -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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/fsm.c 2004-01-14 02:10:26.000000000 -0800 @@ -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 #include +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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/iucv.c 2004-01-14 02:10:26.000000000 -0800 @@ -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 #include #include +#include #include #include #include "iucv.h" #include #include #include +#include //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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/iucv.h 2004-01-14 02:10:26.000000000 -0800 @@ -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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/lcs.c 2004-01-14 02:10:26.000000000 -0800 @@ -11,7 +11,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Martin Schwidefsky * - * $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++; @@ -1890,7 +1889,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; @@ -1898,12 +1897,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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/netiucv.c 2004-01-14 02:10:26.000000000 -0800 @@ -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); } /* @@ -1493,7 +1491,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); @@ -1742,7 +1740,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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/qeth.c 2004-01-14 02:10:26.000000000 -0800 @@ -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 (query/purge ARP, SNMP, fixes) * Andreas Herrmann (bugfixes) + * Thomas Spatzier (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; } @@ -7807,7 +7867,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 { @@ -8118,7 +8178,7 @@ qeth_hardsetup_card(struct qeth_card *ca } exit: - spin_unlock(&card->hardsetup_lock); + up(&card->hardsetup_sema); return result; } @@ -8170,13 +8230,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)) @@ -8220,7 +8280,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"); @@ -8366,8 +8426,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); @@ -8563,7 +8623,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 " @@ -8591,7 +8652,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 " @@ -8843,11 +8905,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; @@ -9501,19 +9563,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; }; @@ -9771,15 +9834,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 @@ -9805,7 +9860,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; } @@ -10667,19 +10722,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; @@ -10715,6 +10757,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, @@ -10765,10 +10822,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(); @@ -10807,7 +10865,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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/qeth.h 2004-01-14 02:10:26.000000000 -0800 @@ -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 2004-01-14 02:10:26.000000000 -0800 +++ 25-akpm/drivers/s390/net/qeth_mpc.h 2004-01-14 02:10:26.000000000 -0800 @@ -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 _