]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.18pre26 2.2.18 2.2.18pre26 2.2.18pre27
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:22:56 +0000 (15:22 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:22:56 +0000 (15:22 -0500)
o Last resync of the S/390 tree with IBM (Martin schwidefsky
| s390_daemonize skipped, thats too ugly  and co)
o Swat irq leak in sbni driver (Arnaldo Carvalho de Melo)
o Update urls for Arnaldo (Arnaldo Carvalho de Melo)
o Small UDP mcast fix (Dave Miller)
o Fix TCP rto estimator for very fast long (Dave Miller)
paths

16 files changed:
CREDITS
Makefile
drivers/net/sbni.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/char/con3215.c
drivers/s390/net/Makefile
drivers/s390/net/ctc.c
drivers/s390/net/iucv.c
drivers/s390/net/iucv.h
drivers/s390/net/netiucv.c [new file with mode: 0644]
include/asm-s390/pgtable.h
include/asm-s390/s390mach.h
include/asm-s390/uaccess.h
net/ipv4/tcp_input.c
net/ipv6/udp.c

diff --git a/CREDITS b/CREDITS
index 2d790eb15ffb444c262ec911b1d0d21eb38a121d..47cd9ee2d8f6bfb9a0d6484539ecdfabdf69cad8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1467,11 +1467,19 @@ S: Germany
 
 N: Arnaldo Carvalho de Melo
 E: acme@conectiva.com.br
+E: acme@gnu.org
+W: http://bazar.conectiva.com.br/~acme
+W: http://advogato.org/person/acme
+P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD  841A B6AB 4681 9224 DF01
 D: wanrouter hacking
-D: cyclades 2X sync card driver (still in early devel stage)
 D: USB hacking
-S: R. Prof. Rubens Elke Braga, 558 - Parolin
-S: 80220-320 Curitiba - Parana
+D: misc Makefile, Config.in, drivers and network stacks fixes
+D: IPX Multithreading for 2.4
+D: Cyclom 2X synchronous card driver
+D: i18n for minicom, net-tools, util-linux, fetchmail, etc
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - ParanĂ¡
 S: Brazil
 
 N: Michael Meskes
index 21b8c725f1ae6f9d3bc76e6aff020bd859ed5039..78e6d405d69f3d88d558ee4624e8c0167a2232dd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 18
-EXTRAVERSION = pre25
+EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 208851c4ea2c73ea4c1c538327662a754bae8281..605cb489e7bf67d3b14ce60ec2b0b64092154617 100644 (file)
@@ -456,6 +456,7 @@ static int __init sbni_probe1(struct device *dev, int ioaddr)
        if(dev->priv == NULL)
        {
                DP( printk("%s: cannot allocate memory\n", dev->name); )
+               free_irq(dev->irq, dev);
                return -ENOMEM;
        }
    
index 19557d0443401e796ff969484e7e921164a2f368..951207e09853e1193115c7b7a17b8d3113845361 100644 (file)
@@ -35,6 +35,7 @@
             are the fixes in dasd_format
  * 10/26/00 fixed ITPM PL010261EPA race condition when formatting  
             are the fixes in dasd_do_chanq
+ * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers
  */
 
 #include <linux/config.h>
@@ -1694,15 +1695,18 @@ dasd_format (dasd_device_t * device, format_data_t * fdata)
                         major_from_devindex (devindex), 
                         devindex << DASD_PARTN_BITS);
         } /* end if discipline->format_device */
-        printk (KERN_WARNING PRINTK_HEADER
-                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-                " Formatting finished successfully\n",
-                devno, 
-                irq, 
-                device->name, 
-                major_from_devindex (devindex), 
-                devindex << DASD_PARTN_BITS);
-        
+
+        if (!rc) {
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                        " Formatting finished successfully\n",
+                        devno, 
+                        irq, 
+                        device->name, 
+                        major_from_devindex (devindex), 
+                        devindex << DASD_PARTN_BITS);
+        }
+
         dasd_set_device_level( device->devinfo.irq,
                                DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
                                device->discipline,
@@ -1757,6 +1761,7 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
                }
        case BLKFLSBUF:{
                        rc = fsync_dev (inp->i_rdev);
+                       invalidate_buffers(inp->i_rdev);
                        break;
                }
        case BLKRAGET:{
@@ -1945,6 +1950,10 @@ dasd_release (struct inode *inp, struct file *filp)
        MOD_DEC_USE_COUNT;
 #endif                         /* MODULE */
        }
+       if ( device->open_count == 0 ) {
+               rc = fsync_dev (inp->i_rdev);
+               invalidate_buffers(inp->i_rdev);
+       }
        return rc;
 }
 
index 521a940710a4ca850ba1f0063203bb81fbc94800..cc472471e950ad1f9e99e1421b8b02e375a75cde 100644 (file)
@@ -627,6 +627,7 @@ dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata)
                                  datasize+rpt*sizeof(eckd_count_t));
         if ( fcp != NULL ) {
                 fcp->device = device;
+                fcp->retries = 2;       /* set retry counter to enable ERP */
                 last_data = fcp->data;
                 DE_data = (DE_eckd_data_t *) last_data;
                 last_data = (void*)(DE_data +1);
index c8ac10dfea0553070a261a0cf012587ff9f77963..24f91c68f503fb27ec1b0d630029a1132f3cfd29 100644 (file)
@@ -116,7 +116,7 @@ __initfunc(void con3215_setup(char *str, char *ints))
 {
         int vdev;
 
-        vdev = simple_strtoul(str,&str,10);
+        vdev = simple_strtoul(str,&str,0);
         if (vdev >= 0 && vdev < 65536)
                 raw3215_condevice = vdev;
         return;
@@ -756,6 +756,7 @@ static void raw3215_shutdown(raw3215_info *raw)
                 s390irq_spin_unlock_irqrestore(raw->irq, flags);
                schedule();
                s390irq_spin_lock_irqsave(raw->irq, flags);
+               remove_wait_queue(&raw->empty_wait, &wait);
                 current->state = TASK_RUNNING;
                raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
        }
index 4d4dbb54bf1478438bca4be92b0a5779016b3cae..25b01cbcfea71cea26eda45774f4842d5f692d79 100644 (file)
@@ -2,7 +2,7 @@ all: s390-net.o
 
 CFLAFS += 
 O_TARGET := s390-net.o
-O_OBJS    :=         
+O_OBJS   := iucv.o
 M_OBJS   :=
 
 ifeq ($(CONFIG_CTC),y)
@@ -14,7 +14,11 @@ else
 endif
 
 ifeq ($(CONFIG_IUCV),y)
-  O_OBJS += iucv.o
+  O_OBJS += netiucv.o
+else
+  ifeq ($(CONFIG_IUCV),m)
+    M_OBJS += netiucv.o
+  endif
 endif
 
 include $(TOPDIR)/Rules.make
index 20ea4fe7b77e89683b4d3b834825faa6eaa4d178..9a828e26216994bed5bf3c065c0312b32fe14797 100644 (file)
@@ -276,6 +276,8 @@ static int ctc_no_auto = 0;
 typedef struct net_device  net_device;
 #else
 typedef struct device  net_device;
+typedef struct wait_queue* wait_queue_head_t;
+#define init_waitqueue_head(nothing)
 #endif
 
 struct adapterlist{ 
index e6c12b8e0acf2a2ce57a238c2a45e05c62e2294a..a5b8e20eb008b95b14d6aeff78cdc60ac0804126 100644 (file)
 /*
  *  drivers/s390/net/iucv.c
- *    Network driver for VM using iucv
+ *    Support for VM IUCV functions for use by other part of the
+ *    kernel or loadable modules.
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
- *               Hartmut Penner <hpenner@de.ibm.com> 
- * 
- *    \r
- *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *                Martin Schwidefsky (schwidefsky@de.ibm.com)\r
- *                Alan Altmark (Alan_Altmark@us.ibm.com)
- *                
-
+ *    Copyright (C) 2000 IBM Corporation
+ *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ *               Alan Altmark (Alan_Altmark@us.ibm.com)
  */
 
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
 #include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>              /* printk()                         */
-#include <linux/malloc.h>              /* kmalloc()                        */
-#include <linux/errno.h>               /* error codes                      */
-#include <linux/types.h>               /* size_t                           */
-#include <linux/interrupt.h>           /* mark_bh                          */
-#include <linux/netdevice.h>           /* struct net_device, and other headers */
-#include <linux/inetdevice.h>          /* struct net_device, and other headers */
-#include <linux/if_arp.h>
-#include <linux/rtnetlink.h>
-#include <linux/ip.h>                  /* struct iphdr                     */
-#include <linux/tcp.h>                 /* struct tcphdr                    */
-#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <asm/checksum.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include "iucv.h"
 #include <asm/io.h>
-#include <asm/string.h>
 #include <asm/s390_ext.h>
-
-#include "iucv.h"
-
-
-
-#define DEBUG123
-#define MAX_DEVICES  10
-
-
-extern char _ascebc[];
-
-/* 
- *  global structures 
- */
-static char iucv_userid[MAX_DEVICES][8];
-static char iucv_ascii_userid[MAX_DEVICES][8];
-static int  iucv_pathid[MAX_DEVICES] = {0};
-static unsigned char iucv_ext_int_buffer[40] __attribute__((aligned (8))) ={0};
-static unsigned char glob_command_buffer[40] __attribute__((aligned (8)));
-
-#if LINUX_VERSION_CODE>=0x20300
-typedef struct net_device  net_device;
-#else
-typedef struct device  net_device;
-#endif
-net_device iucv_devs[];
-
-
-/* This structure is private to each device. It is used to pass */
-/* packets in and out, so there is place for a packet           */
-struct iucv_priv {
-    struct net_device_stats stats;
-    int packetlen;
-    int status;
-    u8 *packetdata;
-    int pathid;                    /* used device */
-    unsigned char command_buffer[40] __attribute__((aligned (8)));
-    unsigned char ext_int_buffer[40] __attribute__((aligned (8)));
-    u8* receive_buffer;
-    int receive_buffer_len;
-    u8* send_buffer;
-    int send_buffer_len;    
-    char * new_send_buf;       /* send buffer ptr */
-    unsigned char recv_buf[2048];  /* size is just a guess */
-    unsigned char userid[8];
-};
-
-struct iucv_header {
-  short len;
-};
-
-
-
-static __inline__ int netif_is_busy(net_device *dev)
+#include <asm/spinlock.h>
+#include <asm/ebcdic.h>
+
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_EMERG
+//#define DEBUG3
+//#define DEBUG         /* Turns Printk's on                         */
+//#define DEBUG2        /* This prints the parameter list before and */
+                     /* after the b2f0 call to cp                 */
+#define EXPORT_SYMTAB
+#include <linux/module.h>
+#undef NULL
+#define NULL 0
+#define ADDED_STOR 64          /* ADDITIONAL STORAGE FOR PATHID @'S */
+ulong declare_flag = 0;
+static uchar iucv_external_int_buffer[40];
+struct tq_struct short_task;   /* automatically initialized to zero */
+static iucv_interrupt_ops_t my_ops;
+spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+static void do_int (iucv_ConnectionPending *);
+
+/***************INTERRUPT HANDLING DEFINITIONS***************/
+typedef struct _iucv_packet {
+       struct _iucv_packet *next;
+       uchar data[40];
+} iucv_packet;
+struct tq_struct short_task;
+static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
+iucv_packet *iucv_packets_head, *iucv_packets_tail;
+
+static atomic_t bh_scheduled = ATOMIC_INIT (0);
+void bottom_half_interrupt (void);
+
+/************FUNCTION ID'S****************************/
+#define accept          10
+#define connect         11
+#define declare_buffer  12
+#define purge           9
+#define query           0
+#define quiesc          13
+#define receive         5
+#define reject          8
+#define reply           6
+#define resume          14
+#define retrieve_buffer 2
+#define send            4
+#define setmask         16
+#define sever           15
+
+/*****************************************************************/
+/*  Structure: handler                                           */
+/*  members: next - is a pointer to next handler on chain        */
+/*           prev - is a pointer to prev handler on chain        */
+/*           vmid - 8 char array of machine identification       */
+/*           user_data - 16 char array for user identification   */
+/*           mask - 24 char array used to compare the 2 previous */
+/*           interrupt_table - functions for interrupts          */
+/*           start - pointer to start of block of pointers to    */
+/*                   handler_table_entries                       */
+/*           end - pointer to end of block of pointers to        */
+/*                 handler_table_entries                         */
+/*           size - ulong, size of block                         */
+/*           pgm_data - ulong, program data                      */
+/* NOTE: Keep vmid and user_data together in this order          */
+/*****************************************************************/
+typedef struct {
+       ulong *next;
+       ulong *prev;
+       uchar vmid[8];
+       uchar user_data[16];
+       uchar mask[24];
+       iucv_interrupt_ops_t *interrupt_table;
+       ulong *start;
+       ulong *end;
+       ulong size;
+       ulong pgm_data;
+} handler;
+
+/*******************************************************************/
+/* Structure: handler_table_entry                                  */
+/* members: addrs - pointer to a handler                           */
+/*          pathid - ushort containing path identification         */
+/*          pgm_data - ulong, program data                         */
+/*******************************************************************/
+typedef struct {
+       handler *addrs;
+       ushort pathid;
+       ulong pgm_data;
+} handler_table_entry;
+
+/* main_table: array of pointers to handler_tables         */
+static handler_table_entry *main_table[128];
+/* handler_anchor: points to first handler on chain        */
+static handler *handler_anchor;
+
+/****************FIVE  STRUCTURES************************************/
+/* Data struct 1: iparml_control                                    */
+/*                Used for iucv_accept                              */
+/*                         iucv_connect                             */
+/*                         iucv_quiesce                             */
+/*                         iucv_resume                              */
+/*                         iucv_sever                               */
+/*                         iucv_retrieve_buffer                     */
+/* Data struct 2: iparml_dpl  (data in parameter list)              */
+/*                Used for iucv_send_prmmsg                         */
+/*                         iucv_send2way_prmmsg                     */
+/*                         iucv_send2way_prmmsg_array               */
+/*                         iucv_reply_prmmsg                        */
+/* Data struct 3: iparml_db    (data in a buffer)                   */
+/*                Used for iucv_receive                             */
+/*                         iucv_receive_array                       */
+/*                         iucv_receive_simple                      */
+/*                         iucv_reject                              */
+/*                         iucv_reply                               */
+/*                         iucv_reply_array                         */
+/*                         iucv_send                                */
+/*                         iucv_send_simple                         */
+/*                         iucv_send_array                          */
+/*                         iucv_send2way                            */
+/*                         iucv_send2way_array                      */
+/*                         iucv_declare_buffer                      */
+/* Data struct 4: iparml_purge                                      */
+/*                Used for iucv_purge                               */
+/*                         iucv_query                               */
+/* Data struct 5: iparml_set_mask                                   */
+/*                Used for iucv_set_mask                            */
+/********************************************************************/
+typedef struct {
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iprcode;
+       ushort ipmsglim;
+       ushort res1;
+       uchar ipvmid[8];
+       uchar ipuser[16];
+       uchar iptarget[8];
+} iparml_control;
+
+/******************/
+typedef struct {
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iprcode;
+       ulong ipmsgid;
+       ulong iptrgcls;
+       uchar iprmmsg[8];
+       ulong ipsrccls;
+       ulong ipmsgtag;
+       ulong ipbfadr2;
+       ulong ipbfln2f;
+       ulong res;
+} iparml_dpl;
+
+/*******************/
+typedef struct {
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iprcode;
+       ulong ipmsgid;
+       ulong iptrgcls;
+       ulong ipbfadr1;
+       ulong ipbfln1f;
+       ulong ipsrccls;
+       ulong ipmsgtag;
+       ulong ipbfadr2;
+       ulong ipbfln2f;
+       ulong res;
+} iparml_db;
+
+/********************/
+typedef struct {
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iprcode;
+       ulong ipmsgid;
+       uchar ipaudit[4];
+       uchar res1[4];
+       ulong res2;
+       ulong ipsrccls;
+       ulong ipmsgtag;
+       ulong res3[3];
+} iparml_purge;
+
+/*******************/
+typedef struct {
+       uchar ipmask;
+       uchar res1[2];
+       uchar iprcode;
+       ulong res2[9];
+} iparml_set_mask;
+
+/*********************INTERNAL FUNCTIONS*****************************/
+/********************************************************************/
+/* Name: b2f0                                                       */
+/* Purpose: this function calls cp to execute iucv commands.        */
+/* Input: code - int, identifier of iucv call to cp.                */
+/*        parm - void *, pointer to 40 byte iparml area passed to cp */
+/* Output: iprcode- return code from iucv call to cp                */
+/********************************************************************/
+/* Assembler code performing iucv call                             */
+/*******************************************************************/
+inline ulong
+b2f0 (int code, void *parm)
 {
-#if LINUX_VERSION_CODE<0x02032D
-       return(dev->tbusy);
-#else
-       return(test_bit(LINK_STATE_XOFF,&dev->flags));
+       uchar *iprcode;         /* used to extract iprcode */
+#ifdef DEBUG2
+       int i;
+       uchar *prt_parm;
+       prt_parm = (uchar *) (parm);
+       printk (KERN_DEBUG "parameter list before b2f0 call\n");
+       for (i = 0; i < 40; i++)
+               printk (KERN_DEBUG "%02x ", prt_parm[i]);
+       printk (KERN_DEBUG "\n");
 #endif
+       asm volatile ("LRA   1,0(%1)\n\t"
+                     "LR    0,%0\n\t"
+                     ".long 0xb2f01000"
+                     : : "d" (code), "a" (parm) : "0", "1");
+#ifdef DEBUG2
+       printk (KERN_DEBUG "parameter list after b2f0 call\n");
+       for (i = 0; i < 40; i++)
+               printk (KERN_DEBUG "%02x ", prt_parm[i]);
+       printk (KERN_DEBUG "\n");
+#endif
+       iprcode = (uchar *) (parm + 3);
+       return (ulong) (*iprcode);
 }
 
-
-
-#if LINUX_VERSION_CODE<0x02032D
-#define netif_enter_interrupt(dev) dev->interrupt=1
-#define netif_exit_interrupt(dev) dev->interrupt=0
-#define netif_start(dev) dev->start=1
-#define netif_stop(dev) dev->start=0
-
-static __inline__ void netif_stop_queue(net_device *dev)
+/**************************************************************/
+/* Name: iucv_retrieve_buffer                                 */
+/* Purpose: terminates all use of iucv                        */
+/* Input: void                                                */
+/* Output: Return code from CP                                */
+/**************************************************************/
+int
+iucv_retrieve_buffer (void)
 {
-       dev->tbusy=1;
+       iparml_control parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_retrieve_buffer\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       b2f0_result = b2f0 (retrieve_buffer, &parm);
+       if (b2f0_result == NULL)
+               declare_flag = 0;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n");
+#endif
+       return b2f0_result;
 }
 
-static __inline__ void netif_start_queue(net_device *dev)
+/**************************************************************/
+/* Name: iucv_declare_buffer                                  */
+/* Purpose: specifies the guests real address of an external  */
+/*          interrupt.                                        */
+/* Input: bfr - pointer to  buffer                            */
+/* Output: iprcode - return code from b2f0 call               */
+/* Note : See output options for b2f0 call                    */
+/**************************************************************/
+int
+iucv_declare_buffer (uchar * bfr)
 {
-       dev->tbusy=0;
+       iparml_db parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "Entering iucv_declare_buffer\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipbfadr1 = virt_to_phys (bfr);
+       b2f0_result = b2f0 (declare_buffer, &parm);
+#ifdef DEBUG
+       printk (KERN_DEBUG "Address of EIB = %p\n", bfr);
+       printk (KERN_DEBUG "Exiting iucv_declare_buffer\n");
+#endif
+       return b2f0_result;
 }
 
-static __inline__ void netif_wake_queue(net_device *dev)
+/**************************************************************/
+/* Name: add_pathid                                           */
+/* Purpose: adds a path id to the system                      */
+/* Input: pathid - ushort, pathid to enter system             */
+/*        handle - iucv_handle_t, address of handler to add to */
+/*        pgm_data - ulong, pathid identifier.                */
+/* Output: 0: successful addition of pathid                   */
+/**************************************************************/
+int
+add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data)
+{
+       ulong index1, index2;   /* index1 into main_table */
+       ulong add_flag = 0;
+       ulong old_size = 0, new_size = 0;
+       uchar *to, *from;       /* pointer for copying the table */
+       handler_table_entry *P = 0;     /*P is a pointer to H_T_E */
+       handler *Q = 0;         /*Q is a pointer to handler */
+       ulong *X = 0;           /*Points to array of pointers */
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering add_pathid\n");
+#endif
+       Q = (handler *) handle; /* Q points to a handler    */
+       /*
+        * main_table has 128 entries.
+        * 128*512 = 65536 maximum number of pathid's allowed
+        */
+       index1 = ((ulong) pathid) / 512;
+       index2 = ((ulong) pathid) % 512;
+#ifdef DEBUG
+       printk (KERN_DEBUG "index1 = %d\n ", (int) index1);
+       printk (KERN_DEBUG "index2 = %d\n ", (int) index2);
+       printk (KERN_DEBUG "Q is pointing to %p ", Q);
+#endif
+       spin_lock (&lock);
+       /*
+        * If NULL then handler table does not exist and need to get storage
+        *  and have main_table[index1] point to it
+        * If allocating storage failed, return
+        */
+       if (main_table[index1] == NULL) {
+               main_table[index1] = (handler_table_entry *) kmalloc
+                   (512 * sizeof (handler_table_entry), GFP_KERNEL);
+               if (main_table[index1] == NULL) {
+                       spin_unlock (&lock);
+                       return -ENOBUFS;
+               }
+               memset (main_table[index1], 0,
+                       512 * sizeof (handler_table_entry));
+#ifdef DEBUG
+               printk (KERN_DEBUG "address of table H_T is %p \n",
+                       main_table[index1]);
+#endif
+       }
+       /*
+        * P points to a handler table entry (H_T_E) in which all entries in
+        * that structure should be NULL. If they're not NULL, then there
+        * is a bad pointer and it will return(-2) immediately, otherwise
+        * data will be entered into H_T_E.
+        */
+       P = main_table[index1];
+       if ((P + index2)->addrs) {
+#ifdef DEBUG
+               printk (KERN_DEBUG "main_table[index1] = %p \n",
+                       main_table[index1]);
+               printk (KERN_DEBUG "P+index2 = %p \n", P + index2);
+               printk (KERN_DEBUG "(P+index2)->addrs is %p \n",
+                       (P + index2)->addrs);
+#endif
+               spin_unlock (&lock);
+               printk (KERN_DEBUG "bad pointer1\n");
+               return (-2);
+       }
+       (P + index2)->addrs = handle;
+       /*
+        * checking if address of handle is valid, if it's not valid,
+        * unlock the lock and return(-2) immediately.
+        */
+       if ((P + index2)->addrs == NULL) {
+               spin_unlock (&lock);
+               printk (KERN_DEBUG "bad pointer2\n");
+               return (-2);
+       }
+       (P + index2)->pathid = pathid;
+       if (pgm_data)
+               (P + index2)->pgm_data = pgm_data;
+       else
+               (P + index2)->pgm_data = Q->pgm_data;
+       /*
+        * Step thru the table of addresses of pathid's to find the first
+        * available entry (NULL). If an entry is found, add the pathid,
+        * unlock and exit. If an available entry is not found, allocate a
+        * new, larger table, copy over the old table and deallocate the
+        * old table and add the pathid.
+        */
+#ifdef DEBUG
+       printk (KERN_DEBUG "address of handle is %p\n", handle);
+       printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start));
+       printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end));
+       printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start));
+       printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end));
+       for (X = (Q->start); X < (Q->end); X++)
+               printk (KERN_DEBUG "X = %p ", X);
+       printk (KERN_DEBUG "\n");
+#endif
+       for (X = (Q->start); X < (Q->end); X++) {
+               if (*X == NULL) {
+#ifdef DEBUG
+                       printk (KERN_DEBUG "adding pathid, %p = P+index2\n",
+                               (P + index2));
+#endif
+                       *X = (ulong) (P + index2);
+                       add_flag = 1;
+               }
+               if (add_flag == 1)
+                       break;
+       }
+       if (add_flag == 0) {    /* element not added to list */
+               X = Q->start;
+               old_size = Q->size;
+               new_size = old_size + ADDED_STOR;       /* size of new table */
+               from = (uchar *) (Q->start);    /* address of old table */
+               (*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL);
+               if ((Q->start) == NULL) {
+                       spin_unlock (&lock);
+                       return -ENOBUFS;
+               }
+               memset ((*Q).start, 0, new_size * sizeof (ulong));
+               to = (uchar *) (Q->start);      /* address of new table */
+               /* copy old table to new  */
+               memcpy (to, from, old_size * (sizeof (ulong)));
+#ifdef DEBUG
+               printk (KERN_DEBUG "Getting a new pathid table\n");
+               printk (KERN_DEBUG "to is %p \n", to);
+               printk (KERN_DEBUG "from is %p \n", from);
+#endif
+               Q->size = new_size;     /* storing new size of table */
+               Q->end = (Q->start) + (Q->size);
+               X = Q->start + old_size;        /* next blank in table */
+               *X = (ulong) (P + index2);      /* adding element to new table */
+#ifdef DEBUG
+               printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size));
+               printk (KERN_DEBUG "Q->end is %p \n", Q->end);
+               printk (KERN_DEBUG "Q->start is %p \n", Q->start);
+               printk (KERN_DEBUG "X is %p \n", X);
+               printk (KERN_DEBUG "*X is %u \n", (int) (*X));
+#endif
+               kfree (from);   /* free old table */
+       }
+       spin_unlock (&lock);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting add_pathid\n");
+#endif
+       return (0);
+}                              /* end of add_pathid function */
+
+/***********************EXTERNAL FUNCTIONS***************************/
+/**************************************************************/
+/* Name: iucv_query                                           */
+/* Purpose: determines how large an external interrupt buffer */
+/*          IUCV requires to store information                */
+/* Input : bufsize - ulong: size of interrupt buffer          */
+/*         - filled in by function and returned to caller     */
+/*         conmax  - ulong: maximum number of connections that */
+/*           can be outstanding for this VM                   */
+/*         - filled in by function and returned to caller     */
+/* Output: void                                               */
+/**************************************************************/
+void
+iucv_query (ulong * bufsize, ulong * conmax)
 {
-       dev->tbusy=0;
-       mark_bh(NET_BH);
+       iparml_purge parm;      /* DOESN'T MATTER WHICH IPARML IS USED    */
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_purge\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       /*
+        * Assembler instruction calling b2f0  and storing R0 and R1
+        */
+       asm volatile ("LRA   1,0(%3)\n\t"
+                     "LR    0,%2\n\t"
+                     ".long 0xb2f01000\n\t"
+                     "ST    0,%0\n\t"
+                     "ST    1,%1\n\t":"=m" (*bufsize),
+                     "=m" (*conmax):"d" (query), "a" (&parm):"0", "1");
+       return;
 }
 
