## Automatically generated incremental diff
## From:   linux-2.2.18-pre25
## To:     linux-2.2.18-pre27
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.2.18-pre25/CREDITS linux/CREDITS
--- linux-2.2.18-pre25/CREDITS	Tue Dec  4 00:17:04 2001
+++ linux/CREDITS	Tue Dec  4 00:17:22 2001
@@ -1467,11 +1467,19 @@
 
 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
diff -urN linux-2.2.18-pre25/Makefile linux/Makefile
--- linux-2.2.18-pre25/Makefile	Tue Dec  4 00:17:04 2001
+++ linux/Makefile	Tue Dec  4 00:17:22 2001
@@ -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/)
 
diff -urN linux-2.2.18-pre25/drivers/net/sbni.c linux/drivers/net/sbni.c
--- linux-2.2.18-pre25/drivers/net/sbni.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/net/sbni.c	Tue Dec  4 00:17:24 2001
@@ -456,6 +456,7 @@
 	if(dev->priv == NULL)
 	{
 		DP( printk("%s: cannot allocate memory\n", dev->name); )
+		free_irq(dev->irq, dev);
 		return -ENOMEM;
 	}
    
diff -urN linux-2.2.18-pre25/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.2.18-pre25/drivers/s390/block/dasd.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/block/dasd.c	Tue Dec  4 00:17:24 2001
@@ -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 @@
                         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 @@
 		}
 	case BLKFLSBUF:{
 			rc = fsync_dev (inp->i_rdev);
+			invalidate_buffers(inp->i_rdev);
 			break;
 		}
 	case BLKRAGET:{
@@ -1944,6 +1949,10 @@
 #ifdef MODULE
 	MOD_DEC_USE_COUNT;
 #endif				/* MODULE */
+	}
+	if ( device->open_count == 0 ) {
+		rc = fsync_dev (inp->i_rdev);
+		invalidate_buffers(inp->i_rdev);
 	}
 	return rc;
 }
diff -urN linux-2.2.18-pre25/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- linux-2.2.18-pre25/drivers/s390/block/dasd_eckd.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/block/dasd_eckd.c	Tue Dec  4 00:17:25 2001
@@ -627,6 +627,7 @@
                                  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);
diff -urN linux-2.2.18-pre25/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- linux-2.2.18-pre25/drivers/s390/char/con3215.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/char/con3215.c	Tue Dec  4 00:17:25 2001
@@ -116,7 +116,7 @@
 {
         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 @@
                 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);
 	}
diff -urN linux-2.2.18-pre25/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile
--- linux-2.2.18-pre25/drivers/s390/net/Makefile	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/net/Makefile	Tue Dec  4 00:17:25 2001
@@ -2,7 +2,7 @@
 
 CFLAFS += 
 O_TARGET := s390-net.o
-O_OBJS    :=         
+O_OBJS   := iucv.o
 M_OBJS   :=
 
 ifeq ($(CONFIG_CTC),y)
@@ -14,7 +14,11 @@
 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
