diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/s390/net |
Linux-2.6.12-rc2v2.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')
31 files changed, 32463 insertions, 0 deletions
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig new file mode 100644 index 00000000000..a7efc394515 --- /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 00000000000..7cabb80a2e4 --- /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 00000000000..06804d39a9c --- /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, |