-#else
-#define netif_enter_interrupt(dev)
-#define netif_exit_interrupt(dev)
-#define netif_start(dev)
-#define netif_stop(dev)
+/**************************************************************/
+/* Name: iucv_purge                                           */
+/* Purpose: cancels a message you have sent                   */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, mid of message                      */
+/*        srccls - ulong, sourse message class                */
+/*        audit  - uchar[4], info about ansync. error condit. */
+/*                 filled in by function and passed back      */
+/* Output: void                                               */
+/* NOTE: pathid is required, flag is always turned on         */
+/**************************************************************/
+int
+iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4])
+{
+       iparml_purge parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_purge\n");
 #endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipmsgid = msgid;
+       parm.ippathid = pathid;
+       parm.ipsrccls = srccls;
+       parm.ipflags1 |= specify_pathid;        /* pathid id flag */
+       if (parm.ipmsgid)
+               parm.ipflags1 |= specify_msgid;
+       if (parm.ipsrccls)
+               parm.ipflags1 |= source_class;
+       b2f0_result = b2f0 (purge, &parm);
+       if (b2f0_result != NULL)
+               return b2f0_result;
+       memcpy (audit, parm.ipaudit, 4);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_purge\n");
+#endif
+       return b2f0_result;
+}
 
-
-
-/*
- * Following the iucv primitives 
- */
-
-
-extern inline void b2f0(int code,void* parm)
+/**************************************************************/
+/* Name: iucv_quiesce                                         */
+/* Purpose: temporarily suspends incoming messages            */
+/* Input: pathid - ushort, pathid                             */
+/*        user_data - uchar[16], user id                      */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: see b2f0 output list                                 */
+/**************************************************************/
+int
+iucv_quiesce (ushort pathid, uchar user_data[16])
 {
-  asm volatile ("LR    1,%1\n\tLR    0,%0\n\t.long 0xb2f01000" ::
-                "d" (code) ,"a" (parm) :"0", "1");
+       iparml_control parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_quiesce\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, 16);
+       parm.ippathid = pathid;
+       b2f0_result = b2f0 (quiesc, &parm);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_quiesce\n");
+#endif
+       return b2f0_result;
 }
 
-int iucv_enable(void *parms)
+/**************************************************************/
+/* Name: iucv_resume                                          */
+/* Purpose: restores communication over a quiesced path       */
+/* Input: pathid - ushort, pathid                             */
+/*        user_data - uchar[16], user id                      */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: see b2f0 output list                                 */
+/**************************************************************/
+int
+iucv_resume (ushort pathid, uchar user_data[16])
 {
-  MASK_T *parm = parms;
-  memset(parms,0,sizeof(parm));
-  parm->ipmask = 0xF8;
-  b2f0(SETMASK,parm);
-  memset(parms,0,sizeof(parm));
-  parm->ipmask = 0xF8;
-  b2f0(SETCMASK,parm);
-  return parm->iprcode;
+       iparml_control parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_resume\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, 16);
+       parm.ippathid = pathid;
+       b2f0_result = b2f0 (resume, &parm);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_resume\n");
+#endif
+       return b2f0_result;
 }
 
-
-int iucv_declare_buffer(void *parms, DCLBFR_T *buffer)
+/**************************************************************/
+/* Name: iucv_reject                                          */
+/* Purpose: rejects a message                                 */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, mid of message                      */
+/*        trgcls - ulong, target message class                */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: pathid is required field, flag always turned on      */
+/*       RESTRICTION: target class cannot be zero             */
+/* NOTE: see b2f0 output list                                 */
+/**************************************************************/
+int
+iucv_reject (ushort pathid, ulong msgid, ulong trgcls)
 {
-  DCLBFR_T *parm = parms;
-  memset(parms,0,sizeof(parm));
-  parm->ipflags1= 0x00;
-  parm->ipbfadr1 = virt_to_phys(buffer);
-  b2f0(DECLARE_BUFFER, parm);
-  return parm->iprcode;
+       iparml_db parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_reject\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipmsgid = msgid;
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipflags1 |= specify_pathid;        /* flag for pathid */
+       if (parm.ipmsgid)
+               parm.ipflags1 |= specify_msgid;
+       if (parm.iptrgcls)
+               parm.ipflags1 |= target_class;
+       b2f0_result = b2f0 (reject, &parm);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_reject\n");
+#endif
+       return b2f0_result;
 }
 
-
-int iucv_retrieve_buffer(void *parms)
+/**************************************************************/
+/* Name: iucv_setmask                                         */
+/* Purpose: enables or disables certain iucv external interr. */
+/* Input: non_priority_interrupts - uchar                     */
+/*        priority_interrupts - uchar                         */
+/*        non_priority_completion_interrupts - uchar          */
+/*        priority_completion_interrupts) - uchar             */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: see b2f0 output list                                 */
+/**************************************************************/
+int
+iucv_setmask (uchar non_priority_interrupts,
+             uchar priority_interrupts,
+             uchar non_priority_completion_interrupts,
+             uchar priority_completion_interrupts)
 {
-  DCLBFR_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  parm->iprcode = 0x0;
-  b2f0(RETRIEVE_BUFFER, parm);
-  return parm->iprcode;
+       iparml_set_mask parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_setmask\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       if (non_priority_interrupts)
+               parm.ipmask |= 0x80;
+       if (priority_interrupts)
+               parm.ipmask |= 0x40;
+       if (non_priority_completion_interrupts)
+               parm.ipmask |= 0x20;
+       if (priority_completion_interrupts)
+               parm.ipmask |= 0x10;
+       b2f0_result = b2f0 (setmask, &parm);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_setmask\n");
+#endif
+       return b2f0_result;
 }
 
-
-int iucv_connect(void *parms,
-                 const char *userid,
-                 const char *host,
-                 const char *ipusr,
-                 unsigned short * used_pathid)
+/**************************************************************/
+/* Name: iucv_sever                                           */
+/* Purpose: terminates an iucv path to another machine        */
+/* Input: pathid - ushort, pathid                             */
+/*        user_data - uchar[16], user id                      */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: see b2f0 output list                                 */
+/**************************************************************/
+int
+iucv_sever (ushort pathid, uchar user_data[16])
 {
-  CONNECT_T *parm = parms;                              /* ipflags was 0x60*/
-  memset(parms,0x0,sizeof(parm));
-  parm->ipflags1 = 0x80;
-  parm->ipmsglim = 0x0a;
-  memcpy(parm->ipvmid,userid,8);
-  if (ipusr)
-    memcpy(parm->ipuser,ipusr,16);
-  memcpy(parm->iptarget,host,8);
-  b2f0(CONNECT, parm);
-  *used_pathid = parm->ippathid;
-  return parm->iprcode;
+       ulong index1, index2;
+       ulong b2f0_result;
+       handler_table_entry *P = 0;
+       handler *Q = 0;
+       ulong *X;
+       iparml_control parm;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_sever\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, 16);
+       parm.ippathid = pathid;
+       b2f0_result = b2f0 (sever, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       index1 = ((ulong) pathid) / 512;
+       index2 = ((ulong) pathid) % 512;
+       spin_lock (&lock);
+       P = main_table[index1];
+       if (((P + index2)->addrs) == NULL) {    /* called from interrupt code */
+               spin_unlock (&lock);
+               return (-2);    /* bad pointer */
+       }
+       Q = (*(P + index2)).addrs;
+#ifdef DEBUG
+       printk (KERN_DEBUG "pathid is %d\n", pathid);
+       printk (KERN_DEBUG "index1 is %d\n", (int) index1);
+       printk (KERN_DEBUG "index2 is %d\n", (int) index2);
+       printk (KERN_DEBUG "H_T_E is %p\n", P);
+       printk (KERN_DEBUG "address of handler is %p\n", Q);
+       for (X = ((*Q).start); X < ((*Q).end); X++)
+               printk (KERN_DEBUG " %x ", (int) (*X));
+       printk (KERN_DEBUG "\n above is pathid table\n");
+#endif
+/********************************************************************/
+/* Searching the pathid address table for matching address, once    */
+/* found, NULL the field. Then Null the H_T_E fields.               */
+/********************************************************************/
+       for (X = ((*Q).start); X < ((*Q).end); X++)
+               if (*X == (ulong) (P + index2)) {
+#ifdef DEBUG
+                       printk (KERN_DEBUG "found a path to sever\n");
+                       printk (KERN_DEBUG "severing %d \n", (int) (*X));
+#endif
+                       *X = NULL;
+                       (*(P + index2)).addrs = NULL;   /*clearing the fields */
+                       (*(P + index2)).pathid = 0;
+                       (*(P + index2)).pgm_data = 0;
+               }
+       spin_unlock (&lock);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_sever\n");
+#endif
+       return b2f0_result;
 }
 