diff -urN linux-2.2.18-pre25/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- linux-2.2.18-pre25/drivers/s390/net/ctc.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/net/ctc.c	Tue Dec  4 00:17:25 2001
@@ -276,6 +276,8 @@
 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{ 
diff -urN linux-2.2.18-pre25/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- linux-2.2.18-pre25/drivers/s390/net/iucv.c	Tue Dec  4 00:17:06 2001
+++ linux/drivers/s390/net/iucv.c	Tue Dec  4 00:17:25 2001
@@ -1,1184 +1,2041 @@
 /*
  *  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> 
- * 
- *    
- *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *                Martin Schwidefsky (schwidefsky@de.ibm.com)
- *                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 <asm/spinlock.h>
+#include <asm/ebcdic.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)
-{
-#if LINUX_VERSION_CODE<0x02032D
-	return(dev->tbusy);
-#else
-	return(test_bit(LINK_STATE_XOFF,&dev->flags));
-#endif
-}
-
-
-
-#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)
-{
-	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
-#define netif_enter_interrupt(dev)
-#define netif_exit_interrupt(dev)
-#define netif_start(dev)
-#define netif_stop(dev)
-#endif
-
-
-
-/*
- * Following the iucv primitives 
- */
-
-
-extern inline void b2f0(int code,void* parm)
-{
-  asm volatile ("LR    1,%1\n\tLR    0,%0\n\t.long 0xb2f01000" ::
-                "d" (code) ,"a" (parm) :"0", "1");
-}
-
-int iucv_enable(void *parms)
-{
-  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;
-}
-
-
-int iucv_declare_buffer(void *parms, DCLBFR_T *buffer)
-{
-  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;
-}
-
-
-int iucv_retrieve_buffer(void *parms)
-{
-  DCLBFR_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  parm->iprcode = 0x0;
-  b2f0(RETRIEVE_BUFFER, parm);
-  return parm->iprcode;
-}
-
-
-int iucv_connect(void *parms,
-                 const char *userid,
-                 const char *host,
-                 const char *ipusr,
-                 unsigned short * used_pathid)
-{
-  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;
-}
-
-
-
-int iucv_accept(void *parms,int pathid)
-{
-#ifdef DEBUG
-  int i=0;
-#endif
-  ACCEPT_T *parm = parms;
-  memset(parms,0,sizeof(parm));
-  parm->ippathid = pathid;
-  parm->ipflags1 = 0x80;
-  parm->ipmsglim = 0x0a;
+#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)
+{
+	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);
+}
+
+/**************************************************************/
+/* Name: iucv_retrieve_buffer                                 */
+/* Purpose: terminates all use of iucv                        */
+/* Input: void                                                */
+/* Output: Return code from CP                                */
+/**************************************************************/
+int
+iucv_retrieve_buffer (void)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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("iucv: iucv_accept input.\n");
-  for (i=0;i<40; i++)
-  {
-    printk("%02x ",((char *)parms)[i]);
-  }
-  printk("\n");
+		printk (KERN_DEBUG "address of table H_T is %p \n",
+			main_table[index1]);
 #endif
-  b2f0(ACCEPT, parm);
-  return parm->iprcode;
-}
-
-
-
-int iucv_receive(void *parms,void *bufferarray,int len)
-{
-#ifdef DEBUG
-  int i=0;
+	}
+	/*
+	 * 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
-  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;
+		kfree (from);	/* free old table */
+	}
+	spin_unlock (&lock);
 #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 "exiting add_pathid\n");
 #endif
-  return parm->iprcode;
-}
-
+	return (0);
+}				/* end of add_pathid function */
 
