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
*
......@@ -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_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 = {
......
/*
* $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
......
/*
* $Id: cu3088.c,v 1.31 2003/09/29 15:24:27 cohuck Exp $
* $Id: cu3088.c,v 1.33 2003/10/14 12:10:19 cohuck Exp $
*
* CTC / LCS ccw_device driver
*
......@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
......@@ -55,15 +56,7 @@ static struct ccw_device_id cu3088_ids[] = {
static struct ccw_driver cu3088_driver;
static void
cu3088_root_dev_release (struct device *dev)
{
}
struct device cu3088_root_dev = {
.bus_id = "cu3088",
.release = cu3088_root_dev_release,
};
struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
......@@ -90,7 +83,7 @@ group_write(struct device_driver *drv, 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);
......
/**
* $Id: fsm.c,v 1.4 2003/03/28 08:54:40 mschwide Exp $
* $Id: fsm.c,v 1.6 2003/10/15 11:37:29 mschwide Exp $
*
* A generic FSM based on fsm used in isdn4linux
*
......@@ -10,6 +10,10 @@
#include <linux/module.h>
#include <linux/timer.h>
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Finite state machine helper functions");
MODULE_LICENSE("GPL");
fsm_instance *
init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
int nr_events, const fsm_node *tmpl, int tmpl_len, int order)
......
/*
* $Id: iucv.c,v 1.15 2003/10/01 09:25:15 mschwide Exp $
* $Id: iucv.c,v 1.19 2003/12/18 15:28:49 braunu Exp $
*
* IUCV network driver
*
......@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.15 $
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.19 $
*
*/
......@@ -44,12 +44,14 @@
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/device.h>
#include <asm/atomic.h>
#include "iucv.h"
#include <asm/io.h>
#include <asm/s390_ext.h>
#include <asm/ebcdic.h>
#include <asm/ccwdev.h> //for root device stuff
#define DEBUG
......@@ -79,20 +81,12 @@ iucv_bus_match (struct device *dev, 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__);
......
......@@ -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- */
/*
......
......@@ -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;
}
/**
......
/*
* $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 *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, ':'))) {
......
/*
*
* 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;
}
if (!memcmp(skb->nh.raw, skb->dev->broadcast, 6)) {
i = RTN_BROADCAST;
} 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);
__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 0;
}
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 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer,
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 @@ qeth_send_control_data(struct qeth_card *card, unsigned char *buffer,
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 @@ qeth_send_setip(struct qeth_card *card, __u8 * ip,
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 @@ qeth_softsetup_card(struct qeth_card *card, int wait_for_lock)
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 "
......@@ -8855,7 +8917,7 @@ qeth_procfile_open(struct inode *inode, struct file *file)
"device cardtype port chksum prio-q'ing "
"rtr fsz cnt\n");
length += sprintf(buffer + length,
"-------------------- --- ----"
"-------------------------- --- ----"
"------ -------------- -- -- ---------- "
"--- --- ---\n");
card = firstcard;
......@@ -9509,9 +9571,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file,
{
int result;
down_interruptible(&qeth_procfile_ioctl_lock);
if (!down_interruptible(&qeth_procfile_ioctl_lock)) {
switch (cmd) {
case QETH_IOCPROC_OSAEINTERFACES:
result = qeth_procfile_getinterfaces(arg);
break;
......@@ -9522,6 +9583,8 @@ qeth_procfile_ioctl(struct inode *inode, struct file *file,
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 @@ qeth_activate(struct qeth_card *card)
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;
......
......@@ -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->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;
......
......@@ -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
......
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