-
-
-int iucv_accept(void *parms,int pathid)
+/**************************************************************/
+/* Name: iucv_receive                                         */
+/* Purpose: receives incoming message                         */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - *ulong, mid of message                     */
+/*        trgcls - *ulong, target message class               */
+/*        buffer - pointer of buffer                          */
+/*        buflen - length of buffer                           */
+/*        adds_curr_buffer - pointer to updated buffer address*/
+/*                           to write to                      */
+/*        adds_curr_length - pointer to updated length in     */
+/*                           buffer available to write to     */
+/*        reply_required - uchar *, flag                      */
+/*        priority_msg - uchar *, flag                        */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: pathid must be specified, flag being turned on       */
+/* RESTRICTIONS: target class CANNOT be zero because the code */
+/* checks for a non-NULL value to turn flag on, therefore if  */
+/* target class = zero, flag will not be turned on.           */
+/**************************************************************/
+int
+iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls,
+             void *buffer, ulong buflen,
+             uchar * reply_required,
+             uchar * priority_msg,
+             ulong * adds_curr_buffer, ulong * adds_curr_length)
 {
+       iparml_db parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-  int i=0;
+       printk (KERN_DEBUG "entering iucv_receive\n");
 #endif
-  ACCEPT_T *parm = parms;
-  memset(parms,0,sizeof(parm));
-  parm->ippathid = pathid;
-  parm->ipflags1 = 0x80;
-  parm->ipmsglim = 0x0a;
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipmsgid = *msgid;
+       parm.ippathid = pathid;
+       parm.iptrgcls = *trgcls;
+       parm.ipflags1 |= specify_pathid;        /* turning pathid flag */
+       if (parm.ipmsgid)
+               parm.ipflags1 |= 0x05;
+       if (parm.iptrgcls)
+               parm.ipflags1 |= target_class;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen;
+       b2f0_result = b2f0 (receive, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       if (msgid)
+               *msgid = parm.ipmsgid;
+       if (trgcls)
+               *trgcls = parm.iptrgcls;
+       if (parm.ipflags1 & prior_msg)
+               if (priority_msg)
+                       *priority_msg = 0x01;   /*yes, priority msg */
+       if (!(parm.ipflags1 & 0x10))    /*& with X'10'     */
+               if (reply_required)
+                       *reply_required = 0x01; /*yes, reply required */
+       if (!(parm.ipflags1 & parm_data)) {     /*msg not in parmlist */
+               if (adds_curr_length)
+                       *adds_curr_length = parm.ipbfln1f;
+               if (adds_curr_buffer)
+                       *adds_curr_buffer = parm.ipbfadr1;
+       } else {
+               if ((buflen) >= 8) {
+                       if (buffer)
+                               memcpy ((char *) buffer,
+                                       (char *) parm.ipbfadr1, 8);
+                       if (adds_curr_length)
+                               *adds_curr_length = ((buflen) - 8);
+                       if (adds_curr_buffer)
+                               *adds_curr_buffer = (ulong) buffer + 8;
+               } else {
+                       parm.iprcode |= 0x05;
+                       b2f0_result = (ulong) parm.iprcode;
+               }
+       }
 #ifdef DEBUG
-  printk("iucv: iucv_accept input.\n");
-  for (i=0;i<40; i++)
-  {
-    printk("%02x ",((char *)parms)[i]);
-  }
-  printk("\n");
+       printk (KERN_DEBUG "exiting iucv_receive\n");
 #endif
-  b2f0(ACCEPT, parm);
-  return parm->iprcode;
+       return b2f0_result;
 }
 
+/**************************************************************/
+/* Name: iucv_receive_simple                                  */
+/* Purpose: receives fully-qualified message                  */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, id of message                       */
+/*        trgcls - ulong, target message class                */
+/*        buffer - pointer of buffer                          */
+/*        buflen - length of buffer                           */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls,
+                    void *buffer, ulong buflen)
+{
+       iparml_db parm;
+       ulong b2f0_result;
+       pr_debug ("entering iucv_receive_simple\n");
+
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipmsgid = msgid;
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen;
+
+       b2f0_result = b2f0 (receive, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+
+       if (parm.ipflags1 & IPRMDATA) { /*msg in parmlist */
+               if ((buflen) >= 8)
+                       memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8);
+               else
+                       b2f0_result = 5;
+       }
+       pr_debug ("exiting iucv_receive_simple\n");
+       return b2f0_result;
+}
 
-
-int iucv_receive(void *parms,void *bufferarray,int len)
+/**************************************************************/
+/* Name: iucv_receive_array                                   */
+/* Purpose: receives incoming message                         */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  -* ulong, mid of message                     */
+/*        trgcls -* ulong, target message class               */
+/*        buffer - pointer of iucv_array_t                    */
+/*        buflen - ulong , length of buffer                   */
+/*        reply_required - uchar *, flag returned to caller   */
+/*        priority_msg - uchar *, flag returned to caller     */
+/*        adds_curr_buffer - pointer to updated buffer array  */
+/*                   to write to                              */
+/*        adds_curr_length - pointer to updated length in     */
+/*                   buffer available to write to             */
+/* Output: iprcode - return code from b2f0 call               */
+/* NOTE: pathid must be specified, flag being turned on       */
+/* RESTRICTIONS: target class CANNOT be zero because the code */
+/* checks for a non-NULL value to turn flag on, therefore if  */
+/* target class = if target class = zero flag will not be     */
+/* turned on, therefore if target class is specified it cannot */
+/* be zero.                                                   */
+/**************************************************************/
+int
+iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls,
+                   iucv_array_t * buffer, ulong * buflen,
+                   uchar * reply_required,
+                   uchar * priority_msg,
+                   ulong * adds_curr_buffer, ulong * adds_curr_length)
 {
+       iparml_db parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-  int i=0;
-#endif
-  RECEIVE_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  /*parm->ipflags1 = 0x42;*/
-  parm->ipflags1 = 0x0;
-  parm->ipmsgid  = 0x0;
-  parm->iptrgcls = 0x0;
-  parm->ipbfadr1 = (ULONG) virt_to_phys(bufferarray);
-  parm->ipbfln1f  = len;
-  parm->ipbfln2f  = 0x0;
-  b2f0(RECEIVE, parm);
-  if (parm->iprcode == 0)
-    len = parm->ipbfln1f;
-//  len = len-parm->ipbfln1f;
-#ifdef DEBUG
-  printk("iucv: iucv_receive command input:\n");
-   for (i=0;i<40;i++)  /* show iucv buffer before send */
-    {
-      printk("%02x ",((char *)parms)[i]);
-    }
-  printk("\n");
-
-  printk("iucv: iucv_receive data buffer:\n");
-  for (i=0;i<len;i++)  /* show data received */
-   {
-     printk("%02x ",((char *)bufferarray)[i]);
-   }
-  printk("\n");
-  printk("received length: %02x ",len);
-
+       printk (KERN_DEBUG "entering iucv_receive_array\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ipmsgid = *msgid;
+       parm.ippathid = pathid;
+       parm.iptrgcls = *trgcls;
+       parm.ipflags1 |= array; /* using an address list  */
+       parm.ipflags1 |= specify_pathid;        /*turning on pathid flag */
+       if (parm.ipmsgid)
+               parm.ipflags1 |= 0x05;
+       if (parm.iptrgcls)
+               parm.ipflags1 |= target_class;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = *buflen;
+       b2f0_result = b2f0 (receive, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       if (msgid)
+               *msgid = parm.ipmsgid;
+       if (trgcls)
+               *trgcls = parm.iptrgcls;
+       if (parm.ipflags1 & prior_msg)
+               if (priority_msg)
+                       *priority_msg = 0x01;   /*yes, priority msg */
+       if (!(parm.ipflags1 & 0x10))    /*& with X'10'     */
+               if (reply_required)
+                       *reply_required = 0x01; /*yes, reply required */
+       if (!(parm.ipflags1 & parm_data)) {     /*msg not in parmlist */
+               if (adds_curr_length)
+                       *adds_curr_length = parm.ipbfln1f;
+               if (adds_curr_buffer)
+                       *adds_curr_buffer = parm.ipbfadr1;
+       } else {
+               if ((buffer->length) >= 8) {
+                       memcpy ((char *) buffer->address,
+                               (char *) parm.ipbfadr1, 8);
+                       if (adds_curr_buffer)
+                               *adds_curr_buffer =
+                                   (ulong) ((buffer->address) + 8);
+                       if (adds_curr_length)
+                               *adds_curr_length = ((buffer->length) - 8);
+
+               } else {
+                       parm.iprcode |= 0x05;
+                       b2f0_result = (ulong) parm.iprcode;
+               }
+       }
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_receive\n");
 #endif
-  return parm->iprcode;
+       return b2f0_result;
 }
 
-
-int iucv_send(void *parms,int pathid,void *bufferarray,int len,
-              void *recv_buf, int recv_len)
+/**************************************************************/
+/* Name: iucv_send                                            */
+/* Purpose: sends messages                                    */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message returned to caller  */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        buffer - pointer to buffer                          */
+/*        buflen - ulong, length of buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send (ushort pathid, ulong * msgid,
+          ulong trgcls, ulong srccls,
+          ulong msgtag, uchar priority_msg, void *buffer, ulong buflen)
 {
+       iparml_db parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-  int i=0;
-#endif
-  SEND_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  /*  parm->ipflags1 = 0x48; ??*/
-  parm->ippathid = pathid;
-  parm->ipflags1 = 0x14;                       /* any options ?? */
-  parm->ipmsgid  = 0x0;
-  parm->iptrgcls = 0x0;
-  parm->ipbfadr1 = virt_to_phys(bufferarray);
-  parm->ipbfln1f = len;
-  parm->ipsrccls = 0x0;
-  parm->ipmsgtag = 0x0;
-  parm->ipbfadr2 = virt_to_phys(recv_buf);
-  parm->ipbfln2f = recv_len;
-
-
+       printk (KERN_DEBUG "entering iucv_send\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen; /* length of message */
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 |= one_way_msg;   /* one way message */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (send, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       if (msgid)
+               *msgid = parm.ipmsgid;
 #ifdef DEBUG
-  printk("iucv: iucv_send command input:\n");
-  for (i=0;i<40;i++)  /* show iucv buffer before send */
-   {
-     printk("%02x ",((char *)parms)[i]);
-   }
-  printk("\n");
-
-  printk("iucv: iucv_send data buffer:\n");
-  for (i=0;i<len;i++)  /* show send data before send */
-   {
-     printk("%02x ",((char *)bufferarray)[i]);
-   }
-  printk("\n");
+       printk (KERN_DEBUG "exiting iucv_send\n");
 #endif
+       return b2f0_result;
+}
 
-  b2f0(SEND, parm);
-
-#ifdef DEBUGXX
- printk("iucv: iucv_send buffer after send:\n");
- for (i=0;i<len;i++) /* show send buffer after send */
-   {
-     printk("%1x",((char *)bufferarray)[i]);
-   }
-   printk("\n");
+/**************************************************************/
+/* Name: iucv_send_array                                      */
+/* Purpose: sends messages in buffer array                    */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message returned to caller  */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        buffer - pointer to iucv_array_t                    */
+/*        buflen - ulong, length of buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send_array (ushort pathid, ulong * msgid,
+                ulong trgcls, ulong srccls,
+                ulong msgtag, uchar priority_msg,
+                iucv_array_t * buffer, ulong buflen)
+{
+       iparml_db parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send_array\n");
 #endif
-
-  return parm->iprcode;
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen; /* length of message */
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 |= one_way_msg;   /* one way message */
+       parm.ipflags1 |= array; /* one way w/ array */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send_array\n");
+#endif
+       return b2f0_result;
 }
 
-
-
-int iucv_sever(void *parms)
+/**************************************************************/
+/* Name: iucv_send_prmmsg                                     */
+/* Purpose: sends messages in parameter list                  */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message                     */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        prmmsg - uchar[8], message being sent               */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send_prmmsg (ushort pathid, ulong * msgid,
+                 ulong trgcls, ulong srccls,
+                 ulong msgtag, uchar priority_msg, uchar prmmsg[8])
 {
-  SEVER_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  parm->ippathid = 0x0;
-  parm->ipflags1 = 0x0;
-  parm->iprcode  = 0xF;
-  memset(parm->ipuser,0,16);
-  b2f0(SEVER, parm);
-  return parm->iprcode;
+       iparml_dpl parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send_prmmsg\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 |= parm_data;     /* message in prmlist */
+       parm.ipflags1 |= one_way_msg;   /* one way message */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       memcpy (parm.iprmmsg, prmmsg, 8);
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send_prmmsg\n");
+#endif
+       return b2f0_result;
 }
 
-
-#ifdef DEBUG
-/*--------------------------*/
-/* Dump buffer formatted    */
-/*--------------------------*/
-static void dumpit(char* buf, int len)
+/**************************************************************/
+/* Name: iucv_send2way                                        */
+/* Purpose: sends messages in both directions                 */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message                     */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        buffer - pointer to buffer                          */
+/*        buflen - ulong, length of buffer                    */
+/*        ansbuf - pointer to buffer on reply                 */
+/*        anslen - length of ansbuf buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send2way (ushort pathid, ulong * msgid,
+              ulong trgcls, ulong srccls,
+              ulong msgtag, uchar priority_msg,
+              void *buffer, ulong buflen, void *ansbuf, ulong anslen)
 {
-  int i;
-  for (i=0;i<len;i++) {
-    if (!(i%16)&&i!=0)
-      printk("\n");
-    else if (!(i%4)&&i!=0)
-      printk(" ");
-    printk(  "%02X",buf[i]);
-  }
-  if (len%16)
-    printk(  "\n");
-}
+       iparml_db parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send2way\n");
 #endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen; /* length of message */
+       parm.ipbfadr2 = (ulong) ansbuf;
+       parm.ipbfln2f = anslen;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send2way\n");
+#endif
+       return b2f0_result;
+}
 
-
-
-/*--------------------------*/
-/* Get device from pathid   */
-/*--------------------------*/
-net_device * get_device_from_pathid(int pathid)
+/**************************************************************/
+/* Name: iucv_send2way_array                                  */
+/* Purpose: sends messages in both directions in arrays       */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message                     */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        buffer - pointer to iucv_array_t                    */
+/*        buflen - ulong, length of buffer                    */
+/*        ansbuf - pointer to iucv_array_t on reply           */
+/*        anslen - length of ansbuf buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send2way_array (ushort pathid, ulong * msgid,
+                    ulong trgcls, ulong srccls,
+                    ulong msgtag, uchar priority_msg,
+                    iucv_array_t * buffer, ulong buflen,
+                    iucv_array_t * ansbuf, ulong anslen)
 {
-   int i;
-    for (i=0;i<=MAX_DEVICES;i++)
-    {
-      if (iucv_pathid[i] == pathid)
-        return &iucv_devs[i];
-    }
-    printk("iucv: get_device_from_pathid: no device for pathid %X\n",pathid);
- return 0;
+       iparml_db parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send2way_array\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr1 = (ulong) buffer;
+       parm.ipbfln1f = buflen; /* length of message */
+       parm.ipbfadr2 = (ulong) ansbuf;
+       parm.ipbfln2f = anslen;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 |= array; /* send  w/ array  */
+       parm.ipflags1 |= reply_array;   /* reply w/ array  */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send2way_array\n");
+#endif
+       return b2f0_result;
 }
 
-
-
-/*--------------------------*/
-/* Get device from userid   */
-/*--------------------------*/
-net_device * get_device_from_userid(char * userid)
+/**************************************************************/
+/* Name: iucv_send2way_prmmsg                                 */
+/* Purpose: sends messages in both directions w/parameter lst */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message                     */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        prmmsg - uchar[8], message being sent in parameter  */
+/*        ansbuf - pointer to buffer                          */
+/*        anslen - length of ansbuf buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send2way_prmmsg (ushort pathid, ulong * msgid,
+                     ulong trgcls, ulong srccls,
+                     ulong msgtag, uchar priority_msg,
+                     uchar prmmsg[8], void *ansbuf, ulong anslen)
 {
-   int i;
-   net_device * dev;
-   struct iucv_priv *privptr;
-      for (i=0;i<=MAX_DEVICES;i++)
-      {
-        dev = &iucv_devs[i];
-        privptr = (struct iucv_priv *)(dev->priv);
-        if (memcmp(privptr->userid,userid,8)==0)
-          return &iucv_devs[i];
-      }
-      printk("iucv: get_device_from_uid: no device for userid %s\n",userid);
-   return 0;
+       iparml_dpl parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipbfadr2 = (ulong) ansbuf;
+       parm.ipbfln2f = anslen;
+       parm.ipflags1 |= parm_data;     /* message in prmlist */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       memcpy (parm.iprmmsg, prmmsg, 8);
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
+#endif
+       return b2f0_result;
 }
 
-
-/*--------------------------*/
-/* Open iucv Device Driver */
-/*--------------------------*/
-int iucv_open(net_device *dev)
+/**************************************************************/
+/* Name: iucv_reply                                           */
+/* Purpose: responds to the two-way messages that you receive */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, id of message                       */
+/*        trgcls - ulong, target message class                */
+/*        priority_msg - uchar, flag                          */
+/*        buf    - pointer, address of buffer                 */
+/*        buflen - length of buffer                           */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_reply (ushort pathid, ulong msgid, ulong trgcls,
+           uchar priority_msg, void *buf, ulong buflen)
 {
-    int rc;
-    unsigned short iucv_used_pathid;
-    struct iucv_priv *privptr;
-    char iucv_host[8]   ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 
-    char vmident[16]    ={0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
-                          0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
-
+       iparml_db parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-    printk(  "iucv: iucv_open, device: %s\n",dev->name);
+       printk (KERN_DEBUG "entering iucv_reply\n");
 #endif
-
-    privptr = (struct iucv_priv *)(dev->priv);
-    if(privptr->pathid != -1) {
-       netif_start(dev);
-       netif_start_queue(dev);
-       return 0;
-    }
-    if ((rc = iucv_connect(privptr->command_buffer,
-                           privptr->userid,
-                           iucv_host,
-                           vmident,
-                           &iucv_used_pathid))!=0) {
-      printk(  "iucv: iucv connect failed with rc %X\n",rc);
-      iucv_retrieve_buffer(privptr->command_buffer);
-      return -ENODEV;
-    }
-
-    privptr->pathid = iucv_used_pathid;
-    iucv_pathid[dev-iucv_devs]=privptr->pathid;
-
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr2 = (ulong) buf;
+       parm.ipbfln2f = buflen; /* length of message */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (reply, &parm);
 #ifdef DEBUG
-    printk(  "iucv: iucv_connect ended with rc: %X\n",rc);
-    printk(  "iucv[%d] pathid %X \n",(int)(dev-iucv_devs),privptr->pathid);
+       printk (KERN_DEBUG "exiting iucv_reply\n");
 #endif
-    netif_start(dev);
-    netif_start_queue(dev);
-    return 0;
+       return b2f0_result;
 }
 
-
-
-/*-----------------------------------------------------------------------*/
-/* Receive a packet: retrieve, encapsulate and pass over to upper levels */
-/*-----------------------------------------------------------------------*/
-void iucv_rx(net_device *dev, int len, unsigned char *buf)
+/**************************************************************/
+/* Name: iucv_reply_array                                     */
+/* Purpose: responds to the two-way messages that you receive */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, id of message                       */
+/*        trgcls - ulong, target message class                */
+/*        priority_msg - uchar, flag                          */
+/*        buf    - pointer, address of array                  */
+/*        buflen - length of buffer                           */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls,
+                 uchar priority_msg, iucv_array_t * buffer, ulong buflen)
 {
-
-  struct sk_buff *skb;
-  struct iucv_priv *privptr = (struct iucv_priv *)dev->priv;
-
+       iparml_db parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-  printk(  "iucv: iucv_rx len: %X, device %s\n",len,dev->name);
-  printk(  "iucv rx: received orig:\n");
-  dumpit(buf,len);
+       printk (KERN_DEBUG "entering iucv_reply_array\n");
 #endif
-
-  /* strip iucv header now */
-  len = len - 2;   /* short header */
-  buf = buf + 2;   /* short header */
-
-  skb = dev_alloc_skb(len+2); /* why +2 ? alignment ? */
-  if (!skb) {
-    printk(  "iucv rx: low on mem, returning...\n");
-    return;
-  }
-  skb_reserve(skb, 2);                        /* align IP on 16B boundary*/
-  memcpy(skb_put(skb, len), buf, len);
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
+       parm.iptrgcls = trgcls;
+       parm.ipbfadr2 = (ulong) buffer;
+       parm.ipbfln2f = buflen; /* length of message */
+       parm.ipflags1 |= reply_array;   /* reply w/ array  */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (reply, &parm);
 #ifdef DEBUG
-  printk(  "iucv rx: data before netif_rx()\n");
-  dumpit(buf,len);
+       printk (KERN_DEBUG "exiting iucv_reply_array\n");
 #endif
+       return b2f0_result;
+}
 
