patch-2.4.2 linux/drivers/s390/net/iucv.c

Next file: linux/drivers/s390/net/iucv.h
Previous file: linux/drivers/s390/net/fsm.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.1/linux/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
@@ -1,1178 +1,2050 @@
 /*
  *  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)
- *                
-
+ *    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/config.h>
 #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/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
 #include <linux/init.h>
-#include <linux/string.h>
-#include <asm/checksum.h>
-#include <asm/io.h>
-#include <asm/string.h>
-
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
 #include "iucv.h"
+#include <asm/io.h>
+#include <asm/s390_ext.h>
+#include <asm/ebcdic.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;
-#ifdef DEBUG
-  printk("iucv: iucv_accept input.\n");
-  for (i=0;i<40; i++)
-  {
-    printk("%02x ",((char *)parms)[i]);
-  }
-  printk("\n");
-#endif
-  b2f0(ACCEPT, parm);
-  return parm->iprcode;
-}
-
-
-
-int iucv_receive(void *parms,void *bufferarray,int len)
-{
+#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                 */
+#ifdef CONFIG_MODULES
+#define EXPORT_SYMTAB
+#include <linux/module.h>
+#endif
+#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
-  int i=0;
+		printk (KERN_DEBUG "address of table H_T is %p \n",
+			main_table[index1]);
 #endif
-  RECEIVE_T *parm = parms;
-  memset(parms,0x0,sizeof(parm));
-  /*parm->ipflags1 = 0x42;*/
-  parm->ipflags1 = 0x0;
-  parm->ipmsgid  = 0x0;
-  parm->iptrgcls = 0x0;
-  parm->ipbfadr1 = (ULONG) virt_to_phys(bufferarray);
-  parm->ipbfln1f  = len;
-  parm->ipbfln2f  = 0x0;
-  b2f0(RECEIVE, parm);
-  if (parm->iprcode == 0)
-    len = parm->ipbfln1f;
-//  len = len-parm->ipbfln1f;
-#ifdef DEBUG
-  printk("iucv: iucv_receive command input:\n");
-   for (i=0;i<40;i++)  /* show iucv buffer before send */
-    {
-      printk("%02x ",((char *)parms)[i]);
-    }
-  printk("\n");
-
-  printk("iucv: iucv_receive data buffer:\n");
-  for (i=0;i<len;i++)  /* show data received */
-   {
-     printk("%02x ",((char *)bufferarray)[i]);
-   }
-  printk("\n");
-  printk("received length: %02x ",len);
-
+	}
+	/*
+	 * 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
-  return parm->iprcode;
-}
-
-
-int iucv_send(void *parms,int pathid,void *bufferarray,int len,
-              void *recv_buf, int recv_len)
-{
+		kfree (from);	/* free old table */
+	}
+	spin_unlock (&lock);
 #ifdef DEBUG
-  int i=0;
+	printk (KERN_DEBUG "exiting add_pathid\n");
 #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;
-
+	return (0);
+}				/* end of add_pathid function */
 
+/***********************EXTERNAL FUNCTIONS***************************/
+/**************************************************************/
+/* Name: iucv_query                                           */
+/* Purpose: determines how large an external interrupt buffer */
+/*          IUCV requires to store information                */
+/* Input : bufsize - ulong: size of interrupt buffer          */
+/*         - filled in by function and returned to caller     */
+/*         conmax  - ulong: maximum number of connections that */
+/*           can be outstanding for this VM                   */
+/*         - filled in by function and returned to caller     */
+/* Output: void                                               */
+/**************************************************************/
+void
+iucv_query (ulong * bufsize, ulong * conmax)
+{
+	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
-  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");
-#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;
-}
-
-
+	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
-/*--------------------------*/
-/* 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");
-}
+	printk (KERN_DEBUG "exiting iucv_receive\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;
+	return b2f0_result;
 }
 
-
-
-/*--------------------------*/
-/* 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(void)
-{
-  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;
-  
-  netif_enter_interrupt(dev);        /* lock ! */
-  
-#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
-  
-  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;
-      }
-#ifdef DEBUG
-      dumpit(&((char *)extern_int_buffer)[8],8);
-#endif
-      dev = get_device_from_userid(&((char*)extern_int_buffer)[8]);
-      privptr = (struct iucv_priv *)(dev->priv);
-      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 */
-	  dev = get_device_from_pathid(extern_int_buffer->ippathid);
-	  privptr = (struct iucv_priv *)(dev->priv);
-	  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);
 	}