-int iucv_send(void *parms,int pathid,void *bufferarray,int len,
-              void *recv_buf, int recv_len)
-{
+/***********************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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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;
+}
+
+/**************************************************************/
+/* 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])
+{
+	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;
+}
+
+/**************************************************************/
+/* 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])
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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])
+{
+	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
-  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 "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;
+}
+
+/**************************************************************/
+/* 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
+	printk (KERN_DEBUG "entering iucv_receive\n");
+#endif
+	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_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_receive\n");
 #endif
-
-  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");
-#endif
-
-  return parm->iprcode;
-}
-
-
-
-int iucv_sever(void *parms)
-{
-  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;
+	return b2f0_result;
 }
 
-
-#ifdef DEBUG
-/*--------------------------*/
-/* Dump buffer formatted    */
-/*--------------------------*/
-static void dumpit(char* buf, int len)
-{
-  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");
-}
-#endif
-
-
-
-/*--------------------------*/
-/* Get device from pathid   */
-/*--------------------------*/
-net_device * get_device_from_pathid(int pathid)
-{
-   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;
-}
-
-
-
-/*--------------------------*/
-/* Get device from userid   */
-/*--------------------------*/
-net_device * get_device_from_userid(char * userid)
-{
-   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;
+/**************************************************************/
+/* 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;
 }
 
-
-/*--------------------------*/
-/* Open iucv Device Driver */
-/*--------------------------*/
-int iucv_open(net_device *dev)
-{
-    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};
-
-#ifdef DEBUG
-    printk(  "iucv: iucv_open, device: %s\n",dev->name);
-#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;
-
+/**************************************************************/
+/* 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
+	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(  "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_receive\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)
-{
-
-  struct sk_buff *skb;
-  struct iucv_priv *privptr = (struct iucv_priv *)dev->priv;
-
-#ifdef DEBUG
-  printk(  "iucv: iucv_rx len: %X, device %s\n",len,dev->name);
-  printk(  "iucv rx: received orig:\n");
-  dumpit(buf,len);
-#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);
-#ifdef DEBUG
-  printk(  "iucv rx: data before netif_rx()\n");
-  dumpit(buf,len);
-#endif
-
-  /* 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)
-{
-  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);
-#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;
+/**************************************************************/
+/* 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
+	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 (KERN_DEBUG "exiting iucv_send\n");
+#endif
+	return b2f0_result;
+}
+
+/**************************************************************/
+/* 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
+	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;
+}
+
+/**************************************************************/
+/* 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])
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	iparml_db parm;
+	ulong b2f0_result;
+#ifdef DEBUG
+	printk (KERN_DEBUG "entering iucv_reply\n");
+#endif
+	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 (KERN_DEBUG "exiting iucv_reply\n");
+#endif
+	return b2f0_result;
+}
+
+/**************************************************************/
+/* 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)
+{
+	iparml_db parm;
+	ulong b2f0_result;
+#ifdef DEBUG
+	printk (KERN_DEBUG "entering iucv_reply_array\n");
+#endif
+	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 (KERN_DEBUG "exiting iucv_reply_array\n");
+#endif
+	return b2f0_result;
+}
+
+/**************************************************************/
+/* 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])
+{
+	iparml_dpl parm;
+	ulong b2f0_result;
+#ifdef DEBUG
+	printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
+#endif
+	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 (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
+#endif
+	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 (KERN_DEBUG "entering iucv_connect\n");
+#endif
+	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 (KERN_DEBUG "rc from declare buffer is: %i\n",
+				rc);
+#endif
+			return rc;
+		} else
+			declare_flag = 1;
 	}
-      break;
-      
-      
-    case 0x03: /* connection severed ext interrrupt */
-      /* we do not handle this one at this time */
-#ifdef DEBUG
-      printk(  "connection severed.\n");
-#endif
-      break;
-      
-      
-    case 0x04: /* connection quiesced ext interrrupt */
-      /* we do not handle this one at this time */
-#ifdef DEBUG
-      printk(  "connection quiesced.\n");
-#endif
-      break;
-      
-      
-    case 0x05: /* connection resumed ext interrrupt */
-      /* we do not handle this one at this time */
-#ifdef DEBUG
-      printk(  "connection resumed.\n");
-#endif
-      break;
-      
-      
-    case 0x06: /* priority message complete ext interrupt */
-    case 0x07: /* non priority message complete ext interrupt */
-      /* send it to iucv_rx for handling */
+	/* 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);
+	}
+	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);
 	}
-      else
-	{
-	  printk(  "iucv: msg complete interrupt error, rc: %X\n",
-		   (unsigned int)extern_int_buffer->ipaudit);
+	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 */
 	}
-      /* 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 */
+	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(  "message pending.\n");
+		printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
 #endif
-      rcvptr = &privptr->receive_buffer[0];
+		return (add_pathid_result);
+	}
+	*pathid = parm.ippathid;
+	if (parm.ipflags1 & prior_msg)
+		if (priority_permitted)
+			*priority_permitted = 0x01;
+#ifdef DEBUG
+	printk (KERN_DEBUG "exiting iucv_connect\n");
+#endif
+	return b2f0_result;
+}
+
+/**************************************************************/
+/* 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)
+{
+	ulong index1, index2;
+	handler_table_entry *P = 0;
+	iparml_control parm;
+	ulong b2f0_result;
+#ifdef DEBUG
+	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;
+}
+
+/**************************************************************/
+/* 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)
+{
+	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;
+}
+
+/******************************************************************/
+/* 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                                                   */
+/******************************************************************/
+
+inline void
+top_half_interrupt (struct pt_regs *regs, __u16 code)
+{
+	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
+		short_task.routine = (void *) bottom_half_interrupt;
+		queue_task (&short_task, &tq_immediate);
+		mark_bh (IMMEDIATE_BH);
+	}
+	return;
+}
 
-      /* 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");
+/*******************************************************************/
+/* Name: bottom_half_interrupt                                     */
+/* Purpose: Handle interrupt at a more safer time                  */
+/* Input: void                                                     */
+/* Output: void                                                    */
+/*******************************************************************/
+void
+bottom_half_interrupt (void)
+{
+	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
-	    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);
+	return;
+}
+/*******************************************************************/
+/* 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
+	int i;
+	uchar *prt_parm;
+#endif
+#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;
-	      }
-	  } /* 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");
+	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
-  
-}  /* 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);
+			}
+		}
+		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
-  *((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);
+			}
+		}
+		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
-  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;
-    }
-
-#ifdef DEBUG
-    printk(  "iucv: enter iucv_tx, using %s\n",dev->name);
+			}
+		}
+		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
-
-    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*/
-
-#ifdef DEBUG
-    printk(  "iucv:leaving iucv_tx, device %s\n",dev->name);
+			}
+		}
+		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
-
-    return retval;              /* zero == done; nonzero == fail*/
-}   /* end  iucv_tx( struct sk_buff *skb, struct device *dev)  */
-
-
-
-
-
-
-/*---------------*/
-/* iucv_release */
-/*---------------*/
-int iucv_release(net_device *dev)
-{
-    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);
-    }
-
+			}
+		}
+		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;
+	handler *new_handler = 0;
+#ifdef DEBUG
+	int i;
+	uchar *prt_parm;
+	printk (KERN_DEBUG "enter iucv_register_program\n");
+#endif
+	my_ops = *ops;
+	/* Allocate handler table */
+	new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+	if (new_handler == NULL) {
 #ifdef DEBUG
-      printk("iucv: iucv_sever ended with rc: %X\n",rc);
+		printk (KERN_DEBUG
+			"IUCV: returned NULL address for new handle \n");
 #endif
-
-    return rc;
-} /* end  iucv_release() */
-
-
-
-
-
-/*-----------------------------------------------*/
-/* Configuration changes (passed on by ifconfig) */
-/*-----------------------------------------------*/
-int iucv_config(net_device *dev, struct ifmap *map)
-{
-   if (dev->flags & IFF_UP)        /* can't act on a running interface*/
-        return -EBUSY;
-
-   /* ignore other fields */
-   return 0;
-}
-/*  end  iucv_config()  */
-
-
-
-
-
-/*----------------*/
-/* Ioctl commands */
-/*----------------*/
-int iucv_ioctl(net_device *dev, struct ifreq *rq, int cmd)
-{
-#ifdef DEBUG
-    printk(  "iucv: device %s; iucv_ioctl\n",dev->name);
+		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 0;
-}
-
-/*---------------------------------*/
-/* Return statistics to the caller */
-/*---------------------------------*/
-struct net_device_stats *iucv_stats(net_device *dev)
-{
-    struct iucv_priv *priv = (struct iucv_priv *)dev->priv;
-#ifdef DEBUG
-    printk(  "iucv: device %s; iucv_stats\n",dev->name);
+		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
-    return &priv->stats;
-}
-
-
-/*
- * iucv_change_mtu     
- * IUCV can handle MTU sizes from 576 to approx. 32000    
- */
-
-static int iucv_change_mtu(net_device *dev, int new_mtu)
-{
+	}
+	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(  "iucv: device %s; iucv_change_mtu\n",dev->name);
+			printk (KERN_DEBUG "rc from declare buffer is: %i\n",
+				rc);
 #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)
-{
-    int rc;
-    struct iucv_priv *privptr;
-
+		}
+	}
 #ifdef DEBUG
-    printk(  "iucv: iucv_init, device: %s\n",dev->name);
-#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;
-    }
+	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)
+{
+	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 (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
+	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
+			break;
+		}
+	if (!R) {
+		spin_unlock (&lock);
+		return (0);
+	}
+	S = Q->start;
 #ifdef DEBUG
-    printk(  "iucv: iucv_init endend OK for device %s.\n",dev->name);
-#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))
-#endif
-{
-    int result=0, i=0,j=0, k=0, device_present=0;
-    char *s = str;
-    net_device * dev ={0};
-
-#ifdef DEBUG
-    printk(  "iucv: start registering device(s)... \n");
-#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);
-#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 */
-
-#ifdef DEBUG
-    printk(  "iucv: end register devices, %d devices present\n",device_present);
-#endif
-    /* return device_present ? 0 : -ENODEV; */
-#if LINUX_VERSION_CODE>=0x020300
-    return 1;
-#else
-    return;
-#endif
-}
-
-#if LINUX_VERSION_CODE>=0x020300
-__setup("iucv=", iucv_setup);
-#endif
-
-
-/*-------------*/
-/* 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 */
-    }
-};
-
+	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
+	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 ((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;
+}
+
+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);
diff -urN linux-2.2.18-pre25/drivers/s390/net/iucv.h linux/drivers/s390/net/iucv.h
--- linux-2.2.18-pre25/drivers/s390/net/iucv.h	Tue Jan  4 10:12:18 2000
+++ linux/drivers/s390/net/iucv.h	Tue Dec  4 00:17:25 2001
@@ -1,146 +1,353 @@
 /*
- *  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
+
+/*---------------------------------------------------------*/
+/* 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 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 iptype;
+	ushort ipmsglim;
+	ushort res1;
+	uchar res2[8];
+	uchar ipuser[16];
+	ulong res3;
+	uchar ippollfg;
+	uchar res4[3];
+} iucv_ConnectionComplete;
 
-#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 */
-typedef struct {
-  USHORT res0;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  res1;
-  ULONG  res2;
-  ULONG  ipbfadr1;
-  ULONG  res[6];
-} DCLBFR_T;
-
-typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  USHORT ipmsglim;
-  USHORT res1;
-  UCHAR  ipvmid[8];
-  UCHAR  ipuser[16];
-  UCHAR  iptarget[8];
-} CONNECT_T;
-
-typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  USHORT ipmsglim;
-  USHORT res1;
-  UCHAR  res2[8];
-  UCHAR  ipuser[16];
-  UCHAR  res3[8];
-} ACCEPT_T;
-
-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;
-
-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;
-
-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;
-
-typedef struct {
-  USHORT ippathid;
-  UCHAR  ipflags1;
-  UCHAR  iprcode;
-  ULONG  res1[3];
-  UCHAR  ipuser[16];
-  ULONG  res2[2];
-} SEVER_T;
-
-typedef struct {
-  UCHAR  ipmask;
-  UCHAR  res1[2];
-  UCHAR  iprcode;
-  ULONG  res2[9];
-} MASK_T;
-
-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;
+typedef struct {
+	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 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 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 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 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 {
+	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 {
+	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 -urN linux-2.2.18-pre25/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- linux-2.2.18-pre25/drivers/s390/net/netiucv.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/net/netiucv.c	Tue Dec  4 00:17:25 2001
@@ -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 */
+	 }
+};
diff -urN linux-2.2.18-pre25/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- linux-2.2.18-pre25/include/asm-s390/pgtable.h	Tue Dec  4 00:17:09 2001
+++ linux/include/asm-s390/pgtable.h	Tue Dec  4 00:17:27 2001
@@ -477,8 +477,9 @@
 #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))
diff -urN linux-2.2.18-pre25/include/asm-s390/s390mach.h linux/include/asm-s390/s390mach.h
--- linux-2.2.18-pre25/include/asm-s390/s390mach.h	Tue Dec  4 00:17:09 2001
+++ linux/include/asm-s390/s390mach.h	Tue Dec  4 00:17:27 2001
@@ -86,9 +86,9 @@
 #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 )
 {
diff -urN linux-2.2.18-pre25/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- linux-2.2.18-pre25/include/asm-s390/uaccess.h	Tue Dec  4 00:17:09 2001
+++ linux/include/asm-s390/uaccess.h	Tue Dec  4 00:17:27 2001
@@ -192,7 +192,7 @@
 ({                                                              \
         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 @@
 ({                                                              \
         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));                 \
diff -urN linux-2.2.18-pre25/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- linux-2.2.18-pre25/net/ipv4/tcp_input.c	Tue Dec  4 00:17:09 2001
+++ linux/net/ipv4/tcp_input.c	Tue Dec  4 00:17:27 2001
@@ -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_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));
 }
  
diff -urN linux-2.2.18-pre25/net/ipv6/udp.c linux/net/ipv6/udp.c
--- linux-2.2.18-pre25/net/ipv6/udp.c	Mon Aug  9 12:04:41 1999
+++ linux/net/ipv6/udp.c	Tue Dec  4 00:17:27 2001
@@ -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 @@
 
 	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)