-  /* Write metadata, and then pass to the receive level */
-  skb->mac.raw = skb->data;
-  skb->pkt_type = PACKET_HOST;
-  skb->dev = dev;
-  skb->protocol = htons(ETH_P_IP);
-  skb->ip_summed = CHECKSUM_UNNECESSARY;                /* don't check it*/
-  privptr->stats.rx_packets++;
-  netif_rx(skb);
-
-  return;
-} /* end  iucv_rx() */
-
-
-
-
-/*----------------------------*/
-/* handle interrupts          */
-/*----------------------------*/
-void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
+/**************************************************************/
+/* Name: iucv_reply_prmmsg                                    */
+/* Purpose: responds to the two-way messages in parameter list */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong, id of message                       */
+/*        trgcls - ulong, target message class                */
+/*        priority_msg - uchar, flag                          */
+/*        prmmsg - uchar[8], message in parameter list        */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls,
+                  uchar priority_msg, uchar prmmsg[8])
 {
-  int rc;
-  struct in_device *indev;
-  struct in_ifaddr *inaddr;
-  unsigned long len=0;
-  net_device *dev=0;
-  struct iucv_priv *privptr;
-  INTERRUPT_T * extern_int_buffer;
-  unsigned short iucv_data_len=0;
-  unsigned short iucv_next=0;
-  unsigned char * rcvptr;
-  
-  /* get own buffer: */
-  extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer;
-  
-#ifdef DEBUG
-  printk(  "iucv: do_iucv_interrupt %x received; pathid: %02X\n",
-          extern_int_buffer->iptype,extern_int_buffer->ippathid);
-  printk(   "iucv: extern_int_buffer:\n");
-  dumpit((char *)&extern_int_buffer[0],40);
+       iparml_dpl parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
 #endif
-
-  if (extern_int_buffer->iptype == 0x01)
-    dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
-  else
-    dev = get_device_from_pathid(extern_int_buffer->ippathid);
-
-  if (dev == NULL)
-    return;
-
-  netif_enter_interrupt(dev);        /* lock ! */
-  privptr = (struct iucv_priv *)(dev->priv);
-  
-  switch (extern_int_buffer->iptype)
-    {
-    case 0x01: /* connection pending ext interrrupt */
-#ifdef DEBUG
-      printk(  "iucv: connection pending IRQ.\n");
-#endif
-      
-      rc = iucv_accept(glob_command_buffer,
-                      extern_int_buffer->ippathid);
-      if (rc != 0) {
-       printk(  "iucv: iucv_accept failed with rc: %X\n",rc);
-       iucv_retrieve_buffer(glob_command_buffer);
-       break;
-      }
-
-      privptr->pathid =  extern_int_buffer->ippathid;
-      
-#ifdef DEBUG
-      printk(  "iucv: iucv_accept ended with rc: %X\n",rc);
-      printk(  "iucv: device %s found.\n",dev->name);
-#endif
-      break;
-      
-    case 0x02: /* connection completed ext interrrupt */
-      /* set own global IP address */
-      /* & set global routing addr */
-#ifdef DEBUG
-      printk(  "connection completed.\n");
-#endif
-      
-      if( extern_int_buffer->ipmsgtag !=0)
-       {
-         /* get ptr's to kernel struct with local & broadcast address */
-         indev = dev->ip_ptr;
-         inaddr = (struct in_ifaddr*) indev->ifa_list;
-       }
-      break;
-      
-      
-    case 0x03: /* connection severed ext interrrupt */
-      /* we do not handle this one at this time */
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
+       parm.iptrgcls = trgcls;
+       memcpy (parm.iprmmsg, prmmsg, 8);
+       parm.ipflags1 |= parm_data;
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       b2f0_result = b2f0 (reply, &parm);
 #ifdef DEBUG
-      printk(  "connection severed.\n");
+       printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
 #endif
-      break;
-      
-      
-    case 0x04: /* connection quiesced ext interrrupt */
-      /* we do not handle this one at this time */
+       return b2f0_result;
+}
+
+/**************************************************************/
+/* Name: iucv_connect                                         */
+/* Purpose: establishes an IUCV path to another vm            */
+/* Input: pathid - ushort *, pathid returned to user          */
+/*        msglim - ushort, limit of outstanding messages      */
+/*        user_data - uchar[16], user data                    */
+/*        userid - uchar[8], user's id                        */
+/*        system_name - uchar[8], system identification       */
+/*        priority_requested - uchar- flag                    */
+/*        prmdata - uchar, flag prgrm can handler messages    */
+/*                  in parameter list                         */
+/*        quiesce - uchar, flag to quiesce a path being establ */
+/*        control - uchar, flag, option not used              */
+/*        local   - uchar, flag, establish connection only on */
+/*                  local system                              */
+/*        priority_permitted - uchar *, flag returned to user */
+/*        handle - address of handler                         */
+/*        pgm_data - ulong                                    */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16],
+             uchar userid[8], uchar system_name[8],
+             uchar priority_requested, uchar prmdata,
+             uchar quiesce, uchar control,
+             uchar local, uchar * priority_permitted,
+             iucv_handle_t handle, ulong pgm_data)
+{
+       iparml_control parm;
+       ulong b2f0_result;
+       int add_pathid_result, rc;
+       handler *R;
 #ifdef DEBUG
-      printk(  "connection quiesced.\n");
+       printk (KERN_DEBUG "entering iucv_connect\n");
 #endif
-      break;
-      
-      
-    case 0x05: /* connection resumed ext interrrupt */
-      /* we do not handle this one at this time */
+       memset (&parm, 0, sizeof (parm));
+       if (declare_flag == NULL) {
+               rc = iucv_declare_buffer (iucv_external_int_buffer);
+               if (rc) {
+                       printk (KERN_DEBUG "IUCV: registration failed\n");
 #ifdef DEBUG
-      printk(  "connection resumed.\n");
+                       printk (KERN_DEBUG "rc from declare buffer is: %i\n",
+                               rc);
 #endif
-      break;
-      
-      
-    case 0x06: /* priority message complete ext interrupt */
-    case 0x07: /* non priority message complete ext interrupt */
-      /* send it to iucv_rx for handling */
+                       return rc;
+               } else
+                       declare_flag = 1;
+       }
+       /* Checking if handle is valid  */
+       spin_lock (&lock);
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               if (R == handle)
+                       break;
+       if (R == NULL) {
+               spin_unlock (&lock);
 #ifdef DEBUG
-      printk(  "message completed.\n");
+               printk (KERN_DEBUG "iucv_connect: Invalid Handle\n");
 #endif
-      
-      if (extern_int_buffer->ipaudit ==0)  /* ok case */
-       {
+               return (-2);
+       }
+       if (pathid == NULL) {
+               spin_unlock (&lock);
 #ifdef DEBUG
-         printk(  "iucv: msg complete interrupt successful, rc: %X\n",
-                  (unsigned int)extern_int_buffer->ipaudit);
+               printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n");
 #endif
-         ;
+               return (-3);
        }
-      else
-       {
-         printk(  "iucv: msg complete interrupt error, rc: %X\n",
-                  (unsigned int)extern_int_buffer->ipaudit);
+       spin_unlock (&lock);
+       parm.ipmsglim = msglim;
+       memcpy (parm.ipuser, user_data, 16);
+       memcpy (parm.ipvmid, userid, 8);
+       memcpy (parm.iptarget, system_name, 8);
+       if (parm.iptarget)
+               ASCEBC (parm.iptarget, 8);
+       if (parm.ipvmid) {
+               ASCEBC (parm.ipvmid, 8);
+               EBC_TOUPPER(parm.ipvmid, 8);
        }
-      /* a transmission is over: tell we are no more busy */
-      privptr->stats.tx_packets++;
-      netif_wake_queue(dev);                /* transmission is no longer busy*/
-      break;
-      
-      
-    case 0x08: /* priority message pending */
-    case 0x09: /* non priority message pending */
-#ifdef DEBUG
-      printk(  "message pending.\n");
-#endif
-      rcvptr = &privptr->receive_buffer[0];
-
-      /* re-set receive buffer */
-      memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
-      len = privptr->receive_buffer_len;
-      
-        /* get data now */
-        if (extern_int_buffer->ipflags1 & 0x80)
-         {  /* data is in the message */
-#ifdef DEBUG
-           printk(  "iucv: iucv_receive data is in header!\n");
-#endif
-           memcpy(privptr->receive_buffer,
-                  (char *)extern_int_buffer->iprmmsg1,
-                  (unsigned long)(extern_int_buffer->iprmmsg2));
-         }
-        else /* data is in buffer, do a receive */
-         {
-           rc = iucv_receive(privptr->command_buffer,rcvptr,len);
-           if (rc != 0  || len == 0)
-             {
-               printk(  "iucv: iucv_receive failed with rc: %X, length: %lX\n",rc,len);
-               iucv_retrieve_buffer(privptr->command_buffer);
-               break;
-             }
-         } /* end else */
-       
-      iucv_next = 0; 
-      /* get next packet offset */  
-      iucv_data_len= *((unsigned short*)rcvptr); 
-        do{ /* until receive buffer is empty, i.e. iucv_next == 0 ! */
-
-        /* get data length:    */
-        iucv_data_len= iucv_data_len - iucv_next;
-       
-#ifdef DEBUG
-        printk(  "iucv: iucv_receive: len is %02X, last: %02X\n",
-                iucv_data_len,iucv_next);
-#endif
-        /* transmit upstairs */
-        iucv_rx(dev,(iucv_data_len),rcvptr);
-       
-#ifdef DEBUG
-        printk(  "iucv: transaction complete now.\n");
-#endif
-        iucv_next = *((unsigned short*)rcvptr);
-        rcvptr = rcvptr + iucv_data_len;
-        /* get next packet offset */  
-        iucv_data_len= *((unsigned short*)rcvptr);
-       
-      } while (iucv_data_len != 0);
-      netif_start_queue(dev);                 /* transmission is no longer busy*/
-      break;
-      
-    default:
-      printk(  "unknown iucv interrupt \n");
-      break;
-      
-    } /* end switch */
-  netif_exit_interrupt(dev);              /* release lock*/
-  
-#ifdef DEBUG
-  printk(  "iucv: leaving do_iucv_interrupt.\n");
-#endif
-  
-}  /* end    do_iucv_interrupt()  */
-
-
-
-/*-------------------------------------------*/
-/*   Transmit a packet (low level interface) */
-/*-------------------------------------------*/
-int iucv_hw_tx(char *send_buf, int len,net_device *dev)
-{
-  /* This function deals with hw details.                         */
-  /* This interface strips off the ethernet header details.       */
-  /* In other words, this function implements the iucv behaviour,*/
-  /* while all other procedures are rather device-independent     */
-  struct iucv_priv *privptr;
-  int rc, recv_len=2000;
-  
-  privptr = (struct iucv_priv *)(dev->priv);
-  
-#ifdef DEBUG
-  printk(  "iucv: iucv_hw_tx, device %s\n",dev->name);
-  printk(  "iucv: hw_TX_data len: %X\n",len);
-  dumpit(send_buf,len);
-#endif
-  
-  /* I am paranoid. Ain't I? */
-  if (len < sizeof(struct iphdr))
-    {
-      printk(  "iucv: Hmm... packet too short (%i octets)\n",len);
-      return -EINVAL;
-    }
-  
-  /*
-   * build IUCV header (preceeding halfword offset)   
-   * works as follows: Each packet is preceded by the 
-   * halfword offset to the next one. 
-   * The last packet is followed by an offset of zero.
-   * E.g., AL2(12),10-byte packet, AL2(34), 32-byte packet, AL2(0)
-   */
-  
-  memcpy(&privptr->send_buffer[2],send_buf,len+2);
-  privptr->send_buffer[len+2] = 0;
-  privptr->send_buffer[len+3] = 0;
-  *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
-  
-#ifdef DEBUG
-  printk(  "iucv: iucv_hw_tx, device %s\n",dev->name);
-  printk(  "iucv: send len: %X\n",len+4);
-  dumpit(privptr->send_buffer,len+4);
-#endif
-  *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
-  
-  /* Ok, now the packet is ready for transmission: send it. */
-  if ((rc = iucv_send(privptr->command_buffer,
-                     privptr->pathid,
-                     &privptr->send_buffer[0],len+4,
-                     privptr->recv_buf,recv_len))!=0) {
-    printk(  "iucv: send_iucv failed, rc: %X\n",rc);
-    iucv_retrieve_buffer(privptr->command_buffer);
-  }
-#ifdef DEBUG
-  printk(  "iucv: send_iucv ended, rc: %X\n",rc);
-#endif
-  return rc;
-} /* end   iucv_hw_tx()  */
-
-
-
-
-
-
-/*------------------------------------------*/
-/* Transmit a packet (called by the kernel) */
-/*------------------------------------------*/
-int iucv_tx(struct sk_buff *skb, net_device *dev)
-{
-    int retval=0;
-
-    struct iucv_priv *privptr;
-
-    if (dev == NULL)
-    {
-      printk("iucv: NULL dev passed\n");
-      return 0;
-    }
-
-    privptr = (struct iucv_priv *) (dev->priv);
-
-    if (skb == NULL)
-    {
-      printk("iucv: %s: NULL buffer passed\n", dev->name);
-      privptr->stats.tx_errors++;
-      return 0;
-    }
-
+       if (priority_requested)
+               parm.ipflags1 |= prior_msg;
+       if (prmdata)
+               parm.ipflags1 |= parm_data;     /*data in parameter list */
+       if (quiesce)
+               parm.ipflags1 |= quiesce_msg;
+       if (control) {
+               /* do nothing at the time being  */
+               /*control not provided yet */
+       }
+       if (local)
+               parm.ipflags1 |= local_conn;    /*connect on local system */
+       b2f0_result = b2f0 (connect, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
+       if (add_pathid_result) {
 #ifdef DEBUG
-    printk(  "iucv: enter iucv_tx, using %s\n",dev->name);
+               printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
 #endif
-
-    if (netif_is_busy(dev))                        /* shouldn't happen */
-    {
-      privptr->stats.tx_errors++;
-      dev_kfree_skb(skb);
-      printk("iucv: %s: transmit access conflict ! leaving iucv_tx.\n", dev->name);
-    }
-
-    netif_stop_queue(dev);                                   /* transmission is busy*/
-    dev->trans_start = jiffies;                       /* save the timestamp*/
-
-    /* actual deliver of data is device-specific, and not shown here */
-    retval = iucv_hw_tx(skb->data, skb->len, dev);
-
-    dev_kfree_skb(skb);                               /* release it*/
-
+               return (add_pathid_result);
+       }
+       *pathid = parm.ippathid;
+       if (parm.ipflags1 & prior_msg)
+               if (priority_permitted)
+                       *priority_permitted = 0x01;
 #ifdef DEBUG
-    printk(  "iucv:leaving iucv_tx, device %s\n",dev->name);
+       printk (KERN_DEBUG "exiting iucv_connect\n");
 #endif
+       return b2f0_result;
+}
 
-    return retval;              /* zero == done; nonzero == fail*/
-}   /* end  iucv_tx( struct sk_buff *skb, struct device *dev)  */
-
-
-
-
-
-
-/*---------------*/
-/* iucv_release */
-/*---------------*/
-int iucv_release(net_device *dev)
+/**************************************************************/
+/* Name: iucv_accept                                          */
+/* Purpose: completes the iucv communication path             */
+/* Input: pathid - ushort , pathid                            */
+/*        msglim - ushort, limit of outstanding messages      */
+/*        user_data - uchar[16], user data                    */
+/*        priority_requested - uchar- flag                    */
+/*        prmdata - uchar, flag prgrm can handler messages    */
+/*                  in parameter list                         */
+/*        quiesce - uchar, flag to quiesce a path being establ*/
+/*        control - uchar, flag, option not used              */
+/*        priority_permitted -uchar *, flag returned to caller*/
+/*        handle - address of handler                         */
+/*        pgm_data - ulong                                    */
+/* Output: iprcode - return code from b2f0 call               */
+/**************************************************************/
+int
+iucv_accept (ushort pathid, ushort msglim, uchar user_data[16],
+            uchar priority_requested,
+            uchar prmdata, uchar quiesce, uchar control,
+            uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data)
 {
-    int rc =0;
-    struct iucv_priv *privptr;
-    privptr = (struct iucv_priv *) (dev->priv);
-
-    netif_stop(dev);
-    netif_stop_queue(dev);           /* can't transmit any more*/
-    rc = iucv_sever(privptr->command_buffer);
-    if (rc!=0)
-    {
-       printk("iucv: %s: iucv_release pending...rc:%02x\n",dev->name,rc);
-    }
-
+       ulong index1, index2;
+       handler_table_entry *P = 0;
+       iparml_control parm;
+       ulong b2f0_result;
 #ifdef DEBUG
-      printk("iucv: iucv_sever ended with rc: %X\n",rc);
+       printk (KERN_DEBUG "entering iucv_accept\n");
 #endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.ipmsglim = msglim;
+       memcpy (parm.ipuser, user_data, 16);
+       if (priority_requested)
+               parm.ipflags1 |= prior_msg;
+       if (prmdata)
+               parm.ipflags1 |= parm_data;     /*data in parameter list */
+       if (quiesce)
+               parm.ipflags1 |= quiesce_msg;
+       if (control) {
+               /* do nothing at the time being  */
+               /*control not provided yet */
+       }
+       b2f0_result = b2f0 (accept, &parm);
+       if (b2f0_result)
+               return b2f0_result;
+       index1 = ((ulong) pathid) / 512;
+       index2 = ((ulong) pathid) % 512;
+       spin_lock (&lock);
+       if (pgm_data) {
+               P = main_table[index1];
+               (P + index2)->pgm_data = pgm_data;
+       }
+       spin_unlock (&lock);
+       if (parm.ipflags1 & prior_msg)
+               if (priority_permitted)
+                       *priority_permitted = 0x01;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_accept\n");
+#endif
+       return b2f0_result;
+}
 
-    return rc;
-} /* end  iucv_release() */
-
-
-
-
-
-/*-----------------------------------------------*/
-/* Configuration changes (passed on by ifconfig) */
-/*-----------------------------------------------*/
-int iucv_config(net_device *dev, struct ifmap *map)
+/**************************************************************/
+/* Name: iucv_send2way_prmmsg_array                           */
+/* Purpose: sends messages in both directions w/parameter lst */
+/* Input: pathid - ushort, pathid                             */
+/*        msgid  - ulong *, id of message returned to caller  */
+/*        trgcls - ulong, target message class                */
+/*        srccls - ulong, source message class                */
+/*        msgtag - ulong, message tag                         */
+/*        priority_msg - uchar, flag                          */
+/*        prmmsg - uchar[8], message being sent in parameter  */
+/*        ansbuf - pointer to array of buffers                */
+/*        anslen - length of ansbuf buffer                    */
+/* Output: iprcode - return code from b2f0 call               */
+/*         msgid - returns message id                         */
+/**************************************************************/
+int
+iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid,
+                           ulong trgcls, ulong srccls,
+                           ulong msgtag, uchar priority_msg,
+                           uchar prmmsg[8],
+                           iucv_array_t * ansbuf, ulong anslen)
 {
-   if (dev->flags & IFF_UP)        /* can't act on a running interface*/
-        return -EBUSY;
-
-   /* ignore other fields */
-   return 0;
+       iparml_dpl parm;
+       ulong b2f0_result;
+#ifdef DEBUG
+       printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
+#endif
+       memset (&(parm), 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipbfadr2 = (ulong) ansbuf;
+       parm.ipbfln2f = anslen;
+       parm.ipflags1 |= 0x88;  /* message in prmlist */
+       if (priority_msg)
+               parm.ipflags1 |= prior_msg;     /* priority message */
+       memcpy (parm.iprmmsg, prmmsg, 8);
+       b2f0_result = b2f0 (send, &parm);
+       if (msgid)
+               *msgid = parm.ipmsgid;
+#ifdef DEBUG
+       printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
+#endif
+       return b2f0_result;
 }
-/*  end  iucv_config()  */
-
 
+/******************************************************************/
+/* Name: top_half_handler                                         */
+/* Purpose: handle minimum amount of interrupt in fastest time    */
+/*  possible and then pass interrupt to bottom half handler.      */
+/* Input: external interrupt buffer                               */
+/* Output: void                                                   */
+/******************************************************************/
 
-
-
-/*----------------*/
-/* Ioctl commands */
-/*----------------*/
-int iucv_ioctl(net_device *dev, struct ifreq *rq, int cmd)
+inline void
+top_half_interrupt (struct pt_regs *regs, __u16 code)
 {
-#ifdef DEBUG
-    printk(  "iucv: device %s; iucv_ioctl\n",dev->name);
+       iucv_packet *pkt;
+       pkt = (iucv_packet *) kmalloc
+           (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC);
+       if (pkt == NULL) {
+               printk (KERN_DEBUG "out of memory\n");
+               return;
+       }
+       memcpy (pkt->data, iucv_external_int_buffer, 40);
+#ifdef DEBUG3
+printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4));
+#endif
+       /* put new packet on the list */
+       spin_lock (&iucv_packets_lock);
+       pkt->next = NULL;
+       if (iucv_packets_tail != NULL)
+               iucv_packets_tail->next = pkt;
+       else
+               iucv_packets_head = pkt;
+       iucv_packets_tail = pkt;
+       spin_unlock (&iucv_packets_lock);
+
+       if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
+#ifdef DEBUG3
+printk (KERN_EMERG "TH: Queuing BH\n");
 #endif
-    return 0;
+               short_task.routine = (void *) bottom_half_interrupt;
+               queue_task (&short_task, &tq_immediate);
+               mark_bh (IMMEDIATE_BH);
+       }
+       return;
 }
 
-/*---------------------------------*/
-/* Return statistics to the caller */
-/*---------------------------------*/
-struct net_device_stats *iucv_stats(net_device *dev)
+/*******************************************************************/
+/* Name: bottom_half_interrupt                                     */
+/* Purpose: Handle interrupt at a more safer time                  */
+/* Input: void                                                     */
+/* Output: void                                                    */
+/*******************************************************************/
+void
+bottom_half_interrupt (void)
 {
-    struct iucv_priv *priv = (struct iucv_priv *)dev->priv;
-#ifdef DEBUG
-    printk(  "iucv: device %s; iucv_stats\n",dev->name);
+       iucv_packet *iucv_packet_list;
+       iucv_packet *tmp;
+       ulong flags;
+
+       atomic_set (&bh_scheduled, 0);
+       spin_lock_irqsave (&iucv_packets_lock, flags);
+       iucv_packet_list = iucv_packets_head;
+       iucv_packets_head = iucv_packets_tail = NULL;
+       spin_unlock_irqrestore (&iucv_packets_lock, flags);
+
+       /* now process all the request in the iucv_packet_list */
+#ifdef DEBUG3
+       printk (KERN_EMERG "BH: Process all packets\n");
+#endif
+       while (iucv_packet_list != NULL) {
+#ifdef DEBUG3
+               printk( KERN_EMERG "BH:>  %08x\n", 
+                       *(int *)(iucv_packet_list->data+4));
+#endif
+               do_int ((iucv_ConnectionPending *) iucv_packet_list->data);
+#ifdef DEBUG3
+               printk( KERN_EMERG "BH:<  %08x\n",
+                       *(int *)(iucv_packet_list->data+4));
+#endif
+               tmp = iucv_packet_list;
+               iucv_packet_list = iucv_packet_list->next;
+               kfree (tmp);
+       }
+#ifdef DEBUG3
+       printk (KERN_EMERG "BH: Done\n");
 #endif
-    return &priv->stats;
+       return;
 }
-
-
-/*
- * iucv_change_mtu     
- * IUCV can handle MTU sizes from 576 to approx. 32000    
- */
-
-static int iucv_change_mtu(net_device *dev, int new_mtu)
+/*******************************************************************/
+/* Name: do_int                                                    */
+/* Purpose: Handle interrupt in a more safe environment            */
+/* Inuput: int_buf - pointer to copy of external interrupt buffer  */
+/* Output: void                                                    */
+/*******************************************************************/
+void
+do_int (iucv_ConnectionPending * int_buf)
 {
+       ulong index1 = 0, index2 = 0;
+       handler_table_entry *P = 0;     /* P is a pointer */
+       handler *Q = 0, *R;     /* Q and R are pointers */
+       iucv_interrupt_ops_t *interrupt = 0;    /* interrupt addresses */
+       uchar temp_buff1[24], temp_buff2[24];   /* masked handler id. */
+       int add_pathid_result = 0, j = 0;
+       uchar no_listener[16] = "NO LISTENER";
 #ifdef DEBUG
-    printk(  "iucv: device %s; iucv_change_mtu\n",dev->name);
+       int i;
+       uchar *prt_parm;
 #endif
-       if ((new_mtu < 64) || (new_mtu > 32000))
-        return -EINVAL;
-       dev->mtu = new_mtu;
-       return 0;
-}
-
-
-
-
-/*--------------------------------------------*/
-/* The init function (sometimes called probe).*/
-/* It is invoked by register_netdev()         */
-/*--------------------------------------------*/
-int iucv_init(net_device *dev)
+#ifdef DEBUG3
+       printk (KERN_DEBUG "BH:-  Entered do_int "
+                          "pathid %d, type %02X\n",
+               int_buf->ippathid, int_buf->iptype);
+#endif
+#ifdef DEBUG
+       prt_parm = (uchar *) (int_buf);
+       printk (KERN_DEBUG "External Interrupt Buffer\n");
+       for (i = 0; i < 40; i++)
+               printk (KERN_DEBUG "%02x ", prt_parm[i]);
+       printk (KERN_DEBUG "\n");
+#endif
+       ASCEBC (no_listener, 16);
+       if (int_buf->iptype != 01) {
+               index1 = ((ulong) (int_buf->ippathid)) / 512;
+               index2 = ((ulong) (int_buf->ippathid)) % 512;
+               spin_lock (&lock);
+
+               P = main_table[index1];
+               Q = (P + index2)->addrs;
+               interrupt = Q->interrupt_table; /* interrupt functions */
+               spin_unlock (&lock);
+#ifdef DEBUG
+               printk (KERN_DEBUG "Handler is: \n");
+               prt_parm = (uchar *) Q;
+               for (i = 0; i < sizeof (handler); i++)
+                       printk (KERN_DEBUG " %02x ", prt_parm[i]);
+               printk (KERN_DEBUG "\n");
+#endif
+       }                       /* end of if statement */
+       switch (int_buf->iptype) {
+       case 0x01:              /* connection pending */
+               spin_lock (&lock);
+               for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
+                       memcpy (temp_buff1, &(int_buf->ipvmid), 24);
+                       memcpy (temp_buff2, &(R->vmid), 24);
+                       for (j = 0; j < 24; j++) {
+                               temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j];
+                               temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j];
+                       }
+#ifdef DEBUG
+                       for (i = 0; i < sizeof (temp_buff1); i++)
+                               printk (KERN_DEBUG " %c ", temp_buff1[i]);
+                       printk (KERN_DEBUG "\n");
+                       for (i = 0; i < sizeof (temp_buff2); i++)
+                               printk (KERN_DEBUG " %c ", temp_buff2[i]);
+                       printk (KERN_DEBUG "\n");
+#endif
+                       if (memcmp((void *) temp_buff1,
+                                  (void *) temp_buff2, 24) == 0) {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "found a matching handler\n");
+#endif
+                               break;
+                       }
+               }
+               spin_unlock (&lock);
+               if (R) {
+                       /* ADD PATH TO PATHID TABLE */
+                       add_pathid_result =
+                           add_pathid (int_buf->ippathid, R, R->pgm_data);
+                       if (add_pathid_result == NULL) {
+                               interrupt = R->interrupt_table;
+                               if ((*interrupt).ConnectionPending) {
+                                       EBCASC (int_buf->ipvmid, 8);
+                                       
+                                           ((*interrupt).
+                                        ConnectionPending) (int_buf,
+                                                            R->pgm_data);
+                               } else {
+                                       iucv_sever (int_buf->ippathid,
+                                                   no_listener);
+                               }
+                       } /* end if if(add_p...... */
+                       else {
+                               iucv_sever (int_buf->ippathid, no_listener);
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "add_pathid failed with rc = %d\n",
+                                       (int) add_pathid_result);
+#endif
+                       }
+               } else
+                       iucv_sever (int_buf->ippathid, no_listener);
+               break;
+       case 0x02:              /*connection complete */
+               if (Q) {
+                       if ((*interrupt).ConnectionComplete)
+                               ((*interrupt).ConnectionComplete)
+                                   
+                                   ((iucv_ConnectionComplete *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "ConnectionComplete not called\n");
+                               printk (KERN_DEBUG "routine@ is %p\n",
+                                       (*interrupt).ConnectionComplete);
+#endif
+                       }
+               }
+               break;
+       case 0x03:              /* connection severed */
+               if (Q) {
+                       if ((*interrupt).ConnectionSevered)
+                               ((*interrupt).ConnectionSevered)
+                                   
+                                   ((iucv_ConnectionSevered *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else
+                               iucv_sever (int_buf->ippathid, no_listener);
+               } else
+                       iucv_sever (int_buf->ippathid, no_listener);
+               break;
+       case 0x04:              /* connection quiesced */
+               if (Q) {
+                       if ((*interrupt).ConnectionQuiesced)
+                               ((*interrupt).ConnectionQuiesced)
+                                   
+                                   ((iucv_ConnectionQuiesced *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "ConnectionQuiesced not called\n");
+                               printk (KERN_DEBUG "routine@ is %p\n",
+                                       (*interrupt).ConnectionQuiesced);
+#endif
+                       }
+               }
+               break;
+       case 0x05:              /* connection resumed */
+               if (Q) {
+                       if ((*interrupt).ConnectionResumed)
+                               ((*interrupt).ConnectionResumed)
+                                   
+                                   ((iucv_ConnectionResumed *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "ConnectionResumed not called\n");
+                               printk (KERN_DEBUG "routine@ is %p\n",
+                                       (*interrupt).ConnectionResumed);
+#endif
+                       }
+               }
+               break;
+       case 0x06:              /* priority message complete */
+       case 0x07:              /* nonpriority message complete */
+               if (Q) {
+                       if ((*interrupt).MessageComplete)
+                               ((*interrupt).MessageComplete)
+                                   
+                                   ((iucv_MessageComplete *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "MessageComplete not called\n");
+                               printk (KERN_DEBUG "routine@ is %p\n",
+                                       (*interrupt).MessageComplete);
+#endif
+                       }
+               }
+               break;
+       case 0x08:              /* priority message pending  */
+       case 0x09:              /* nonpriority message pending  */
+               if (Q) {
+                       if ((*interrupt).MessagePending)
+                               ((*interrupt).MessagePending)
+                                   
+                                   ((iucv_MessagePending *) int_buf,
+                                    (P + index2)->pgm_data);
+                       else {
+#ifdef DEBUG
+                               printk (KERN_DEBUG
+                                       "MessagePending not called\n");
+                               printk (KERN_DEBUG "routine@ is %p\n",
+                                       (*interrupt).MessagePending);
+#endif
+                       }
+               }
+               break;
+       default:                /* unknown iucv type */
+               printk (KERN_DEBUG "unknown iucv interrupt \n");
+               break;
+       }                       /* end switch */
+#ifdef DEBUG3
+       printk (KERN_DEBUG "BH:-  Exiting do_int "
+                          "pathid %d, type %02X\n",
+               int_buf->ippathid, int_buf->iptype);
+#endif
+       return;
+}                              /* end of function call */
+
+/**************************************************************/
+/* Name: iucv_register_program                                */
+/* Purpose: registers a new handler                           */
+/* Input: pgmname- uchar[16], user id                         */
+/*        userid - uchar[8], machine id                       */
+/*        prmmask- mask                                       */
+/*        ops    - pointer to iucv_interrupt_ops buffer       */
+/* Output: new_handler - address of new handler               */
+/**************************************************************/
+iucv_handle_t
+iucv_register_program (uchar pgmname[16],
+                      uchar userid[8],
+                      uchar pgmmask[24],
+                      iucv_interrupt_ops_t * ops, ulong pgm_data)
 {
-    int rc;
-    struct iucv_priv *privptr;
-
+       int rc;
+       handler *new_handler = 0;
 #ifdef DEBUG
-    printk(  "iucv: iucv_init, device: %s\n",dev->name);
+       int i;
+       uchar *prt_parm;
+       printk (KERN_DEBUG "enter iucv_register_program\n");
 #endif
-
-    /* request the 0x4000 external interrupt */
-    if (register_external_interrupt(0x4000, do_iucv_interrupt) != 0)
-            panic("Couldn't request external interrupts 0x4000");
-
-    dev->open            = iucv_open;
-    dev->stop            = iucv_release;
-    dev->set_config      = iucv_config;
-    dev->hard_start_xmit = iucv_tx;
-    dev->do_ioctl        = iucv_ioctl;
-    dev->get_stats       = iucv_stats;
-    dev->change_mtu      = iucv_change_mtu;
-
-    /* keep the default flags, just add NOARP */
-
-    dev->hard_header_len = 0;
-    dev->addr_len        = 0;
-    dev->type            = ARPHRD_SLIP;
-    dev->tx_queue_len    = 100;
-    dev->flags           = IFF_NOARP|IFF_POINTOPOINT;
-    dev->mtu    = 4092;
-
-    dev_init_buffers(dev);
-
-    /* Then, allocate the priv field. This encloses the statistics */
-    /* and a few private fields.*/
-    dev->priv = kmalloc(sizeof(struct iucv_priv), GFP_KERNEL);
-    if (dev->priv == NULL){
-       printk(  "iucv: no memory for dev->priv.\n");
-       return -ENOMEM;
-    }
-    memset(dev->priv, 0, sizeof(struct iucv_priv));
-    privptr = (struct iucv_priv *)(dev->priv);
-
-
-    privptr->send_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
-    if (privptr->send_buffer == NULL) {
-      printk(KERN_INFO "%s: could not get pages for send buffer\n",
-            dev->name);
-      return -ENOMEM;
-    }
-    memset(privptr->send_buffer, 0, 8*PAGE_SIZE);
-    privptr->send_buffer_len=8*PAGE_SIZE;
-    
-    privptr->receive_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
-    if (privptr->receive_buffer == NULL) {
-      printk(KERN_INFO "%s: could not get pages for receive buffer\n",
-            dev->name);
-      return -ENOMEM;
-    }
-    memset(privptr->receive_buffer, 0, 8*PAGE_SIZE);
-    privptr->receive_buffer_len=8*PAGE_SIZE;
-
-    /* now use the private fields ... */
-    /* init pathid                    */
-    privptr->pathid = -1;
-
-    /* init private userid from global userid */
-    memcpy(privptr->userid,iucv_userid[dev-iucv_devs],8);
-
-
-    /* we can use only ONE buffer for external interrupt ! */
-    rc=iucv_declare_buffer(privptr->command_buffer,
-                           (DCLBFR_T *)iucv_ext_int_buffer);
-    if (rc!=0 && rc!=19)   /* ignore existing buffer */
-      {
-         printk(  "iucv:iucv_declare failed, rc: %X\n",rc);
-         return -ENODEV;
-      }
-
-    rc = iucv_enable(privptr->command_buffer);
-    if (rc!=0)
-    {
-            printk(  "iucv:iucv_enable failed, rc: %x\n",rc);
-            iucv_retrieve_buffer(privptr->command_buffer);
-            return -ENODEV;
-    }
+       my_ops = *ops;
+       /* Allocate handler table */
+       new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+       if (new_handler == NULL) {
 #ifdef DEBUG
-    printk(  "iucv: iucv_init endend OK for device %s.\n",dev->name);
+               printk (KERN_DEBUG
+                       "IUCV: returned NULL address for new handle \n");
 #endif
-    return 0;
-}
-
-
-/*
- * setup iucv devices
- * 
- * string passed: iucv=userid1,...,useridn 
- */
-#if LINUX_VERSION_CODE>=0x020300
-static int  __init iucv_setup(char *str)
-#else
-__initfunc(void iucv_setup(char *str,int *ints))
+               return NULL;
+       }
+       /* fill in handler table */
+       memcpy (new_handler->user_data, pgmname, 16);
+       memcpy (new_handler->vmid, userid, 8);
+       memcpy (new_handler->mask, pgmmask, 24);
+       new_handler->pgm_data = pgm_data;
+       /* Convert from ASCII to EBCDIC */
+       if (new_handler->vmid) {
+               ASCEBC (new_handler->vmid, 8);
+               EBC_TOUPPER(new_handler->vmid, 8);
+       }
+       /* fill in handler table */
+       new_handler->interrupt_table = ops;
+       new_handler->size = ADDED_STOR;
+       /* Allocate storage for pathid table */
+       new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
+       memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
+       if (new_handler->start == NULL) {
+#ifdef DEBUG
+               printk (KERN_DEBUG
+                       "IUCV: returned NULL address for pathid table,"
+                       " exiting\n");
+#endif
+               return NULL;
+       }
+       new_handler->end = (*new_handler).start + ADDED_STOR;
+       new_handler->next = 0;
+       new_handler->prev = 0;
+       /* Place handler at beginning of chain */
+       spin_lock (&lock);
+       if (handler_anchor == NULL)
+               handler_anchor = new_handler;
+       else {
+               handler_anchor->prev = (ulong *) new_handler;
+               new_handler->next = (ulong *) handler_anchor;
+               handler_anchor = new_handler;
+#ifdef DEBUG
+               printk (KERN_DEBUG "adding a another handler to list\n");
+               printk (KERN_DEBUG "handler_anchor->prev is %p \n",
+                       handler_anchor->prev);
+               printk (KERN_DEBUG "new_handler->next is %p \n",
+                       new_handler->next);
+               printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
+#endif
+       }
+       spin_unlock (&lock);
+       if (declare_flag == NULL) {
+               rc = iucv_declare_buffer (iucv_external_int_buffer);
+               if (rc == 0) {
+                       declare_flag = 1;
+                       /* request the 0x4000 external interrupt */
+                       rc =
+                           register_external_interrupt (0x4000,
+                                                        top_half_interrupt);
+               } else {
+                       panic ("Registration failed");
+#ifdef DEBUG
+                       printk (KERN_DEBUG "rc from declare buffer is: %i\n",
+                               rc);
+#endif
+               }
+       }
+#ifdef DEBUG
+       printk (KERN_DEBUG "address of handle is %p ", new_handler);
+       printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler)));
+       printk (KERN_DEBUG "exit iucv_register_program\n");
+       printk (KERN_DEBUG "main_table is %p \n", main_table);
+       printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
+       printk (KERN_DEBUG "Handler is: \n");
+       prt_parm = (uchar *) new_handler;
+       for (i = 0; i < sizeof (handler); i++)
+               printk (KERN_DEBUG " %02x ", prt_parm[i]);
+       printk (KERN_DEBUG "\n");
 #endif
+       return new_handler;     /* send buffer address back */
+}                              /* end of register function */
+
+/**************************************************************/
+/* Name: iucv_unregister                                      */
+/* Purpose: remove handler from chain and sever all paths     */
+/* Input: handle - address of handler to be severed           */
+/* Output: returns 0                                          */
+/**************************************************************/
+int
+iucv_unregister (iucv_handle_t handle)
 {
-    int result=0, i=0,j=0, k=0, device_present=0;
-    char *s = str;
-    net_device * dev ={0};
-
+       handler *temp_next = 0, *temp_prev = 0;
+       handler *Q = 0, *R;
+       handler_table_entry *H_T_E = 0;
+       ulong *S = 0;           /*points to the beginning of block of h_t_e's*/
 #ifdef DEBUG
-    printk(  "iucv: start registering device(s)... \n");
+       printk (KERN_DEBUG "enter iucv_unregister\n");
+       printk (KERN_DEBUG "address of handle is %p ", handle);
+       printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle)));
 #endif
-
-    /*
-     * scan device userids
-     */
-
-    while(*s != 0x20 && *s != '\0'){
-       if(*s == ','){
-          /* fill userid up to 8 chars */
-          for(k=i;k<8;k++){
-             iucv_userid[j][k] = 0x40;
-          } /* end for */
-          /* new device  */
-          j++;
-          s++; /* ignore current char */
-          i=0;
-          if (j>MAX_DEVICES) {
-             printk("iucv: setup devices: max devices %d reached.\n",
-                   MAX_DEVICES);
-             break;
-          } /* end if */
-          continue;
-       } /* end if */
-       iucv_ascii_userid[j][i] = (int)*s;
-       iucv_userid[j][i] = _ascebc[(int)*s++];
-       i++;
-    } /* end while */
-
-    /* 
-     * fill last userid up to 8 chars
-     */
-    for(k=i;k<8;k++) {
-      iucv_userid[j][k] = 0x40;
-    }
-
-    /*
-     * set device name and register
-     */
-
-    for (k=0;k<=j;k++) {
-      memcpy(iucv_devs[k].name, "iucv0", 4);
-      dev = &iucv_devs[k];
-      dev->name[4] = k + '0';
-
-#ifdef DEBUGX
-      printk("iucv: (ASCII- )Userid:%s\n",&iucv_ascii_userid[k][0]);
-      printk("iucv: (ASCII-)Userid: ");
-      for (i=0;i<8;i++) {
-        printk(  "%02X ",(int)iucv_ascii_userid[k][i]);
-      }
-      printk("\n");
-      printk("iucv: (EBCDIC-)Userid: ");
-      for (i=0;i<8;i++) {
-         printk(  "%02X ",(int)iucv_userid[k][i]);
-      }
-      printk("\n");
-      printk("iucv: device name :%s\n",iucv_devs[k].name);
+       spin_lock (&lock);
+       Q = (handler *) handle;
+       /*
+        * Checking if handle is still registered: if yes, continue
+        *  if not registered, return.
+        */
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               if (Q == R) {
+#ifdef DEBUG
+                       printk (KERN_DEBUG "found a matching handler\n");
 #endif
-
-      if ( (result = register_netdev(iucv_devs + k)) )
-          printk("iucv: error %i registering device \"%s\"\n",
-                 result, iucv_devs[k].name);
-      else
-      {
-              device_present++;
-      }
-    } /* end for */
-
+                       break;
+               }
+       if (!R) {
+               spin_unlock (&lock);
+               return (0);
+       }
+       S = Q->start;
 #ifdef DEBUG
-    printk(  "iucv: end register devices, %d devices present\n",device_present);
+       printk (KERN_DEBUG "Q is handle? %p ", Q);
+       printk (KERN_DEBUG "Q->start is %p ", Q->start);
+       printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start));
+       printk (KERN_DEBUG "Q->end is %p ", Q->end);
+       printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end));
 #endif
-    /* return device_present ? 0 : -ENODEV; */
-#if LINUX_VERSION_CODE>=0x020300
-    return 1;
-#else
-    return;
+       while (S < (Q->end)) {  /* index thru table */
+               if (*S) {
+                       H_T_E = (handler_table_entry *) (*S);
+#ifdef DEBUG
+                       printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E);
+                       printk (KERN_DEBUG "Address of handle in H_T_E is %p",
+                               (H_T_E->addrs));
 #endif
-}
-
-#if LINUX_VERSION_CODE>=0x020300
-__setup("iucv=", iucv_setup);
+                       if ((H_T_E->addrs) != handle) {
+                               spin_unlock (&lock);
+                               return (-2);    /*handler addresses don't match */
+                       } else {
+                               spin_unlock (&lock);
+                               iucv_sever (H_T_E->pathid, Q->user_data);
+                               spin_lock (&lock);
+                       }
+               }
+               S++;            /* index by size of ulong */
+       }
+       kfree (Q->start);
+       temp_next = (handler *) Q->next;        /* address of next handler on list */
+       temp_prev = (handler *) Q->prev;        /* address of prev handler on list */
+       if ((temp_next != NULL) & (temp_prev != NULL)) {
+               (*temp_next).prev = (ulong *) temp_prev;
+               (*temp_prev).next = (ulong *) temp_next;
+       } else if ((temp_next != NULL) & (temp_prev == NULL)) {
+               (*temp_next).prev = NULL;
+               handler_anchor = temp_next;
+       } else if ((temp_next == NULL) & (temp_prev != NULL))
+               (*temp_prev).next = NULL;
+       else
+               handler_anchor = NULL;
+       if (handler_anchor == NULL)
+               iucv_retrieve_buffer ();
+       kfree (handle);
+       spin_unlock (&lock);
+#ifdef DEBUG
+       printk (KERN_DEBUG "exit iucv_unregister\n");
 #endif
+       return 0;
+}
 
-
-/*-------------*/
-/* The devices */
-/*-------------*/
-char iucv_names[MAX_DEVICES*8]; /* MAX_DEVICES eight-byte buffers */
-net_device iucv_devs[MAX_DEVICES] = {
-    {
-        iucv_names, /* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+8,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+16,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+24,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+32,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+40,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+48,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+56,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+64,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    },
-    {
-        iucv_names+72,/* name -- set at load time */
-        0, 0, 0, 0,  /* shmem addresses */
-        0x000,       /* ioport */
-        0,           /* irq line */
-        0, 0, 0,     /* various flags: init to 0 */
-        NULL,        /* next ptr */
-        iucv_init,  /* init function, fill other fields with NULL's */
-    }
-};
-
+EXPORT_SYMBOL (iucv_accept);
+EXPORT_SYMBOL (iucv_connect);
+EXPORT_SYMBOL (iucv_purge);
+EXPORT_SYMBOL (iucv_query);
+EXPORT_SYMBOL (iucv_quiesce);
+EXPORT_SYMBOL (iucv_receive);
+EXPORT_SYMBOL (iucv_receive_simple);
+EXPORT_SYMBOL (iucv_receive_array);
+EXPORT_SYMBOL (iucv_reject);
+EXPORT_SYMBOL (iucv_reply);
+EXPORT_SYMBOL (iucv_reply_array);
+EXPORT_SYMBOL (iucv_reply_prmmsg);
+EXPORT_SYMBOL (iucv_resume);
+EXPORT_SYMBOL (iucv_send);
+EXPORT_SYMBOL (iucv_send2way);
+EXPORT_SYMBOL (iucv_send2way_array);
+EXPORT_SYMBOL (iucv_send_array);
+EXPORT_SYMBOL (iucv_send2way_prmmsg);
+EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
+EXPORT_SYMBOL (iucv_send_prmmsg);
+EXPORT_SYMBOL (iucv_setmask);
+EXPORT_SYMBOL (iucv_sever);
+EXPORT_SYMBOL (iucv_register_program);
+EXPORT_SYMBOL (iucv_unregister);
index 7905fb49a8a65639a43f7faaf3c5c191bc1d19d6..82c5115657e26f0eb11503efbd6da44a0bfce4c3 100644 (file)
 /*
- *  drivers/s390/net/iucv.h
- *    Network driver for VM using iucv
+ *  drivers/s390/net/netiucv.h
+ *    IUCV base support.
  *
  *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
- *               Hartmut Penner <hpenner@de.ibm.com> 
+ *    Copyright (C) 2000 IBM Corporation
+ *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ *
+ *
+ * Functionality:
+ * To explore any of the IUCV functions, one must first register
+ * their program using iucv_register(). Once your program has
+ * successfully completed a register, it can use the other functions.
+ * For furthur reference on all IUCV functionality, refer to the
+ * CP Programming Services book, also available on the web
+ * thru www.ibm.com/s390/vm.
  */
-
 #ifndef _IUCV_H
 #define _IUCV_H
+#define uchar  unsigned char
+#define ushort unsigned short
+#define ulong  unsigned long
+#define iucv_handle_t void *
+/***********************FLAGS*************************************/
+#define  source_class   0x01
+#define  target_class   0x01
+#define  local_conn     0x01
+#define  specify_pathid 0x02
+#define  specify_msgid  0x04
+#define  reply_array    0x08
+#define  one_way_msg    0x10
+#define  prior_msg      0x20
+#define  array          0x40
+#define  quiesce_msg    0x40
+#define  parm_data      0x80
+#define  IPRMDATA       0x80
+#define  IPBUFLST       0x40
+#define  IPPRTY         0x20
+#define  IPNORPY        0x10
+#define  IPANSLST       0x08
+#define  IPFGMID        0x04
+#define  IPFGPID        0x02
+#define  IPFGMCL        0x01
 
-
-#define UCHAR  unsigned char
-#define USHORT unsigned short
-#define ULONG  unsigned long
-
-#define DEFAULT_BUFFERSIZE  2048
-#define DEFAULT_FN_LENGTH   27
-#define TRANSFERLENGTH      10
-
-
-
-/* function ID's */
-#define RETRIEVE_BUFFER 2
-#define REPLY           3
-#define SEND            4
-#define RECEIVE         5
-#define ACCEPT          10
-#define CONNECT         11
-#define DECLARE_BUFFER  12
-#define SEVER           15
-#define SETMASK         16
-#define SETCMASK        17
-#define PURGE           9999
-
-/* structures */
+/*---------------------------------------------------------*/
+/* Mapping of external interrupt buffers                   */
+/* Names: iucv_ConnectionPending    ->  connection pending */
+/*        iucv_ConnectionComplete   ->  connection complete */
+/*        iucv_ConnectionSevered    ->  connection severed */
+/*        iucv_ConnectionQuiesced   ->  connection quiesced */
+/*        iucv_ConnectionResumed    ->  connection resumed */
+/*        iucv_MessagePending       ->  message pending    */
+/*        iucv_MessageComplete      ->  message complete   */
+/*---------------------------------------------------------*/
 typedef struct {
-  USHORT res0;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  res1;
-  ULONG  res2;
-  ULONG  ipbfadr1;
-  ULONG  res[6];
-} DCLBFR_T;
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iptype;
+       ushort ipmsglim;
+       ushort res1;
+       uchar ipvmid[8];
+       uchar ipuser[16];
+       ulong res3;
+       uchar ippollfg;
+       uchar res4[3];
+} iucv_ConnectionPending;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  USHORT ipmsglim;
-  USHORT res1;
-  UCHAR  ipvmid[8];
-  UCHAR  ipuser[16];
-  UCHAR  iptarget[8];
-} CONNECT_T;
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iptype;
+       ushort ipmsglim;
+       ushort res1;
+       uchar res2[8];
+       uchar ipuser[16];
+       ulong res3;
+       uchar ippollfg;
+       uchar res4[3];
+} iucv_ConnectionComplete;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  USHORT ipmsglim;
-  USHORT res1;
-  UCHAR  res2[8];
-  UCHAR  ipuser[16];
-  UCHAR  res3[8];
-} ACCEPT_T;
+       ushort ippathid;
+       uchar res1;
+       uchar iptype;
+       ulong res2;
+       uchar res3[8];
+       uchar ipuser[16];
+       ulong res4;
+       uchar ippollfg;
+       uchar res5[3];
+} iucv_ConnectionSevered;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  ipmsgid;
-  ULONG  iptrgcls;
-  ULONG  ipbfadr1;
-  ULONG  ipbfln1f;
-  ULONG  ipsrccls;
-  ULONG  ipmsgtag;
-  ULONG  ipbfadr2;
-  ULONG  ipbfln2f;
-  ULONG  res;
-} SEND_T;
+       ushort ippathid;
+       uchar res1;
+       uchar iptype;
+       ulong res2;
+       uchar res3[8];
+       uchar ipuser[16];
+       ulong res4;
+       uchar ippollfg;
+       uchar res5[3];
+} iucv_ConnectionQuiesced;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  ipmsgid;
-  ULONG  iptrgcls;
-  ULONG  iprmmsg1;
-  ULONG  iprmmsg2;
-  ULONG  res1[2];
-  ULONG  ipbfadr2;
-  ULONG  ipbfln2f;
-  ULONG  res2;
-} REPLY_T;
+       ushort ippathid;
+       uchar res1;
+       uchar iptype;
+       ulong res2;
+       uchar res3[8];
+       uchar ipuser[16];
+       ulong res4;
+       uchar ippollfg;
+       uchar res5[3];
+} iucv_ConnectionResumed;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  ipmsgid;
-  ULONG  iptrgcls;
-  ULONG  ipbfadr1;
-  ULONG  ipbfln1f;
-  ULONG  res1[3];
-  ULONG  ipbfln2f;
-  ULONG  res2;
-} RECEIVE_T;
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iptype;
+       ulong ipmsgid;
+       ulong iptrgcls;
+       ulong iprmmsg1;
+       union u1 {
+               ulong ipbfln1f;
+               ulong iprmmsg2;
+       } ln1msg2;
+       ulong res1[3];
+       ulong ipbfln2f;
+       uchar ippollfg;
+       uchar res2[3];
+} iucv_MessagePending;
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  res1[3];
-  UCHAR  ipuser[16];
-  ULONG  res2[2];
-} SEVER_T;
+       ushort ippathid;
+       uchar ipflags1;
+       uchar iptype;
+       ulong ipmsgid;
+       ulong ipaudit;
+       ulong iprmmsg1;
+       ulong iprmmsg2;
+       ulong ipsrccls;
+       ulong ipmsgtag;
+       ulong res;
+       ulong ipbfln2f;
+       uchar ippollfg;
+       uchar res2[3];
+} iucv_MessageComplete;
+
+/************************structures*************************/
+/*---------------------------------------------------------*/
+/*iucv_interrupt_ops_t: List of functions for interrupt    */
+/* handling.                                               */
+/*---------------------------------------------------------*/
 
 typedef struct {
-  UCHAR  ipmask;
-  UCHAR  res1[2];
-  UCHAR  iprcode;
-  ULONG  res2[9];
-} MASK_T;
+       void (*ConnectionPending) (iucv_ConnectionPending * eib,
+                                  ulong pgm_data);
+       void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
+                                   ulong pgm_data);
+       void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
+                                  ulong pgm_data);
+       void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
+                                   ulong pgm_data);
+       void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
+                                  ulong pgm_data);
+       void (*MessagePending) (iucv_MessagePending * eib,
+                               ulong pgm_data);
+       void (*MessageComplete) (iucv_MessageComplete * eib,
+                                ulong pgm_data);
+} iucv_interrupt_ops_t;
+
+/*---------------------------------------------------------*/
+/*iucv_array_t : Defines buffer array                      */
+/*---------------------------------------------------------*/
 
 typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iptype;
