Commit 99e0846e authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: network drivers

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.
parent 08f64b97
/* /*
* $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 * CTC / ESCON network driver
* *
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 ...@@ -272,7 +272,7 @@ static void
print_banner(void) print_banner(void)
{ {
static int printed = 0; static int printed = 0;
char vbuf[] = "$Revision: 1.47 $"; char vbuf[] = "$Revision: 1.50 $";
char *version = vbuf; char *version = vbuf;
if (printed) if (printed)
...@@ -2441,14 +2441,12 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev) ...@@ -2441,14 +2441,12 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
/** /**
* If channels are not running, try to restart them * If channels are not running, try to restart them
* notify anybody about a link failure and throw * and throw away packet.
* away packet.
*/ */
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) { if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev); fsm_event(privptr->fsm, DEV_EVENT_START, dev);
if (privptr->protocol == CTC_PROTO_LINUX_TTY) if (privptr->protocol == CTC_PROTO_LINUX_TTY)
return -EBUSY; return -EBUSY;
dst_link_failure(skb);
dev_kfree_skb(skb); dev_kfree_skb(skb);
privptr->stats.tx_dropped++; privptr->stats.tx_dropped++;
privptr->stats.tx_errors++; privptr->stats.tx_errors++;
...@@ -2994,20 +2992,20 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev) ...@@ -2994,20 +2992,20 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
} }
static int static void
ctc_remove_device(struct ccwgroup_device *cgdev) ctc_remove_device(struct ccwgroup_device *cgdev)
{ {
struct ctc_priv *priv; struct ctc_priv *priv;
priv = cgdev->dev.driver_data; priv = cgdev->dev.driver_data;
if (!priv) if (!priv)
return 0; return;
if (cgdev->state == CCWGROUP_ONLINE)
ctc_shutdown_device(cgdev);
ctc_remove_files(&cgdev->dev); ctc_remove_files(&cgdev->dev);
cgdev->dev.driver_data = NULL; cgdev->dev.driver_data = NULL;
kfree(priv); kfree(priv);
put_device(&cgdev->dev); put_device(&cgdev->dev);
return 0;
} }
static struct ccwgroup_driver ctc_group_driver = { static struct ccwgroup_driver ctc_group_driver = {
......
/* /*
* $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. * CTC / ESCON network driver, tty interface.
* *
...@@ -761,7 +761,6 @@ ctc_tty_ioctl(struct tty_struct *tty, struct file *file, ...@@ -761,7 +761,6 @@ ctc_tty_ioctl(struct tty_struct *tty, struct file *file,
error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); error = put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
if (error) if (error)
return error; return error;
put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
return 0; return 0;
case TIOCSSOFTCAR: case TIOCSSOFTCAR:
#ifdef CTC_DEBUG_MODEM_IOCTL #ifdef CTC_DEBUG_MODEM_IOCTL
......
/* /*
* $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 * CTC / LCS ccw_device driver
* *
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#include <asm/ccwgroup.h> #include <asm/ccwgroup.h>
...@@ -55,15 +56,7 @@ static struct ccw_device_id cu3088_ids[] = { ...@@ -55,15 +56,7 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver; static struct ccw_driver cu3088_driver;
static void struct device *cu3088_root_dev;
cu3088_root_dev_release (struct device *dev)
{
}
struct device cu3088_root_dev = {
.bus_id = "cu3088",
.release = cu3088_root_dev_release,
};
static ssize_t static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count) 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) ...@@ -90,7 +83,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
start = end + 1; 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); &cu3088_driver, 2, argv);
return (ret == 0) ? count : ret; return (ret == 0) ? count : ret;
...@@ -144,12 +137,12 @@ cu3088_init (void) ...@@ -144,12 +137,12 @@ cu3088_init (void)
{ {
int rc; int rc;
rc = device_register(&cu3088_root_dev); cu3088_root_dev = s390_root_dev_register("cu3088");
if (rc) if (IS_ERR(cu3088_root_dev))
return rc; return PTR_ERR(cu3088_root_dev);
rc = ccw_driver_register(&cu3088_driver); rc = ccw_driver_register(&cu3088_driver);
if (rc) if (rc)
device_unregister(&cu3088_root_dev); s390_root_dev_unregister(cu3088_root_dev);
return rc; return rc;
} }
...@@ -158,7 +151,7 @@ static void __exit ...@@ -158,7 +151,7 @@ static void __exit
cu3088_exit (void) cu3088_exit (void)
{ {
ccw_driver_unregister(&cu3088_driver); ccw_driver_unregister(&cu3088_driver);
device_unregister(&cu3088_root_dev); s390_root_dev_unregister(cu3088_root_dev);
} }
MODULE_DEVICE_TABLE(ccw,cu3088_ids); MODULE_DEVICE_TABLE(ccw,cu3088_ids);
......
/** /**
* $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 * A generic FSM based on fsm used in isdn4linux
* *
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/timer.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 * fsm_instance *
init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, 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) int nr_events, const fsm_node *tmpl, int tmpl_len, int order)
......
/* /*
* $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 * IUCV network driver
* *
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 @@ ...@@ -44,12 +44,14 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h>
#include <linux/device.h> #include <linux/device.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include "iucv.h" #include "iucv.h"
#include <asm/io.h> #include <asm/io.h>
#include <asm/s390_ext.h> #include <asm/s390_ext.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/ccwdev.h> //for root device stuff
#define DEBUG #define DEBUG
...@@ -79,20 +81,12 @@ iucv_bus_match (struct device *dev, struct device_driver *drv) ...@@ -79,20 +81,12 @@ iucv_bus_match (struct device *dev, struct device_driver *drv)
return 0; return 0;
} }
static void
iucv_root_release (struct device *dev)
{
}
struct bus_type iucv_bus = { struct bus_type iucv_bus = {
.name = "iucv", .name = "iucv",
.match = iucv_bus_match, .match = iucv_bus_match,
}; };
struct device iucv_root = { struct device *iucv_root;
.bus_id = "iucv",
.release = iucv_root_release,
};
/* General IUCV interrupt structure */ /* General IUCV interrupt structure */
typedef struct { typedef struct {
...@@ -355,7 +349,7 @@ do { \ ...@@ -355,7 +349,7 @@ do { \
static void static void
iucv_banner(void) iucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.15 $"; char vbuf[] = "$Revision: 1.19 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
...@@ -378,6 +372,11 @@ iucv_init(void) ...@@ -378,6 +372,11 @@ iucv_init(void)
{ {
int ret; int ret;
if (!MACHINE_IS_VM) {
printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
return -EPROTONOSUPPORT;
}
if (iucv_external_int_buffer) if (iucv_external_int_buffer)
return 0; return 0;
...@@ -387,11 +386,11 @@ iucv_init(void) ...@@ -387,11 +386,11 @@ iucv_init(void)
return ret; return ret;
} }
ret = device_register(&iucv_root); iucv_root = s390_root_dev_register("iucv");
if (ret != 0) { if (IS_ERR(iucv_root)) {
printk(KERN_ERR "IUCV: failed to register iucv root.\n"); printk(KERN_ERR "IUCV: failed to register iucv root.\n");
bus_unregister(&iucv_bus); bus_unregister(&iucv_bus);
return ret; return PTR_ERR(iucv_root);
} }
/* Note: GFP_DMA used used to get memory below 2G */ /* Note: GFP_DMA used used to get memory below 2G */
...@@ -401,6 +400,7 @@ iucv_init(void) ...@@ -401,6 +400,7 @@ iucv_init(void)
printk(KERN_WARNING printk(KERN_WARNING
"%s: Could not allocate external interrupt buffer\n", "%s: Could not allocate external interrupt buffer\n",
__FUNCTION__); __FUNCTION__);
s390_root_dev_unregister(iucv_root);
return -ENOMEM; return -ENOMEM;
} }
memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt)); memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt));
...@@ -413,6 +413,7 @@ iucv_init(void) ...@@ -413,6 +413,7 @@ iucv_init(void)
__FUNCTION__); __FUNCTION__);
kfree(iucv_external_int_buffer); kfree(iucv_external_int_buffer);
iucv_external_int_buffer = NULL; iucv_external_int_buffer = NULL;
s390_root_dev_unregister(iucv_root);
return -ENOMEM; return -ENOMEM;
} }
memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE); memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE);
...@@ -439,7 +440,7 @@ iucv_exit(void) ...@@ -439,7 +440,7 @@ iucv_exit(void)
kfree(iucv_external_int_buffer); kfree(iucv_external_int_buffer);
if (iucv_param_pool) if (iucv_param_pool)
kfree(iucv_param_pool); kfree(iucv_param_pool);
device_unregister(&iucv_root); s390_root_dev_unregister(iucv_root);
bus_unregister(&iucv_bus); bus_unregister(&iucv_bus);
printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
} }
...@@ -772,7 +773,7 @@ iucv_register_program (__u8 pgmname[16], ...@@ -772,7 +773,7 @@ iucv_register_program (__u8 pgmname[16],
} }
/* Allocate handler entry */ /* Allocate handler entry */
new_handler = (handler *)kmalloc(sizeof(handler), GFP_KERNEL); new_handler = (handler *)kmalloc(sizeof(handler), GFP_ATOMIC);
if (new_handler == NULL) { if (new_handler == NULL) {
printk(KERN_WARNING "%s: storage allocation for new handler " printk(KERN_WARNING "%s: storage allocation for new handler "
"failed.\n", __FUNCTION__); "failed.\n", __FUNCTION__);
...@@ -787,7 +788,7 @@ iucv_register_program (__u8 pgmname[16], ...@@ -787,7 +788,7 @@ iucv_register_program (__u8 pgmname[16],
max_connections = iucv_query_maxconn(); max_connections = iucv_query_maxconn();
iucv_pathid_table = kmalloc(max_connections * sizeof(handler *), iucv_pathid_table = kmalloc(max_connections * sizeof(handler *),
GFP_KERNEL); GFP_ATOMIC);
if (iucv_pathid_table == NULL) { if (iucv_pathid_table == NULL) {
printk(KERN_WARNING "%s: iucv_pathid_table storage " printk(KERN_WARNING "%s: iucv_pathid_table storage "
"allocation failed\n", __FUNCTION__); "allocation failed\n", __FUNCTION__);
......
...@@ -203,7 +203,7 @@ typedef struct { ...@@ -203,7 +203,7 @@ typedef struct {
} iucv_array_t __attribute__ ((aligned (8))); } iucv_array_t __attribute__ ((aligned (8)));
extern struct bus_type iucv_bus; extern struct bus_type iucv_bus;
extern struct device iucv_root; extern struct device *iucv_root;
/* -prototypes- */ /* -prototypes- */
/* /*
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com> * 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 * 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 * it under the terms of the GNU General Public License as published by
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
/** /**
* initialization string for output * 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 ")"; 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, ...@@ -1168,7 +1168,6 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
return -EIO; return -EIO;
} }
if (card->state != DEV_STATE_UP) { if (card->state != DEV_STATE_UP) {
dst_link_failure(skb);
dev_kfree_skb(skb); dev_kfree_skb(skb);
card->stats.tx_dropped++; card->stats.tx_dropped++;
card->stats.tx_errors++; card->stats.tx_errors++;
...@@ -1891,7 +1890,7 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) ...@@ -1891,7 +1890,7 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
/** /**
* lcs_remove_device, free buffers and card * lcs_remove_device, free buffers and card
*/ */
static int static void
lcs_remove_device(struct ccwgroup_device *ccwgdev) lcs_remove_device(struct ccwgroup_device *ccwgdev)
{ {
struct lcs_card *card; struct lcs_card *card;
...@@ -1899,12 +1898,18 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) ...@@ -1899,12 +1898,18 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
LCS_DBF_TEXT(3, setup, "remdev"); LCS_DBF_TEXT(3, setup, "remdev");
card = (struct lcs_card *)ccwgdev->dev.driver_data; card = (struct lcs_card *)ccwgdev->dev.driver_data;
if (!card) 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); sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);
lcs_cleanup_card(card); lcs_cleanup_card(card);
lcs_free_card(card); lcs_free_card(card);
put_device(&ccwgdev->dev); put_device(&ccwgdev->dev);
return 0;
} }
/** /**
......
/* /*
* $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 * IUCV network driver
* *
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 *skb, struct net_device *dev) ...@@ -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 * If connection is not running, try to restart it
* notify anybody about a link failure and throw * and throw away packet.
* away packet.
*/ */
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) { if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev); fsm_event(privptr->fsm, DEV_EVENT_START, dev);
dst_link_failure(skb);
dev_kfree_skb(skb); dev_kfree_skb(skb);
privptr->stats.tx_dropped++; privptr->stats.tx_dropped++;
privptr->stats.tx_errors++; privptr->stats.tx_errors++;
...@@ -1464,7 +1462,7 @@ netiucv_add_files(struct device *dev) ...@@ -1464,7 +1462,7 @@ netiucv_add_files(struct device *dev)
return ret; return ret;
ret = sysfs_create_group(&dev->kobj, &netiucv_stat_attr_group); ret = sysfs_create_group(&dev->kobj, &netiucv_stat_attr_group);
if (ret) if (ret)
sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
return ret; return ret;
} }
...@@ -1472,7 +1470,7 @@ static inline void ...@@ -1472,7 +1470,7 @@ static inline void
netiucv_remove_files(struct device *dev) 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_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group);
} }
static int static int
...@@ -1485,7 +1483,7 @@ netiucv_register_device(struct net_device *ndev, int ifno) ...@@ -1485,7 +1483,7 @@ netiucv_register_device(struct net_device *ndev, int ifno)
snprintf(dev->bus_id, BUS_ID_SIZE, "%s%x", str, ifno); snprintf(dev->bus_id, BUS_ID_SIZE, "%s%x", str, ifno);
dev->bus = &iucv_bus; dev->bus = &iucv_bus;
dev->parent = &iucv_root; dev->parent = iucv_root;
ret = device_register(dev); ret = device_register(dev);
...@@ -1731,7 +1729,7 @@ static struct device_driver netiucv_driver = { ...@@ -1731,7 +1729,7 @@ static struct device_driver netiucv_driver = {
static void static void
netiucv_banner(void) netiucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.26 $"; char vbuf[] = "$Revision: 1.30 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
......
/* /*
* *
* 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 * Linux on zSeries OSA Express and HiperSockets support
* *
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* numerous bugfixes) * numerous bugfixes)
* Frank Pavlic <pavlic@de.ibm.com> (query/purge ARP, SNMP, fixes) * Frank Pavlic <pavlic@de.ibm.com> (query/purge ARP, SNMP, fixes)
* Andreas Herrmann <aherrman@de.ibm.com> (bugfixes) * 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 * 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 * 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 " ...@@ -165,7 +166,7 @@ MODULE_PARM_DESC(qeth_sparebufs, "the number of pre-allocated spare buffers "
"reserved for low memory situations"); "reserved for low memory situations");
/****************** MODULE STUFF **********************************/ /****************** 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 (" static const char *version = "qeth S/390 OSA-Express driver ("
VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H
QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; QETH_VERSION_IPV6 QETH_VERSION_VLAN ")";
...@@ -314,6 +315,21 @@ my_spin_lock_nonbusy(struct qeth_card *card, spinlock_t * lock) ...@@ -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 #ifdef CONFIG_ARCH_S390X
#define QETH_GET_ADDR(x) ((__u32)(unsigned long)x) #define QETH_GET_ADDR(x) ((__u32)(unsigned long)x)
#else /* CONFIG_ARCH_S390X */ #else /* CONFIG_ARCH_S390X */
...@@ -612,6 +628,10 @@ static int ...@@ -612,6 +628,10 @@ static int
qeth_is_multicast_skb_at_all(struct sk_buff *skb, int version) qeth_is_multicast_skb_at_all(struct sk_buff *skb, int version)
{ {
int i; int i;
struct qeth_card *card;
i = RTN_UNSPEC;
card = (struct qeth_card *)skb->dev->priv;
if (skb->dst && skb->dst->neighbour) { if (skb->dst && skb->dst->neighbour) {
i = skb->dst->neighbour->type; i = skb->dst->neighbour->type;
return ((i == RTN_BROADCAST) || return ((i == RTN_BROADCAST) ||
...@@ -622,20 +642,38 @@ qeth_is_multicast_skb_at_all(struct sk_buff *skb, int version) ...@@ -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; return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
} else if (version == 6) { } else if (version == 6) {
return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0; return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
}
if (!memcmp(skb->nh.raw, skb->dev->broadcast, 6)) {
i = RTN_BROADCAST;
} else { } else {
PRINT_STUPID("QETH_IP_VERSION is %x\n", version); __u16 hdr_mac;
PRINT_STUPID("skb->protocol=x%x=%i\n",
skb->protocol, skb->protocol); hdr_mac = *((__u16*)skb->nh.raw);
HEXDUMP16(STUPID, "skb:", skb->data); /* 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 0; }
return ((i == RTN_BROADCAST)||
(i == RTN_MULTICAST)||
(i == RTN_ANYCAST)) ? i : 0;
} }
static int static int
qeth_get_prioqueue(struct qeth_card *card, struct sk_buff *skb, qeth_get_prioqueue(struct qeth_card *card, struct sk_buff *skb,
int multicast, int version) int multicast, int version)
{ {
if (!version) if (!version && (card->type == QETH_CARD_TYPE_OSAE))
return QETH_DEFAULT_QUEUE; return QETH_DEFAULT_QUEUE;
switch (card->no_queues) { switch (card->no_queues) {
case 1: case 1:
...@@ -1327,7 +1365,7 @@ __qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, ...@@ -1327,7 +1365,7 @@ __qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
QETH_FAKE_LL_ADDR_LEN); QETH_FAKE_LL_ADDR_LEN);
} else { } else {
/* clear source MAC for security reasons */ /* 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); 0, QETH_FAKE_LL_ADDR_LEN);
} }
memcpy(skb->mac.raw + QETH_FAKE_LL_PROT_POS, memcpy(skb->mac.raw + QETH_FAKE_LL_PROT_POS,
...@@ -1947,7 +1985,6 @@ qeth_free_buffer(struct qeth_card *card, int queue, int bufno, ...@@ -1947,7 +1985,6 @@ qeth_free_buffer(struct qeth_card *card, int queue, int bufno,
case ERROR_LINK_FAILURE: case ERROR_LINK_FAILURE:
case ERROR_KICK_THAT_PUPPY: case ERROR_KICK_THAT_PUPPY:
QETH_DBF_TEXT4(0, trace, "endeglnd"); QETH_DBF_TEXT4(0, trace, "endeglnd");
dst_link_failure(skb);
atomic_dec(&skb->users); atomic_dec(&skb->users);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
break; break;
...@@ -2425,7 +2462,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2425,7 +2462,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!card) { if (!card) {
QETH_DBF_TEXT2(0, trace, "XMNSNOCD"); QETH_DBF_TEXT2(0, trace, "XMNSNOCD");
dst_link_failure(skb);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
return 0; return 0;
} }
...@@ -2436,7 +2472,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2436,7 +2472,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!atomic_read(&card->is_startlaned)) { if (!atomic_read(&card->is_startlaned)) {
card->stats->tx_carrier_errors++; card->stats->tx_carrier_errors++;
QETH_DBF_CARD2(0, trace, "XMNS", card); QETH_DBF_CARD2(0, trace, "XMNS", card);
dst_link_failure(skb);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
return 0; return 0;
} }
...@@ -2548,7 +2583,8 @@ static void ...@@ -2548,7 +2583,8 @@ static void
qeth_wakeup_procfile(void) qeth_wakeup_procfile(void)
{ {
QETH_DBF_TEXT5(0, trace, "procwkup"); 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) PROCFILE_SLEEP_SEM_MAX_VALUE)
up(&qeth_procfile_ioctl_sem); up(&qeth_procfile_ioctl_sem);
} }
...@@ -2558,7 +2594,6 @@ qeth_sleepon_procfile(void) ...@@ -2558,7 +2594,6 @@ qeth_sleepon_procfile(void)
{ {
QETH_DBF_TEXT5(0, trace, "procslp"); QETH_DBF_TEXT5(0, trace, "procslp");
if (down_interruptible(&qeth_procfile_ioctl_sem)) { if (down_interruptible(&qeth_procfile_ioctl_sem)) {
up(&qeth_procfile_ioctl_sem);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
return 0; return 0;
...@@ -2634,6 +2669,8 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer, ...@@ -2634,6 +2669,8 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer,
QETH_DBF_TEXT2(0, trace, "scd:doio"); QETH_DBF_TEXT2(0, trace, "scd:doio");
sprintf(dbf_text, "%4x", (__s16) result); sprintf(dbf_text, "%4x", (__s16) result);
QETH_DBF_TEXT2(0, trace, dbf_text); QETH_DBF_TEXT2(0, trace, dbf_text);
/* re-enable qeth_send_control_data again */
atomic_set(&card->write_busy,0);
return NULL; return NULL;
} }
...@@ -2644,7 +2681,7 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer, ...@@ -2644,7 +2681,7 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer,
atomic_set(&card->write_busy, 0); atomic_set(&card->write_busy, 0);
return NULL; return NULL;
} }
rec_buf = card->ipa_buf; rec_buf = card->dma_stuff->recbuf;
QETH_DBF_CARD2(0, trace, "scro", card); QETH_DBF_CARD2(0, trace, "scro", card);
} else { } else {
if (qeth_sleepon(card, (setip) ? QETH_IPA_TIMEOUT : if (qeth_sleepon(card, (setip) ? QETH_IPA_TIMEOUT :
...@@ -3350,6 +3387,11 @@ qeth_send_setdelipm(struct qeth_card *card, __u8 * ip, __u8 * mac, ...@@ -3350,6 +3387,11 @@ qeth_send_setdelipm(struct qeth_card *card, __u8 * ip, __u8 * mac,
(result==0xe00e)?"unsupported arp assist cmd": \ (result==0xe00e)?"unsupported arp assist cmd": \
(result==0xe00f)?"arp assist not enabled": \ (result==0xe00f)?"arp assist not enabled": \
(result==0xe080)?"startlan disabled": \ (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": \ (result==-1)?"IPA communication timeout": \
"unknown return code") "unknown return code")
...@@ -3392,7 +3434,8 @@ qeth_send_setip(struct qeth_card *card, __u8 * ip, ...@@ -3392,7 +3434,8 @@ qeth_send_setip(struct qeth_card *card, __u8 * ip,
QETH_DBF_TEXT2(0, trace, dbf_text); 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); QETH_DBF_CARD2(0, trace, "sipr", card);
if (ip_vers == 4) { if (ip_vers == 4) {
*((__u32 *) (&dbf_text[0])) = *((__u32 *) ip); *((__u32 *) (&dbf_text[0])) = *((__u32 *) ip);
...@@ -3557,8 +3600,8 @@ qeth_set_vipas(struct qeth_card *card, int set_only) ...@@ -3557,8 +3600,8 @@ qeth_set_vipas(struct qeth_card *card, int set_only)
le is last entry */ le is last entry */
char dbf_text[15]; char dbf_text[15];
int result; int result;
__u8 netmask[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, __u8 netmask[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
struct qeth_vipa_entry *priv_add_list = NULL; struct qeth_vipa_entry *priv_add_list = NULL;
struct qeth_vipa_entry *priv_del_list = NULL; struct qeth_vipa_entry *priv_del_list = NULL;
...@@ -3576,9 +3619,10 @@ qeth_set_vipas(struct qeth_card *card, int set_only) ...@@ -3576,9 +3619,10 @@ qeth_set_vipas(struct qeth_card *card, int set_only)
* so we clone the entry */ * so we clone the entry */
ne = (struct qeth_vipa_entry *) ne = (struct qeth_vipa_entry *)
kmalloc(sizeof (struct qeth_vipa_entry), kmalloc(sizeof (struct qeth_vipa_entry),
GFP_KERNEL); GFP_ATOMIC);
if (ne) { if (ne) {
ne->version = e->version; ne->version = e->version;
ne->flag = e->flag;
memcpy(ne->ip, e->ip, 16); memcpy(ne->ip, e->ip, 16);
ne->next = priv_add_list; ne->next = priv_add_list;
priv_add_list = ne; priv_add_list = ne;
...@@ -3613,6 +3657,7 @@ qeth_set_vipas(struct qeth_card *card, int set_only) ...@@ -3613,6 +3657,7 @@ qeth_set_vipas(struct qeth_card *card, int set_only)
GFP_KERNEL); GFP_KERNEL);
if (ne) { if (ne) {
ne->version = e->version; ne->version = e->version;
ne->flag = e->flag;
memcpy(ne->ip, e->ip, 16); memcpy(ne->ip, e->ip, 16);
ne->next = priv_del_list; ne->next = priv_del_list;
priv_del_list = ne; priv_del_list = ne;
...@@ -3645,7 +3690,7 @@ qeth_set_vipas(struct qeth_card *card, int set_only) ...@@ -3645,7 +3690,7 @@ qeth_set_vipas(struct qeth_card *card, int set_only)
sprintf(dbf_text, "%4x", result); sprintf(dbf_text, "%4x", result);
QETH_DBF_TEXT2(0, trace, dbf_text); QETH_DBF_TEXT2(0, trace, dbf_text);
if (priv_add_list->version == 4) { 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", "unset...\n",
*((__u32 *) & priv_add_list->ip[0])); *((__u32 *) & priv_add_list->ip[0]));
sprintf(dbf_text, "%08x", sprintf(dbf_text, "%08x",
...@@ -4085,6 +4130,9 @@ __qeth_setipms_ipv6(struct qeth_card *card, int use_setipm_retries) ...@@ -4085,6 +4130,9 @@ __qeth_setipms_ipv6(struct qeth_card *card, int use_setipm_retries)
while (addr) { while (addr) {
if (qeth_is_ipma_in_list(addr, if (qeth_is_ipma_in_list(addr,
card->ip_mc_current_state.ipm6_ifa)) { card->ip_mc_current_state.ipm6_ifa)) {
qeth_remove_mc_ifa_from_list(
&card->ip_mc_new_state.ipm6_ifa,
addr);
addr = addr->next; addr = addr->next;
continue; continue;
} }
...@@ -4118,8 +4166,13 @@ __qeth_setipms_ipv6(struct qeth_card *card, int use_setipm_retries) ...@@ -4118,8 +4166,13 @@ __qeth_setipms_ipv6(struct qeth_card *card, int use_setipm_retries)
CARD_BUS_ID(card), result); CARD_BUS_ID(card), result);
sprintf(dbf_text, "sms6%4x", result); sprintf(dbf_text, "sms6%4x", result);
QETH_DBF_TEXT3(0, trace, dbf_text); QETH_DBF_TEXT3(0, trace, dbf_text);
qeth_remove_mc_ifa_from_list } else {
(&card->ip_mc_current_state.ipm6_ifa, addr); 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; addr = addr->next;
} }
...@@ -4555,7 +4608,7 @@ __qeth_takeover_ip_ipms6_mc(struct qeth_card *card, struct inet6_dev *in6_dev) ...@@ -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); ndisc_mc_map(&im6->mca_addr, buf, card->dev, 0);
ipmanew = ipmanew =
(struct qeth_ipm_mac *) (struct qeth_ipm_mac *)
kmalloc(sizeof (struct qeth_ipm_mac), GFP_KERNEL); kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
if (!ipmanew) { if (!ipmanew) {
PRINT_WARN("No memory for IPM address " PRINT_WARN("No memory for IPM address "
"handling. Multicast IP " "handling. Multicast IP "
...@@ -4630,7 +4683,7 @@ qeth_takeover_ip_ipms6(struct qeth_card *card) ...@@ -4630,7 +4683,7 @@ qeth_takeover_ip_ipms6(struct qeth_card *card)
while (ifa) { while (ifa) {
ifanew = ifanew =
kmalloc(sizeof (struct inet6_ifaddr), GFP_KERNEL); kmalloc(sizeof (struct inet6_ifaddr), GFP_ATOMIC);
if (!ifanew) { if (!ifanew) {
PRINT_WARN("No memory for IP address " PRINT_WARN("No memory for IP address "
"handling. Some of the IPs " "handling. Some of the IPs "
...@@ -4864,7 +4917,7 @@ __qeth_takeover_ip_ipms_mc(struct qeth_card *card, struct in_device *in4_dev) ...@@ -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); qeth_get_mac_for_ipm(im4->multiaddr, buf, in4_dev->dev);
ipmanew = ipmanew =
(struct qeth_ipm_mac *) (struct qeth_ipm_mac *)
kmalloc(sizeof (struct qeth_ipm_mac), GFP_KERNEL); kmalloc(sizeof (struct qeth_ipm_mac), GFP_ATOMIC);
if (!ipmanew) { if (!ipmanew) {
PRINT_WARN("No memory for IPM address " PRINT_WARN("No memory for IPM address "
"handling. Multicast IP %08x" "handling. Multicast IP %08x"
...@@ -4930,7 +4983,7 @@ qeth_takeover_ip_ipms(struct qeth_card *card) ...@@ -4930,7 +4983,7 @@ qeth_takeover_ip_ipms(struct qeth_card *card)
ifa = ((struct in_device *) card->dev->ip_ptr)->ifa_list; ifa = ((struct in_device *) card->dev->ip_ptr)->ifa_list;
while (ifa) { while (ifa) {
ifanew = kmalloc(sizeof (struct in_ifaddr), GFP_KERNEL); ifanew = kmalloc(sizeof (struct in_ifaddr), GFP_ATOMIC);
if (!ifanew) { if (!ifanew) {
PRINT_WARN("No memory for IP address " PRINT_WARN("No memory for IP address "
"handling. Some of the IPs " "handling. Some of the IPs "
...@@ -5212,7 +5265,7 @@ __qeth_softsetup_enable_ipv6(struct qeth_card *card, int do_a_startlan6) ...@@ -5212,7 +5265,7 @@ __qeth_softsetup_enable_ipv6(struct qeth_card *card, int do_a_startlan6)
QETH_DBF_TEXT2(0, trace, dbf_text); QETH_DBF_TEXT2(0, trace, dbf_text);
atomic_set(&card->is_softsetup, 0); atomic_set(&card->is_softsetup, 0);
/* do not return an error */ /* do not return an error */
if (result == 0xe080) if ((result == 0xe080) || (result == 0xf080))
result = 0; result = 0;
return result; return result;
} }
...@@ -5300,13 +5353,17 @@ __qeth_softsetup_start_assists(struct qeth_card *card) ...@@ -5300,13 +5353,17 @@ __qeth_softsetup_start_assists(struct qeth_card *card)
"failure -- please check the " "failure -- please check the "
"network, plug in the cable or " "network, plug in the cable or "
"enable the OSA port" : "enable the OSA port" :
(result==0xf080) ?
"startlan disabled (VM: LAN " \
"is offline for functions " \
"requiring LAN access.":
"unknown return code"); "unknown return code");
sprintf(dbf_text, "stln%4x", result); sprintf(dbf_text, "stln%4x", result);
QETH_DBF_TEXT2(0, trace, dbf_text); QETH_DBF_TEXT2(0, trace, dbf_text);
atomic_set(&card->is_softsetup, 0); atomic_set(&card->is_softsetup, 0);
atomic_set(&card->is_startlaned, 0); atomic_set(&card->is_startlaned, 0);
/* do not return an error */ /* do not return an error */
if (result == 0xe080) { if ((result == 0xe080) || (result == 0xf080)) {
result = 0; result = 0;
} }
return result; return result;
...@@ -5527,7 +5584,10 @@ __qeth_softsetup_routingv6(struct qeth_card *card) ...@@ -5527,7 +5584,10 @@ __qeth_softsetup_routingv6(struct qeth_card *card)
if (!atomic_read(&card->enable_routing_attempts6)) if (!atomic_read(&card->enable_routing_attempts6))
return; 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->enable_routing_attempts6, 0);
atomic_set(&card->rt6fld, 0); atomic_set(&card->rt6fld, 0);
return; return;
...@@ -5580,9 +5640,9 @@ qeth_softsetup_card(struct qeth_card *card, int wait_for_lock) ...@@ -5580,9 +5640,9 @@ qeth_softsetup_card(struct qeth_card *card, int wait_for_lock)
int use_setip_retries = 1; int use_setip_retries = 1;
if (wait_for_lock == QETH_WAIT_FOR_LOCK) { 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) { } else if (wait_for_lock == QETH_DONT_WAIT_FOR_LOCK) {
if (!spin_trylock(&card->softsetup_lock)) { if (!down_trylock(&card->softsetup_sema)) {
return -EAGAIN; return -EAGAIN;
} }
} else if (wait_for_lock == QETH_LOCK_ALREADY_HELD) { } else if (wait_for_lock == QETH_LOCK_ALREADY_HELD) {
...@@ -5634,7 +5694,7 @@ qeth_softsetup_card(struct qeth_card *card, int wait_for_lock) ...@@ -5634,7 +5694,7 @@ qeth_softsetup_card(struct qeth_card *card, int wait_for_lock)
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
} }
if (wait_for_lock != QETH_LOCK_ALREADY_HELD) if (wait_for_lock != QETH_LOCK_ALREADY_HELD)
spin_unlock(&card->softsetup_lock); up(&card->softsetup_sema);
return result; return result;
} }
...@@ -7835,7 +7895,7 @@ qeth_hardsetup_card(struct qeth_card *card, int in_recovery) ...@@ -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 cleanup_qdio = in_recovery; /* if we are in recovery, we clean
the qdio stuff up */ the qdio stuff up */
spin_lock(&card->hardsetup_lock); down(&card->hardsetup_sema);
atomic_set(&card->write_busy, 0); atomic_set(&card->write_busy, 0);
do { do {
...@@ -8146,7 +8206,7 @@ qeth_hardsetup_card(struct qeth_card *card, int in_recovery) ...@@ -8146,7 +8206,7 @@ qeth_hardsetup_card(struct qeth_card *card, int in_recovery)
} }
exit: exit:
spin_unlock(&card->hardsetup_lock); up(&card->hardsetup_sema);
return result; return result;
} }
...@@ -8198,13 +8258,13 @@ qeth_reinit_thread(void *param) ...@@ -8198,13 +8258,13 @@ qeth_reinit_thread(void *param)
atomic_set(&card->escape_softsetup, 1); 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); atomic_set(&card->escape_softsetup, 0);
goto out; goto out;
} }
atomic_set(&card->escape_softsetup, 0); atomic_set(&card->escape_softsetup, 0);
if (atomic_read(&card->shutdown_phase)) { if (atomic_read(&card->shutdown_phase)) {
spin_unlock(&card->softsetup_lock); up(&card->softsetup_sema);
goto out_wakeup; goto out_wakeup;
} }
if (!qeth_verify_card(card)) if (!qeth_verify_card(card))
...@@ -8248,7 +8308,7 @@ qeth_reinit_thread(void *param) ...@@ -8248,7 +8308,7 @@ qeth_reinit_thread(void *param)
} else { } else {
QETH_DBF_TEXT1(0, trace, "ri-sftst"); QETH_DBF_TEXT1(0, trace, "ri-sftst");
qeth_softsetup_card(card, QETH_LOCK_ALREADY_HELD); qeth_softsetup_card(card, QETH_LOCK_ALREADY_HELD);
spin_unlock(&card->softsetup_lock); up(&card->softsetup_sema);
if (!already_registered) { if (!already_registered) {
QETH_DBF_TEXT1(0, trace, "ri-regcd"); QETH_DBF_TEXT1(0, trace, "ri-regcd");
...@@ -8374,8 +8434,8 @@ qeth_alloc_card(void) ...@@ -8374,8 +8434,8 @@ qeth_alloc_card(void)
qeth_fill_qeth_card_options(card); qeth_fill_qeth_card_options(card);
spin_lock_init(&card->softsetup_lock); init_MUTEX(&card->softsetup_sema);
spin_lock_init(&card->hardsetup_lock); init_MUTEX(&card->hardsetup_sema);
spin_lock_init(&card->ioctl_lock); spin_lock_init(&card->ioctl_lock);
#ifdef QETH_VLAN #ifdef QETH_VLAN
spin_lock_init(&card->vlan_lock); spin_lock_init(&card->vlan_lock);
...@@ -8571,7 +8631,8 @@ __qeth_correct_routing_status_v4(struct qeth_card *card) ...@@ -8571,7 +8631,8 @@ __qeth_correct_routing_status_v4(struct qeth_card *card)
card->options.do_prio_queueing = NO_PRIO_QUEUEING; card->options.do_prio_queueing = NO_PRIO_QUEUEING;
} else { } else {
/* if it's a mc router, it's no router */ /* 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 == PRIMARY_CONNECTOR) ||
(card->options.routing_type4 == SECONDARY_CONNECTOR)) { (card->options.routing_type4 == SECONDARY_CONNECTOR)) {
PRINT_WARN("routing not applicable, reset " PRINT_WARN("routing not applicable, reset "
...@@ -8599,7 +8660,8 @@ __qeth_correct_routing_status_v6(struct qeth_card *card) ...@@ -8599,7 +8660,8 @@ __qeth_correct_routing_status_v6(struct qeth_card *card)
card->options.do_prio_queueing = NO_PRIO_QUEUEING; card->options.do_prio_queueing = NO_PRIO_QUEUEING;
} else { } else {
/* if it's a mc router, it's no router */ /* 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 == PRIMARY_CONNECTOR) ||
(card->options.routing_type6 == SECONDARY_CONNECTOR)) { (card->options.routing_type6 == SECONDARY_CONNECTOR)) {
PRINT_WARN("routing not applicable, reset " PRINT_WARN("routing not applicable, reset "
...@@ -8855,7 +8917,7 @@ qeth_procfile_open(struct inode *inode, struct file *file) ...@@ -8855,7 +8917,7 @@ qeth_procfile_open(struct inode *inode, struct file *file)
"device cardtype port chksum prio-q'ing " "device cardtype port chksum prio-q'ing "
"rtr fsz cnt\n"); "rtr fsz cnt\n");
length += sprintf(buffer + length, length += sprintf(buffer + length,
"-------------------- --- ----" "-------------------------- --- ----"
"------ -------------- -- -- ---------- " "------ -------------- -- -- ---------- "
"--- --- ---\n"); "--- --- ---\n");
card = firstcard; card = firstcard;
...@@ -9509,9 +9571,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file, ...@@ -9509,9 +9571,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file,
{ {
int result; int result;
down_interruptible(&qeth_procfile_ioctl_lock); if (!down_interruptible(&qeth_procfile_ioctl_lock)) {
switch (cmd) { switch (cmd) {
case QETH_IOCPROC_OSAEINTERFACES: case QETH_IOCPROC_OSAEINTERFACES:
result = qeth_procfile_getinterfaces(arg); result = qeth_procfile_getinterfaces(arg);
break; break;
...@@ -9522,6 +9583,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file, ...@@ -9522,6 +9583,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file,
result = -EOPNOTSUPP; result = -EOPNOTSUPP;
} }
up(&qeth_procfile_ioctl_lock); up(&qeth_procfile_ioctl_lock);
} else
result = -ERESTARTSYS;
return result; return result;
}; };
...@@ -9779,15 +9842,7 @@ static struct ccw_driver qeth_ccw_driver = { ...@@ -9779,15 +9842,7 @@ static struct ccw_driver qeth_ccw_driver = {
.remove = ccwgroup_remove_ccwdev, .remove = ccwgroup_remove_ccwdev,
}; };
static void static struct device *qeth_root_dev;
qeth_root_dev_release (struct device *dev)
{
}
static struct device qeth_root_dev = {
.bus_id = "qeth",
.release = qeth_root_dev_release,
};
static struct ccwgroup_driver qeth_ccwgroup_driver; static struct ccwgroup_driver qeth_ccwgroup_driver;
static ssize_t static ssize_t
...@@ -9813,7 +9868,7 @@ qeth_group_store(struct device_driver *drv, const char *buf, size_t count) ...@@ -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", pr_debug("creating qeth group device from '%s', '%s' and '%s'\n",
bus_ids[0], bus_ids[1], bus_ids[2]); 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); &qeth_ccw_driver, 3, argv);
return count; return count;
} }
...@@ -10674,19 +10729,6 @@ qeth_activate(struct qeth_card *card) ...@@ -10674,19 +10729,6 @@ qeth_activate(struct qeth_card *card)
return -ENODEV; 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 static int
qeth_set_online(struct ccwgroup_device *gdev) qeth_set_online(struct ccwgroup_device *gdev)
{ {
...@@ -10723,6 +10765,21 @@ qeth_set_offline(struct ccwgroup_device *gdev) ...@@ -10723,6 +10765,21 @@ qeth_set_offline(struct ccwgroup_device *gdev)
return 0; 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 = { static struct ccwgroup_driver qeth_ccwgroup_driver = {
.name = "qeth", .name = "qeth",
.driver_id = 0xD8C5E3C8, .driver_id = 0xD8C5E3C8,
...@@ -10773,10 +10830,11 @@ qeth_init(void) ...@@ -10773,10 +10830,11 @@ qeth_init(void)
if (result) if (result)
goto out_cdrv; goto out_cdrv;
result = device_register(&qeth_root_dev); qeth_root_dev = s390_root_dev_register("qeth");
if (result) if (IS_ERR(qeth_root_dev)) {
result = PTR_ERR(qeth_root_dev);
goto out_file; goto out_file;
}
qeth_register_notifiers(); qeth_register_notifiers();
qeth_add_procfs_entries(); qeth_add_procfs_entries();
...@@ -10815,7 +10873,7 @@ qeth_exit(void) ...@@ -10815,7 +10873,7 @@ qeth_exit(void)
driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group); driver_remove_file(&qeth_ccwgroup_driver.driver, &driver_attr_group);
ccw_driver_unregister(&qeth_ccw_driver); ccw_driver_unregister(&qeth_ccw_driver);
ccwgroup_driver_unregister(&qeth_ccwgroup_driver); ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
device_unregister(&qeth_root_dev); s390_root_dev_unregister(qeth_root_dev);
while (firstcard) { while (firstcard) {
struct qeth_card *card = firstcard; struct qeth_card *card = firstcard;
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#define QETH_NAME " qeth" #define QETH_NAME " qeth"
#define VERSION_QETH_H "$Revision: 1.58 $" #define VERSION_QETH_H "$Revision: 1.60 $"
/******************** CONFIG STUFF ***********************/ /******************** CONFIG STUFF ***********************/
//#define QETH_DBF_LIKE_HELL //#define QETH_DBF_LIKE_HELL
...@@ -288,6 +288,12 @@ ...@@ -288,6 +288,12 @@
#define QETH_HEADER_PASSTHRU 0x10 #define QETH_HEADER_PASSTHRU 0x10
#define QETH_HEADER_IPV6 0x80 #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_FLAGS 0x07
#define QETH_CAST_UNICAST 6 #define QETH_CAST_UNICAST 6
#define QETH_CAST_MULTICAST 4 #define QETH_CAST_MULTICAST 4
...@@ -888,8 +894,8 @@ struct qeth_card { /* pointed to by dev->priv */ ...@@ -888,8 +894,8 @@ struct qeth_card { /* pointed to by dev->priv */
atomic_t is_open; /* card is in use */ atomic_t is_open; /* card is in use */
/* prevents deadlocks :-O */ /* prevents deadlocks :-O */
spinlock_t softsetup_lock; struct semaphore softsetup_sema;
spinlock_t hardsetup_lock; struct semaphore hardsetup_sema;
spinlock_t ioctl_lock; spinlock_t ioctl_lock;
atomic_t softsetup_thread_is_running; atomic_t softsetup_thread_is_running;
struct semaphore softsetup_thread_sem; struct semaphore softsetup_thread_sem;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#ifndef __QETH_MPC_H__ #ifndef __QETH_MPC_H__
#define __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_IPA_TIMEOUT (card->ipa_timeout)
#define QETH_MPC_TIMEOUT 2000 #define QETH_MPC_TIMEOUT 2000
...@@ -143,6 +143,7 @@ extern unsigned char DM_ACT[]; ...@@ -143,6 +143,7 @@ extern unsigned char DM_ACT[];
#define IPA_PASSTHRU 0x00001000L #define IPA_PASSTHRU 0x00001000L
#define IPA_FULL_VLAN 0x00004000L #define IPA_FULL_VLAN 0x00004000L
#define IPA_SOURCE_MAC_AVAIL 0x00010000L #define IPA_SOURCE_MAC_AVAIL 0x00010000L
#define IPA_OSA_MC_ROUTER_AVAIL 0x00020000L
#define IPA_SETADP_QUERY_COMMANDS_SUPPORTED 0x01 #define IPA_SETADP_QUERY_COMMANDS_SUPPORTED 0x01
#define IPA_SETADP_ALTER_MAC_ADDRESS 0x02 #define IPA_SETADP_ALTER_MAC_ADDRESS 0x02
...@@ -319,8 +320,9 @@ struct ipa_cmd{ ...@@ -319,8 +320,9 @@ struct ipa_cmd{
}__attribute__ ((packed)); }__attribute__ ((packed));
#define QETH_IOC_MAGIC 0x22 #define QETH_IOC_MAGIC 0x22
#define QETH_IOCPROC_OSAEINTERFACES _IOWR(QETH_IOC_MAGIC, 1, arg) /* these don't really have 'unsigned long' arguments but were defined that way */
#define QETH_IOCPROC_INTERFACECHANGES _IOWR(QETH_IOC_MAGIC, 2, arg) #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_QUERY_CARD_INFO 0x00000002L
#define SNMP_REGISETER_MIB 0x00000004L #define SNMP_REGISETER_MIB 0x00000004L
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment