Commit 7747d41e authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: network driver

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

Network driver changes:
 - lcs: Add missing irb error checking.
 - lcs: Fix multicasting.
 - lcs: Use a seperate lock (ipm_lock) for multicast list.
 - lcs: Add missing in_dev_put in multicase address list handling.
 - iucv: Set static variables to NULL after kfree.
 - iucv: Do bus_unregister if module initialization fails.
 - netiucv: Convert iucvMagic to EBCDIC in con_action_start.
 - netiucv: Remove administration of ifno-stuff for device name,
 - netiucv: Add attribute to remove a netiucv device.
 - qeth: Add version string that is displayed at driver load time.
 - qeth: Fix memory leak in qeth_arp_query.
 - qeth: Remove duplicate case statements in qeth_do_ioctl.
 - qeth: Fix OSA broadcast filtering.
 - qeth: Increase timeout for purge ARP cache IPA.
 - qeth: Fix hsi device naming.
 - qeth: Add do_QDIO count to qeth performance statistics.
 - qeth: Allow writing to IP address takeover attribute only in
         state DOWN or RECOVER.
 - qeth: Fix hang when removing a vlan device.
 - qeth: Cleanup error messages for ARP commands.
 - qeth: Return EOPNOTSUPP for purge ARP on HiperSockets.
 - qeth: Drop skbs if the net_device of a qeth device is down.
 - qeth: Simplify ip address list processing.