-  ULONG  ipmsgid;
-  ULONG  ipaudit;
-  ULONG  iprmmsg1;
-  ULONG  iprmmsg2;
-  ULONG  ipsrccls;
-  ULONG  ipmsgtag;
-  ULONG  ipbfadr2;
-  ULONG  ipbfln2f;
-  UCHAR  ippollfg;
-  UCHAR  res2[3];
-} INTERRUPT_T;
+       void *address;
+       int length;
+} iucv_array_t __attribute__ ((aligned (8)));
+
+/*************************-prototypes-******************************/
+
+iucv_handle_t iucv_register_program (uchar pgmname[16],
+                                    uchar userid[8],
+                                    uchar pgmmask[24],
+                                    iucv_interrupt_ops_t * ops,
+                                    ulong pgm_data);
+
+int iucv_unregister (iucv_handle_t handle);
+
+int iucv_purge (ulong msgid,
+               ushort pathid,
+               ulong srccls,
+               uchar audit[4]);
+
+void iucv_query (ulong * bufsize,
+                ulong * conmax);
+
+int iucv_quiesce (ushort pathid,
+                 uchar user_data[16]);
+
+int iucv_resume (ushort pathid,
+                uchar user_data[16]);
+
+int iucv_reject (ushort pathid,
+                ulong msgid,
+                ulong trgcls);
+
+int iucv_setmask (uchar non_priority_interrupts,
+                 uchar priority_interrupts,
+                 uchar non_priority_completion_interrupts,
+                 uchar priority_completion_interrupts);
+
+int iucv_connect (ushort * pathid,
+                 ushort msglim,
+                 uchar user_data[16],
+                 uchar userid[8],
+                 uchar system_name[8],
+                 uchar priority_requested,
+                 uchar prmdata,
+                 uchar quiesce,
+                 uchar control,
+                 uchar local,
+                 uchar * priority_permitted,
+                 iucv_handle_t handle,
+                 ulong pgm_data);
+
+int iucv_accept (ushort pathid,
+                ushort msglim,
+                uchar user_data[16],
+                uchar priority_requested,
+                uchar prmdata,
+                uchar quiesce,
+                uchar control,
+                uchar * priority_permitted,
+                iucv_handle_t handle,
+                ulong pgm_data);
+
+int iucv_sever (ushort pathid,
+               uchar user_data[16]);
+
+int iucv_receive (ushort pathid,
+                 ulong * msgid,
+                 ulong * trgcls,
+                 void *buffer, ulong buflen,
+                 uchar * reply_required,
+                 uchar * priority_msg,
+                 ulong * adds_curr_buffer,
+                 ulong * adds_curr_length);
+
+int iucv_receive_simple (ushort pathid,
+                        ulong msgid,
+                        ulong trgcls,
+                        void *buffer, ulong buflen);
+
+int iucv_receive_array (ushort pathid,
+                       ulong * msgid,
+                       ulong * trgcls,
+                       iucv_array_t * buffer,
+                       ulong * buflen,
+                       uchar * reply_required,
+                       uchar * priority_msg,
+                       ulong * adds_curr_buffer,
+                       ulong * adds_curr_length);
+
+int iucv_send (ushort pathid,
+              ulong * msgid,
+              ulong trgcls,
+              ulong srccls,
+              ulong msgtag,
+              uchar priority_msg,
+              void *buffer,
+              ulong buflen);
+
+int iucv_send_array (ushort pathid,
+                    ulong * msgid,
+                    ulong trgcls,
+                    ulong srccls,
+                    ulong msgtag,
+                    uchar priority_msg,
+                    iucv_array_t * buffer,
+                    ulong buflen);
+
+int iucv_send_prmmsg (ushort pathid,
+                     ulong * msgid,
+                     ulong trgcls,
+                     ulong srccls,
+                     ulong msgtag,
+                     uchar priority_msg,
+                     uchar prmmsg[8]);
+
+int iucv_send2way (ushort pathid,
+                  ulong * msgid,
+                  ulong trgcls,
+                  ulong srccls,
+                  ulong msgtag,
+                  uchar priority_msg,
+                  void *buffer,
+                  ulong buflen,
+                  void *ansbuf,
+                  ulong anslen);
+
+int iucv_send2way_array (ushort pathid,
+                        ulong * msgid,
+                        ulong trgcls,
+                        ulong srccls,
+                        ulong msgtag,
+                        uchar priority_msg,
+                        iucv_array_t * buffer,
+                        ulong buflen,
+                        iucv_array_t * ansbuf,
+                        ulong anslen);
+
+int iucv_send2way_prmmsg (ushort pathid,
+                         ulong * msgid,
+                         ulong trgcls,
+                         ulong srccls,
+                         ulong msgtag,
+                         uchar priority_msg,
+                         uchar prmmsg[8],
+                         void *ansbuf,
+                         ulong anslen);
+
+int iucv_send2way_prmmsg_array (ushort pathid,
+                               ulong * msgid,
+                               ulong trgcls, ulong srccls,
+                               ulong msgtag,
+                               uchar priority_msg,
+                               uchar prmmsg[8],
+                               iucv_array_t * ansbuf,
+                               ulong anslen);
+int iucv_reply (ushort pathid,
+               ulong msgid,
+               ulong trgcls,
+               uchar priority_msg,
+               void *buf,
+               ulong buflen);
+
+int iucv_reply_array (ushort pathid,
+                     ulong msgid,
+                     ulong trgcls,
+                     uchar priority_msg,
+                     iucv_array_t * buffer,
+                     ulong buflen);
 