-      else
-	{
-	  printk(  "iucv: msg complete interrupt error, rc: %X\n",
-		   (unsigned int)extern_int_buffer->ipaudit);
+	spin_unlock (&lock);
+	parm.ipmsglim = msglim;
+	memcpy (parm.ipuser, user_data, 16);
+	memcpy (parm.ipvmid, userid, 8);
+	memcpy (parm.iptarget, system_name, 8);
+	if (parm.iptarget)
+		ASCEBC (parm.iptarget, 8);
+	if (parm.ipvmid) {
+		ASCEBC (parm.ipvmid, 8);
+		EBC_TOUPPER(parm.ipvmid, 8);
 	}
-      /* a transmission is over: tell we are no more busy */
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
-      privptr->stats.tx_packets++;
-      netif_wake_queue(dev);                /* transmission is no longer busy*/
-      break;
-      
-      
-    case 0x08: /* priority message pending */
-    case 0x09: /* non priority message pending */
-#ifdef DEBUG
-      printk(  "message pending.\n");
-#endif
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
-      rcvptr = &privptr->receive_buffer[0];
-      
-      /* re-set receive buffer */
-      memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
-      len = privptr->receive_buffer_len;
-      
-        /* get data now */
-        if (extern_int_buffer->ipflags1 & 0x80)
-	  {  /* data is in the message */
+	if (priority_requested)
+		parm.ipflags1 |= prior_msg;
+	if (prmdata)
+		parm.ipflags1 |= parm_data;	/*data in parameter list */
+	if (quiesce)
+		parm.ipflags1 |= quiesce_msg;
+	if (control) {
+		/* do nothing at the time being  */
+		/*control not provided yet */
+	}
+	if (local)
+		parm.ipflags1 |= local_conn;	/*connect on local system */
+	b2f0_result = b2f0 (connect, &parm);
+	if (b2f0_result)
+		return b2f0_result;
+	add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
+	if (add_pathid_result) {
 #ifdef DEBUG
-	    printk(  "iucv: iucv_receive data is in header!\n");
+		printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
 #endif
-	    memcpy(privptr->receive_buffer,
-		   (char *)extern_int_buffer->iprmmsg1,
-		   (unsigned long)(extern_int_buffer->iprmmsg2));
-	  }
-        else /* data is in buffer, do a receive */
-	  {
-	    rc = iucv_receive(privptr->command_buffer,rcvptr,len);
-	    if (rc != 0  || len == 0)
-	      {
-		printk(  "iucv: iucv_receive failed with rc: %X, length: %lX\n",rc,len);
-		iucv_retrieve_buffer(privptr->command_buffer);
-		break;
-	      }
-	  } /* end else */
-	
-      iucv_next = 0; 
-      /* get next packet offset */  
-      iucv_data_len= *((unsigned short*)rcvptr); 
-        do{ /* until receive buffer is empty, i.e. iucv_next == 0 ! */
+		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_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
+		INIT_LIST_HEAD(&short_task.list);
+		short_task.sync = 0;
+		short_task.routine = (void *) bottom_half_interrupt;
+		queue_task (&short_task, &tq_immediate);
+		mark_bh (IMMEDIATE_BH);
+	}
+	return;
+}
 
-        /* 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");
+/*******************************************************************/
+/* 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
-  
-}  /* 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);
+	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;
+	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
-  
-  /* 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);
+	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);
+		kfree(new_handler);
+		return NULL;
+	}
+	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
+	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
-
-    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);
+	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;
+}
+
+#ifdef CONFIG_MODULES
+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);
 #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 */
-    }
-};
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)