parent a7a53392
/*
* $Id: iucv.c,v 1.28 2004/04/15 06:34:58 braunu Exp $
* $Id: iucv.c,v 1.30 2004/05/13 09:21:23 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.28 $
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.30 $
*
*/
......@@ -98,7 +98,7 @@ typedef struct {
__u8 res3[24];
} iucv_GeneralInterrupt;
static iucv_GeneralInterrupt *iucv_external_int_buffer;
static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL;
/* Spin Lock declaration */
......@@ -351,7 +351,7 @@ do { \
static void
iucv_banner(void)
{
char vbuf[] = "$Revision: 1.28 $";
char vbuf[] = "$Revision: 1.30 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
......@@ -403,6 +403,7 @@ iucv_init(void)
"%s: Could not allocate external interrupt buffer\n",
__FUNCTION__);
s390_root_dev_unregister(iucv_root);
bus_unregister(&iucv_bus);
return -ENOMEM;
}
memset(iucv_external_int_buffer, 0, sizeof(iucv_GeneralInterrupt));
......@@ -416,6 +417,7 @@ iucv_init(void)
kfree(iucv_external_int_buffer);
iucv_external_int_buffer = NULL;
s390_root_dev_unregister(iucv_root);
bus_unregister(&iucv_bus);
return -ENOMEM;
}
memset(iucv_param_pool, 0, sizeof(iucv_param) * PARAM_POOL_SIZE);
......@@ -441,10 +443,14 @@ static void
iucv_exit(void)
{
iucv_retrieve_buffer();
if (iucv_external_int_buffer)
if (iucv_external_int_buffer) {
kfree(iucv_external_int_buffer);
if (iucv_param_pool)
iucv_external_int_buffer = NULL;
}
if (iucv_param_pool) {
kfree(iucv_param_pool);
iucv_param_pool = NULL;
}
s390_root_dev_unregister(iucv_root);
bus_unregister(&iucv_bus);
printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
......
......@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
* $Revision: 1.74 $ $Date: 2004/04/05 00:01:04 $
* $Revision: 1.80 $ $Date: 2004/05/13 08:22:06 $
*
* 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.74 $"
#define VERSION_LCS_C "$Revision: 1.80 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255];
......@@ -99,9 +99,9 @@ lcs_register_debug_facility(void)
return -ENOMEM;
}
debug_register_view(lcs_dbf_setup, &debug_hex_ascii_view);
debug_set_level(lcs_dbf_setup, 5);
debug_set_level(lcs_dbf_setup, 2);
debug_register_view(lcs_dbf_trace, &debug_hex_ascii_view);
debug_set_level(lcs_dbf_trace, 5);
debug_set_level(lcs_dbf_trace, 2);
return 0;
}
......@@ -338,6 +338,7 @@ lcs_setup_card(struct lcs_card *card)
(void *)lcs_start_kernel_thread,card);
card->thread_mask = 0;
spin_lock_init(&card->lock);
spin_lock_init(&card->ipm_lock);
#ifdef CONFIG_IP_MULTICAST
INIT_LIST_HEAD(&card->ipm_list);
#endif
......@@ -935,18 +936,14 @@ lcs_check_multicast_support(struct lcs_card *card)
/**
* set or del multicast address on LCS card
*/
static int
lcs_fix_multicast_list(void *data)
static void
lcs_fix_multicast_list(struct lcs_card *card)
{
struct list_head *l, *n;
struct lcs_ipm_list *ipm;
struct lcs_card *card;
card = (struct lcs_card *) data;
daemonize("fixipm");
LCS_DBF_TEXT(4,trace, "fixipm");
spin_lock(&card->lock);
spin_lock(&card->ipm_lock);
list_for_each_safe(l, n, &card->ipm_list) {
ipm = list_entry(l, struct lcs_ipm_list, list);
switch (ipm->ipm_state) {
......@@ -968,8 +965,7 @@ lcs_fix_multicast_list(void *data)
}
if (card->state == DEV_STATE_UP)
netif_wake_queue(card->dev);
spin_unlock(&card->lock);
return 0;
spin_unlock(&card->ipm_lock);
}
/**
......@@ -988,28 +984,30 @@ lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev)
/**
* function called by net device to handle multicast address relevant things
*/
static void
lcs_set_multicast_list(struct net_device *dev)
static int
lcs_register_mc_addresses(void *data)
{
struct lcs_card *card;
char buf[MAX_ADDR_LEN];
struct list_head *l;
struct ip_mc_list *im4;
struct in_device *in4_dev;
struct lcs_ipm_list *ipm, *tmp;
struct lcs_card *card;
LCS_DBF_TEXT(4, trace, "setmulti");
in4_dev = in_dev_get(dev);
daemonize("regipm");
LCS_DBF_TEXT(4, trace, "regmulti");
card = (struct lcs_card *) data;
in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
return;
return 0;
read_lock(&in4_dev->lock);
card = (struct lcs_card *) dev->priv;
spin_lock(&card->lock);
spin_lock(&card->ipm_lock);
/* Check for multicast addresses to be removed. */
list_for_each(l, &card->ipm_list) {
ipm = list_entry(l, struct lcs_ipm_list, list);
for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) {
lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
if (memcmp(buf, &ipm->ipm.mac_addr,
LCS_MAC_LENGTH) == 0 &&
ipm->ipm.ip_addr == im4->multiaddr)
......@@ -1020,7 +1018,7 @@ lcs_set_multicast_list(struct net_device *dev)
}
/* Check for multicast addresses to be added. */
for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
ipm = NULL;
list_for_each(l, &card->ipm_list) {
tmp = list_entry(l, struct lcs_ipm_list, list);
......@@ -1046,14 +1044,56 @@ lcs_set_multicast_list(struct net_device *dev)
ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED;
list_add(&ipm->list, &card->ipm_list);
}
spin_unlock(&card->lock);
spin_unlock(&card->ipm_lock);
read_unlock(&in4_dev->lock);
set_bit(3, &card->thread_mask);
schedule_work(&card->kernel_thread_starter);
lcs_fix_multicast_list(card);
in_dev_put(in4_dev);
return 0;
}
/**
* function called by net device to
* handle multicast address relevant things
*/
static void
lcs_set_multicast_list(struct net_device *dev)
{
struct lcs_card *card;
LCS_DBF_TEXT(4, trace, "setmulti");
card = (struct lcs_card *) dev->priv;
set_bit(3, &card->thread_mask);
schedule_work(&card->kernel_thread_starter);
}
#endif /* CONFIG_IP_MULTICAST */
static long
lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
{
if (!IS_ERR(irb))
return 0;
switch (PTR_ERR(irb)) {
case -EIO:
PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT_(2, trace, " rc%d", -EIO);
break;
case -ETIMEDOUT:
PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT);
break;
default:
PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
cdev->dev.bus_id);
LCS_DBF_TEXT(2, trace, "ckirberr");
LCS_DBF_TEXT(2, trace, " rc???");
}
return PTR_ERR(irb);
}
/**
* IRQ Handler for LCS channels
*/
......@@ -1064,6 +1104,9 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct lcs_channel *channel;
int index;
if (lcs_check_irb_error(cdev, irb))
return;
card = CARD_FROM_DEV(cdev);
if (card->read.ccwdev == cdev)
channel = &card->read;
......@@ -1513,7 +1556,7 @@ lcs_start_kernel_thread(struct lcs_card *card)
kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD);
#ifdef CONFIG_IP_MULTICAST
if (test_and_clear_bit(3, &card->thread_mask))
kernel_thread(lcs_fix_multicast_list, (void *) card, SIGCHLD);
kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD);
#endif
}
......@@ -1903,7 +1946,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
goto out;
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (lcs_check_multicast_support(card))
if (!lcs_check_multicast_support(card))
card->dev->set_multicast_list = lcs_set_multicast_list;
#endif
netif_stop_queue(card->dev);
......
......@@ -6,7 +6,7 @@
#include <linux/workqueue.h>
#include <asm/ccwdev.h>
#define VERSION_LCS_H "$Revision: 1.15 $"
#define VERSION_LCS_H "$Revision: 1.16 $"
#define LCS_DBF_TEXT(level, name, text) \
do { \
......@@ -273,6 +273,7 @@ struct lcs_channel {
*/
struct lcs_card {
spinlock_t lock;
spinlock_t ipm_lock;
enum lcs_dev_states state;
struct net_device *dev;
struct net_device_stats stats;
......
/*
* $Id: netiucv.c,v 1.51 2004/04/23 08:11:21 mschwide Exp $
* $Id: netiucv.c,v 1.53 2004/05/07 14:29:37 mschwide 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.51 $
* RELEASE-TAG: IUCV network driver $Revision: 1.53 $
*
*/
......@@ -60,6 +60,7 @@
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/ebcdic.h>
#include "iucv.h"
#include "fsm.h"
......@@ -113,9 +114,6 @@ struct iucv_connection {
*/
static struct iucv_connection *connections;
/* Keep track of interfaces. */
static int ifno;
/**
* Representation of event-data for the
* connection state machine.
......@@ -549,7 +547,7 @@ conn_action_rx(fsm_instance *fi, int event, void *arg)
iucv_MessagePending *eib = (iucv_MessagePending *)ev->data;
struct netiucv_priv *privptr = (struct netiucv_priv *)conn->netdev->priv;
__u16 msglen = eib->ln1msg2.ipbfln1f;
__u32 msglen = eib->ln1msg2.ipbfln1f;
int rc;
pr_debug("%s() called\n", __FUNCTION__);
......@@ -571,6 +569,7 @@ conn_action_rx(fsm_instance *fi, int event, void *arg)
conn->rx_buff->data, msglen, NULL, NULL, NULL);
if (rc != 0 || msglen < 5) {
privptr->stats.rx_errors++;
printk(KERN_INFO "iucv_receive returned %08x\n", rc);
return;
}
netiucv_unpack_skb(conn, conn->rx_buff);
......@@ -647,7 +646,7 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
fsm_newstate(fi, CONN_STATE_IDLE);
if (privptr)
privptr->stats.tx_errors += txpackets;
printk(KERN_DEBUG "iucv_send returned %08x\n",
printk(KERN_INFO "iucv_send returned %08x\n",
rc);
} else {
if (privptr) {
......@@ -770,7 +769,7 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
struct iucv_event *ev = (struct iucv_event *)arg;
struct iucv_connection *conn = ev->conn;
__u16 msglimit;
int rc;
int rc, len;
__u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
......@@ -778,7 +777,10 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
pr_debug("%s() called\n", __FUNCTION__);
memcpy(iucvMagic, conn->netdev->name, IFNAMSIZ);
len = (IFNAMSIZ < sizeof(conn->netdev->name)) ?
IFNAMSIZ : sizeof(conn->netdev->name);
memcpy(iucvMagic, conn->netdev->name, len);
ASCEBC (iucvMagic, len);
if (conn->handle == 0) {
conn->handle =
iucv_register_program(iucvMagic, conn->userid, mask,
......@@ -992,6 +994,7 @@ static void
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
struct net_device *dev = (struct net_device *)arg;
struct netiucv_priv *privptr = dev->priv;
pr_debug("%s() called\n", __FUNCTION__);
......@@ -999,8 +1002,8 @@ dev_action_connup(fsm_instance *fi, int event, void *arg)
case DEV_STATE_STARTWAIT:
fsm_newstate(fi, DEV_STATE_RUNNING);
printk(KERN_INFO
"%s: connected with remote side\n",
dev->name);
"%s: connected with remote side %s\n",
dev->name, privptr->conn->userid);
break;
case DEV_STATE_STOPWAIT:
printk(KERN_INFO
......@@ -1140,7 +1143,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
skb_pull(skb, NETIUCV_HDRLEN);
skb_trim(skb, skb->len - NETIUCV_HDRLEN);
}
printk(KERN_DEBUG "iucv_send returned %08x\n",
printk(KERN_INFO "iucv_send returned %08x\n",
rc);
} else {
if (copied)
......@@ -1612,7 +1615,7 @@ netiucv_remove_files(struct device *dev)
}
static int
netiucv_register_device(struct net_device *ndev, int ifno)
netiucv_register_device(struct net_device *ndev)
{
struct netiucv_priv *priv = ndev->priv;
struct device *dev = kmalloc(sizeof(struct device), GFP_KERNEL);
......@@ -1623,7 +1626,7 @@ netiucv_register_device(struct net_device *ndev, int ifno)
if (dev) {
memset(dev, 0, sizeof(struct device));
snprintf(dev->bus_id, BUS_ID_SIZE, "netiucv%x", ifno);
snprintf(dev->bus_id, BUS_ID_SIZE, "net%s", ndev->name);
dev->bus = &iucv_bus;
dev->parent = iucv_root;
/*
......@@ -1801,16 +1804,15 @@ netiucv_setup_netdevice(struct net_device *dev)
* Allocate and initialize everything of a net device.
*/
static struct net_device *
netiucv_init_netdevice(int ifno, char *username)
netiucv_init_netdevice(char *username)
{
struct netiucv_priv *privptr;
struct net_device *dev;
dev = alloc_netdev(sizeof(struct netiucv_priv), "",
dev = alloc_netdev(sizeof(struct netiucv_priv), "iucv%d",
netiucv_setup_netdevice);
if (!dev)
return NULL;
sprintf(dev->name, "iucv%d", ifno);
privptr = (struct netiucv_priv *)dev->priv;
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
......@@ -1861,7 +1863,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
while (i<9)
username[i++] = ' ';
username[9] = '\0';
dev = netiucv_init_netdevice(ifno, username);
dev = netiucv_init_netdevice(username);
if (!dev) {
printk(KERN_WARNING
"netiucv: Could not allocate network device structure "
......@@ -1869,16 +1871,18 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
return -ENODEV;
}
if ((ret = netiucv_register_device(dev, ifno)))
goto out_free_ndev;
/* sysfs magic */
SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev);
if ((ret = register_netdev(dev))) {
netiucv_unregister_device((struct device*)((struct netiucv_priv*)dev->priv)->dev);
goto out_free_ndev;
}
if ((ret = netiucv_register_device(dev))) {
unregister_netdev(dev);
goto out_free_ndev;
}
/* sysfs magic */
SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev);
printk(KERN_INFO "%s: '%s'\n", dev->name, netiucv_printname(username));
ifno++;
return count;
......@@ -1891,6 +1895,61 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
DRIVER_ATTR(connection, 0200, NULL, conn_write);
static ssize_t
remove_write (struct device_driver *drv, const char *buf, size_t count)
{
struct iucv_connection **clist = &connections;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
char name[IFNAMSIZ];
char *p;
int i;
pr_debug("%s() called\n", __FUNCTION__);
if (count >= IFNAMSIZ)
count = IFNAMSIZ-1;
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
if ((*p == '\n') | (*p == ' ')) {
/* trailing lf, grr */
break;
} else {
name[i]=*p;
}
}
name[i] = '\0';
while (*clist) {
ndev = (*clist)->netdev;
priv = (struct netiucv_priv*)ndev->priv;
dev = priv->dev;
if (strncmp(name, ndev->name, count)) {
clist = &((*clist)->next);
continue;
}
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
printk(KERN_WARNING
"netiucv: net device %s active with peer %s\n",
ndev->name, priv->conn->userid);
printk(KERN_WARNING
"netiucv: %s cannot be removed\n",
ndev->name);
return -EBUSY;
}
unregister_netdev(ndev);
netiucv_unregister_device(dev);
return count;
}
printk(KERN_WARNING
"netiucv: net device %s unknown\n", name);
return -EINVAL;
}
DRIVER_ATTR(remove, 0200, NULL, remove_write);
static struct device_driver netiucv_driver = {
.name = "netiucv",
.bus = &iucv_bus,
......@@ -1899,7 +1958,7 @@ static struct device_driver netiucv_driver = {
static void
netiucv_banner(void)
{
char vbuf[] = "$Revision: 1.51 $";
char vbuf[] = "$Revision: 1.53 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
......@@ -1924,6 +1983,7 @@ netiucv_exit(void)
}
driver_remove_file(&netiucv_driver, &driver_attr_connection);
driver_remove_file(&netiucv_driver, &driver_attr_remove);
driver_unregister(&netiucv_driver);
printk(KERN_INFO "NETIUCV driver unloaded\n");
......@@ -1943,10 +2003,10 @@ netiucv_init(void)
/* Add entry for specifying connections. */
ret = driver_create_file(&netiucv_driver, &driver_attr_connection);
if (ret == 0)
if (ret == 0) {
ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
netiucv_banner();
else {
} else {
printk(KERN_ERR "NETIUCV: failed to add driver attribute.\n");
driver_unregister(&netiucv_driver);
}
......
......@@ -23,7 +23,7 @@
#include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.102 $"
#define VERSION_QETH_H "$Revision: 1.107 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
......@@ -186,6 +186,8 @@ struct qeth_perf_stats {
__u64 outbound_start_time;
unsigned int outbound_cnt;
unsigned int outbound_time;
unsigned int inbound_do_qdio;
unsigned int outbound_do_qdio;
};
#endif /* CONFIG_QETH_PERF_STATS */
......@@ -279,7 +281,7 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_IN_BUF_COUNT_MAX 128
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
((card)->qdio.in_buf_pool.buf_count / 4)
((card)->qdio.in_buf_pool.buf_count / 2)
/* buffers we have to be behind before we get a PCI */
#define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1)
......@@ -606,6 +608,7 @@ struct qeth_reply {
wait_queue_head_t wait_q;
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
int seqno;
unsigned long offset;
int received;
int rc;
void *param;
......@@ -613,8 +616,10 @@ struct qeth_reply {
atomic_t refcnt;
};
struct qeth_card_info {
#define QETH_BROADCAST_WITH_ECHO 1
#define QETH_BROADCAST_WITHOUT_ECHO 2
struct qeth_card_info {
char if_name[IF_NAME_LEN];
unsigned short unit_addr2;
unsigned short cula;
......@@ -646,7 +651,6 @@ struct qeth_card_options {
enum qeth_checksum_types checksum_type;
int broadcast_mode;
int macaddr_mode;
int enable_takeover;
int fake_broadcast;
int add_hhlen;
int fake_ll;
......
......@@ -12,6 +12,11 @@
#ifndef __QETH_FS_H__
#define __QETH_FS_H__
#define VERSION_QETH_FS_H "$Revision: 1.8 $"
extern const char *VERSION_QETH_PROC_C;
extern const char *VERSION_QETH_SYS_C;
#ifdef CONFIG_PROC_FS
extern int
qeth_create_procfs_entries(void);
......
/*
*
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.89 $)
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.107 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
......@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com>
*
* $Revision: 1.89 $ $Date: 2004/04/27 16:27:26 $
* $Revision: 1.107 $ $Date: 2004/05/13 16:07:59 $
*
* 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
......@@ -78,10 +78,9 @@ qeth_eyecatcher(void)
#include "qeth_mpc.h"
#include "qeth_fs.h"
#define VERSION_QETH_C "$Revision: 1.89 $"
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 ")";
#define VERSION_QETH_C "$Revision: 1.107 $"
static const char *version = "qeth S/390 OSA-Express driver";
/**
* Debug Facility Stuff
*/
......@@ -105,8 +104,6 @@ struct qeth_card_list_struct qeth_card_list;
static void qeth_send_control_data_cb(struct qeth_channel *,
struct qeth_cmd_buffer *);
static atomic_t qeth_hsi_count;
/**
* here we go with function implementation
*/
......@@ -154,6 +151,10 @@ qeth_irq_tasklet(unsigned long);
static int
qeth_set_online(struct ccwgroup_device *);
static struct qeth_ipaddr *
qeth_get_addr_buffer(enum qeth_prot_versions);
/**
* free channel command buffers
*/
......@@ -478,8 +479,6 @@ qeth_remove_device(struct ccwgroup_device *cgdev)
card->use_hard_stop = 1;
qeth_set_offline(cgdev);
}
if (card->info.type == QETH_CARD_TYPE_IQD)
atomic_dec(&qeth_hsi_count);
/* remove form our internal list */
write_lock_irqsave(&qeth_card_list.rwlock, flags);
list_del(&card->list);
......@@ -700,7 +699,7 @@ static void
qeth_set_ip_addr_list(struct qeth_card *card)
{
struct list_head failed_todos;
struct qeth_ipaddr *todo, *addr, *tmp;
struct qeth_ipaddr *todo, *addr;
unsigned long flags;
int rc;
......@@ -709,9 +708,10 @@ qeth_set_ip_addr_list(struct qeth_card *card)
INIT_LIST_HEAD(&failed_todos);
process_todos:
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry_safe(todo, tmp, &card->ip_tbd_list, entry) {
while (!list_empty(&card->ip_tbd_list)) {
todo = list_entry(card->ip_tbd_list.next,
struct qeth_ipaddr, entry);
list_del_init(&todo->entry);
rc = __qeth_ref_ip_on_card(card, todo, &addr);
if (rc == 0) {
......@@ -721,28 +721,24 @@ qeth_set_ip_addr_list(struct qeth_card *card)
/* new entry to be added to on-card list */
spin_unlock_irqrestore(&card->ip_lock, flags);
rc = qeth_register_addr_entry(card, todo);
if (!rc){
spin_lock_irqsave(&card->ip_lock, flags);
spin_lock_irqsave(&card->ip_lock, flags);
if (!rc)
list_add_tail(&todo->entry, &card->ip_list);
spin_unlock_irqrestore(&card->ip_lock, flags);
} else
else
list_add_tail(&todo->entry, &failed_todos);
goto process_todos;
} else if (rc == -1) {
/* on-card entry to be removed */
list_del_init(&addr->entry);
spin_unlock_irqrestore(&card->ip_lock, flags);
rc = qeth_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, flags);
if (!rc) {
kfree(addr);
kfree(todo);
} else {
spin_lock_irqsave(&card->ip_lock, flags);
list_add_tail(&addr->entry, &card->ip_list);
list_add_tail(&todo->entry, &failed_todos);
spin_unlock_irqrestore(&card->ip_lock, flags);
}
goto process_todos;
}
}
spin_unlock_irqrestore(&card->ip_lock, flags);
......@@ -937,7 +933,6 @@ qeth_set_intial_options(struct qeth_card *card)
card->options.checksum_type = QETH_CHECKSUM_DEFAULT;
card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL;
card->options.enable_takeover = 1;
card->options.fake_broadcast = 0;
card->options.add_hhlen = DEFAULT_ADD_HHLEN;
card->options.fake_ll = 0;
......@@ -998,10 +993,6 @@ qeth_determine_card_type(struct qeth_card *card)
if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
(CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
card->info.type = known_devices[i][4];
if (card->options.enable_takeover)
card->info.func_level = known_devices[i][6];
else
card->info.func_level = known_devices[i][7];
card->qdio.no_out_queues = known_devices[i][8];
card->info.is_multicast_different = known_devices[i][9];
return 0;
......@@ -1627,10 +1618,13 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
spin_unlock_irqrestore(&card->lock, flags);
keep_reply = 0;
if (reply->callback != NULL) {
if (cmd)
if (cmd) {
reply->offset = (__u16)((char*)cmd -
(char *)iob->data);
keep_reply = reply->callback(card,
reply,
(unsigned long)cmd);
}
else
keep_reply = reply->callback(card,
reply,
......@@ -1703,7 +1697,10 @@ qeth_send_control_data(struct qeth_card *card, int len,
init_timer(&timer);
timer.function = qeth_cmd_timeout;
timer.data = (unsigned long) reply;
timer.expires = jiffies + QETH_TIMEOUT;
if (IS_IPA(iob->data))
timer.expires = jiffies + QETH_IPA_TIMEOUT;
else
timer.expires = jiffies + QETH_TIMEOUT;
init_waitqueue_head(&reply->wait_q);
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list, &card->cmd_waiter_list);
......@@ -1743,12 +1740,10 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
(struct qeth_card *,struct qeth_reply*, unsigned long),
void *reply_param)
{
struct qeth_ipa_cmd *cmd;
int rc;
QETH_DBF_TEXT(trace,4,"sendipa");
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
&card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
......@@ -2227,12 +2222,14 @@ qeth_process_inbound_buffer(struct qeth_card *card,
while((skb = qeth_get_next_skb(card, buf->buffer, &element,
&offset, &hdr))){
qeth_rebuild_skb(card, skb, hdr);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_time += qeth_get_micros() -
card->perf_stats.inbound_start_time;
card->perf_stats.inbound_cnt++;
#endif
if (((*(int *)0xff0)==1) &&
(skb->pkt_type == PACKET_BROADCAST))
qeth_hex_dump(skb->data, 100);
/* is device UP ? */
if (!(card->dev->flags & IFF_UP)){
dev_kfree_skb_irq(skb);
continue;
}
skb->dev = card->dev;
rxrc = netif_rx(skb);
card->dev->last_rx = jiffies;
......@@ -2330,6 +2327,9 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
* 'index') un-requeued -> this buffer is the first buffer that
* will be requeued the next time
*/
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_do_qdio++;
#endif
rc = do_QDIO(CARD_DDEV(card),
QDIO_FLAG_SYNC_INPUT,
0, queue->next_buf_to_init, count, NULL);
......@@ -2369,6 +2369,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_cnt++;
card->perf_stats.inbound_start_time = qeth_get_micros();
#endif
if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
......@@ -2391,6 +2392,10 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
qeth_put_buffer_pool_entry(card, buffer->pool_entry);
qeth_queue_input_buffer(card, index);
}
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_time += qeth_get_micros() -
card->perf_stats.inbound_start_time;
#endif
}
static inline int
......@@ -2479,6 +2484,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
}
queue->card->dev->trans_start = jiffies;
#ifdef CONFIG_QETH_PERF_STATS
queue->card->perf_stats.outbound_do_qdio++;
#endif
if (under_int)
rc = do_QDIO(CARD_DDEV(queue->card),
QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
......@@ -2497,7 +2505,6 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
}
#ifdef CONFIG_QETH_PERF_STATS
queue->card->perf_stats.bufs_sent += count;
queue->card->perf_stats.outbound_cnt++;
#endif
}
......@@ -2850,6 +2857,9 @@ qeth_init_qdio_queues(struct qeth_card *card)
for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i)
qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]);
card->qdio.in_q->next_buf_to_init = card->qdio.in_buf_pool.buf_count - 1;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_do_qdio++;
#endif
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0,
card->qdio.in_buf_pool.buf_count - 1, NULL);
if (rc) {
......@@ -3134,20 +3144,6 @@ qeth_mpc_initialize(struct qeth_card *card)
return rc;
}
static void
qeth_set_device_name(struct qeth_card *card)
{
char buf[IF_NAME_LEN];
memset(buf, 0, IF_NAME_LEN);
if (card->info.type == QETH_CARD_TYPE_IQD) {
sprintf(buf,"hsi%d", atomic_read(&qeth_hsi_count));
atomic_inc(&qeth_hsi_count);
memcpy(card->dev->name,buf,IF_NAME_LEN);
}
}
static struct net_device *
qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype)
{
......@@ -3167,6 +3163,8 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype)
}
break;
case QETH_CARD_TYPE_IQD:
dev = alloc_netdev(0, "hsi%d", ether_setup);
break;
default:
dev = alloc_etherdev(0);
}
......@@ -3200,6 +3198,7 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
return -EBUSY;
}
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_cnt++;
card->perf_stats.outbound_start_time = qeth_get_micros();
#endif
/*
......@@ -3210,6 +3209,10 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!(rc = qeth_send_packet(card, skb)))
netif_wake_queue(dev);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() -
card->perf_stats.outbound_start_time;
#endif
return rc;
}
......@@ -3556,7 +3559,6 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf
int first_lap = 1;
QETH_DBF_TEXT(trace, 6, "qdfillbf");
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
......@@ -3710,10 +3712,6 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
if (!rc){
card->stats.tx_packets++;
card->stats.tx_bytes += skb->len;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() -
card->perf_stats.outbound_start_time;
#endif
}
return rc;
}
......@@ -3859,9 +3857,9 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
if (rc) {
tmp = rc;
PRINT_WARN("Could not set number of ARP entries on %s: "
"%s (0x%x)\n",
"%s (0x%x/%d)\n",
card->info.if_name, qeth_arp_get_error_cause(&rc),
tmp);
tmp, tmp);
}
return rc;
}
......@@ -3870,7 +3868,7 @@ static int
qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_arp_cmd *cmd;
struct qeth_ipa_cmd *cmd;
struct qeth_arp_query_data *qdata;
struct qeth_arp_query_info *qinfo;
int entry_size;
......@@ -3879,17 +3877,17 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
QETH_DBF_TEXT(trace,4,"arpquecb");
qinfo = (struct qeth_arp_query_info *) reply->param;
cmd = (struct qeth_ipa_arp_cmd *) data;
if (cmd->ihdr.return_code) {
QETH_DBF_TEXT_(trace,4,"qaer1%i", cmd->ihdr.return_code);
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
QETH_DBF_TEXT_(trace,4,"qaer1%i", cmd->hdr.return_code);
return 0;
}
if (cmd->shdr.return_code) {
cmd->ihdr.return_code = cmd->shdr.return_code;
QETH_DBF_TEXT_(trace,4,"qaer2%i", cmd->ihdr.return_code);
if (cmd->data.setassparms.hdr.return_code) {
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
QETH_DBF_TEXT_(trace,4,"qaer2%i", cmd->hdr.return_code);
return 0;
}
qdata = &cmd->data.query_arp;
qdata = &cmd->data.setassparms.data.query_arp;
switch(qdata->reply_bits){
case 5:
entry_size = sizeof(struct qeth_arp_qi_entry5);
......@@ -3906,20 +3904,21 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
if ((qinfo->udata_len - qinfo->udata_offset) <
qdata->no_entries * entry_size){
QETH_DBF_TEXT_(trace, 4, "qaer3%i", -ENOMEM);
cmd->ihdr.return_code = -ENOMEM;
cmd->hdr.return_code = -ENOMEM;
goto out_error;
}
QETH_DBF_TEXT_(trace, 4, "anore%i", cmd->shdr.number_of_replies);
QETH_DBF_TEXT_(trace, 4, "aseqn%i", cmd->shdr.seq_no);
QETH_DBF_TEXT_(trace, 4, "anore%i",
cmd->data.setassparms.hdr.number_of_replies);
QETH_DBF_TEXT_(trace, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
QETH_DBF_TEXT_(trace, 4, "anoen%i", qdata->no_entries);
for (i = 0; i < qdata->no_entries; ++i){
memcpy(qinfo->udata + qinfo->udata_offset,
qdata->data + i*entry_size, entry_size);
qinfo->no_entries++;
qinfo->udata_offset += entry_size;
}
/*copy entries to user buffer*/
memcpy(qinfo->udata + qinfo->udata_offset,
(char *)&qdata->data, qdata->no_entries*entry_size);
qinfo->no_entries += qdata->no_entries;
qinfo->udata_offset += (qdata->no_entries*entry_size);
/* check if all replies received ... */
if (cmd->shdr.seq_no < cmd->shdr.number_of_replies)
if (cmd->data.setassparms.hdr.seq_no <
cmd->data.setassparms.hdr.number_of_replies)
return 1;
memcpy(qinfo->udata, &qinfo->no_entries, 4);
memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET,&qdata->reply_bits,2);
......@@ -3930,70 +3929,32 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
return 0;
}
static struct qeth_cmd_buffer *
qeth_get_ipacmd_buffer(struct qeth_card *, enum qeth_ipa_cmds,
enum qeth_prot_versions);
struct qeth_cmd_buffer *
qeth_get_ipa_arp_cmd_buffer(struct qeth_card *card, u16 cmd_code,
u32 data_len, enum qeth_prot_versions proto)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_arp_cmd *cmd;
u16 s1, s2;
QETH_DBF_TEXT(trace,4,"getarpcm");
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, proto);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
if ((IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN + data_len) > 256) {
/* adjust sizes in IPA_PDU_HEADER */
s1 = (u32) IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN +
data_len;
s2 = (u32) QETH_ARP_CMD_BASE_LEN + data_len;
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
}
cmd = (struct qeth_ipa_arp_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->shdr.assist_no = IPA_ARP_PROCESSING;
cmd->shdr.length = 8 + data_len;
cmd->shdr.command_code = cmd_code;
cmd->shdr.return_code = 0;
cmd->shdr.seq_no = 0;
return iob;
}
static int
qeth_send_ipa_arp_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
char *data, int data_len,
int (*reply_cb)
(struct qeth_card *,struct qeth_reply*, unsigned long),
int len, int (*reply_cb)
(struct qeth_card *,
struct qeth_reply*, unsigned long),
void *reply_param)
{
int rc;
QETH_DBF_TEXT(trace,4,"sendarp");
memcpy(QETH_IPA_ARP_DATA_POS(iob->data), data, data_len);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
&card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
rc = qeth_send_control_data(card, IPA_PDU_HEADER_SIZE +
QETH_ARP_CMD_BASE_LEN + data_len, iob,
rc = qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob,
reply_cb, reply_param);
return rc;
}
static struct qeth_cmd_buffer *
qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
__u16, __u16, enum qeth_prot_versions);
static int
qeth_arp_query(struct qeth_card *card, char *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_arp_query_data *qdata;
struct qeth_arp_query_info qinfo = {0, };
int tmp;
int rc;
......@@ -4008,40 +3969,33 @@ qeth_arp_query(struct qeth_card *card, char *udata)
*/
if (card->info.guestlan)
return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/
IPA_ARP_PROCESSING)) {
PRINT_WARN("ARP processing not supported "
"on %s!\n", card->info.if_name);
return -EOPNOTSUPP;
}
/* get size of userspace mem area */
if (copy_from_user(&qinfo.udata_len, udata, 4))
return -EFAULT;
if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL)))
return -ENOMEM;
memset(qinfo.udata, 0, qinfo.udata_len);
qinfo.udata_offset = QETH_QARP_ENTRIES_OFFSET;
/* alloc mem area for the actual query */
if (!(qdata = kmalloc(sizeof(struct qeth_arp_query_data),
GFP_KERNEL))){
kfree(qinfo.udata);
return -ENOMEM;
}
memset(qdata, 0, sizeof(struct qeth_arp_query_data));
/* do not give sizeof(struct qeth_arp_query_data) to next command;
* this would cause the IPA PDU size to be set to a value of > 256
* and this is to much for HiperSockets */
iob = qeth_get_ipa_arp_cmd_buffer(card, IPA_CMD_ASS_ARP_QUERY_INFO,
0, QETH_PROT_IPV4);
iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_QUERY_INFO,
sizeof(int),QETH_PROT_IPV4);
rc = qeth_send_ipa_arp_cmd(card, iob,
(char *) qdata,
sizeof(struct qeth_arp_query_data),
QETH_SETASS_BASE_LEN+QETH_ARP_CMD_LEN,
qeth_arp_query_cb,
(void *)&qinfo);
if (rc) {
tmp = rc;
PRINT_WARN("Error while querying ARP cache on %s: %s (0x%x)\n",
PRINT_WARN("Error while querying ARP cache on %s: %s "
"(0x%x/%d)\n",
card->info.if_name, qeth_arp_get_error_cause(&rc),
tmp);
tmp, tmp);
copy_to_user(udata, qinfo.udata, 4);
} else {
copy_to_user(udata, qinfo.udata, qinfo.udata_len);
......@@ -4054,10 +4008,6 @@ static int
qeth_default_setassparms_cb(struct qeth_card *, struct qeth_reply *,
unsigned long);
static struct qeth_cmd_buffer *
qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
__u16, __u16, enum qeth_prot_versions);
static int
qeth_send_setassparms(struct qeth_card *, struct qeth_cmd_buffer *,
__u16, long,
......@@ -4101,9 +4051,9 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry)
tmp = rc;
qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
PRINT_WARN("Could not add ARP entry for address %s on %s: "
"%s (0x%x)\n",
"%s (0x%x/%d)\n",
buf, card->info.if_name,
qeth_arp_get_error_cause(&rc), tmp);
qeth_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
}
......@@ -4144,9 +4094,9 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry
memset(buf, 0, 16);
qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf);
PRINT_WARN("Could not delete ARP entry for address %s on %s: "
"%s (0x%x)\n",
"%s (0x%x/%d)\n",
buf, card->info.if_name,
qeth_arp_get_error_cause(&rc), tmp);
qeth_arp_get_error_cause(&rc), tmp, tmp);
}
return rc;
}
......@@ -4165,7 +4115,7 @@ qeth_arp_flush_cache(struct qeth_card *card)
* funcs flags); since all zeros is no valueable information,
* we say EOPNOTSUPP for all ARP functions
*/
if (card->info.guestlan)
if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD))
return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
PRINT_WARN("ARP processing not supported "
......@@ -4176,9 +4126,9 @@ qeth_arp_flush_cache(struct qeth_card *card)
IPA_CMD_ASS_ARP_FLUSH_CACHE, 0);
if (rc){
tmp = rc;
PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x)\n",
PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x/%d)\n",
card->info.if_name, qeth_arp_get_error_cause(&rc),
tmp);
tmp, tmp);
}
return rc;
}
......@@ -4198,7 +4148,6 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -ENODEV;
switch (cmd){
case SIOCDEVPRIVATE:
case SIOC_QETH_ARP_SET_NO_ENTRIES:
if (!capable(CAP_NET_ADMIN)){
rc = -EPERM;
......@@ -4206,7 +4155,6 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
rc = qeth_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue);
break;
case SIOCDEVPRIVATE+1:
case SIOC_QETH_ARP_QUERY_INFO:
if (!capable(CAP_NET_ADMIN)){
rc = -EPERM;
......@@ -4214,7 +4162,6 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
rc = qeth_arp_query(card, rq->ifr_ifru.ifru_data);
break;
case SIOCDEVPRIVATE+2:
case SIOC_QETH_ARP_ADD_ENTRY:
if (!capable(CAP_NET_ADMIN)){
rc = -EPERM;
......@@ -4226,7 +4173,6 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
else
rc = qeth_arp_add_entry(card, &arp_entry);
break;
case SIOCDEVPRIVATE+3:
case SIOC_QETH_ARP_REMOVE_ENTRY:
if (!capable(CAP_NET_ADMIN)){
rc = -EPERM;
......@@ -4238,7 +4184,6 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
else
rc = qeth_arp_remove_entry(card, &arp_entry);
break;
case SIOCDEVPRIVATE+4:
case SIOC_QETH_ARP_FLUSH_CACHE:
if (!capable(CAP_NET_ADMIN)){
rc = -EPERM;
......@@ -4246,10 +4191,8 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
rc = qeth_arp_flush_cache(card);
break;
case SIOCDEVPRIVATE+5:
case SIOC_QETH_ADP_SET_SNMP_CONTROL:
break;
case SIOCDEVPRIVATE+6:
case SIOC_QETH_GET_CARD_TYPE:
break;
case SIOCGMIIPHY:
......@@ -4282,6 +4225,8 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
default:
rc = -EOPNOTSUPP;
}
if (rc)
QETH_DBF_TEXT_(trace, 2, "ioce%d", rc);
return rc;
}
......@@ -4325,27 +4270,124 @@ static void
qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct qeth_card *card;
unsigned long flags;
QETH_DBF_TEXT(trace,4,"vlanreg");
card = (struct qeth_card *) dev->priv;
spin_lock_irq(&card->vlanlock);
spin_lock_irqsave(&card->vlanlock, flags);
card->vlangrp = grp;
spin_unlock_irq(&card->vlanlock);
spin_unlock_irqrestore(&card->vlanlock, flags);
}
static inline void
qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
unsigned short vid)
{
int i;
struct sk_buff *skb;
struct sk_buff_head tmp_list;
skb_queue_head_init(&tmp_list);
for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i){
while ((skb = skb_dequeue(&buf->skb_list))){
if (vlan_tx_tag_present(skb) &&
(vlan_tx_tag_get(skb) == vid)) {
atomic_dec(&skb->users);
dev_kfree_skb(skb);
} else
skb_queue_tail(&tmp_list, skb);
}
}
while ((skb = skb_dequeue(&tmp_list)))
skb_queue_tail(&buf->skb_list, skb);
}
static void
qeth_free_vlan_skbs(struct qeth_card *card, unsigned short vid)
{
int i, j;
QETH_DBF_TEXT(trace, 4, "frvlskbs");
for (i = 0; i < card->qdio.no_out_queues; ++i){
for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
qeth_free_vlan_buffer(card, &card->qdio.
out_qs[i]->bufs[j], vid);
}
}
static void
qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)
{
struct in_device *in_dev;
struct in_ifaddr *ifa;
struct qeth_ipaddr *addr;
QETH_DBF_TEXT(trace, 4, "frvaddr4");
if (!card->vlangrp)
return;
in_dev = in_dev_get(card->vlangrp->vlan_devices[vid]);
if (!in_dev)
return;
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){
addr = qeth_get_addr_buffer(QETH_PROT_IPV4);
if (addr){
addr->u.a4.addr = ifa->ifa_address;
addr->u.a4.mask = ifa->ifa_mask;
addr->type = QETH_IP_TYPE_NORMAL;
if (!qeth_delete_ip(card, addr))
kfree(addr);
}
}
in_dev_put(in_dev);
}
static void
qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)
{
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifa;
struct qeth_ipaddr *addr;
QETH_DBF_TEXT(trace, 4, "frvaddr6");
if (!card->vlangrp)
return;
in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
if (!in6_dev)
return;
for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next){
addr = qeth_get_addr_buffer(QETH_PROT_IPV6);
if (addr){
memcpy(&addr->u.a6.addr, &ifa->addr,
sizeof(struct in6_addr));
addr->u.a6.pfxlen = ifa->prefix_len;
addr->type = QETH_IP_TYPE_NORMAL;
if (!qeth_delete_ip(card, addr))
kfree(addr);
}
}
in6_dev_put(in6_dev);
}
static void
qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct qeth_card *card;
unsigned long flags;
QETH_DBF_TEXT(trace,4,"vlkilvid");
card = (struct qeth_card *) dev->priv;
spin_lock_irq(&card->vlanlock);
/* free all skbs for the vlan device */
qeth_free_vlan_skbs(card, vid);
spin_lock_irqsave(&card->vlanlock, flags);
/* unregister IP addresses of vlan device */
qeth_free_vlan_addresses4(card, vid);
qeth_free_vlan_addresses6(card, vid);
if (card->vlangrp)
card->vlangrp->vlan_devices[vid] = NULL;
spin_unlock_irq(&card->vlanlock);
spin_unlock_irqrestore(&card->vlanlock, flags);
qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
/* delete mc addresses for this vlan dev */
qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD);
schedule_work(&card->kernel_thread_starter);
......@@ -4401,10 +4443,6 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot)
memset(addr,0,sizeof(struct qeth_ipaddr));
addr->type = QETH_IP_TYPE_NORMAL;
addr->proto = prot;
addr->is_multicast = 0;
addr->users = 0;
addr->set_flags = 0;
addr->del_flags = 0;
return addr;
}
......@@ -4811,6 +4849,26 @@ qeth_netdev_init(struct net_device *dev)
return 0;
}
static void
qeth_init_func_level(struct qeth_card *card)
{
if (card->ipato.enabled) {
if (card->info.type == QETH_CARD_TYPE_IQD)
card->info.func_level =
QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
else
card->info.func_level =
QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT;
} else {
if (card->info.type == QETH_CARD_TYPE_IQD)
card->info.func_level =
QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
else
card->info.func_level =
QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT;
}
}
/**
* hardsetup card, initialize MPC and QDIO stuff
*/
......@@ -4848,6 +4906,7 @@ qeth_hardsetup_card(struct qeth_card *card)
return rc;
}
qeth_init_tokens(card);
qeth_init_func_level(card);
rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
if (rc == -ERESTARTSYS) {
QETH_DBF_TEXT(setup, 2, "break2");
......@@ -4885,7 +4944,6 @@ qeth_hardsetup_card(struct qeth_card *card)
QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
goto out;
}
qeth_set_device_name(card);
card->dev->priv = card;
card->dev->type = qeth_get_arphdr_type(card->info.type,
card->info.link_type);
......@@ -4898,7 +4956,7 @@ qeth_hardsetup_card(struct qeth_card *card)
}
static struct qeth_cmd_buffer *
qeth_get_adapter_cmd(struct qeth_card *card, __u32 command)
qeth_get_adapter_cmd(struct qeth_card *card, __u32 command, __u32 cmdlen)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
......@@ -4906,11 +4964,10 @@ qeth_get_adapter_cmd(struct qeth_card *card, __u32 command)
iob = qeth_get_ipacmd_buffer(card,IPA_CMD_SETADAPTERPARMS,
QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.cmdlength =
sizeof(struct qeth_ipacmd_setadpparms);
cmd->data.setadapterparms.command_code = command;
cmd->data.setadapterparms.frames_used_total = 1;
cmd->data.setadapterparms.frame_seq_no = 1;
cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
cmd->data.setadapterparms.hdr.command_code = command;
cmd->data.setadapterparms.hdr.used_total = 1;
cmd->data.setadapterparms.hdr.seq_no = 1;
return iob;
}
......@@ -4952,7 +5009,7 @@ qeth_default_setadapterparms_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0)
cmd->hdr.return_code = cmd->data.setadapterparms.return_code;
cmd->hdr.return_code = cmd->data.setadapterparms.hdr.return_code;
return 0;
}
......@@ -4980,7 +5037,8 @@ qeth_query_setadapterparms(struct qeth_card *card)
struct qeth_cmd_buffer *iob;
QETH_DBF_TEXT(trace,3,"queryadp");
iob = qeth_get_adapter_cmd(card,IPA_SETADP_QUERY_COMMANDS_SUPPORTED);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED,
sizeof(struct qeth_ipacmd_setadpparms));
rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
return rc;
}
......@@ -5010,7 +5068,8 @@ qeth_setadpparms_change_macaddr(struct qeth_card *card)
QETH_DBF_TEXT(trace,4,"chgmac");
iob = qeth_get_adapter_cmd(card,IPA_SETADP_ALTER_MAC_ADDRESS);
iob = qeth_get_adapter_cmd(card,IPA_SETADP_ALTER_MAC_ADDRESS,
sizeof(struct qeth_ipacmd_setadpparms));
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC;
cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN;
......@@ -5030,7 +5089,8 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
QETH_DBF_TEXT(trace,4,"adpmode");
iob = qeth_get_adapter_cmd(card, command);
iob = qeth_get_adapter_cmd(card, command,
sizeof(struct qeth_ipacmd_setadpparms));
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.data.mode = mode;
rc = qeth_send_ipa_cmd(card, iob, qeth_default_setadapterparms_cb,
......@@ -5459,18 +5519,20 @@ qeth_start_ipa_broadcast(struct qeth_card *card)
int rc;
QETH_DBF_TEXT(trace,3,"stbrdcst");
card->info.broadcast_capable = 0;
if (!qeth_is_supported(card, IPA_FILTERING)) {
PRINT_WARN("Broadcast not supported on %s\n",
card->info.if_name);
return -EOPNOTSUPP;
rc = -EOPNOTSUPP;
goto out;
}
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
IPA_CMD_ASS_START, 0);
if (rc) {
PRINT_WARN("Could not enable broadcasting "
PRINT_WARN("Could not enable broadcasting filtering "
"on %s: 0x%x\n",
card->info.if_name, rc);
return rc;
goto out;
}
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
......@@ -5478,12 +5540,24 @@ qeth_start_ipa_broadcast(struct qeth_card *card)
if (rc) {
PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n",
card->info.if_name, rc);
return rc;
goto out;
}
card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO;
PRINT_INFO("Broadcast enabled \n");
card->dev->flags |= IFF_BROADCAST;
card->info.broadcast_capable = 1;
return 0;
rc = qeth_send_simple_setassparms(card, IPA_FILTERING,
IPA_CMD_ASS_ENABLE, 1);
if (rc) {
PRINT_WARN("Could not set up broadcast echo filtering on "
"%s: 0x%x\n", card->info.if_name, rc);
goto out;
}
card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO;
out:
if (card->info.broadcast_capable)
card->dev->flags |= IFF_BROADCAST;
else
card->dev->flags &= ~IFF_BROADCAST;
return rc;
}
static int
......@@ -5781,7 +5855,6 @@ static void
qeth_clear_ip_list(struct qeth_card *card, int clean, int recover)
{
struct qeth_ipaddr *addr, *tmp;
int first_run = 1;
unsigned long flags;
QETH_DBF_TEXT(trace,4,"clearip");
......@@ -5791,29 +5864,21 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover)
list_del(&addr->entry);
kfree(addr);
}
again:
if (first_run)
first_run = 0;
else
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
while (!list_empty(&card->ip_list)) {
addr = list_entry(card->ip_list.next,
struct qeth_ipaddr, entry);
list_del_init(&addr->entry);
if (clean){
if (clean) {
spin_unlock_irqrestore(&card->ip_lock, flags);
qeth_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, flags);
}
if (!recover || addr->is_multicast)
if (!recover || addr->is_multicast) {
kfree(addr);
else {
if (clean)
spin_lock_irqsave(&card->ip_lock, flags);
list_add_tail(&addr->entry, &card->ip_tbd_list);
if (clean) {
spin_unlock_irqrestore(&card->ip_lock, flags);
goto again;
}
continue;
}
list_add_tail(&addr->entry, &card->ip_tbd_list);
}
spin_unlock_irqrestore(&card->ip_lock, flags);
}
......@@ -6775,12 +6840,16 @@ qeth_init(void)
int rc=0;
qeth_eyecatcher();
printk(KERN_INFO "qeth: loading %s\n",version);
PRINT_INFO("loading %s (%s/%s/%s/%s/%s/%s/%s %s %s)\n",
version, VERSION_QETH_C, VERSION_QETH_H,
VERSION_QETH_MPC_H, VERSION_QETH_MPC_C,
VERSION_QETH_FS_H, VERSION_QETH_PROC_C,
VERSION_QETH_SYS_C, QETH_VERSION_IPV6,
QETH_VERSION_VLAN);
INIT_LIST_HEAD(&qeth_card_list.list);
rwlock_init(&qeth_card_list.rwlock);
atomic_set(&qeth_hsi_count, 0);
if (qeth_register_dbf_views())
goto out_err;
if (qeth_sysfs_register())
......
......@@ -11,6 +11,8 @@
#include <asm/cio.h>
#include "qeth_mpc.h"
const char *VERSION_QETH_MPC_C = "$Revision: 1.11 $";
unsigned char IDX_ACTIVATE_READ[]={
0x00,0x00,0x80,0x00, 0x00,0x00,0x00,0x00,
0x19,0x01,0x01,0x80, 0x00,0x00,0x00,0x00,
......@@ -129,8 +131,7 @@ unsigned char IPA_PDU_HEADER[]={
0x00,0x00,0x00,0x14, 0x00,0x00,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))/256,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))%256,
0x10,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,
0x10,0x00,0x00,0x01, 0x00,0x00,0x00,0x00,
0xc1,0x03,0x00,0x01, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x24,
sizeof(struct qeth_ipa_cmd)/256,
......
......@@ -14,7 +14,9 @@
#include <asm/qeth.h>
#define VERSION_QETH_MPC_H "$Revision: 1.27 $"
#define VERSION_QETH_MPC_H "$Revision: 1.34 $"
extern const char *VERSION_QETH_MPC_C;
#define IPA_PDU_HEADER_SIZE 0x40
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
......@@ -33,6 +35,7 @@ extern unsigned char IPA_PDU_HEADER[];
#define OSA_ADDR_LEN 6
#define QETH_TIMEOUT (10 * HZ)
#define QETH_IPA_TIMEOUT (45 * HZ)
#define QETH_IDX_COMMAND_SEQNO -1
#define SR_INFO_LEN 16
......@@ -245,12 +248,28 @@ struct qeth_ipacmd_setassparms_hdr {
__u8 seq_no;
} __attribute__((packed));
struct qeth_arp_query_data {
__u16 request_bits;
__u16 reply_bits;
__u32 no_entries;
char data;
} __attribute__((packed));
/* used as parameter for arp_query reply */
struct qeth_arp_query_info {
__u32 udata_len;
__u32 udata_offset;
__u32 no_entries;
char *udata;
};
/* SETASSPARMS IPA Command: */
struct qeth_ipacmd_setassparms {
struct qeth_ipacmd_setassparms_hdr hdr;
union {
__u32 flags_32bit;
struct qeth_arp_cache_entry add_arp_entry;
struct qeth_arp_query_data query_arp;
__u8 ip[16];
} data;
} __attribute__ ((packed));
......@@ -277,16 +296,20 @@ struct qeth_change_addr {
__u8 addr[OSA_ADDR_LEN];
} __attribute__ ((packed));
struct qeth_ipacmd_setadpparms {
struct qeth_ipacmd_setadpparms_hdr {
__u32 supp_hw_cmds;
__u32 reserved1;
__u16 cmdlength;
__u16 reserved2;
__u32 command_code;
__u16 return_code;
__u8 frames_used_total;
__u8 frame_seq_no;
__u8 used_total;
__u8 seq_no;
__u32 reserved3;
} __attribute__ ((packed));
struct qeth_ipacmd_setadpparms {
struct qeth_ipacmd_setadpparms_hdr hdr;
union {
struct qeth_query_cmds_supp query_cmds_supp;
struct qeth_change_addr change_addr;
......@@ -357,36 +380,16 @@ enum qeth_ipa_arp_return_codes {
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
};
#define QETH_QARP_DATA_SIZE 3968
struct qeth_arp_query_data {
__u16 request_bits;
__u16 reply_bits;
__u32 no_entries;
char data[QETH_QARP_DATA_SIZE];
} __attribute__((packed));
/* used as parameter for arp_query reply */
struct qeth_arp_query_info {
__u32 udata_len;
__u32 udata_offset;
__u32 no_entries;
char *udata;
};
#define IPA_ARP_CMD_LEN (IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_arp_cmd))
#define QETH_ARP_CMD_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
#define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setassparms_hdr))
#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
QETH_ARP_CMD_BASE_LEN)
struct qeth_ipa_arp_cmd {
struct qeth_ipacmd_hdr ihdr;
struct qeth_ipacmd_setassparms_hdr shdr;
union {
struct qeth_arp_query_data query_arp;
} data;
} __attribute__((packed));
QETH_SETASS_BASE_LEN)
#define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setadpparms_hdr))
#define QETH_SNMP_SETADP_CMDLENGTH 16
#define QETH_ARP_DATA_SIZE 3968
#define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8)
/* Helper functions */
#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST)
......
/*
*
* linux/drivers/s390/net/qeth_fs.c ($Revision: 1.5 $)
* linux/drivers/s390/net/qeth_fs.c ($Revision: 1.9 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to procfs.
......@@ -21,6 +21,8 @@
#include "qeth_mpc.h"
#include "qeth_fs.h"
const char *VERSION_QETH_PROC_C = "$Revision: 1.9 $";
/***** /proc/qeth *****/
#define QETH_PROCFILE_NAME "qeth"
static struct proc_dir_entry *qeth_procfile;
......@@ -91,13 +93,19 @@ qeth_get_router_str(struct qeth_card *card, int ipv)
return "pri";
else if (routing_type == SECONDARY_ROUTER)
return "sec";
else if (routing_type == MULTICAST_ROUTER)
else if (routing_type == MULTICAST_ROUTER) {
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return "mc+";
return "mc";
else if (routing_type == PRIMARY_CONNECTOR)
} else if (routing_type == PRIMARY_CONNECTOR) {
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return "p+c";
return "p.c";
else if (routing_type == SECONDARY_CONNECTOR)
} else if (routing_type == SECONDARY_CONNECTOR) {
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return "s+c";
return "s.c";
else if (routing_type == NO_ROUTER)
} else if (routing_type == NO_ROUTER)
return "no";
else
return "unk";
......@@ -244,14 +252,18 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
: 0
);
seq_printf(s, " Inbound time (in us) : %i\n"
" Inbound cnt : %i\n"
" Inbound count : %i\n"
" Inboud do_QDIO count : %i\n"
" Outbound time (in us, incl QDIO) : %i\n"
" Outbound cnt : %i\n"
" Outbound count : %i\n"
" Outbound do_QDIO count : %i\n"
" Watermarks L/H : %i/%i\n\n",
card->perf_stats.inbound_time,
card->perf_stats.inbound_cnt,
card->perf_stats.inbound_do_qdio,
card->perf_stats.outbound_time,
card->perf_stats.outbound_cnt,
card->perf_stats.outbound_do_qdio,
QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK
);
......
/*
*
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.24 $)
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.29 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to sysfs.
......@@ -20,6 +20,8 @@
#include "qeth_mpc.h"
#include "qeth_fs.h"
const char *VERSION_QETH_SYS_C = "$Revision: 1.29 $";
/*****************************************************************************/
/* */
/* /sys-fs stuff UNDER DEVELOPMENT !!! */
......@@ -737,6 +739,10 @@ qeth_dev_ipato_enable_store(struct device *dev, const char *buf, size_t count)
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")){
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
......
......@@ -12,15 +12,13 @@
#define __ASM_S390_IOCTL_H__
#include <linux/ioctl.h>
#define QETH_IOCTL_LETTER 'Q'
#define SIOC_QETH_ARP_SET_NO_ENTRIES _IOWR(QETH_IOCTL_LETTER, 1, int)
#define SIOC_QETH_ARP_QUERY_INFO _IOWR(QETH_IOCTL_LETTER, 2, int)
#define SIOC_QETH_ARP_ADD_ENTRY _IOWR(QETH_IOCTL_LETTER, 3, int)
#define SIOC_QETH_ARP_REMOVE_ENTRY _IOWR(QETH_IOCTL_LETTER, 4, int)
#define SIOC_QETH_ARP_FLUSH_CACHE _IOWR(QETH_IOCTL_LETTER, 5, int)
#define SIOC_QETH_ADP_SET_SNMP_CONTROL _IOWR(QETH_IOCTL_LETTER, 6, int)
#define SIOC_QETH_GET_CARD_TYPE _IOWR(QETH_IOCTL_LETTER, 7, int)
#define SIOC_QETH_ARP_SET_NO_ENTRIES (SIOCDEVPRIVATE)
#define SIOC_QETH_ARP_QUERY_INFO (SIOCDEVPRIVATE + 1)
#define SIOC_QETH_ARP_ADD_ENTRY (SIOCDEVPRIVATE + 2)
#define SIOC_QETH_ARP_REMOVE_ENTRY (SIOCDEVPRIVATE + 3)
#define SIOC_QETH_ARP_FLUSH_CACHE (SIOCDEVPRIVATE + 4)
#define SIOC_QETH_ADP_SET_SNMP_CONTROL (SIOCDEVPRIVATE + 5)
#define SIOC_QETH_GET_CARD_TYPE (SIOCDEVPRIVATE + 6)
struct qeth_arp_cache_entry {
__u8 macaddr[6];
......
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