+int iucv_reply_prmmsg (ushort pathid,
+                      ulong msgid,
+                      ulong trgcls,
+                      uchar priority_msg,
+                      uchar prmmsg[8]);
 
 #endif
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
new file mode 100644 (file)
index 0000000..efc0c00
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+ *  drivers/s390/net/netiucv.c
+ *    Network driver for VM using iucv
+ *
+ *  S/390 version
+ *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
+ *               Hartmut Penner <hpenner@de.ibm.com>
+ *
+ *
+ *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *                Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *    Re-write:   Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
+ *                Uses iucv.c kernel module for IUCV services. 
+ *
+ * -------------------------------------------------------------------------- 
+ *  An IUCV frame consists of one or more packets preceded by a 16-bit
+ *  header.   The header contains the offset to the next packet header,
+ *  measured from the beginning of the _frame_.  If zero, there are no more
+ *  packets in the frame.  Consider a frame which contains a 10-byte packet
+ *  followed by a 20-byte packet:
+ *        +-----+----------------+-----+----------------------------+-----+
+ *        |h'12'| 10-byte packet |h'34'|  20-byte packet            |h'00'|
+ *        +-----+----------------+-----+----------------------------+-----+
+ * Offset: 0     2                12    14                           34  
+ *
+ *  This means that each header will always have a larger value than the
+ *  previous one (except for the final zero header, of course).
+ *  
+ *  For outbound packets, we send ONE frame per packet.  So, our frame is:
+ *       AL2(packet length+2), packet, AL2(0)
+ *  The maximum packet size is the MTU, so the maximum IUCV frame we send
+ *  is MTU+4 bytes.
+ *
+ *  For inbound frames, we don't care how long the frame is.  We tear apart
+ *  the frame, processing packets up to MTU size in length, until no more
+ *  packets remain in the frame.
+ *
+ * --------------------------------------------------------------------------
+ *  The code uses the 2.3.43 network driver interfaces.  If compiled on an
+ *  an older level of the kernel, the module provides its own macros.
+ *  Doc is in Linux Weekly News (lwn.net) memo from David Miller, 9 Feb 2000.
+ *  There are a few other places with 2.3-specific enhancements.
+ *
+ * --------------------------------------------------------------------------
+*/
+//#define DEBUG 1
+
+/* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */
+/* (See bottom of program.)                                                */
+#define MAX_DEVICES 10         /* Allows "iucv0" to "iucv9"    */
+#define MAX_VM_MTU 32764       /* 32K IUCV buffer, minus 4     */
+#define MAX_TX_Q 50            /* Maximum pending TX           */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+MODULE_AUTHOR
+    ("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)");
+MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s");
+MODULE_PARM_DESC (iucv,
+                 "Specify the userids associated with iucv0-iucv9:\n"
+                 "iucv=userid1,userid2,...,userid10\n");
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/sched.h>       /* task queues                  */
+#include <linux/malloc.h>      /* kmalloc()                    */
+#include <linux/errno.h>       /* error codes                  */
+#include <linux/types.h>       /* size_t                       */
+#include <linux/interrupt.h>   /* mark_bh                      */
+#include <linux/netdevice.h>   /* struct net_device, etc.      */
+#include <linux/if_arp.h>      /* ARPHRD_SLIP                  */
+#include <linux/skbuff.h>      /* skb                          */
+#include <linux/init.h>                /* __setup()                    */
+#include <asm/io.h>            /* virt_to_phys()               */
+#include <asm/string.h>                /* memset, memcpy, etc.         */
+#include "iucv.h"
+#define min(a,b) (a < b) ? a : b
+
+#ifdef DEBUG
+#undef KERN_INFO
+#undef KERN_DEBUG
+#define KERN_INFO    KERN_EMERG
+#define KERN_DEBUG   KERN_EMERG
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+typedef struct net_device net_device;
+#else
+typedef struct device net_device;
+#endif
+
+static __inline__ int
+netif_is_busy (net_device * dev)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45))
+       return (dev->tbusy);
+#else
+       return (test_bit (LINK_STATE_XOFF, &dev->flags));
+#endif
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45))
+       /* Provide our own 2.3.45 interfaces */
+#define netif_enter_interrupt(dev) dev->interrupt=1
+#define netif_exit_interrupt(dev) dev->interrupt=0
+#define netif_start(dev) dev->start=1
+#define netif_stop(dev) dev->start=0
+
+static __inline__ void
+netif_stop_queue (net_device * dev)
+{
+       dev->tbusy = 1;
+}
+
+static __inline__ void
+netif_start_queue (net_device * dev)
+{
+       dev->tbusy = 0;
+}
+
+static __inline__ void
+netif_wake_queue (net_device * dev)
+{
+       dev->tbusy = 0;
+       mark_bh (NET_BH);
+}
+
+#else
+       /* As of 2.3.45, we don't do these things anymore */
+#define netif_enter_interrupt(dev)
+#define netif_exit_interrupt(dev)
+#define netif_start(dev)
+#define netif_stop(dev)
+#endif
+
+static int iucv_start (net_device *);
+static int iucv_stop (net_device *);
+static int iucv_change_mtu (net_device *, int);
+static int iucv_init (net_device *);
+static void iucv_rx (net_device *, uchar *, int);
+static int iucv_tx (struct sk_buff *, net_device *);
+
+static void connection_severed (iucv_ConnectionSevered *, ulong);
+static void connection_pending (iucv_ConnectionPending *, ulong);
+static void connection_complete (iucv_ConnectionComplete *, ulong);
+static void message_pending (iucv_MessagePending *, ulong);
+static void send_complete (iucv_MessageComplete *, ulong);
+
+void register_iucv_dev (int, char *);
+
+static iucv_interrupt_ops_t netiucv_ops = {
+       &connection_pending,
+       &connection_complete,
+       &connection_severed,
+       NULL,                   /* Quiesced             */
+       NULL,                   /* Resumed              */
+       &message_pending,       /* Message pending      */
+       &send_complete          /* Message complete     */
+};
+
+static char iucv_userid[MAX_DEVICES][8];
+net_device iucv_netdev[MAX_DEVICES];
+static char iucv_names[MAX_DEVICES][8];
+static char eodata[2] = { '\0', '\0' };
+
+/* This structure is private to each device. It contains the    */
+/* information necessary to do IUCV operations.                 */
+struct iucv_priv {
+       struct net_device_stats stats;
+       net_device *dev;
+       iucv_handle_t handle;
+       uchar userid[9];        /* Printable userid */
+       uchar userid2[8];       /* Used for IUCV operations */
+
+       /* Note: atomic_compare_and_swap() return value is backwards */
+       /*       from what you might think: FALSE=0=OK, TRUE=1=FAIL  */
+       atomic_t state;
+#define FREE 0
+#define CONNECTING 1
+#define CONNECTED 2
+       u16 pathid;
+};
+
+struct iucvtag {
+       iucv_array_t iucvvec[3];
+       u16 framelen;
+       struct sk_buff *skb;
+};
+
+uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+       0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
+};
+
+/* This mask means the 16-byte IUCV "magic" and the origin userid must */
+/* match exactly as specified in order to give connection_pending()    */
+/* control.                                                           */
+const char mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+#ifdef DEBUG
+/*--------------------------*/
+/* Dump buffer formatted    */
+/*--------------------------*/
+static void
+dumpit (char *buf, int len)
+{
+       int i;
+       printk (KERN_DEBUG);
+       for (i = 0; i < len; i++) {
+               if (!(i % 32) && i != 0)
+                       printk ("\n");
+               else if (!(i % 4) && i != 0)
+                       printk (" ");
+               printk ("%02X", buf[i]);
+       }
+       if (len % 32)
+               printk ("\n");
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* Open a connection to another Linux or VM TCP/IP stack.          */
+/* Called by kernel.                                              */
+/*                                                                 */
+/* 1. Register a handler. (Up to now, any attempt by another stack */
+/*    has been rejected by the IUCV handler.)  We give the handler */
+/*    the net_device* so that we can locate the dev associated     */
+/*    with the partner userid if he tries to connect to us or      */
+/*    if the connection is broken.                                 */
+/*                                                                 */
+/* 2. Connect to remote stack.  If we get a connection pending     */
+/*    interrupt while we're in the middle of connecting, don't     */
+/*    worry.  VM will sever its and use ours, because the DEVICE   */
+/*    is defined to be:                                            */
+/*           DEVICE devname IUCV 0 0 linuxvm A                     */
+/*        or DEVICE devname IUCV 0 0 linuxvm B                     */
+/*    In EBCDIC, "0" (0xF0) is greater than "A" (0xC1) or "B", so  */
+/*    win all races.  We will sever any connects that occur while  */
+/*    we are connecting.  The "0 0" is where we get iucvMagic from.*/
+/*                                                                */
+/*    FIXME: If two Linux machines get into this race condition,   */
+/*           both will sever.  Manual intervention required.       */
+/*           Need a better IUCV "hello"-like function that permits */
+/*           some negotiation.  But can't do that until VM TCP/IP  */
+/*           would support it.                                     */
+/*                                                                 */
+/* 3. Return 0 to indicate device ok.  Anything else is an error.  */
+/*-----------------------------------------------------------------*/
+static int
+iucv_start (net_device * dev)
+{
+       int rc, i;
+       uchar pri;
+       uchar unused = '\0';
+       struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+
+       pr_debug ("iucv_start(%s)\n", dev->name);
+
+       if (p == NULL) {
+               /* Allocate priv data */
+               p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv),
+                                                 GFP_KERNEL);
+               if (p == NULL) {
+                       printk (KERN_CRIT "%s: no memory for dev->priv.\n",
+                               dev->name);
+                       return -ENOMEM;
+               }
+               memset (p, 0, sizeof (struct iucv_priv));
+               dev->priv = p;
+               p->dev = dev;
+
+               memcpy (p->userid, iucv_userid[dev - iucv_netdev], 8);  /* Save userid */
+               memcpy (p->userid2, p->userid, 8);      /* Again, with feeling.  */
+
+               for (i = 0; i < 8; i++) {       /* Change userid to printable form */
+                       if (p->userid[i] == ' ') {
+                               p->userid[i] = '\0';
+                               break;
+                       }
+               }
+               p->userid[8] = '\0';
+               atomic_set (&p->state, FREE);
+               p->handle =
+                   iucv_register_program (iucvMagic, p->userid2, (char *) mask,
+                                          &netiucv_ops, (ulong) dev);
+               if (p->handle <= 0) {
+                       printk (KERN_ERR
+                               "%s: iucv_register_program error, rc=%i\n",
+                               dev->name, (int) p->handle);
+                       dev->priv = NULL;
+                       kfree (p);
+                       return -ENODEV;
+               }
+               pr_debug ("state@ = %p\n", &p->state);
+               MOD_INC_USE_COUNT;
+       }
+
+       if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
+               pr_debug ("Other side connecting during start\n");
+               return 0;
+       }
+
+       rc =
+           iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2,
+                         iucv_host, unused, unused, unused, unused, unused,
+                         &pri, p->handle, (ulong) p);
+
+       /* Some errors are not fatal.  In these cases we will report "OK". */
+       switch (rc) {
+       case 0:         /* Wait for connection to complete */
+               pr_debug ("...waiting for connection to complete...");
+               return 0;
+       case 11:                /* Wait for parter to connect */
+               printk (KERN_NOTICE "Device %s: "
+                       "User %s is not available now.\n",
+                       dev->name, p->userid);
+               atomic_set (&p->state, FREE);
+               return 0;
+       case 12:                /* Wait for partner to connect */
+               printk (KERN_NOTICE "Device %s: "
+                       "User %s is not ready to talk now.\n",
+                       dev->name, p->userid);
+               atomic_set (&p->state, FREE);
+               return 0;
+       case 13:                /* Fatal */
+               printk (KERN_ERR "Device %s: "
+                       "You have too many IUCV connections."
+                       "Check MAXCONN in CP directory.\n", dev->name);
+               break;
+       case 14:                /* Fatal */
+               printk (KERN_ERR "Device %s: "
+                       "User %s has too many IUCV connections."
+                       "Check MAXCONN in CP directory.\n",
+                       dev->name, p->userid);
+               break;
+       case 15:                /* Fatal */
+               printk (KERN_ERR "Device %s: "
+                       "No IUCV authorization found in CP directory.\n",
+                       dev->name);
+               break;
+       default:                /* Really fatal! Should not occur!! */
+               printk (KERN_ERR "%s: "
+                       "return code %i from iucv_connect()\n", dev->name, rc);
+       }
+
+       rc = iucv_unregister (p->handle);
+       dev->priv = NULL;
+       kfree (p);
+       MOD_DEC_USE_COUNT;
+       return -ENODEV;
+}                              /* end iucv_start() */
+
+/*********************************************************************/
+/* Our connection TO another stack has been accepted.                */
+/*********************************************************************/
+static void
+connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
+{
+       struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+       pr_debug ("...%s connection complete... txq=%u\n",
+                 p->dev->name, cci->ipmsglim);
+       atomic_set (&p->state, CONNECTED);
+       p->pathid = cci->ippathid;
+       p->dev->tx_queue_len = cci->ipmsglim;
+       netif_start (p->dev);
+       netif_start_queue (p->dev);
+       printk (KERN_INFO "%s: Connection to user %s is up\n",
+               p->dev->name, p->userid);
+}                              /* end connection_complete() */
+
+/*********************************************************************/
+/* A connection FROM another stack is pending.  If we are in the     */
+/* middle of connecting, sever the new connection.                   */
+/*                                                                  */
+/* We only get here if we've done an iucv_register(), so we know     */
+/* the remote user is the correct user.                              */
+/*********************************************************************/
+static void
+connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
+{
+       /* Only get this far if handler is set up, so we know userid is ok. */
+       /* and the device is started.                                       */
+       /* pgm_data is different for this one.  We get dev*, not priv*.     */
+       net_device *dev = (net_device *) pgm_data;
+       struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+       int rc;
+       uchar udata[16];
+       uchar no = '\0';
+       uchar na;
+
+       /* If we're not waiting on a connect, reject the connection */
+       if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
+               iucv_sever (cpi->ippathid, udata);
+               return;
+       }
+
+       rc = iucv_accept (cpi->ippathid,        /* Path id              */
+                         MAX_TX_Q,     /* msglimit                     */
+                         udata,        /* user_Data                    */
+                         no,   /* will we send priority msgs?  */
+                         no,   /* do we accept prmdata?        */
+                         no,   /* quiece immediately?          */
+                         no,   /* control path?                */
+                         &na,  /* other side accept prmdata?   */
+                         p->handle,    /* registration handle  */
+                         (ulong) p);   /* private data         */
+       if (rc != 0) {
+               atomic_set (&p->state, FREE);
+               printk (KERN_ERR "%s: iucv accept failed rc=%i\n",
+                       p->dev->name, rc);
+       } else {
+               p->pathid = cpi->ippathid;
+               p->dev->tx_queue_len = cpi->ipmsglim;
+               netif_start (p->dev);
+               netif_start_queue (p->dev);
+               atomic_set (&p->state, CONNECTED);
+               printk (KERN_INFO "Device %s: Connection to user %s is up\n",
+                       p->dev->name, p->userid);
+       }
+}                              /* end connection_pending() */
+
+/*********************************************************************/
+/* Our connection to another stack has been severed.                 */
+/*********************************************************************/
+static void
+connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data)
+{
+       struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+
+       printk (KERN_INFO "%s: Connection to user %s is down\n",
+               p->dev->name, p->userid);
+
+       if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0)
+               return;         /* In case reconnect in progress already */
+
+       netif_stop_queue (p->dev);
+       netif_stop (p->dev);
+}                              /* end connection_severed() */
+
+/*-----------------------------------------------------*/
+/* STOP device.                   Called by kernel.    */
+/*-----------------------------------------------------*/
+static int
+iucv_stop (net_device * dev)
+{
+       int rc = 0;
+       struct iucv_priv *p;
+       pr_debug ("%s: iucv_stop\n", dev->name);
+
+       netif_stop_queue (dev);
+       netif_stop (dev);
+
+       p = (struct iucv_priv *) (dev->priv);
+       if (p == NULL)
+               return 0;
+
+       rc = iucv_unregister (p->handle);       /* Will sever connections */
+       dev->priv = NULL;
+       kfree (p);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}                              /* end  iucv_stop() */
+
+/*---------------------------------------------------------------------*/
+/* Inbound packets from other host are ready for receipt.  Receive     */
+/* them (they arrive as a single transmission), break them up into     */
+/* separate packets, and send them to the "generic" packet processor.  */
+/*---------------------------------------------------------------------*/
+static void
+message_pending (iucv_MessagePending * mpi, ulong pgm_data)
+{
+       struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+       int rc;
+       u32 buffer_length;
+       u16 packet_offset, prev_offset = 0;
+       void *buffer;
+
+       buffer_length = mpi->ln1msg2.ipbfln1f;
+       pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
+                 buffer_length);
+
+       buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA);
+       if (buffer == NULL) {
+               p->stats.rx_dropped++;
+               return;
+       }
+
+       rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
+                                 buffer, buffer_length);
+
+       if (rc != 0 || buffer_length < 5) {
+               printk (KERN_INFO
+                       "%s: iucv_receive error. rc=%X, length=%u\n",
+                       p->dev->name, rc, buffer_length);
+               p->stats.rx_errors++;
+               kfree (buffer);
+               return;
+       }
+
+       packet_offset = *((u16 *) buffer);
+
+       while (packet_offset != 0) {
+               if (packet_offset <= prev_offset
+                   || packet_offset > buffer_length - 2) {
+                       printk (KERN_INFO "%s: bad inbound packet offset %u, "
+                               "prev %u, total %u\n", p->dev->name,
+                               packet_offset, prev_offset, buffer_length);
+                       p->stats.rx_errors++;
+                       break;
+               } else {
+                       /* Kick the packet upstairs */
+                       iucv_rx (p->dev,
+                                buffer + prev_offset + 2,
+                                packet_offset - prev_offset - 2);
+                       prev_offset = packet_offset;
+                       packet_offset = *((u16 *) (buffer + packet_offset));
+               }
+       }
+
+       kfree (buffer);
+       return;
+}                              /* end message_pending() */
+
+/*-------------------------------------------------------------*/
+/* Add meta-data to packet and send upstairs.                  */
+/*-------------------------------------------------------------*/
+static void
+iucv_rx (net_device * dev, uchar * buf, int len)
+{
+       struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+       struct sk_buff *skb;
+
+       pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len);
+#ifdef DEBUG
+       dumpit (buf, 20);
+#endif
+
+       if (len > p->dev->mtu) {
+               printk (KERN_INFO
+                       "%s: inbound packet length %u exceeds MTU %i\n",
+                       p->dev->name, len, p->dev->mtu);
+               p->stats.rx_errors++;
+               return;
+       }
+
+       skb = dev_alloc_skb (len);
+       if (!skb) {
+               p->stats.rx_dropped++;
+               return;
+       }
+
+       /* If not enough room, skb_put will panic */
+       memcpy (skb_put (skb, len), buf, len);
+
+       /* Write metadata, and then pass to the receive level.  Since we */
+       /* are not an Ethernet device, we have special fields to set.    */
+       /* This is all boilerplace, not to be messed with.               */
+       skb->dev = p->dev;      /* Set device       */
+       skb->mac.raw = skb->data;       /* Point to packet  */
+       skb->pkt_type = PACKET_HOST;    /* ..for this host. */
+       skb->protocol = htons (ETH_P_IP);       /* IP packet        */
+       skb->ip_summed = CHECKSUM_UNNECESSARY;  /* No checksum      */
+       p->stats.rx_packets++;
+       p->stats.rx_bytes += len;
+       netif_rx (skb);
+
+       return;
+}                              /* end  iucv_rx() */
+
+/*-------------------------------------------------------------*/
+/* TRANSMIT a packet.                      Called by kernel.  */
+/* This function deals with hw details of packet transmission. */
+/*-------------------------------------------------------------*/
+static int
+iucv_tx (struct sk_buff *skb, net_device * dev)
+{
+       int rc, pktlen;
+       struct iucvtag *tag;
+       struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+
+       if (skb == NULL)        /* Nothing to do */
+               return 0;
+
+       if (netif_is_busy (dev)) {
+               p->stats.tx_dropped++;
+               dev_kfree_skb (skb);
+               printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n",
+                       dev->name);
+               return -EBUSY;
+       }
+
+       netif_stop_queue (dev); /* transmission is busy */
+
+       dev->trans_start = jiffies;     /* save the timestamp */
+
+       /* Tag contains data that must survive exit from this */
+       /* routine.  MessageComplete exit will free the tag   */
+       /* and any structures it points to.                   */
+       tag =
+           (struct iucvtag *) kmalloc (sizeof (struct iucvtag),
+                                       GFP_DMA | GFP_KERNEL);
+       if (!tag) {
+               p->stats.tx_dropped++;
+               dev_kfree_skb (skb);
+               return -ENOMEM;
+       }
+
+       pktlen = skb->len;
+       tag->framelen = (u16) pktlen + 2;
+       tag->skb = skb;
+       tag->iucvvec[0].address = &tag->framelen;
+       tag->iucvvec[0].length = 2;
+       tag->iucvvec[1].address = (void *) virt_to_phys (skb->data);
+       tag->iucvvec[1].length = pktlen;
+       tag->iucvvec[2].address = (void *) virt_to_phys (eodata);
+       tag->iucvvec[2].length = 2;
+       pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag);
+
+       /* Ok, now the packet is ready for transmission: send it. */
+       rc =
+           iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0,
+                            tag->iucvvec, pktlen + 4);
+       if (rc == 0)
+               p->stats.tx_packets++;
+       else {
+               if (rc == 3)    /* Exceeded MSGLIMIT */
+                       p->stats.tx_dropped++;
+               else {
+                       p->stats.tx_errors++;
+                       printk (KERN_INFO "%s: iucv send failed, rc=%i\n",
+                               p->dev->name, rc);
+               }
+               dev_kfree_skb (skb);
+               kfree (tag);
+       }
+
+       netif_wake_queue (p->dev);
+       return rc;              /* zero == done; nonzero == fail */
+}                              /* end iucv_tx() */
+
+/*-----------------------------------------------------------*/
+/* SEND COMPLETE                    Called by IUCV handler.  */
+/* Free SKB associated with this transmission and free       */
+/* the IUCV buffer list and SKB pointer.                     */
+/*-----------------------------------------------------------*/
+static void
+send_complete (iucv_MessageComplete * mci, ulong pgm_data)
+{
+       struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag;
+       pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb);
+       dev_kfree_skb (tag->skb);
+       kfree (tag);
+}                              /* end send_complete() */
+
+/*-----------------------------------------------------------*/
+/* STATISTICS reporting.                  Called by kernel.  */
+/*-----------------------------------------------------------*/
+static struct net_device_stats *
+iucv_stats (net_device * dev)
+{
+       struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+       return &p->stats;
+}                              /* end iucv_stats() */
+
+/*-----------------------------------------------------------*/
+/* MTU change    .                        Called by kernel.  */
+/* IUCV can handle mtu sizes from 576 (the IP architectural  */
+/* minimum) up to maximum supported by VM.  I don't think IP */
+/* pays attention to new mtu until device is restarted.      */
+/*-----------------------------------------------------------*/
+static int
+iucv_change_mtu (net_device * dev, int new_mtu)
+{
+       if ((new_mtu < 576) || (new_mtu > MAX_VM_MTU))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}                              /* end iucv_change_mtu() */
+
+/*-----------------------------------------------------------*/
+/* INIT device.                           Called by kernel.  */
+/* Called by register_netdev() in kernel.                    */
+/*-----------------------------------------------------------*/
+static int
+iucv_init (net_device * dev)
+{
+       dev->open = iucv_start;
+       dev->stop = iucv_stop;
+       dev->hard_start_xmit = iucv_tx;
+       dev->get_stats = iucv_stats;
+       dev->change_mtu = iucv_change_mtu;
+       dev->hard_header_len = 0;
+       dev->addr_len = 0;
+       dev->type = ARPHRD_SLIP;
+       dev->tx_queue_len = MAX_TX_Q;   /* Default - updated based on IUCV */
+       /* keep the default flags, just add NOARP and POINTOPOINT */
+       dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+       dev->mtu = 9216;
+
+       dev_init_buffers (dev);
+       pr_debug ("%s: iucv_init  dev@=%p\n", dev->name, dev);
+       return 0;
+}
+
+#ifndef MODULE
+/*-----------------------------------------------------------------*/
+/* Process iucv=userid1,...,useridn kernel parameter.              */
+/*                                                                 */
+/* Each user id provided will be associated with device 'iucvnn'.  */
+/* iucv_init will be called to initialize each device.             */
+/*-----------------------------------------------------------------*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#define init_return(a) return a
+static int __init
+iucv_setup (char *iucv)
+#else
+#define init_return(a) return
+__initfunc (void iucv_setup (char *iucv, int *ints))
+#endif
+{
+       int i, devnumber;
+       char *s;
+       char temp_userid[9];
+
+       i = devnumber = 0;
+       memset (temp_userid, ' ', 8);
+       temp_userid[8] = '\0';
+
+       if (!iucv)
+               init_return (0);
+
+       for (s = iucv; *s != '\0'; s++) {
+               if (*s == ' ')  /* Compress out blanks */
+                       continue;
+
+               if (devnumber >= MAX_DEVICES) {
+                       printk (KERN_ERR "More than %i IUCV hosts specified\n",
+                               MAX_DEVICES);
+                       init_return (-ENODEV);
+               }
+
+               if (*s != ',') {
+                       temp_userid[i++] = *s;
+
+                       if (i == 8 || *(s + 1) == ',' || *(s + 1) == '\0') {
+                               register_iucv_dev (devnumber, temp_userid);
+                               devnumber++;
+                               i = 0;
+                               memset (temp_userid, ' ', 8);
+                               if (*(s + 1) != '\0')
+                                       *(s + 1) = ' ';
+                       }
+               }
+       }                       /* while */
+
+       init_return (1);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+__setup ("iucv=", iucv_setup);
+#endif
+#else                          /* BUILT AS MODULE */
+/*-------------------------------------------------------------------*/
+/* Process iucv=userid1,...,useridn module paramter.                 */
+/*                                                                   */
+/* insmod passes the module an array of string pointers, each of     */
+/* which points to a userid.  The commas are stripped out by insmod. */
+/* MODULE_PARM defines the name of the array.  (See start of module.)*/
+/*                                                                   */
+/* Each user id provided will be associated with device 'iucvnn'.    */
+/* iucv_init will be called to initialize each device.               */
+/*-------------------------------------------------------------------*/
+char *iucv[MAX_DEVICES] = { NULL };
+int
+init_module (void)
+{
+       int i;
+       for (i = 0; i < MAX_DEVICES; i++) {
+               if (iucv[i] == NULL)
+                       break;
+               register_iucv_dev (i, iucv[i]);
+       }
+       return 0;
+}
+
+void
+cleanup_module (void)
+{
+       int i;
+       for (i = 0; i < MAX_DEVICES; i++) {
+               if (iucv[i])
+                       unregister_netdev (&iucv_netdev[i]);
+       }
+       return;
+}
+#endif                         /* MODULE */
+
+void
+register_iucv_dev (int devnumber, char *userid)
+{
+       int rc;
+       net_device *dev;
+
+       memset (iucv_userid[devnumber], ' ', 8);
+       memcpy (iucv_userid[devnumber], userid, min (strlen (userid), 8));
+       dev = &iucv_netdev[devnumber];
+       sprintf (dev->name, "iucv%i", devnumber);
+
+       pr_debug ("netiucv: registering %s\n", dev->name);
+
+       if ((rc = register_netdev (dev))) {
+               printk (KERN_ERR
+                       "netiucv: register_netdev(%s) error %i\n",
+                       dev->name, rc);
+       }
+       return;
+}
+
+/* These structures are static because setup() can be called very */
+/* early in kernel init if this module is built into the kernel.  */
+/* Certainly no kmalloc() is available, probably no C runtime.    */
+/* If support changed to be module only, this can all be done     */
+/* dynamically.                                                   */
+static char iucv_names[MAX_DEVICES][8];        /* Allows "iucvXXX" plus null */
+net_device iucv_netdev[MAX_DEVICES] = {
+       {
+        &iucv_names[0][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[1][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[2][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[3][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[4][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[5][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[6][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[7][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[8][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        },
+       {
+        &iucv_names[9][0],     /* Name filled in at load time  */
+        0, 0, 0, 0,            /* shmem addresses              */
+        0x0000,                /* I/O port                     */
+        0,                     /* irq line                     */
+        0, 0, 0,               /* flags                        */
+        NULL,                  /* next device in list          */
+        iucv_init,             /* probe function, rest to null */
+        }
+};
index 63166d18df07aff52ba33e92b108fe6f953ca733..d8d927bc1d754a384c0c1a8c15da6be2caab2121 100644 (file)
@@ -477,8 +477,9 @@ extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED
 #define mk_pte_phys(physpage, pgprot) \
 ({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })
 
+#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot); return pte; }
+{ pte_val(pte) = __pte_set_ro( (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot) ); return pte; }
 
 #define pte_page(pte) \
 ((unsigned long) __va(pte_val(pte) & PAGE_MASK))
index 7436895795852b242e59a9ad5f61799b2625d588..961e17ecf0749d6a806b5e4e08df620b08475e3e 100644 (file)
@@ -86,9 +86,9 @@ typedef struct _mache {
 #define MCHCHK_STATUS_IN_PROGRESS   0x00000002
 #define MCHCHK_STATUS_WAITING       0x00000004
 
-void        s390_init_machine_check( void );
-void __init s390_do_machine_check  ( void );
-void        s390_do_crw_pending    ( crwe_t *pcrwe );
+void s390_init_machine_check( void );
+void s390_do_machine_check  ( void );
+void s390_do_crw_pending    ( crwe_t *pcrwe );
 
 extern __inline__ int stcrw( __u32 *pcrw )
 {
index 5960c243c667ca0f77e0c8d856ca3bcc549008e5..26c5ceab231dc73d3b5e5a306e50e8ad2dafc59e 100644 (file)
@@ -192,7 +192,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
 ({                                                              \
         long __pu_err = -EFAULT;                                \
         __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
-        __typeof__(x) __x = (x);                                \
+        __typeof__(*(ptr)) __x = (x);                           \
         if (__access_ok((long)__pu_addr,sizeof(*(ptr)))) {      \
                 __pu_err = 0;                                   \
                 __put_user((__x), (__pu_addr));                 \
@@ -304,7 +304,7 @@ extern int __put_user_bad(void);
 ({                                                              \
         long __gu_err = -EFAULT;                                \
         __typeof__(*(ptr)) *__gu_addr = (ptr);                  \
-        __typeof__(x) __x;                                      \
+        __typeof__(*(ptr)) __x;                                 \
         if (__access_ok((long)__gu_addr,sizeof(*(ptr)))) {      \
                 __gu_err = 0;                                   \
                 __get_user((__x), (__gu_addr));                 \
index f5a45f6e92b4a9a7efcd36abd2699af1e9c804a5..9921c2f06c5032680648ff9c56002272e60107d1 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.164.2.17 2000/09/16 16:32:57 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.164.2.18 2000/12/08 20:29:33 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -187,7 +187,7 @@ static __inline__ void tcp_rtt_estimator(struct tcp_opt *tp, __u32 mrtt)
 
 static __inline__ void tcp_set_rto(struct tcp_opt *tp)
 {
-       tp->rto = (tp->srtt >> 3) + tp->mdev;
+       tp->rto = (tp->srtt >> 3) + max(HZ/5, tp->mdev);
        tp->rto += (tp->rto >> 2) + (tp->rto >> (tp->snd_cwnd-1));
 }
  
index 5688d3db20b1e0debdfabee366646d9d9f9b11cb..72233a6c3c6ab06caf9801dad504b96fbf9033a4 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.40.2.1 1999/06/20 20:14:55 davem Exp $
+ *     $Id: udp.c,v 1.40.2.2 2000/12/08 20:29:33 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -561,8 +561,8 @@ static void udpv6_mcast_deliver(struct udphdr *uh,
 
        buff = NULL;
        sk2 = sk;
-       while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, saddr,
-                                                 uh->source, daddr, dif))) {
+       while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr,
+                                                 uh->source, saddr, dif))) {
                if (!buff) {
                        buff = skb_clone(skb, GFP_ATOMIC);
                        if (!buff)