summaryrefslogtreecommitdiffstats
path: root/drivers/s390/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/net
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/s390/net')
-rw-r--r--drivers/s390/net/Kconfig108
-rw-r--r--drivers/s390/net/Makefile14
-rw-r--r--drivers/s390/net/claw.c4447
-rw-r--r--drivers/s390/net/claw.h335
-rw-r--r--drivers/s390/net/ctcdbug.c83
-rw-r--r--drivers/s390/net/ctcdbug.h123
-rw-r--r--drivers/s390/net/ctcmain.c3304
-rw-r--r--drivers/s390/net/ctctty.c1276
-rw-r--r--drivers/s390/net/ctctty.h37
-rw-r--r--drivers/s390/net/cu3088.c166
-rw-r--r--drivers/s390/net/cu3088.h41
-rw-r--r--drivers/s390/net/fsm.c220
-rw-r--r--drivers/s390/net/fsm.h265
-rw-r--r--drivers/s390/net/iucv.c2567
-rw-r--r--drivers/s390/net/iucv.h849
-rw-r--r--drivers/s390/net/lcs.c2347
-rw-r--r--drivers/s390/net/lcs.h321
-rw-r--r--drivers/s390/net/netiucv.c2149
-rw-r--r--drivers/s390/net/qeth.h1162
-rw-r--r--drivers/s390/net/qeth_eddp.c643
-rw-r--r--drivers/s390/net/qeth_eddp.h85
-rw-r--r--drivers/s390/net/qeth_fs.h163
-rw-r--r--drivers/s390/net/qeth_main.c8236
-rw-r--r--drivers/s390/net/qeth_mpc.c168
-rw-r--r--drivers/s390/net/qeth_mpc.h538
-rw-r--r--drivers/s390/net/qeth_proc.c495
-rw-r--r--drivers/s390/net/qeth_sys.c1788
-rw-r--r--drivers/s390/net/qeth_tso.c285
-rw-r--r--drivers/s390/net/qeth_tso.h58
-rw-r--r--drivers/s390/net/smsgiucv.c180
-rw-r--r--drivers/s390/net/smsgiucv.h10
31 files changed, 32463 insertions, 0 deletions
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
new file mode 100644
index 000000000000..a7efc394515e
--- /dev/null
+++ b/drivers/s390/net/Kconfig
@@ -0,0 +1,108 @@
+menu "S/390 network device drivers"
+ depends on NETDEVICES && ARCH_S390
+
+config LCS
+ tristate "Lan Channel Station Interface"
+ depends on NETDEVICES && (NET_ETHERNET || TR || FDDI)
+ help
+ Select this option if you want to use LCS networking on IBM S/390
+ or zSeries. This device driver supports Token Ring (IEEE 802.5),
+ FDDI (IEEE 802.7) and Ethernet.
+ This option is also available as a module which will be
+ called lcs.ko. If you do not know what it is, it's safe to say "Y".
+
+config CTC
+ tristate "CTC device support"
+ depends on NETDEVICES
+ help
+ Select this option if you want to use channel-to-channel networking
+ on IBM S/390 or zSeries. This device driver supports real CTC
+ coupling using ESCON. It also supports virtual CTCs when running
+ under VM. It will use the channel device configuration if this is
+ available. This option is also available as a module which will be
+ called ctc.ko. If you do not know what it is, it's safe to say "Y".
+
+config IUCV
+ tristate "IUCV support (VM only)"
+ help
+ Select this option if you want to use inter-user communication
+ under VM or VIF. If unsure, say "Y" to enable a fast communication
+ link between VM guests. At boot time the user ID of the guest needs
+ to be passed to the kernel. Note that both kernels need to be
+ compiled with this option and both need to be booted with the user ID
+ of the other VM guest.
+
+config NETIUCV
+ tristate "IUCV network device support (VM only)"
+ depends on IUCV && NETDEVICES
+ help
+ Select this option if you want to use inter-user communication
+ vehicle networking under VM or VIF. It enables a fast communication
+ link between VM guests. Using ifconfig a point-to-point connection
+ can be established to the Linux for zSeries and S7390 system
+ running on the other VM guest. This option is also available
+ as a module which will be called netiucv.ko. If unsure, say "Y".
+
+config SMSGIUCV
+ tristate "IUCV special message support (VM only)"
+ depends on IUCV
+ help
+ Select this option if you want to be able to receive SMSG messages
+ from other VM guest systems.
+
+config CLAW
+ tristate "CLAW device support"
+ depends on NETDEVICES
+ help
+ This driver supports channel attached CLAW devices.
+ CLAW is Common Link Access for Workstation. Common devices
+ that use CLAW are RS/6000s, Cisco Routers (CIP) and 3172 devices.
+ To compile as a module choose M here: The module will be called
+ claw.ko to compile into the kernel choose Y
+
+config QETH
+ tristate "Gigabit Ethernet device support"
+ depends on NETDEVICES && IP_MULTICAST && QDIO
+ help
+ This driver supports the IBM S/390 and zSeries OSA Express adapters
+ in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
+ interfaces in QDIO and HIPER mode.
+
+ For details please refer to the documentation provided by IBM at
+ <http://www10.software.ibm.com/developerworks/opensource/linux390>
+
+ To compile this driver as a module, choose M here: the
+ module will be called qeth.ko.
+
+
+comment "Gigabit Ethernet default settings"
+ depends on QETH
+
+config QETH_IPV6
+ bool "IPv6 support for gigabit ethernet"
+ depends on (QETH = IPV6) || (QETH && IPV6 = 'y')
+ help
+ If CONFIG_QETH is switched on, this option will include IPv6
+ support in the qeth device driver.
+
+config QETH_VLAN
+ bool "VLAN support for gigabit ethernet"
+ depends on (QETH = VLAN_8021Q) || (QETH && VLAN_8021Q = 'y')
+ help
+ If CONFIG_QETH is switched on, this option will include IEEE
+ 802.1q VLAN support in the qeth device driver.
+
+config QETH_PERF_STATS
+ bool "Performance statistics in /proc"
+ depends on QETH
+ help
+ When switched on, this option will add a file in the proc-fs
+ (/proc/qeth_perf_stats) containing performance statistics. It
+ may slightly impact performance, so this is only recommended for
+ internal tuning of the device driver.
+
+config CCWGROUP
+ tristate
+ default (LCS || CTC || QETH)
+
+endmenu
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
new file mode 100644
index 000000000000..7cabb80a2e41
--- /dev/null
+++ b/drivers/s390/net/Makefile
@@ -0,0 +1,14 @@
+#
+# S/390 network devices
+#
+
+ctc-objs := ctcmain.o ctctty.o ctcdbug.o
+
+obj-$(CONFIG_IUCV) += iucv.o
+obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
+obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
+obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
+obj-$(CONFIG_LCS) += lcs.o cu3088.o
+qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o qeth_tso.o
+qeth-$(CONFIG_PROC_FS) += qeth_proc.o
+obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
new file mode 100644
index 000000000000..06804d39a9c6
--- /dev/null
+++ b/drivers/s390/net/claw.c
@@ -0,0 +1,4447 @@
+/*
+ * drivers/s390/net/claw.c
+ * ESCON CLAW network driver
+ *
+ * $Revision: 1.35 $ $Date: 2005/03/24 12:25:38 $
+ *
+ * Linux fo zSeries version
+ * Copyright (C) 2002,2005 IBM Corporation
+ * Author(s) Original code written by:
+ * Kazuo Iimura (iimura@jp.ibm.com)
+ * Rewritten by
+ * Andy Richter (richtera@us.ibm.com)
+ * Marc Price (mwprice@us.ibm.com)
+ *
+ * sysfs parms:
+ * group x.x.rrrr,x.x.wwww
+ * read_buffer nnnnnnn
+ * write_buffer nnnnnn
+ * host_name aaaaaaaa
+ * adapter_name aaaaaaaa
+ * api_type aaaaaaaa
+ *
+ * eg.
+ * group 0.0.0200 0.0.0201
+ * read_buffer 25
+ * write_buffer 20
+ * host_name LINUX390
+ * adapter_name RS6K
+ * api_type TCPIP
+ *
+ * where
+ *
+ * The device id is decided by the order entries
+ * are added to the group the first is claw0 the second claw1
+ * up to CLAW_MAX_DEV
+ *
+ * rrrr - the first of 2 consecutive device addresses used for the
+ * CLAW protocol.
+ * The specified address is always used as the input (Read)
+ * channel and the next address is used as the output channel.
+ *
+ * wwww - the second of 2 consecutive device addresses used for
+ * the CLAW protocol.
+ * The specified address is always used as the output
+ * channel and the previous address is used as the input channel.
+ *
+ * read_buffer - specifies number of input buffers to allocate.
+ * write_buffer - specifies number of output buffers to allocate.
+ * host_name - host name
+ * adaptor_name - adaptor name
+ * api_type - API type TCPIP or API will be sent and expected
+ * as ws_name
+ *
+ * Note the following requirements:
+ * 1) host_name must match the configured adapter_name on the remote side
+ * 2) adaptor_name must match the configured host name on the remote side
+ *
+ * Change History
+ * 1.00 Initial release shipped
+ * 1.10 Changes for Buffer allocation
+ * 1.15 Changed for 2.6 Kernel No longer compiles on 2.4 or lower
+ * 1.25 Added Packing support
+ */
+#include <asm/bitops.h>
+#include <asm/ccwdev.h>
+#include <asm/ccwgroup.h>
+#include <asm/debug.h>
+#include <asm/idals.h>
+#include <asm/io.h>
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tcp.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include "cu3088.h"
+#include "claw.h"
+
+MODULE_AUTHOR("Andy Richter <richtera@us.ibm.com>");
+MODULE_DESCRIPTION("Linux for zSeries CLAW Driver\n" \
+ "Copyright 2000,2005 IBM Corporation\n");
+MODULE_LICENSE("GPL");
+
+/* Debugging is based on DEBUGMSG, IOTRACE, or FUNCTRACE options:
+ DEBUGMSG - Enables output of various debug messages in the code
+ IOTRACE - Enables output of CCW and other IO related traces
+ FUNCTRACE - Enables output of function entry/exit trace
+ Define any combination of above options to enable tracing
+
+ CLAW also uses the s390dbf file system see claw_trace and claw_setup
+*/
+
+/* following enables tracing */
+//#define DEBUGMSG
+//#define IOTRACE
+//#define FUNCTRACE
+
+#ifdef DEBUGMSG
+#define DEBUG
+#endif
+
+#ifdef IOTRACE
+#define DEBUG
+#endif
+
+#ifdef FUNCTRACE
+#define DEBUG
+#endif
+
+ char debug_buffer[255];
+/**
+ * Debug Facility Stuff
+ */
+static debug_info_t *claw_dbf_setup;
+static debug_info_t *claw_dbf_trace;
+
+/**
+ * CLAW Debug Facility functions
+ */
+static void
+claw_unregister_debug_facility(void)
+{
+ if (claw_dbf_setup)
+ debug_unregister(claw_dbf_setup);
+ if (claw_dbf_trace)
+ debug_unregister(claw_dbf_trace);
+}
+
+static int
+claw_register_debug_facility(void)
+{
+ claw_dbf_setup = debug_register("claw_setup", 1, 1, 8);
+ claw_dbf_trace = debug_register("claw_trace", 1, 2, 8);
+ if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) {
+ printk(KERN_WARNING "Not enough memory for debug facility.\n");
+ claw_unregister_debug_facility();
+ return -ENOMEM;
+ }
+ debug_register_view(claw_dbf_setup, &debug_hex_ascii_view);
+ debug_set_level(claw_dbf_setup, 2);
+ debug_register_view(claw_dbf_trace, &debug_hex_ascii_view);
+ debug_set_level(claw_dbf_trace, 2);
+ return 0;
+}
+
+static inline void
+claw_set_busy(struct net_device *dev)
+{
+ ((struct claw_privbk *) dev->priv)->tbusy=1;
+ eieio();
+}
+
+static inline void
+claw_clear_busy(struct net_device *dev)
+{
+ clear_bit(0, &(((struct claw_privbk *) dev->priv)->tbusy));
+ netif_wake_queue(dev);
+ eieio();
+}
+
+static inline int
+claw_check_busy(struct net_device *dev)
+{
+ eieio();
+ return ((struct claw_privbk *) dev->priv)->tbusy;
+}
+
+static inline void
+claw_setbit_busy(int nr,struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ set_bit(nr, (void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+}
+
+static inline void
+claw_clearbit_busy(int nr,struct net_device *dev)
+{
+ clear_bit(nr,(void *)&(((struct claw_privbk *)dev->priv)->tbusy));
+ netif_wake_queue(dev);
+}
+
+static inline int
+claw_test_and_setbit_busy(int nr,struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return test_and_set_bit(nr,
+ (void *)&(((struct claw_privbk *) dev->priv)->tbusy));
+}
+
+
+/* Functions for the DEV methods */
+
+static int claw_probe(struct ccwgroup_device *cgdev);
+static void claw_remove_device(struct ccwgroup_device *cgdev);
+static void claw_purge_skb_queue(struct sk_buff_head *q);
+static int claw_new_device(struct ccwgroup_device *cgdev);
+static int claw_shutdown_device(struct ccwgroup_device *cgdev);
+static int claw_tx(struct sk_buff *skb, struct net_device *dev);
+static int claw_change_mtu( struct net_device *dev, int new_mtu);
+static int claw_open(struct net_device *dev);
+static void claw_irq_handler(struct ccw_device *cdev,
+ unsigned long intparm, struct irb *irb);
+static void claw_irq_tasklet ( unsigned long data );
+static int claw_release(struct net_device *dev);
+static void claw_write_retry ( struct chbk * p_ch );
+static void claw_write_next ( struct chbk * p_ch );
+static void claw_timer ( struct chbk * p_ch );
+
+/* Functions */
+static int add_claw_reads(struct net_device *dev,
+ struct ccwbk* p_first, struct ccwbk* p_last);
+static void inline ccw_check_return_code (struct ccw_device *cdev,
+ int return_code);
+static void inline ccw_check_unit_check (struct chbk * p_ch,
+ unsigned char sense );
+static int find_link(struct net_device *dev, char *host_name, char *ws_name );
+static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
+static int init_ccw_bk(struct net_device *dev);
+static void probe_error( struct ccwgroup_device *cgdev);
+static struct net_device_stats *claw_stats(struct net_device *dev);
+static int inline pages_to_order_of_mag(int num_of_pages);
+static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
+#ifdef DEBUG
+static void dumpit (char *buf, int len);
+#endif
+/* sysfs Functions */
+static ssize_t claw_hname_show(struct device *dev, char *buf);
+static ssize_t claw_hname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_adname_show(struct device *dev, char *buf);
+static ssize_t claw_adname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_apname_show(struct device *dev, char *buf);
+static ssize_t claw_apname_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_wbuff_show(struct device *dev, char *buf);
+static ssize_t claw_wbuff_write(struct device *dev,
+ const char *buf, size_t count);
+static ssize_t claw_rbuff_show(struct device *dev, char *buf);
+static ssize_t claw_rbuff_write(struct device *dev,
+ const char *buf, size_t count);
+static int claw_add_files(struct device *dev);
+static void claw_remove_files(struct device *dev);
+
+/* Functions for System Validate */
+static int claw_process_control( struct net_device *dev, struct ccwbk * p_ccw);
+static int claw_send_control(struct net_device *dev, __u8 type, __u8 link,
+ __u8 correlator, __u8 rc , char *local_name, char *remote_name);
+static int claw_snd_conn_req(struct net_device *dev, __u8 link);
+static int claw_snd_disc(struct net_device *dev, struct clawctl * p_ctl);
+static int claw_snd_sys_validate_rsp(struct net_device *dev,
+ struct clawctl * p_ctl, __u32 return_code);
+static int claw_strt_conn_req(struct net_device *dev );
+static void claw_strt_read ( struct net_device *dev, int lock );
+static void claw_strt_out_IO( struct net_device *dev );
+static void claw_free_wrt_buf( struct net_device *dev );
+
+/* Functions for unpack reads */
+static void unpack_read (struct net_device *dev );
+
+/* ccwgroup table */
+
+static struct ccwgroup_driver claw_group_driver = {
+ .owner = THIS_MODULE,
+ .name = "claw",
+ .max_slaves = 2,
+ .driver_id = 0xC3D3C1E6,
+ .probe = claw_probe,
+ .remove = claw_remove_device,
+ .set_online = claw_new_device,
+ .set_offline = claw_shutdown_device,
+};
+
+/*
+*
+* Key functions
+*/
+
+/*----------------------------------------------------------------*
+ * claw_probe *
+ * this function is called for each CLAW device. *
+ *----------------------------------------------------------------*/
+static int
+claw_probe(struct ccwgroup_device *cgdev)
+{
+ int rc;
+ struct claw_privbk *privptr=NULL;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s Enter\n",__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"probe");
+ if (!get_device(&cgdev->dev))
+ return -ENODEV;
+#ifdef DEBUGMSG
+ printk(KERN_INFO "claw: variable cgdev =\n");
+ dumpit((char *)cgdev, sizeof(struct ccwgroup_device));
+#endif
+ privptr = kmalloc(sizeof(struct claw_privbk), GFP_KERNEL);
+ if (privptr == NULL) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+ return -ENOMEM;
+ }
+ memset(privptr,0x00,sizeof(struct claw_privbk));
+ privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+ privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+ if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "Out of memory %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
+ return -ENOMEM;
+ }
+ memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
+ memset(privptr->p_env, 0x00, sizeof(struct claw_env));
+ memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
+ memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
+ memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
+ privptr->p_env->packing = 0;
+ privptr->p_env->write_buffers = 5;
+ privptr->p_env->read_buffers = 5;
+ privptr->p_env->read_size = CLAW_FRAME_SIZE;
+ privptr->p_env->write_size = CLAW_FRAME_SIZE;
+ rc = claw_add_files(&cgdev->dev);
+ if (rc) {
+ probe_error(cgdev);
+ put_device(&cgdev->dev);
+ printk(KERN_WARNING "add_files failed %s %s Exit Line %d \n",
+ cgdev->cdev[0]->dev.bus_id,__FUNCTION__,__LINE__);
+ CLAW_DBF_TEXT_(2,setup,"probex%d",rc);
+ return rc;
+ }
+ printk(KERN_INFO "claw: sysfs files added for %s\n",cgdev->cdev[0]->dev.bus_id);
+ privptr->p_env->p_priv = privptr;
+ cgdev->cdev[0]->handler = claw_irq_handler;
+ cgdev->cdev[1]->handler = claw_irq_handler;
+ cgdev->dev.driver_data = privptr;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "claw:%s exit on line %d, "
+ "rc = 0\n",__FUNCTION__,__LINE__);
+#endif
+ CLAW_DBF_TEXT(2,setup,"prbext 0");
+
+ return 0;
+} /* end of claw_probe */
+
+/*-------------------------------------------------------------------*
+ * claw_tx *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int rc;
+ struct claw_privbk *privptr=dev->priv;
+ unsigned long saveflags;
+ struct chbk *p_ch;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s enter\n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"claw_tx");
+ p_ch=&privptr->channel[WRITE];
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: null pointer passed as sk_buffer\n",
+ dev->name);
+ privptr->stats.tx_dropped++;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s: %s() exit on line %d, rc = EIO\n",
+ dev->name,__FUNCTION__, __LINE__);
+#endif
+ CLAW_DBF_TEXT_(2,trace,"clawtx%d",-EIO);
+ return -EIO;
+ }
+
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: variable sk_buff=\n",dev->name);
+ dumpit((char *) skb, sizeof(struct sk_buff));
+ printk(KERN_INFO "%s: variable dev=\n",dev->name);
+ dumpit((char *) dev, sizeof(struct net_device));
+#endif
+ spin_lock_irqsave(get_ccwdev_lock(p_ch->cdev), saveflags);
+ rc=claw_hw_tx( skb, dev, 1 );
+ spin_unlock_irqrestore(get_ccwdev_lock(p_ch->cdev), saveflags);
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s exit on line %d, rc = %d\n",
+ dev->name, __FUNCTION__, __LINE__, rc);
+#endif
+ CLAW_DBF_TEXT_(4,trace,"clawtx%d",rc);
+ return rc;
+} /* end of claw_tx */
+
+/*------------------------------------------------------------------*
+ * pack the collect queue into an skb and return it *
+ * If not packing just return the top skb from the queue *
+ *------------------------------------------------------------------*/
+
+static struct sk_buff *
+claw_pack_skb(struct claw_privbk *privptr)
+{
+ struct sk_buff *new_skb,*held_skb;
+ struct chbk *p_ch = &privptr->channel[WRITE];
+ struct claw_env *p_env = privptr->p_env;
+ int pkt_cnt,pk_ind,so_far;
+
+ new_skb = NULL; /* assume no dice */
+ pkt_cnt = 0;
+ CLAW_DBF_TEXT(4,trace,"PackSKBe");
+ if (skb_queue_len(&p_ch->collect_queue) > 0) {
+ /* some data */
+ held_skb = skb_dequeue(&p_ch->collect_queue);
+ if (p_env->packing != DO_PACKED)
+ return held_skb;
+ if (held_skb)
+ atomic_dec(&held_skb->users);
+ else
+ return NULL;
+ /* get a new SKB we will pack at least one */
+ new_skb = dev_alloc_skb(p_env->write_size);
+ if (new_skb == NULL) {
+ atomic_inc(&held_skb->users);
+ skb_queue_head(&p_ch->collect_queue,held_skb);
+ return NULL;
+ }
+ /* we have packed packet and a place to put it */
+ pk_ind = 1;
+ so_far = 0;
+ new_skb->cb[1] = 'P'; /* every skb on queue has pack header */
+ while ((pk_ind) && (held_skb != NULL)) {
+ if (held_skb->len+so_far <= p_env->write_size-8) {
+ memcpy(skb_put(new_skb,held_skb->len),
+ held_skb->data,held_skb->len);
+ privptr->stats.tx_packets++;
+ so_far += held_skb->len;
+ pkt_cnt++;
+ dev_kfree_skb_irq(held_skb);
+ held_skb = skb_dequeue(&p_ch->collect_queue);
+ if (held_skb)
+ atomic_dec(&held_skb->users);
+ } else {
+ pk_ind = 0;
+ atomic_inc(&held_skb->users);
+ skb_queue_head(&p_ch->collect_queue,held_skb);
+ }
+ }
+#ifdef IOTRACE
+ printk(KERN_INFO "%s: %s() Packed %d len %d\n",
+ p_env->ndev->name,
+ __FUNCTION__,pkt_cnt,new_skb->len);
+#endif
+ }
+ CLAW_DBF_TEXT(4,trace,"PackSKBx");
+ return new_skb;
+}
+
+/*-------------------------------------------------------------------*
+ * claw_change_mtu *
+ * *
+ *-------------------------------------------------------------------*/
+
+static int
+claw_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct claw_privbk *privptr=dev->priv;
+ int buff_size;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+#ifdef DEBUGMSG
+ printk(KERN_INFO "variable dev =\n");
+ dumpit((char *) dev, sizeof(struct net_device));
+ printk(KERN_INFO "variable new_mtu = %d\n", new_mtu);
+#endif
+ CLAW_DBF_TEXT(4,trace,"setmtu");
+ buff_size = privptr->p_env->write_size;
+ if ((new_mtu < 60) || (new_mtu > buff_size)) {
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=EINVAL\n",
+ dev->name,
+ __FUNCTION__, __LINE__);
+#endif
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Exit on line %d\n",dev->name,
+ __FUNCTION__, __LINE__);
+#endif
+ return 0;
+} /* end of claw_change_mtu */
+
+
+/*-------------------------------------------------------------------*
+ * claw_open *
+ * *
+ *-------------------------------------------------------------------*/
+static int
+claw_open(struct net_device *dev)
+{
+
+ int rc;
+ int i;
+ unsigned long saveflags=0;
+ unsigned long parm;
+ struct claw_privbk *privptr;
+ DECLARE_WAITQUEUE(wait, current);
+ struct timer_list timer;
+ struct ccwbk *p_buf;
+
+#ifdef FUNCTRACE
+ printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
+#endif
+ CLAW_DBF_TEXT(4,trace,"open");
+ if (!dev | (dev->name[0] == 0x00)) {
+ CLAW_DBF_TEXT(2,trace,"BadDev");
+ printk(KERN_WARNING "claw: Bad device at open failing \n");
+ return -ENODEV;
+ }
+ privptr = (struct claw_privbk *)dev->priv;
+ /* allocate and initialize CCW blocks */
+ if (privptr->buffs_alloc == 0) {
+ rc=init_ccw_bk(dev);
+ if (rc) {
+ printk(KERN_INFO "%s:%s Exit on line %d, rc=ENOMEM\n",
+ dev->name,
+ __FUNCTION__, __LINE__);
+ CLAW_DBF_TEXT(2,trace,"openmem");
+ return -ENOMEM;
+ }
+ }
+ privptr->system_validate_comp=0;
+ privptr->release_pend=0;
+ if(strncmp(privptr->p_env->api_type,WS_APPL_NAME_PACKED,6) == 0) {
+ privptr->p_env->read_size=DEF_PACK_BUFSIZE;
+ privptr->p_env->write_size=DEF_PACK_BUFSIZE;
+ privptr->p_env->packing=PACKING_ASK;
+ } else {
+ privptr->p_env->packing=0;
+ privptr->p_env->read_size=CLAW_FRAME_SIZE;
+ privptr->p_env->write_size=CLAW_FRAME_SIZE;
+ }
+ claw_set_busy(dev);
+ tasklet_init(&privptr->channel[READ].tasklet, claw_irq_tasklet,
+ (unsigned long) &privptr->channel[READ]);
+ for ( i = 0; i < 2; i++) {
+ CLAW_DBF_TEXT_(2,trace,"opn_ch%d",i);
+ init_waitqueue_head(&privptr->channel[i].wait);
+ /* skb_queue_head_init(&p_ch->io_queue); */
+ if (i == WRITE)
+ skb_queue_head_init(
+ &privptr->channel[WRITE].collect_queue);
+ privptr->channel[i].flag_a = 0;
+ privptr->channel[i].IO_active = 0;
+ privptr->channel[i].flag &= ~CLAW_TIMER;
+ init_timer(&timer);
+ timer.function = (void *)claw_timer;
+ timer.data = (unsigned long)(&privptr->channel[i]);
+ timer.expires = jiffies + 15*HZ;
+ add_timer(&timer);
+ spin_lock_irqsave(get_ccwdev_lock(
+ privptr->channel[i].cdev), saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].claw_state = CLAW_START_HALT_IO;
+ rc = 0;
+ add_wait_queue(&privptr->channel[i].wait, &wait);
+ rc = ccw_device_halt(
+ (struct ccw_device *)privptr->channel[i].cdev,parm);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(privptr->channel[i].cdev), saveflags);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&privptr->channel[i].wait, &wait);
+ if(rc != 0)
+ ccw_check_return_code(privptr->channel[i].cdev, rc);
+ if((privptr->channel[i].flag & CLAW_TIMER) == 0x00)
+ del_timer(&timer);
+ }
+ if ((((privptr->channel[READ].last_dstat |
+ privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+ (((privptr->channel[READ].flag |
+ privptr->channel[WRITE].flag) & CLAW_TIMER) != 0x00)) {
+#ifdef DEBUGMSG
+ printk(KERN_INFO "%s: channel problems during open - read:"
+ " %02x - write: %02x\n",
+ dev->name,
+ privptr->channel[READ].last_dstat,
+ privptr->channel[WRITE].last_dstat);
+#endif
+ printk(KERN_INFO "%s: remote side is not ready\n", dev->name);
+ CLAW_DBF_TEXT(2,trace,"notrdy");
+
+ for ( i = 0; i < 2; i++) {
+ spin_lock_irqsave(
+ get_ccwdev_lock(privptr->channel[i].cdev),
+ saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].claw_state = CLAW_STOP;
+ rc = ccw_device_halt(
+ (struct ccw_device *)&privptr->channel[i].cdev,
+ parm);
+ spin_unlock_irqrestore(
+ get_ccwdev_lock(privptr->channel[i].cdev),
+ saveflags);
+ if (rc != 0) {
+ ccw_check_return_code(
+ privptr->channel[i].cdev, rc);
+ }
+ }
+ free_pages((unsigned long)privptr->p_buff_ccw,
+ (int)pages_to_order_of_mag(privptr->p_buff_ccw_num));
+ if (privptr->p_env->read_size < PAGE_SIZE) {
+ free_pages((unsigned long)privptr->p_buff_read,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_read_num));
+ }
+ else {
+ p_buf=privptr->p_read_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perread ));
+ p_buf=p_buf->next;
+ }
+ }
+ if (privptr->p_env->write_size < PAGE_SIZE ) {
+ free_pages((unsigned long)privptr->p_buff_write,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_write_num));
+ }
+ else {
+ p_buf=privptr->p_write_active_first;
+ while (p_buf!=NULL) {
+ free_pages((unsigned long)p_buf->p_buffer,
+ (int)pages_to_order_of_mag(
+ privptr->p_buff_pages_perwrite ));