/*
* drivers/s390/net/iucv.c
- * Network driver for VM using iucv
+ * Support for VM IUCV functions for use by other part of the
+ * kernel or loadable modules.
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Stefan Hegewald <hegewald@de.ibm.com>
- * Hartmut Penner <hpenner@de.ibm.com>
- *
- * \r
- * 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- * Martin Schwidefsky (schwidefsky@de.ibm.com)\r
- * Alan Altmark (Alan_Altmark@us.ibm.com)
- *
-
+ * Copyright (C) 2000 IBM Corporation
+ * Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ * Alan Altmark (Alan_Altmark@us.ibm.com)
*/
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
#include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/kernel.h> /* printk() */
-#include <linux/malloc.h> /* kmalloc() */
-#include <linux/errno.h> /* error codes */
-#include <linux/types.h> /* size_t */
-#include <linux/interrupt.h> /* mark_bh */
-#include <linux/netdevice.h> /* struct net_device, and other headers */
-#include <linux/inetdevice.h> /* struct net_device, and other headers */
-#include <linux/if_arp.h>
-#include <linux/rtnetlink.h>
-#include <linux/ip.h> /* struct iphdr */
-#include <linux/tcp.h> /* struct tcphdr */
-#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
#include <linux/init.h>
-#include <linux/string.h>
-#include <asm/checksum.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include "iucv.h"
#include <asm/io.h>
-#include <asm/string.h>
#include <asm/s390_ext.h>
-
-#include "iucv.h"
-
-
-
-#define DEBUG123
-#define MAX_DEVICES 10
-
-
-extern char _ascebc[];
-
-/*
- * global structures
- */
-static char iucv_userid[MAX_DEVICES][8];
-static char iucv_ascii_userid[MAX_DEVICES][8];
-static int iucv_pathid[MAX_DEVICES] = {0};
-static unsigned char iucv_ext_int_buffer[40] __attribute__((aligned (8))) ={0};
-static unsigned char glob_command_buffer[40] __attribute__((aligned (8)));
-
-#if LINUX_VERSION_CODE>=0x20300
-typedef struct net_device net_device;
-#else
-typedef struct device net_device;
-#endif
-net_device iucv_devs[];
-
-
-/* This structure is private to each device. It is used to pass */
-/* packets in and out, so there is place for a packet */
-struct iucv_priv {
- struct net_device_stats stats;
- int packetlen;
- int status;
- u8 *packetdata;
- int pathid; /* used device */
- unsigned char command_buffer[40] __attribute__((aligned (8)));
- unsigned char ext_int_buffer[40] __attribute__((aligned (8)));
- u8* receive_buffer;
- int receive_buffer_len;
- u8* send_buffer;
- int send_buffer_len;
- char * new_send_buf; /* send buffer ptr */
- unsigned char recv_buf[2048]; /* size is just a guess */
- unsigned char userid[8];
-};
-
-struct iucv_header {
- short len;
-};
-
-
-
-static __inline__ int netif_is_busy(net_device *dev)
+#include <asm/spinlock.h>
+#include <asm/ebcdic.h>
+
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_EMERG
+//#define DEBUG3
+//#define DEBUG /* Turns Printk's on */
+//#define DEBUG2 /* This prints the parameter list before and */
+ /* after the b2f0 call to cp */
+#define EXPORT_SYMTAB
+#include <linux/module.h>
+#undef NULL
+#define NULL 0
+#define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */
+ulong declare_flag = 0;
+static uchar iucv_external_int_buffer[40];
+struct tq_struct short_task; /* automatically initialized to zero */
+static iucv_interrupt_ops_t my_ops;
+spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+static void do_int (iucv_ConnectionPending *);
+
+/***************INTERRUPT HANDLING DEFINITIONS***************/
+typedef struct _iucv_packet {
+ struct _iucv_packet *next;
+ uchar data[40];
+} iucv_packet;
+struct tq_struct short_task;
+static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
+iucv_packet *iucv_packets_head, *iucv_packets_tail;
+
+static atomic_t bh_scheduled = ATOMIC_INIT (0);
+void bottom_half_interrupt (void);
+
+/************FUNCTION ID'S****************************/
+#define accept 10
+#define connect 11
+#define declare_buffer 12
+#define purge 9
+#define query 0
+#define quiesc 13
+#define receive 5
+#define reject 8
+#define reply 6
+#define resume 14
+#define retrieve_buffer 2
+#define send 4
+#define setmask 16
+#define sever 15
+
+/*****************************************************************/
+/* Structure: handler */
+/* members: next - is a pointer to next handler on chain */
+/* prev - is a pointer to prev handler on chain */
+/* vmid - 8 char array of machine identification */
+/* user_data - 16 char array for user identification */
+/* mask - 24 char array used to compare the 2 previous */
+/* interrupt_table - functions for interrupts */
+/* start - pointer to start of block of pointers to */
+/* handler_table_entries */
+/* end - pointer to end of block of pointers to */
+/* handler_table_entries */
+/* size - ulong, size of block */
+/* pgm_data - ulong, program data */
+/* NOTE: Keep vmid and user_data together in this order */
+/*****************************************************************/
+typedef struct {
+ ulong *next;
+ ulong *prev;
+ uchar vmid[8];
+ uchar user_data[16];
+ uchar mask[24];
+ iucv_interrupt_ops_t *interrupt_table;
+ ulong *start;
+ ulong *end;
+ ulong size;
+ ulong pgm_data;
+} handler;
+
+/*******************************************************************/
+/* Structure: handler_table_entry */
+/* members: addrs - pointer to a handler */
+/* pathid - ushort containing path identification */
+/* pgm_data - ulong, program data */
+/*******************************************************************/
+typedef struct {
+ handler *addrs;
+ ushort pathid;
+ ulong pgm_data;
+} handler_table_entry;
+
+/* main_table: array of pointers to handler_tables */
+static handler_table_entry *main_table[128];
+/* handler_anchor: points to first handler on chain */
+static handler *handler_anchor;
+
+/****************FIVE STRUCTURES************************************/
+/* Data struct 1: iparml_control */
+/* Used for iucv_accept */
+/* iucv_connect */
+/* iucv_quiesce */
+/* iucv_resume */
+/* iucv_sever */
+/* iucv_retrieve_buffer */
+/* Data struct 2: iparml_dpl (data in parameter list) */
+/* Used for iucv_send_prmmsg */
+/* iucv_send2way_prmmsg */
+/* iucv_send2way_prmmsg_array */
+/* iucv_reply_prmmsg */
+/* Data struct 3: iparml_db (data in a buffer) */
+/* Used for iucv_receive */
+/* iucv_receive_array */
+/* iucv_receive_simple */
+/* iucv_reject */
+/* iucv_reply */
+/* iucv_reply_array */
+/* iucv_send */
+/* iucv_send_simple */
+/* iucv_send_array */
+/* iucv_send2way */
+/* iucv_send2way_array */
+/* iucv_declare_buffer */
+/* Data struct 4: iparml_purge */
+/* Used for iucv_purge */
+/* iucv_query */
+/* Data struct 5: iparml_set_mask */
+/* Used for iucv_set_mask */
+/********************************************************************/
+typedef struct {
+ ushort ippathid;
+ uchar ipflags1;
+ uchar iprcode;
+ ushort ipmsglim;
+ ushort res1;
+ uchar ipvmid[8];
+ uchar ipuser[16];
+ uchar iptarget[8];
+} iparml_control;
+
+/******************/
+typedef struct {
+ ushort ippathid;
+ uchar ipflags1;
+ uchar iprcode;
+ ulong ipmsgid;
+ ulong iptrgcls;
+ uchar iprmmsg[8];
+ ulong ipsrccls;
+ ulong ipmsgtag;
+ ulong ipbfadr2;
+ ulong ipbfln2f;
+ ulong res;
+} iparml_dpl;
+
+/*******************/
+typedef struct {
+ ushort ippathid;
+ uchar ipflags1;
+ uchar iprcode;
+ ulong ipmsgid;
+ ulong iptrgcls;
+ ulong ipbfadr1;
+ ulong ipbfln1f;
+ ulong ipsrccls;
+ ulong ipmsgtag;
+ ulong ipbfadr2;
+ ulong ipbfln2f;
+ ulong res;
+} iparml_db;
+
+/********************/
+typedef struct {
+ ushort ippathid;
+ uchar ipflags1;
+ uchar iprcode;
+ ulong ipmsgid;
+ uchar ipaudit[4];
+ uchar res1[4];
+ ulong res2;
+ ulong ipsrccls;
+ ulong ipmsgtag;
+ ulong res3[3];
+} iparml_purge;
+
+/*******************/
+typedef struct {
+ uchar ipmask;
+ uchar res1[2];
+ uchar iprcode;
+ ulong res2[9];
+} iparml_set_mask;
+
+/*********************INTERNAL FUNCTIONS*****************************/
+/********************************************************************/
+/* Name: b2f0 */
+/* Purpose: this function calls cp to execute iucv commands. */
+/* Input: code - int, identifier of iucv call to cp. */
+/* parm - void *, pointer to 40 byte iparml area passed to cp */
+/* Output: iprcode- return code from iucv call to cp */
+/********************************************************************/
+/* Assembler code performing iucv call */
+/*******************************************************************/
+inline ulong
+b2f0 (int code, void *parm)
{
-#if LINUX_VERSION_CODE<0x02032D
- return(dev->tbusy);
-#else
- return(test_bit(LINK_STATE_XOFF,&dev->flags));
+ uchar *iprcode; /* used to extract iprcode */
+#ifdef DEBUG2
+ int i;
+ uchar *prt_parm;
+ prt_parm = (uchar *) (parm);
+ printk (KERN_DEBUG "parameter list before b2f0 call\n");
+ for (i = 0; i < 40; i++)
+ printk (KERN_DEBUG "%02x ", prt_parm[i]);
+ printk (KERN_DEBUG "\n");
#endif
+ asm volatile ("LRA 1,0(%1)\n\t"
+ "LR 0,%0\n\t"
+ ".long 0xb2f01000"
+ : : "d" (code), "a" (parm) : "0", "1");
+#ifdef DEBUG2
+ printk (KERN_DEBUG "parameter list after b2f0 call\n");
+ for (i = 0; i < 40; i++)
+ printk (KERN_DEBUG "%02x ", prt_parm[i]);
+ printk (KERN_DEBUG "\n");
+#endif
+ iprcode = (uchar *) (parm + 3);
+ return (ulong) (*iprcode);
}
-
-
-#if LINUX_VERSION_CODE<0x02032D
-#define netif_enter_interrupt(dev) dev->interrupt=1
-#define netif_exit_interrupt(dev) dev->interrupt=0
-#define netif_start(dev) dev->start=1
-#define netif_stop(dev) dev->start=0
-
-static __inline__ void netif_stop_queue(net_device *dev)
+/**************************************************************/
+/* Name: iucv_retrieve_buffer */
+/* Purpose: terminates all use of iucv */
+/* Input: void */
+/* Output: Return code from CP */
+/**************************************************************/
+int
+iucv_retrieve_buffer (void)
{
- dev->tbusy=1;
+ iparml_control parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_retrieve_buffer\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ b2f0_result = b2f0 (retrieve_buffer, &parm);
+ if (b2f0_result == NULL)
+ declare_flag = 0;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n");
+#endif
+ return b2f0_result;
}
-static __inline__ void netif_start_queue(net_device *dev)
+/**************************************************************/
+/* Name: iucv_declare_buffer */
+/* Purpose: specifies the guests real address of an external */
+/* interrupt. */
+/* Input: bfr - pointer to buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* Note : See output options for b2f0 call */
+/**************************************************************/
+int
+iucv_declare_buffer (uchar * bfr)
{
- dev->tbusy=0;
+ iparml_db parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "Entering iucv_declare_buffer\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipbfadr1 = virt_to_phys (bfr);
+ b2f0_result = b2f0 (declare_buffer, &parm);
+#ifdef DEBUG
+ printk (KERN_DEBUG "Address of EIB = %p\n", bfr);
+ printk (KERN_DEBUG "Exiting iucv_declare_buffer\n");
+#endif
+ return b2f0_result;
}
-static __inline__ void netif_wake_queue(net_device *dev)
+/**************************************************************/
+/* Name: add_pathid */
+/* Purpose: adds a path id to the system */
+/* Input: pathid - ushort, pathid to enter system */
+/* handle - iucv_handle_t, address of handler to add to */
+/* pgm_data - ulong, pathid identifier. */
+/* Output: 0: successful addition of pathid */
+/**************************************************************/
+int
+add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data)
+{
+ ulong index1, index2; /* index1 into main_table */
+ ulong add_flag = 0;
+ ulong old_size = 0, new_size = 0;
+ uchar *to, *from; /* pointer for copying the table */
+ handler_table_entry *P = 0; /*P is a pointer to H_T_E */
+ handler *Q = 0; /*Q is a pointer to handler */
+ ulong *X = 0; /*Points to array of pointers */
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering add_pathid\n");
+#endif
+ Q = (handler *) handle; /* Q points to a handler */
+ /*
+ * main_table has 128 entries.
+ * 128*512 = 65536 maximum number of pathid's allowed
+ */
+ index1 = ((ulong) pathid) / 512;
+ index2 = ((ulong) pathid) % 512;
+#ifdef DEBUG
+ printk (KERN_DEBUG "index1 = %d\n ", (int) index1);
+ printk (KERN_DEBUG "index2 = %d\n ", (int) index2);
+ printk (KERN_DEBUG "Q is pointing to %p ", Q);
+#endif
+ spin_lock (&lock);
+ /*
+ * If NULL then handler table does not exist and need to get storage
+ * and have main_table[index1] point to it
+ * If allocating storage failed, return
+ */
+ if (main_table[index1] == NULL) {
+ main_table[index1] = (handler_table_entry *) kmalloc
+ (512 * sizeof (handler_table_entry), GFP_KERNEL);
+ if (main_table[index1] == NULL) {
+ spin_unlock (&lock);
+ return -ENOBUFS;
+ }
+ memset (main_table[index1], 0,
+ 512 * sizeof (handler_table_entry));
+#ifdef DEBUG
+ printk (KERN_DEBUG "address of table H_T is %p \n",
+ main_table[index1]);
+#endif
+ }
+ /*
+ * P points to a handler table entry (H_T_E) in which all entries in
+ * that structure should be NULL. If they're not NULL, then there
+ * is a bad pointer and it will return(-2) immediately, otherwise
+ * data will be entered into H_T_E.
+ */
+ P = main_table[index1];
+ if ((P + index2)->addrs) {
+#ifdef DEBUG
+ printk (KERN_DEBUG "main_table[index1] = %p \n",
+ main_table[index1]);
+ printk (KERN_DEBUG "P+index2 = %p \n", P + index2);
+ printk (KERN_DEBUG "(P+index2)->addrs is %p \n",
+ (P + index2)->addrs);
+#endif
+ spin_unlock (&lock);
+ printk (KERN_DEBUG "bad pointer1\n");
+ return (-2);
+ }
+ (P + index2)->addrs = handle;
+ /*
+ * checking if address of handle is valid, if it's not valid,
+ * unlock the lock and return(-2) immediately.
+ */
+ if ((P + index2)->addrs == NULL) {
+ spin_unlock (&lock);
+ printk (KERN_DEBUG "bad pointer2\n");
+ return (-2);
+ }
+ (P + index2)->pathid = pathid;
+ if (pgm_data)
+ (P + index2)->pgm_data = pgm_data;
+ else
+ (P + index2)->pgm_data = Q->pgm_data;
+ /*
+ * Step thru the table of addresses of pathid's to find the first
+ * available entry (NULL). If an entry is found, add the pathid,
+ * unlock and exit. If an available entry is not found, allocate a
+ * new, larger table, copy over the old table and deallocate the
+ * old table and add the pathid.
+ */
+#ifdef DEBUG
+ printk (KERN_DEBUG "address of handle is %p\n", handle);
+ printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start));
+ printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end));
+ printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start));
+ printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end));
+ for (X = (Q->start); X < (Q->end); X++)
+ printk (KERN_DEBUG "X = %p ", X);
+ printk (KERN_DEBUG "\n");
+#endif
+ for (X = (Q->start); X < (Q->end); X++) {
+ if (*X == NULL) {
+#ifdef DEBUG
+ printk (KERN_DEBUG "adding pathid, %p = P+index2\n",
+ (P + index2));
+#endif
+ *X = (ulong) (P + index2);
+ add_flag = 1;
+ }
+ if (add_flag == 1)
+ break;
+ }
+ if (add_flag == 0) { /* element not added to list */
+ X = Q->start;
+ old_size = Q->size;
+ new_size = old_size + ADDED_STOR; /* size of new table */
+ from = (uchar *) (Q->start); /* address of old table */
+ (*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL);
+ if ((Q->start) == NULL) {
+ spin_unlock (&lock);
+ return -ENOBUFS;
+ }
+ memset ((*Q).start, 0, new_size * sizeof (ulong));
+ to = (uchar *) (Q->start); /* address of new table */
+ /* copy old table to new */
+ memcpy (to, from, old_size * (sizeof (ulong)));
+#ifdef DEBUG
+ printk (KERN_DEBUG "Getting a new pathid table\n");
+ printk (KERN_DEBUG "to is %p \n", to);
+ printk (KERN_DEBUG "from is %p \n", from);
+#endif
+ Q->size = new_size; /* storing new size of table */
+ Q->end = (Q->start) + (Q->size);
+ X = Q->start + old_size; /* next blank in table */
+ *X = (ulong) (P + index2); /* adding element to new table */
+#ifdef DEBUG
+ printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size));
+ printk (KERN_DEBUG "Q->end is %p \n", Q->end);
+ printk (KERN_DEBUG "Q->start is %p \n", Q->start);
+ printk (KERN_DEBUG "X is %p \n", X);
+ printk (KERN_DEBUG "*X is %u \n", (int) (*X));
+#endif
+ kfree (from); /* free old table */
+ }
+ spin_unlock (&lock);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting add_pathid\n");
+#endif
+ return (0);
+} /* end of add_pathid function */
+
+/***********************EXTERNAL FUNCTIONS***************************/
+/**************************************************************/
+/* Name: iucv_query */
+/* Purpose: determines how large an external interrupt buffer */
+/* IUCV requires to store information */
+/* Input : bufsize - ulong: size of interrupt buffer */
+/* - filled in by function and returned to caller */
+/* conmax - ulong: maximum number of connections that */
+/* can be outstanding for this VM */
+/* - filled in by function and returned to caller */
+/* Output: void */
+/**************************************************************/
+void
+iucv_query (ulong * bufsize, ulong * conmax)
{
- dev->tbusy=0;
- mark_bh(NET_BH);
+ iparml_purge parm; /* DOESN'T MATTER WHICH IPARML IS USED */
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_purge\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ /*
+ * Assembler instruction calling b2f0 and storing R0 and R1
+ */
+ asm volatile ("LRA 1,0(%3)\n\t"
+ "LR 0,%2\n\t"
+ ".long 0xb2f01000\n\t"
+ "ST 0,%0\n\t"
+ "ST 1,%1\n\t":"=m" (*bufsize),
+ "=m" (*conmax):"d" (query), "a" (&parm):"0", "1");
+ return;
}
-#else
-#define netif_enter_interrupt(dev)
-#define netif_exit_interrupt(dev)
-#define netif_start(dev)
-#define netif_stop(dev)
+/**************************************************************/
+/* Name: iucv_purge */
+/* Purpose: cancels a message you have sent */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, mid of message */
+/* srccls - ulong, sourse message class */
+/* audit - uchar[4], info about ansync. error condit. */
+/* filled in by function and passed back */
+/* Output: void */
+/* NOTE: pathid is required, flag is always turned on */
+/**************************************************************/
+int
+iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4])
+{
+ iparml_purge parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_purge\n");
#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipmsgid = msgid;
+ parm.ippathid = pathid;
+ parm.ipsrccls = srccls;
+ parm.ipflags1 |= specify_pathid; /* pathid id flag */
+ if (parm.ipmsgid)
+ parm.ipflags1 |= specify_msgid;
+ if (parm.ipsrccls)
+ parm.ipflags1 |= source_class;
+ b2f0_result = b2f0 (purge, &parm);
+ if (b2f0_result != NULL)
+ return b2f0_result;
+ memcpy (audit, parm.ipaudit, 4);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_purge\n");
+#endif
+ return b2f0_result;
+}
-
-
-/*
- * Following the iucv primitives
- */
-
-
-extern inline void b2f0(int code,void* parm)
+/**************************************************************/
+/* Name: iucv_quiesce */
+/* Purpose: temporarily suspends incoming messages */
+/* Input: pathid - ushort, pathid */
+/* user_data - uchar[16], user id */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: see b2f0 output list */
+/**************************************************************/
+int
+iucv_quiesce (ushort pathid, uchar user_data[16])
{
- asm volatile ("LR 1,%1\n\tLR 0,%0\n\t.long 0xb2f01000" ::
- "d" (code) ,"a" (parm) :"0", "1");
+ iparml_control parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_quiesce\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, 16);
+ parm.ippathid = pathid;
+ b2f0_result = b2f0 (quiesc, &parm);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_quiesce\n");
+#endif
+ return b2f0_result;
}
-int iucv_enable(void *parms)
+/**************************************************************/
+/* Name: iucv_resume */
+/* Purpose: restores communication over a quiesced path */
+/* Input: pathid - ushort, pathid */
+/* user_data - uchar[16], user id */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: see b2f0 output list */
+/**************************************************************/
+int
+iucv_resume (ushort pathid, uchar user_data[16])
{
- MASK_T *parm = parms;
- memset(parms,0,sizeof(parm));
- parm->ipmask = 0xF8;
- b2f0(SETMASK,parm);
- memset(parms,0,sizeof(parm));
- parm->ipmask = 0xF8;
- b2f0(SETCMASK,parm);
- return parm->iprcode;
+ iparml_control parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_resume\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, 16);
+ parm.ippathid = pathid;
+ b2f0_result = b2f0 (resume, &parm);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_resume\n");
+#endif
+ return b2f0_result;
}
-
-int iucv_declare_buffer(void *parms, DCLBFR_T *buffer)
+/**************************************************************/
+/* Name: iucv_reject */
+/* Purpose: rejects a message */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, mid of message */
+/* trgcls - ulong, target message class */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: pathid is required field, flag always turned on */
+/* RESTRICTION: target class cannot be zero */
+/* NOTE: see b2f0 output list */
+/**************************************************************/
+int
+iucv_reject (ushort pathid, ulong msgid, ulong trgcls)
{
- DCLBFR_T *parm = parms;
- memset(parms,0,sizeof(parm));
- parm->ipflags1= 0x00;
- parm->ipbfadr1 = virt_to_phys(buffer);
- b2f0(DECLARE_BUFFER, parm);
- return parm->iprcode;
+ iparml_db parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_reject\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipmsgid = msgid;
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipflags1 |= specify_pathid; /* flag for pathid */
+ if (parm.ipmsgid)
+ parm.ipflags1 |= specify_msgid;
+ if (parm.iptrgcls)
+ parm.ipflags1 |= target_class;
+ b2f0_result = b2f0 (reject, &parm);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_reject\n");
+#endif
+ return b2f0_result;
}
-
-int iucv_retrieve_buffer(void *parms)
+/**************************************************************/
+/* Name: iucv_setmask */
+/* Purpose: enables or disables certain iucv external interr. */
+/* Input: non_priority_interrupts - uchar */
+/* priority_interrupts - uchar */
+/* non_priority_completion_interrupts - uchar */
+/* priority_completion_interrupts) - uchar */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: see b2f0 output list */
+/**************************************************************/
+int
+iucv_setmask (uchar non_priority_interrupts,
+ uchar priority_interrupts,
+ uchar non_priority_completion_interrupts,
+ uchar priority_completion_interrupts)
{
- DCLBFR_T *parm = parms;
- memset(parms,0x0,sizeof(parm));
- parm->iprcode = 0x0;
- b2f0(RETRIEVE_BUFFER, parm);
- return parm->iprcode;
+ iparml_set_mask parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_setmask\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ if (non_priority_interrupts)
+ parm.ipmask |= 0x80;
+ if (priority_interrupts)
+ parm.ipmask |= 0x40;
+ if (non_priority_completion_interrupts)
+ parm.ipmask |= 0x20;
+ if (priority_completion_interrupts)
+ parm.ipmask |= 0x10;
+ b2f0_result = b2f0 (setmask, &parm);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_setmask\n");
+#endif
+ return b2f0_result;
}
-
-int iucv_connect(void *parms,
- const char *userid,
- const char *host,
- const char *ipusr,
- unsigned short * used_pathid)
+/**************************************************************/
+/* Name: iucv_sever */
+/* Purpose: terminates an iucv path to another machine */
+/* Input: pathid - ushort, pathid */
+/* user_data - uchar[16], user id */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: see b2f0 output list */
+/**************************************************************/
+int
+iucv_sever (ushort pathid, uchar user_data[16])
{
- CONNECT_T *parm = parms; /* ipflags was 0x60*/
- memset(parms,0x0,sizeof(parm));
- parm->ipflags1 = 0x80;
- parm->ipmsglim = 0x0a;
- memcpy(parm->ipvmid,userid,8);
- if (ipusr)
- memcpy(parm->ipuser,ipusr,16);
- memcpy(parm->iptarget,host,8);
- b2f0(CONNECT, parm);
- *used_pathid = parm->ippathid;
- return parm->iprcode;
+ ulong index1, index2;
+ ulong b2f0_result;
+ handler_table_entry *P = 0;
+ handler *Q = 0;
+ ulong *X;
+ iparml_control parm;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_sever\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, 16);
+ parm.ippathid = pathid;
+ b2f0_result = b2f0 (sever, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ index1 = ((ulong) pathid) / 512;
+ index2 = ((ulong) pathid) % 512;
+ spin_lock (&lock);
+ P = main_table[index1];
+ if (((P + index2)->addrs) == NULL) { /* called from interrupt code */
+ spin_unlock (&lock);
+ return (-2); /* bad pointer */
+ }
+ Q = (*(P + index2)).addrs;
+#ifdef DEBUG
+ printk (KERN_DEBUG "pathid is %d\n", pathid);
+ printk (KERN_DEBUG "index1 is %d\n", (int) index1);
+ printk (KERN_DEBUG "index2 is %d\n", (int) index2);
+ printk (KERN_DEBUG "H_T_E is %p\n", P);
+ printk (KERN_DEBUG "address of handler is %p\n", Q);
+ for (X = ((*Q).start); X < ((*Q).end); X++)
+ printk (KERN_DEBUG " %x ", (int) (*X));
+ printk (KERN_DEBUG "\n above is pathid table\n");
+#endif
+/********************************************************************/
+/* Searching the pathid address table for matching address, once */
+/* found, NULL the field. Then Null the H_T_E fields. */
+/********************************************************************/
+ for (X = ((*Q).start); X < ((*Q).end); X++)
+ if (*X == (ulong) (P + index2)) {
+#ifdef DEBUG
+ printk (KERN_DEBUG "found a path to sever\n");
+ printk (KERN_DEBUG "severing %d \n", (int) (*X));
+#endif
+ *X = NULL;
+ (*(P + index2)).addrs = NULL; /*clearing the fields */
+ (*(P + index2)).pathid = 0;
+ (*(P + index2)).pgm_data = 0;
+ }
+ spin_unlock (&lock);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_sever\n");
+#endif
+ return b2f0_result;
}
-
-
-int iucv_accept(void *parms,int pathid)
+/**************************************************************/
+/* Name: iucv_receive */
+/* Purpose: receives incoming message */
+/* Input: pathid - ushort, pathid */
+/* msgid - *ulong, mid of message */
+/* trgcls - *ulong, target message class */
+/* buffer - pointer of buffer */
+/* buflen - length of buffer */
+/* adds_curr_buffer - pointer to updated buffer address*/
+/* to write to */
+/* adds_curr_length - pointer to updated length in */
+/* buffer available to write to */
+/* reply_required - uchar *, flag */
+/* priority_msg - uchar *, flag */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: pathid must be specified, flag being turned on */
+/* RESTRICTIONS: target class CANNOT be zero because the code */
+/* checks for a non-NULL value to turn flag on, therefore if */
+/* target class = zero, flag will not be turned on. */
+/**************************************************************/
+int
+iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls,
+ void *buffer, ulong buflen,
+ uchar * reply_required,
+ uchar * priority_msg,
+ ulong * adds_curr_buffer, ulong * adds_curr_length)
{
+ iparml_db parm;
+ ulong b2f0_result;
#ifdef DEBUG
- int i=0;
+ printk (KERN_DEBUG "entering iucv_receive\n");
#endif
- ACCEPT_T *parm = parms;
- memset(parms,0,sizeof(parm));
- parm->ippathid = pathid;
- parm->ipflags1 = 0x80;
- parm->ipmsglim = 0x0a;
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipmsgid = *msgid;
+ parm.ippathid = pathid;
+ parm.iptrgcls = *trgcls;
+ parm.ipflags1 |= specify_pathid; /* turning pathid flag */
+ if (parm.ipmsgid)
+ parm.ipflags1 |= 0x05;
+ if (parm.iptrgcls)
+ parm.ipflags1 |= target_class;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen;
+ b2f0_result = b2f0 (receive, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ if (msgid)
+ *msgid = parm.ipmsgid;
+ if (trgcls)
+ *trgcls = parm.iptrgcls;
+ if (parm.ipflags1 & prior_msg)
+ if (priority_msg)
+ *priority_msg = 0x01; /*yes, priority msg */
+ if (!(parm.ipflags1 & 0x10)) /*& with X'10' */
+ if (reply_required)
+ *reply_required = 0x01; /*yes, reply required */
+ if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */
+ if (adds_curr_length)
+ *adds_curr_length = parm.ipbfln1f;
+ if (adds_curr_buffer)
+ *adds_curr_buffer = parm.ipbfadr1;
+ } else {
+ if ((buflen) >= 8) {
+ if (buffer)
+ memcpy ((char *) buffer,
+ (char *) parm.ipbfadr1, 8);
+ if (adds_curr_length)
+ *adds_curr_length = ((buflen) - 8);
+ if (adds_curr_buffer)
+ *adds_curr_buffer = (ulong) buffer + 8;
+ } else {
+ parm.iprcode |= 0x05;
+ b2f0_result = (ulong) parm.iprcode;
+ }
+ }
#ifdef DEBUG
- printk("iucv: iucv_accept input.\n");
- for (i=0;i<40; i++)
- {
- printk("%02x ",((char *)parms)[i]);
- }
- printk("\n");
+ printk (KERN_DEBUG "exiting iucv_receive\n");
#endif
- b2f0(ACCEPT, parm);
- return parm->iprcode;
+ return b2f0_result;
}
+/**************************************************************/
+/* Name: iucv_receive_simple */
+/* Purpose: receives fully-qualified message */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, id of message */
+/* trgcls - ulong, target message class */
+/* buffer - pointer of buffer */
+/* buflen - length of buffer */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls,
+ void *buffer, ulong buflen)
+{
+ iparml_db parm;
+ ulong b2f0_result;
+ pr_debug ("entering iucv_receive_simple\n");
+
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipmsgid = msgid;
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen;
+
+ b2f0_result = b2f0 (receive, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+
+ if (parm.ipflags1 & IPRMDATA) { /*msg in parmlist */
+ if ((buflen) >= 8)
+ memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8);
+ else
+ b2f0_result = 5;
+ }
+ pr_debug ("exiting iucv_receive_simple\n");
+ return b2f0_result;
+}
-
-int iucv_receive(void *parms,void *bufferarray,int len)
+/**************************************************************/
+/* Name: iucv_receive_array */
+/* Purpose: receives incoming message */
+/* Input: pathid - ushort, pathid */
+/* msgid -* ulong, mid of message */
+/* trgcls -* ulong, target message class */
+/* buffer - pointer of iucv_array_t */
+/* buflen - ulong , length of buffer */
+/* reply_required - uchar *, flag returned to caller */
+/* priority_msg - uchar *, flag returned to caller */
+/* adds_curr_buffer - pointer to updated buffer array */
+/* to write to */
+/* adds_curr_length - pointer to updated length in */
+/* buffer available to write to */
+/* Output: iprcode - return code from b2f0 call */
+/* NOTE: pathid must be specified, flag being turned on */
+/* RESTRICTIONS: target class CANNOT be zero because the code */
+/* checks for a non-NULL value to turn flag on, therefore if */
+/* target class = if target class = zero flag will not be */
+/* turned on, therefore if target class is specified it cannot */
+/* be zero. */
+/**************************************************************/
+int
+iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls,
+ iucv_array_t * buffer, ulong * buflen,
+ uchar * reply_required,
+ uchar * priority_msg,
+ ulong * adds_curr_buffer, ulong * adds_curr_length)
{
+ iparml_db parm;
+ ulong b2f0_result;
#ifdef DEBUG
- int i=0;
-#endif
- RECEIVE_T *parm = parms;
- memset(parms,0x0,sizeof(parm));
- /*parm->ipflags1 = 0x42;*/
- parm->ipflags1 = 0x0;
- parm->ipmsgid = 0x0;
- parm->iptrgcls = 0x0;
- parm->ipbfadr1 = (ULONG) virt_to_phys(bufferarray);
- parm->ipbfln1f = len;
- parm->ipbfln2f = 0x0;
- b2f0(RECEIVE, parm);
- if (parm->iprcode == 0)
- len = parm->ipbfln1f;
-// len = len-parm->ipbfln1f;
-#ifdef DEBUG
- printk("iucv: iucv_receive command input:\n");
- for (i=0;i<40;i++) /* show iucv buffer before send */
- {
- printk("%02x ",((char *)parms)[i]);
- }
- printk("\n");
-
- printk("iucv: iucv_receive data buffer:\n");
- for (i=0;i<len;i++) /* show data received */
- {
- printk("%02x ",((char *)bufferarray)[i]);
- }
- printk("\n");
- printk("received length: %02x ",len);
-
+ printk (KERN_DEBUG "entering iucv_receive_array\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ipmsgid = *msgid;
+ parm.ippathid = pathid;
+ parm.iptrgcls = *trgcls;
+ parm.ipflags1 |= array; /* using an address list */
+ parm.ipflags1 |= specify_pathid; /*turning on pathid flag */
+ if (parm.ipmsgid)
+ parm.ipflags1 |= 0x05;
+ if (parm.iptrgcls)
+ parm.ipflags1 |= target_class;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = *buflen;
+ b2f0_result = b2f0 (receive, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ if (msgid)
+ *msgid = parm.ipmsgid;
+ if (trgcls)
+ *trgcls = parm.iptrgcls;
+ if (parm.ipflags1 & prior_msg)
+ if (priority_msg)
+ *priority_msg = 0x01; /*yes, priority msg */
+ if (!(parm.ipflags1 & 0x10)) /*& with X'10' */
+ if (reply_required)
+ *reply_required = 0x01; /*yes, reply required */
+ if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */
+ if (adds_curr_length)
+ *adds_curr_length = parm.ipbfln1f;
+ if (adds_curr_buffer)
+ *adds_curr_buffer = parm.ipbfadr1;
+ } else {
+ if ((buffer->length) >= 8) {
+ memcpy ((char *) buffer->address,
+ (char *) parm.ipbfadr1, 8);
+ if (adds_curr_buffer)
+ *adds_curr_buffer =
+ (ulong) ((buffer->address) + 8);
+ if (adds_curr_length)
+ *adds_curr_length = ((buffer->length) - 8);
+
+ } else {
+ parm.iprcode |= 0x05;
+ b2f0_result = (ulong) parm.iprcode;
+ }
+ }
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_receive\n");
#endif
- return parm->iprcode;
+ return b2f0_result;
}
-
-int iucv_send(void *parms,int pathid,void *bufferarray,int len,
- void *recv_buf, int recv_len)
+/**************************************************************/
+/* Name: iucv_send */
+/* Purpose: sends messages */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message returned to caller */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* buffer - pointer to buffer */
+/* buflen - ulong, length of buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg, void *buffer, ulong buflen)
{
+ iparml_db parm;
+ ulong b2f0_result;
#ifdef DEBUG
- int i=0;
-#endif
- SEND_T *parm = parms;
- memset(parms,0x0,sizeof(parm));
- /* parm->ipflags1 = 0x48; ??*/
- parm->ippathid = pathid;
- parm->ipflags1 = 0x14; /* any options ?? */
- parm->ipmsgid = 0x0;
- parm->iptrgcls = 0x0;
- parm->ipbfadr1 = virt_to_phys(bufferarray);
- parm->ipbfln1f = len;
- parm->ipsrccls = 0x0;
- parm->ipmsgtag = 0x0;
- parm->ipbfadr2 = virt_to_phys(recv_buf);
- parm->ipbfln2f = recv_len;
-
-
+ printk (KERN_DEBUG "entering iucv_send\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen; /* length of message */
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 |= one_way_msg; /* one way message */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (send, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ if (msgid)
+ *msgid = parm.ipmsgid;
#ifdef DEBUG
- printk("iucv: iucv_send command input:\n");
- for (i=0;i<40;i++) /* show iucv buffer before send */
- {
- printk("%02x ",((char *)parms)[i]);
- }
- printk("\n");
-
- printk("iucv: iucv_send data buffer:\n");
- for (i=0;i<len;i++) /* show send data before send */
- {
- printk("%02x ",((char *)bufferarray)[i]);
- }
- printk("\n");
+ printk (KERN_DEBUG "exiting iucv_send\n");
#endif
+ return b2f0_result;
+}
- b2f0(SEND, parm);
-
-#ifdef DEBUGXX
- printk("iucv: iucv_send buffer after send:\n");
- for (i=0;i<len;i++) /* show send buffer after send */
- {
- printk("%1x",((char *)bufferarray)[i]);
- }
- printk("\n");
+/**************************************************************/
+/* Name: iucv_send_array */
+/* Purpose: sends messages in buffer array */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message returned to caller */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* buffer - pointer to iucv_array_t */
+/* buflen - ulong, length of buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send_array (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg,
+ iucv_array_t * buffer, ulong buflen)
+{
+ iparml_db parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send_array\n");
#endif
-
- return parm->iprcode;
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen; /* length of message */
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 |= one_way_msg; /* one way message */
+ parm.ipflags1 |= array; /* one way w/ array */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send_array\n");
+#endif
+ return b2f0_result;
}
-
-
-int iucv_sever(void *parms)
+/**************************************************************/
+/* Name: iucv_send_prmmsg */
+/* Purpose: sends messages in parameter list */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* prmmsg - uchar[8], message being sent */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send_prmmsg (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg, uchar prmmsg[8])
{
- SEVER_T *parm = parms;
- memset(parms,0x0,sizeof(parm));
- parm->ippathid = 0x0;
- parm->ipflags1 = 0x0;
- parm->iprcode = 0xF;
- memset(parm->ipuser,0,16);
- b2f0(SEVER, parm);
- return parm->iprcode;
+ iparml_dpl parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send_prmmsg\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 |= parm_data; /* message in prmlist */
+ parm.ipflags1 |= one_way_msg; /* one way message */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ memcpy (parm.iprmmsg, prmmsg, 8);
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send_prmmsg\n");
+#endif
+ return b2f0_result;
}
-
-#ifdef DEBUG
-/*--------------------------*/
-/* Dump buffer formatted */
-/*--------------------------*/
-static void dumpit(char* buf, int len)
+/**************************************************************/
+/* Name: iucv_send2way */
+/* Purpose: sends messages in both directions */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* buffer - pointer to buffer */
+/* buflen - ulong, length of buffer */
+/* ansbuf - pointer to buffer on reply */
+/* anslen - length of ansbuf buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send2way (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg,
+ void *buffer, ulong buflen, void *ansbuf, ulong anslen)
{
- int i;
- for (i=0;i<len;i++) {
- if (!(i%16)&&i!=0)
- printk("\n");
- else if (!(i%4)&&i!=0)
- printk(" ");
- printk( "%02X",buf[i]);
- }
- if (len%16)
- printk( "\n");
-}
+ iparml_db parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send2way\n");
#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen; /* length of message */
+ parm.ipbfadr2 = (ulong) ansbuf;
+ parm.ipbfln2f = anslen;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send2way\n");
+#endif
+ return b2f0_result;
+}
-
-
-/*--------------------------*/
-/* Get device from pathid */
-/*--------------------------*/
-net_device * get_device_from_pathid(int pathid)
+/**************************************************************/
+/* Name: iucv_send2way_array */
+/* Purpose: sends messages in both directions in arrays */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* buffer - pointer to iucv_array_t */
+/* buflen - ulong, length of buffer */
+/* ansbuf - pointer to iucv_array_t on reply */
+/* anslen - length of ansbuf buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send2way_array (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg,
+ iucv_array_t * buffer, ulong buflen,
+ iucv_array_t * ansbuf, ulong anslen)
{
- int i;
- for (i=0;i<=MAX_DEVICES;i++)
- {
- if (iucv_pathid[i] == pathid)
- return &iucv_devs[i];
- }
- printk("iucv: get_device_from_pathid: no device for pathid %X\n",pathid);
- return 0;
+ iparml_db parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send2way_array\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr1 = (ulong) buffer;
+ parm.ipbfln1f = buflen; /* length of message */
+ parm.ipbfadr2 = (ulong) ansbuf;
+ parm.ipbfln2f = anslen;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 |= array; /* send w/ array */
+ parm.ipflags1 |= reply_array; /* reply w/ array */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send2way_array\n");
+#endif
+ return b2f0_result;
}
-
-
-/*--------------------------*/
-/* Get device from userid */
-/*--------------------------*/
-net_device * get_device_from_userid(char * userid)
+/**************************************************************/
+/* Name: iucv_send2way_prmmsg */
+/* Purpose: sends messages in both directions w/parameter lst */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* prmmsg - uchar[8], message being sent in parameter */
+/* ansbuf - pointer to buffer */
+/* anslen - length of ansbuf buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send2way_prmmsg (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg,
+ uchar prmmsg[8], void *ansbuf, ulong anslen)
{
- int i;
- net_device * dev;
- struct iucv_priv *privptr;
- for (i=0;i<=MAX_DEVICES;i++)
- {
- dev = &iucv_devs[i];
- privptr = (struct iucv_priv *)(dev->priv);
- if (memcmp(privptr->userid,userid,8)==0)
- return &iucv_devs[i];
- }
- printk("iucv: get_device_from_uid: no device for userid %s\n",userid);
- return 0;
+ iparml_dpl parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipbfadr2 = (ulong) ansbuf;
+ parm.ipbfln2f = anslen;
+ parm.ipflags1 |= parm_data; /* message in prmlist */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ memcpy (parm.iprmmsg, prmmsg, 8);
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
+#endif
+ return b2f0_result;
}
-
-/*--------------------------*/
-/* Open iucv Device Driver */
-/*--------------------------*/
-int iucv_open(net_device *dev)
+/**************************************************************/
+/* Name: iucv_reply */
+/* Purpose: responds to the two-way messages that you receive */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, id of message */
+/* trgcls - ulong, target message class */
+/* priority_msg - uchar, flag */
+/* buf - pointer, address of buffer */
+/* buflen - length of buffer */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_reply (ushort pathid, ulong msgid, ulong trgcls,
+ uchar priority_msg, void *buf, ulong buflen)
{
- int rc;
- unsigned short iucv_used_pathid;
- struct iucv_priv *privptr;
- char iucv_host[8] ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- char vmident[16] ={0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
- 0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
-
+ iparml_db parm;
+ ulong b2f0_result;
#ifdef DEBUG
- printk( "iucv: iucv_open, device: %s\n",dev->name);
+ printk (KERN_DEBUG "entering iucv_reply\n");
#endif
-
- privptr = (struct iucv_priv *)(dev->priv);
- if(privptr->pathid != -1) {
- netif_start(dev);
- netif_start_queue(dev);
- return 0;
- }
- if ((rc = iucv_connect(privptr->command_buffer,
- privptr->userid,
- iucv_host,
- vmident,
- &iucv_used_pathid))!=0) {
- printk( "iucv: iucv connect failed with rc %X\n",rc);
- iucv_retrieve_buffer(privptr->command_buffer);
- return -ENODEV;
- }
-
- privptr->pathid = iucv_used_pathid;
- iucv_pathid[dev-iucv_devs]=privptr->pathid;
-
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr2 = (ulong) buf;
+ parm.ipbfln2f = buflen; /* length of message */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (reply, &parm);
#ifdef DEBUG
- printk( "iucv: iucv_connect ended with rc: %X\n",rc);
- printk( "iucv[%d] pathid %X \n",(int)(dev-iucv_devs),privptr->pathid);
+ printk (KERN_DEBUG "exiting iucv_reply\n");
#endif
- netif_start(dev);
- netif_start_queue(dev);
- return 0;
+ return b2f0_result;
}
-
-
-/*-----------------------------------------------------------------------*/
-/* Receive a packet: retrieve, encapsulate and pass over to upper levels */
-/*-----------------------------------------------------------------------*/
-void iucv_rx(net_device *dev, int len, unsigned char *buf)
+/**************************************************************/
+/* Name: iucv_reply_array */
+/* Purpose: responds to the two-way messages that you receive */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, id of message */
+/* trgcls - ulong, target message class */
+/* priority_msg - uchar, flag */
+/* buf - pointer, address of array */
+/* buflen - length of buffer */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls,
+ uchar priority_msg, iucv_array_t * buffer, ulong buflen)
{
-
- struct sk_buff *skb;
- struct iucv_priv *privptr = (struct iucv_priv *)dev->priv;
-
+ iparml_db parm;
+ ulong b2f0_result;
#ifdef DEBUG
- printk( "iucv: iucv_rx len: %X, device %s\n",len,dev->name);
- printk( "iucv rx: received orig:\n");
- dumpit(buf,len);
+ printk (KERN_DEBUG "entering iucv_reply_array\n");
#endif
-
- /* strip iucv header now */
- len = len - 2; /* short header */
- buf = buf + 2; /* short header */
-
- skb = dev_alloc_skb(len+2); /* why +2 ? alignment ? */
- if (!skb) {
- printk( "iucv rx: low on mem, returning...\n");
- return;
- }
- skb_reserve(skb, 2); /* align IP on 16B boundary*/
- memcpy(skb_put(skb, len), buf, len);
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
+ parm.iptrgcls = trgcls;
+ parm.ipbfadr2 = (ulong) buffer;
+ parm.ipbfln2f = buflen; /* length of message */
+ parm.ipflags1 |= reply_array; /* reply w/ array */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (reply, &parm);
#ifdef DEBUG
- printk( "iucv rx: data before netif_rx()\n");
- dumpit(buf,len);
+ printk (KERN_DEBUG "exiting iucv_reply_array\n");
#endif
+ return b2f0_result;
+}
- /* Write metadata, and then pass to the receive level */
- skb->mac.raw = skb->data;
- skb->pkt_type = PACKET_HOST;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_IP);
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it*/
- privptr->stats.rx_packets++;
- netif_rx(skb);
-
- return;
-} /* end iucv_rx() */
-
-
-
-
-/*----------------------------*/
-/* handle interrupts */
-/*----------------------------*/
-void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
+/**************************************************************/
+/* Name: iucv_reply_prmmsg */
+/* Purpose: responds to the two-way messages in parameter list */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong, id of message */
+/* trgcls - ulong, target message class */
+/* priority_msg - uchar, flag */
+/* prmmsg - uchar[8], message in parameter list */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls,
+ uchar priority_msg, uchar prmmsg[8])
{
- int rc;
- struct in_device *indev;
- struct in_ifaddr *inaddr;
- unsigned long len=0;
- net_device *dev=0;
- struct iucv_priv *privptr;
- INTERRUPT_T * extern_int_buffer;
- unsigned short iucv_data_len=0;
- unsigned short iucv_next=0;
- unsigned char * rcvptr;
-
- /* get own buffer: */
- extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer;
-
-#ifdef DEBUG
- printk( "iucv: do_iucv_interrupt %x received; pathid: %02X\n",
- extern_int_buffer->iptype,extern_int_buffer->ippathid);
- printk( "iucv: extern_int_buffer:\n");
- dumpit((char *)&extern_int_buffer[0],40);
+ iparml_dpl parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
#endif
-
- if (extern_int_buffer->iptype == 0x01)
- dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
- else
- dev = get_device_from_pathid(extern_int_buffer->ippathid);
-
- if (dev == NULL)
- return;
-
- netif_enter_interrupt(dev); /* lock ! */
- privptr = (struct iucv_priv *)(dev->priv);
-
- switch (extern_int_buffer->iptype)
- {
- case 0x01: /* connection pending ext interrrupt */
-#ifdef DEBUG
- printk( "iucv: connection pending IRQ.\n");
-#endif
-
- rc = iucv_accept(glob_command_buffer,
- extern_int_buffer->ippathid);
- if (rc != 0) {
- printk( "iucv: iucv_accept failed with rc: %X\n",rc);
- iucv_retrieve_buffer(glob_command_buffer);
- break;
- }
-
- privptr->pathid = extern_int_buffer->ippathid;
-
-#ifdef DEBUG
- printk( "iucv: iucv_accept ended with rc: %X\n",rc);
- printk( "iucv: device %s found.\n",dev->name);
-#endif
- break;
-
- case 0x02: /* connection completed ext interrrupt */
- /* set own global IP address */
- /* & set global routing addr */
-#ifdef DEBUG
- printk( "connection completed.\n");
-#endif
-
- if( extern_int_buffer->ipmsgtag !=0)
- {
- /* get ptr's to kernel struct with local & broadcast address */
- indev = dev->ip_ptr;
- inaddr = (struct in_ifaddr*) indev->ifa_list;
- }
- break;
-
-
- case 0x03: /* connection severed ext interrrupt */
- /* we do not handle this one at this time */
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
+ parm.iptrgcls = trgcls;
+ memcpy (parm.iprmmsg, prmmsg, 8);
+ parm.ipflags1 |= parm_data;
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ b2f0_result = b2f0 (reply, &parm);
#ifdef DEBUG
- printk( "connection severed.\n");
+ printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
#endif
- break;
-
-
- case 0x04: /* connection quiesced ext interrrupt */
- /* we do not handle this one at this time */
+ return b2f0_result;
+}
+
+/**************************************************************/
+/* Name: iucv_connect */
+/* Purpose: establishes an IUCV path to another vm */
+/* Input: pathid - ushort *, pathid returned to user */
+/* msglim - ushort, limit of outstanding messages */
+/* user_data - uchar[16], user data */
+/* userid - uchar[8], user's id */
+/* system_name - uchar[8], system identification */
+/* priority_requested - uchar- flag */
+/* prmdata - uchar, flag prgrm can handler messages */
+/* in parameter list */
+/* quiesce - uchar, flag to quiesce a path being establ */
+/* control - uchar, flag, option not used */
+/* local - uchar, flag, establish connection only on */
+/* local system */
+/* priority_permitted - uchar *, flag returned to user */
+/* handle - address of handler */
+/* pgm_data - ulong */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16],
+ uchar userid[8], uchar system_name[8],
+ uchar priority_requested, uchar prmdata,
+ uchar quiesce, uchar control,
+ uchar local, uchar * priority_permitted,
+ iucv_handle_t handle, ulong pgm_data)
+{
+ iparml_control parm;
+ ulong b2f0_result;
+ int add_pathid_result, rc;
+ handler *R;
#ifdef DEBUG
- printk( "connection quiesced.\n");
+ printk (KERN_DEBUG "entering iucv_connect\n");
#endif
- break;
-
-
- case 0x05: /* connection resumed ext interrrupt */
- /* we do not handle this one at this time */
+ memset (&parm, 0, sizeof (parm));
+ if (declare_flag == NULL) {
+ rc = iucv_declare_buffer (iucv_external_int_buffer);
+ if (rc) {
+ printk (KERN_DEBUG "IUCV: registration failed\n");
#ifdef DEBUG
- printk( "connection resumed.\n");
+ printk (KERN_DEBUG "rc from declare buffer is: %i\n",
+ rc);
#endif
- break;
-
-
- case 0x06: /* priority message complete ext interrupt */
- case 0x07: /* non priority message complete ext interrupt */
- /* send it to iucv_rx for handling */
+ return rc;
+ } else
+ declare_flag = 1;
+ }
+ /* Checking if handle is valid */
+ spin_lock (&lock);
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ if (R == handle)
+ break;
+ if (R == NULL) {
+ spin_unlock (&lock);
#ifdef DEBUG
- printk( "message completed.\n");
+ printk (KERN_DEBUG "iucv_connect: Invalid Handle\n");
#endif
-
- if (extern_int_buffer->ipaudit ==0) /* ok case */
- {
+ return (-2);
+ }
+ if (pathid == NULL) {
+ spin_unlock (&lock);
#ifdef DEBUG
- printk( "iucv: msg complete interrupt successful, rc: %X\n",
- (unsigned int)extern_int_buffer->ipaudit);
+ printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n");
#endif
- ;
+ return (-3);
}
- else
- {
- printk( "iucv: msg complete interrupt error, rc: %X\n",
- (unsigned int)extern_int_buffer->ipaudit);
+ spin_unlock (&lock);
+ parm.ipmsglim = msglim;
+ memcpy (parm.ipuser, user_data, 16);
+ memcpy (parm.ipvmid, userid, 8);
+ memcpy (parm.iptarget, system_name, 8);
+ if (parm.iptarget)
+ ASCEBC (parm.iptarget, 8);
+ if (parm.ipvmid) {
+ ASCEBC (parm.ipvmid, 8);
+ EBC_TOUPPER(parm.ipvmid, 8);
}
- /* a transmission is over: tell we are no more busy */
- privptr->stats.tx_packets++;
- netif_wake_queue(dev); /* transmission is no longer busy*/
- break;
-
-
- case 0x08: /* priority message pending */
- case 0x09: /* non priority message pending */
-#ifdef DEBUG
- printk( "message pending.\n");
-#endif
- rcvptr = &privptr->receive_buffer[0];
-
- /* re-set receive buffer */
- memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
- len = privptr->receive_buffer_len;
-
- /* get data now */
- if (extern_int_buffer->ipflags1 & 0x80)
- { /* data is in the message */
-#ifdef DEBUG
- printk( "iucv: iucv_receive data is in header!\n");
-#endif
- memcpy(privptr->receive_buffer,
- (char *)extern_int_buffer->iprmmsg1,
- (unsigned long)(extern_int_buffer->iprmmsg2));
- }
- else /* data is in buffer, do a receive */
- {
- rc = iucv_receive(privptr->command_buffer,rcvptr,len);
- if (rc != 0 || len == 0)
- {
- printk( "iucv: iucv_receive failed with rc: %X, length: %lX\n",rc,len);
- iucv_retrieve_buffer(privptr->command_buffer);
- break;
- }
- } /* end else */
-
- iucv_next = 0;
- /* get next packet offset */
- iucv_data_len= *((unsigned short*)rcvptr);
- do{ /* until receive buffer is empty, i.e. iucv_next == 0 ! */
-
- /* get data length: */
- iucv_data_len= iucv_data_len - iucv_next;
-
-#ifdef DEBUG
- printk( "iucv: iucv_receive: len is %02X, last: %02X\n",
- iucv_data_len,iucv_next);
-#endif
- /* transmit upstairs */
- iucv_rx(dev,(iucv_data_len),rcvptr);
-
-#ifdef DEBUG
- printk( "iucv: transaction complete now.\n");
-#endif
- iucv_next = *((unsigned short*)rcvptr);
- rcvptr = rcvptr + iucv_data_len;
- /* get next packet offset */
- iucv_data_len= *((unsigned short*)rcvptr);
-
- } while (iucv_data_len != 0);
- netif_start_queue(dev); /* transmission is no longer busy*/
- break;
-
- default:
- printk( "unknown iucv interrupt \n");
- break;
-
- } /* end switch */
- netif_exit_interrupt(dev); /* release lock*/
-
-#ifdef DEBUG
- printk( "iucv: leaving do_iucv_interrupt.\n");
-#endif
-
-} /* end do_iucv_interrupt() */
-
-
-
-/*-------------------------------------------*/
-/* Transmit a packet (low level interface) */
-/*-------------------------------------------*/
-int iucv_hw_tx(char *send_buf, int len,net_device *dev)
-{
- /* This function deals with hw details. */
- /* This interface strips off the ethernet header details. */
- /* In other words, this function implements the iucv behaviour,*/
- /* while all other procedures are rather device-independent */
- struct iucv_priv *privptr;
- int rc, recv_len=2000;
-
- privptr = (struct iucv_priv *)(dev->priv);
-
-#ifdef DEBUG
- printk( "iucv: iucv_hw_tx, device %s\n",dev->name);
- printk( "iucv: hw_TX_data len: %X\n",len);
- dumpit(send_buf,len);
-#endif
-
- /* I am paranoid. Ain't I? */
- if (len < sizeof(struct iphdr))
- {
- printk( "iucv: Hmm... packet too short (%i octets)\n",len);
- return -EINVAL;
- }
-
- /*
- * build IUCV header (preceeding halfword offset)
- * works as follows: Each packet is preceded by the
- * halfword offset to the next one.
- * The last packet is followed by an offset of zero.
- * E.g., AL2(12),10-byte packet, AL2(34), 32-byte packet, AL2(0)
- */
-
- memcpy(&privptr->send_buffer[2],send_buf,len+2);
- privptr->send_buffer[len+2] = 0;
- privptr->send_buffer[len+3] = 0;
- *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
-
-#ifdef DEBUG
- printk( "iucv: iucv_hw_tx, device %s\n",dev->name);
- printk( "iucv: send len: %X\n",len+4);
- dumpit(privptr->send_buffer,len+4);
-#endif
- *((unsigned short*) &privptr->send_buffer[0]) = len + 2;
-
- /* Ok, now the packet is ready for transmission: send it. */
- if ((rc = iucv_send(privptr->command_buffer,
- privptr->pathid,
- &privptr->send_buffer[0],len+4,
- privptr->recv_buf,recv_len))!=0) {
- printk( "iucv: send_iucv failed, rc: %X\n",rc);
- iucv_retrieve_buffer(privptr->command_buffer);
- }
-#ifdef DEBUG
- printk( "iucv: send_iucv ended, rc: %X\n",rc);
-#endif
- return rc;
-} /* end iucv_hw_tx() */
-
-
-
-
-
-
-/*------------------------------------------*/
-/* Transmit a packet (called by the kernel) */
-/*------------------------------------------*/
-int iucv_tx(struct sk_buff *skb, net_device *dev)
-{
- int retval=0;
-
- struct iucv_priv *privptr;
-
- if (dev == NULL)
- {
- printk("iucv: NULL dev passed\n");
- return 0;
- }
-
- privptr = (struct iucv_priv *) (dev->priv);
-
- if (skb == NULL)
- {
- printk("iucv: %s: NULL buffer passed\n", dev->name);
- privptr->stats.tx_errors++;
- return 0;
- }
-
+ if (priority_requested)
+ parm.ipflags1 |= prior_msg;
+ if (prmdata)
+ parm.ipflags1 |= parm_data; /*data in parameter list */
+ if (quiesce)
+ parm.ipflags1 |= quiesce_msg;
+ if (control) {
+ /* do nothing at the time being */
+ /*control not provided yet */
+ }
+ if (local)
+ parm.ipflags1 |= local_conn; /*connect on local system */
+ b2f0_result = b2f0 (connect, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
+ if (add_pathid_result) {
#ifdef DEBUG
- printk( "iucv: enter iucv_tx, using %s\n",dev->name);
+ printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
#endif
-
- if (netif_is_busy(dev)) /* shouldn't happen */
- {
- privptr->stats.tx_errors++;
- dev_kfree_skb(skb);
- printk("iucv: %s: transmit access conflict ! leaving iucv_tx.\n", dev->name);
- }
-
- netif_stop_queue(dev); /* transmission is busy*/
- dev->trans_start = jiffies; /* save the timestamp*/
-
- /* actual deliver of data is device-specific, and not shown here */
- retval = iucv_hw_tx(skb->data, skb->len, dev);
-
- dev_kfree_skb(skb); /* release it*/
-
+ return (add_pathid_result);
+ }
+ *pathid = parm.ippathid;
+ if (parm.ipflags1 & prior_msg)
+ if (priority_permitted)
+ *priority_permitted = 0x01;
#ifdef DEBUG
- printk( "iucv:leaving iucv_tx, device %s\n",dev->name);
+ printk (KERN_DEBUG "exiting iucv_connect\n");
#endif
+ return b2f0_result;
+}
- return retval; /* zero == done; nonzero == fail*/
-} /* end iucv_tx( struct sk_buff *skb, struct device *dev) */
-
-
-
-
-
-
-/*---------------*/
-/* iucv_release */
-/*---------------*/
-int iucv_release(net_device *dev)
+/**************************************************************/
+/* Name: iucv_accept */
+/* Purpose: completes the iucv communication path */
+/* Input: pathid - ushort , pathid */
+/* msglim - ushort, limit of outstanding messages */
+/* user_data - uchar[16], user data */
+/* priority_requested - uchar- flag */
+/* prmdata - uchar, flag prgrm can handler messages */
+/* in parameter list */
+/* quiesce - uchar, flag to quiesce a path being establ*/
+/* control - uchar, flag, option not used */
+/* priority_permitted -uchar *, flag returned to caller*/
+/* handle - address of handler */
+/* pgm_data - ulong */
+/* Output: iprcode - return code from b2f0 call */
+/**************************************************************/
+int
+iucv_accept (ushort pathid, ushort msglim, uchar user_data[16],
+ uchar priority_requested,
+ uchar prmdata, uchar quiesce, uchar control,
+ uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data)
{
- int rc =0;
- struct iucv_priv *privptr;
- privptr = (struct iucv_priv *) (dev->priv);
-
- netif_stop(dev);
- netif_stop_queue(dev); /* can't transmit any more*/
- rc = iucv_sever(privptr->command_buffer);
- if (rc!=0)
- {
- printk("iucv: %s: iucv_release pending...rc:%02x\n",dev->name,rc);
- }
-
+ ulong index1, index2;
+ handler_table_entry *P = 0;
+ iparml_control parm;
+ ulong b2f0_result;
#ifdef DEBUG
- printk("iucv: iucv_sever ended with rc: %X\n",rc);
+ printk (KERN_DEBUG "entering iucv_accept\n");
#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.ipmsglim = msglim;
+ memcpy (parm.ipuser, user_data, 16);
+ if (priority_requested)
+ parm.ipflags1 |= prior_msg;
+ if (prmdata)
+ parm.ipflags1 |= parm_data; /*data in parameter list */
+ if (quiesce)
+ parm.ipflags1 |= quiesce_msg;
+ if (control) {
+ /* do nothing at the time being */
+ /*control not provided yet */
+ }
+ b2f0_result = b2f0 (accept, &parm);
+ if (b2f0_result)
+ return b2f0_result;
+ index1 = ((ulong) pathid) / 512;
+ index2 = ((ulong) pathid) % 512;
+ spin_lock (&lock);
+ if (pgm_data) {
+ P = main_table[index1];
+ (P + index2)->pgm_data = pgm_data;
+ }
+ spin_unlock (&lock);
+ if (parm.ipflags1 & prior_msg)
+ if (priority_permitted)
+ *priority_permitted = 0x01;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_accept\n");
+#endif
+ return b2f0_result;
+}
- return rc;
-} /* end iucv_release() */
-
-
-
-
-
-/*-----------------------------------------------*/
-/* Configuration changes (passed on by ifconfig) */
-/*-----------------------------------------------*/
-int iucv_config(net_device *dev, struct ifmap *map)
+/**************************************************************/
+/* Name: iucv_send2way_prmmsg_array */
+/* Purpose: sends messages in both directions w/parameter lst */
+/* Input: pathid - ushort, pathid */
+/* msgid - ulong *, id of message returned to caller */
+/* trgcls - ulong, target message class */
+/* srccls - ulong, source message class */
+/* msgtag - ulong, message tag */
+/* priority_msg - uchar, flag */
+/* prmmsg - uchar[8], message being sent in parameter */
+/* ansbuf - pointer to array of buffers */
+/* anslen - length of ansbuf buffer */
+/* Output: iprcode - return code from b2f0 call */
+/* msgid - returns message id */
+/**************************************************************/
+int
+iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid,
+ ulong trgcls, ulong srccls,
+ ulong msgtag, uchar priority_msg,
+ uchar prmmsg[8],
+ iucv_array_t * ansbuf, ulong anslen)
{
- if (dev->flags & IFF_UP) /* can't act on a running interface*/
- return -EBUSY;
-
- /* ignore other fields */
- return 0;
+ iparml_dpl parm;
+ ulong b2f0_result;
+#ifdef DEBUG
+ printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
+#endif
+ memset (&(parm), 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipbfadr2 = (ulong) ansbuf;
+ parm.ipbfln2f = anslen;
+ parm.ipflags1 |= 0x88; /* message in prmlist */
+ if (priority_msg)
+ parm.ipflags1 |= prior_msg; /* priority message */
+ memcpy (parm.iprmmsg, prmmsg, 8);
+ b2f0_result = b2f0 (send, &parm);
+ if (msgid)
+ *msgid = parm.ipmsgid;
+#ifdef DEBUG
+ printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
+#endif
+ return b2f0_result;
}
-/* end iucv_config() */
-
+/******************************************************************/
+/* Name: top_half_handler */
+/* Purpose: handle minimum amount of interrupt in fastest time */
+/* possible and then pass interrupt to bottom half handler. */
+/* Input: external interrupt buffer */
+/* Output: void */
+/******************************************************************/
-
-
-/*----------------*/
-/* Ioctl commands */
-/*----------------*/
-int iucv_ioctl(net_device *dev, struct ifreq *rq, int cmd)
+inline void
+top_half_interrupt (struct pt_regs *regs, __u16 code)
{
-#ifdef DEBUG
- printk( "iucv: device %s; iucv_ioctl\n",dev->name);
+ iucv_packet *pkt;
+ pkt = (iucv_packet *) kmalloc
+ (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC);
+ if (pkt == NULL) {
+ printk (KERN_DEBUG "out of memory\n");
+ return;
+ }
+ memcpy (pkt->data, iucv_external_int_buffer, 40);
+#ifdef DEBUG3
+printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4));
+#endif
+ /* put new packet on the list */
+ spin_lock (&iucv_packets_lock);
+ pkt->next = NULL;
+ if (iucv_packets_tail != NULL)
+ iucv_packets_tail->next = pkt;
+ else
+ iucv_packets_head = pkt;
+ iucv_packets_tail = pkt;
+ spin_unlock (&iucv_packets_lock);
+
+ if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
+#ifdef DEBUG3
+printk (KERN_EMERG "TH: Queuing BH\n");
#endif
- return 0;
+ short_task.routine = (void *) bottom_half_interrupt;
+ queue_task (&short_task, &tq_immediate);
+ mark_bh (IMMEDIATE_BH);
+ }
+ return;
}
-/*---------------------------------*/
-/* Return statistics to the caller */
-/*---------------------------------*/
-struct net_device_stats *iucv_stats(net_device *dev)
+/*******************************************************************/
+/* Name: bottom_half_interrupt */
+/* Purpose: Handle interrupt at a more safer time */
+/* Input: void */
+/* Output: void */
+/*******************************************************************/
+void
+bottom_half_interrupt (void)
{
- struct iucv_priv *priv = (struct iucv_priv *)dev->priv;
-#ifdef DEBUG
- printk( "iucv: device %s; iucv_stats\n",dev->name);
+ iucv_packet *iucv_packet_list;
+ iucv_packet *tmp;
+ ulong flags;
+
+ atomic_set (&bh_scheduled, 0);
+ spin_lock_irqsave (&iucv_packets_lock, flags);
+ iucv_packet_list = iucv_packets_head;
+ iucv_packets_head = iucv_packets_tail = NULL;
+ spin_unlock_irqrestore (&iucv_packets_lock, flags);
+
+ /* now process all the request in the iucv_packet_list */
+#ifdef DEBUG3
+ printk (KERN_EMERG "BH: Process all packets\n");
+#endif
+ while (iucv_packet_list != NULL) {
+#ifdef DEBUG3
+ printk( KERN_EMERG "BH:> %08x\n",
+ *(int *)(iucv_packet_list->data+4));
+#endif
+ do_int ((iucv_ConnectionPending *) iucv_packet_list->data);
+#ifdef DEBUG3
+ printk( KERN_EMERG "BH:< %08x\n",
+ *(int *)(iucv_packet_list->data+4));
+#endif
+ tmp = iucv_packet_list;
+ iucv_packet_list = iucv_packet_list->next;
+ kfree (tmp);
+ }
+#ifdef DEBUG3
+ printk (KERN_EMERG "BH: Done\n");
#endif
- return &priv->stats;
+ return;
}
-
-
-/*
- * iucv_change_mtu
- * IUCV can handle MTU sizes from 576 to approx. 32000
- */
-
-static int iucv_change_mtu(net_device *dev, int new_mtu)
+/*******************************************************************/
+/* Name: do_int */
+/* Purpose: Handle interrupt in a more safe environment */
+/* Inuput: int_buf - pointer to copy of external interrupt buffer */
+/* Output: void */
+/*******************************************************************/
+void
+do_int (iucv_ConnectionPending * int_buf)
{
+ ulong index1 = 0, index2 = 0;
+ handler_table_entry *P = 0; /* P is a pointer */
+ handler *Q = 0, *R; /* Q and R are pointers */
+ iucv_interrupt_ops_t *interrupt = 0; /* interrupt addresses */
+ uchar temp_buff1[24], temp_buff2[24]; /* masked handler id. */
+ int add_pathid_result = 0, j = 0;
+ uchar no_listener[16] = "NO LISTENER";
#ifdef DEBUG
- printk( "iucv: device %s; iucv_change_mtu\n",dev->name);
+ int i;
+ uchar *prt_parm;
#endif
- if ((new_mtu < 64) || (new_mtu > 32000))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-
-
-
-/*--------------------------------------------*/
-/* The init function (sometimes called probe).*/
-/* It is invoked by register_netdev() */
-/*--------------------------------------------*/
-int iucv_init(net_device *dev)
+#ifdef DEBUG3
+ printk (KERN_DEBUG "BH:- Entered do_int "
+ "pathid %d, type %02X\n",
+ int_buf->ippathid, int_buf->iptype);
+#endif
+#ifdef DEBUG
+ prt_parm = (uchar *) (int_buf);
+ printk (KERN_DEBUG "External Interrupt Buffer\n");
+ for (i = 0; i < 40; i++)
+ printk (KERN_DEBUG "%02x ", prt_parm[i]);
+ printk (KERN_DEBUG "\n");
+#endif
+ ASCEBC (no_listener, 16);
+ if (int_buf->iptype != 01) {
+ index1 = ((ulong) (int_buf->ippathid)) / 512;
+ index2 = ((ulong) (int_buf->ippathid)) % 512;
+ spin_lock (&lock);
+
+ P = main_table[index1];
+ Q = (P + index2)->addrs;
+ interrupt = Q->interrupt_table; /* interrupt functions */
+ spin_unlock (&lock);
+#ifdef DEBUG
+ printk (KERN_DEBUG "Handler is: \n");
+ prt_parm = (uchar *) Q;
+ for (i = 0; i < sizeof (handler); i++)
+ printk (KERN_DEBUG " %02x ", prt_parm[i]);
+ printk (KERN_DEBUG "\n");
+#endif
+ } /* end of if statement */
+ switch (int_buf->iptype) {
+ case 0x01: /* connection pending */
+ spin_lock (&lock);
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
+ memcpy (temp_buff1, &(int_buf->ipvmid), 24);
+ memcpy (temp_buff2, &(R->vmid), 24);
+ for (j = 0; j < 24; j++) {
+ temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j];
+ temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j];
+ }
+#ifdef DEBUG
+ for (i = 0; i < sizeof (temp_buff1); i++)
+ printk (KERN_DEBUG " %c ", temp_buff1[i]);
+ printk (KERN_DEBUG "\n");
+ for (i = 0; i < sizeof (temp_buff2); i++)
+ printk (KERN_DEBUG " %c ", temp_buff2[i]);
+ printk (KERN_DEBUG "\n");
+#endif
+ if (memcmp((void *) temp_buff1,
+ (void *) temp_buff2, 24) == 0) {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "found a matching handler\n");
+#endif
+ break;
+ }
+ }
+ spin_unlock (&lock);
+ if (R) {
+ /* ADD PATH TO PATHID TABLE */
+ add_pathid_result =
+ add_pathid (int_buf->ippathid, R, R->pgm_data);
+ if (add_pathid_result == NULL) {
+ interrupt = R->interrupt_table;
+ if ((*interrupt).ConnectionPending) {
+ EBCASC (int_buf->ipvmid, 8);
+
+ ((*interrupt).
+ ConnectionPending) (int_buf,
+ R->pgm_data);
+ } else {
+ iucv_sever (int_buf->ippathid,
+ no_listener);
+ }
+ } /* end if if(add_p...... */
+ else {
+ iucv_sever (int_buf->ippathid, no_listener);
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "add_pathid failed with rc = %d\n",
+ (int) add_pathid_result);
+#endif
+ }
+ } else
+ iucv_sever (int_buf->ippathid, no_listener);
+ break;
+ case 0x02: /*connection complete */
+ if (Q) {
+ if ((*interrupt).ConnectionComplete)
+ ((*interrupt).ConnectionComplete)
+
+ ((iucv_ConnectionComplete *) int_buf,
+ (P + index2)->pgm_data);
+ else {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "ConnectionComplete not called\n");
+ printk (KERN_DEBUG "routine@ is %p\n",
+ (*interrupt).ConnectionComplete);
+#endif
+ }
+ }
+ break;
+ case 0x03: /* connection severed */
+ if (Q) {
+ if ((*interrupt).ConnectionSevered)
+ ((*interrupt).ConnectionSevered)
+
+ ((iucv_ConnectionSevered *) int_buf,
+ (P + index2)->pgm_data);
+ else
+ iucv_sever (int_buf->ippathid, no_listener);
+ } else
+ iucv_sever (int_buf->ippathid, no_listener);
+ break;
+ case 0x04: /* connection quiesced */
+ if (Q) {
+ if ((*interrupt).ConnectionQuiesced)
+ ((*interrupt).ConnectionQuiesced)
+
+ ((iucv_ConnectionQuiesced *) int_buf,
+ (P + index2)->pgm_data);
+ else {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "ConnectionQuiesced not called\n");
+ printk (KERN_DEBUG "routine@ is %p\n",
+ (*interrupt).ConnectionQuiesced);
+#endif
+ }
+ }
+ break;
+ case 0x05: /* connection resumed */
+ if (Q) {
+ if ((*interrupt).ConnectionResumed)
+ ((*interrupt).ConnectionResumed)
+
+ ((iucv_ConnectionResumed *) int_buf,
+ (P + index2)->pgm_data);
+ else {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "ConnectionResumed not called\n");
+ printk (KERN_DEBUG "routine@ is %p\n",
+ (*interrupt).ConnectionResumed);
+#endif
+ }
+ }
+ break;
+ case 0x06: /* priority message complete */
+ case 0x07: /* nonpriority message complete */
+ if (Q) {
+ if ((*interrupt).MessageComplete)
+ ((*interrupt).MessageComplete)
+
+ ((iucv_MessageComplete *) int_buf,
+ (P + index2)->pgm_data);
+ else {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "MessageComplete not called\n");
+ printk (KERN_DEBUG "routine@ is %p\n",
+ (*interrupt).MessageComplete);
+#endif
+ }
+ }
+ break;
+ case 0x08: /* priority message pending */
+ case 0x09: /* nonpriority message pending */
+ if (Q) {
+ if ((*interrupt).MessagePending)
+ ((*interrupt).MessagePending)
+
+ ((iucv_MessagePending *) int_buf,
+ (P + index2)->pgm_data);
+ else {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "MessagePending not called\n");
+ printk (KERN_DEBUG "routine@ is %p\n",
+ (*interrupt).MessagePending);
+#endif
+ }
+ }
+ break;
+ default: /* unknown iucv type */
+ printk (KERN_DEBUG "unknown iucv interrupt \n");
+ break;
+ } /* end switch */
+#ifdef DEBUG3
+ printk (KERN_DEBUG "BH:- Exiting do_int "
+ "pathid %d, type %02X\n",
+ int_buf->ippathid, int_buf->iptype);
+#endif
+ return;
+} /* end of function call */
+
+/**************************************************************/
+/* Name: iucv_register_program */
+/* Purpose: registers a new handler */
+/* Input: pgmname- uchar[16], user id */
+/* userid - uchar[8], machine id */
+/* prmmask- mask */
+/* ops - pointer to iucv_interrupt_ops buffer */
+/* Output: new_handler - address of new handler */
+/**************************************************************/
+iucv_handle_t
+iucv_register_program (uchar pgmname[16],
+ uchar userid[8],
+ uchar pgmmask[24],
+ iucv_interrupt_ops_t * ops, ulong pgm_data)
{
- int rc;
- struct iucv_priv *privptr;
-
+ int rc;
+ handler *new_handler = 0;
#ifdef DEBUG
- printk( "iucv: iucv_init, device: %s\n",dev->name);
+ int i;
+ uchar *prt_parm;
+ printk (KERN_DEBUG "enter iucv_register_program\n");
#endif
-
- /* request the 0x4000 external interrupt */
- if (register_external_interrupt(0x4000, do_iucv_interrupt) != 0)
- panic("Couldn't request external interrupts 0x4000");
-
- dev->open = iucv_open;
- dev->stop = iucv_release;
- dev->set_config = iucv_config;
- dev->hard_start_xmit = iucv_tx;
- dev->do_ioctl = iucv_ioctl;
- dev->get_stats = iucv_stats;
- dev->change_mtu = iucv_change_mtu;
-
- /* keep the default flags, just add NOARP */
-
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP;
- dev->tx_queue_len = 100;
- dev->flags = IFF_NOARP|IFF_POINTOPOINT;
- dev->mtu = 4092;
-
- dev_init_buffers(dev);
-
- /* Then, allocate the priv field. This encloses the statistics */
- /* and a few private fields.*/
- dev->priv = kmalloc(sizeof(struct iucv_priv), GFP_KERNEL);
- if (dev->priv == NULL){
- printk( "iucv: no memory for dev->priv.\n");
- return -ENOMEM;
- }
- memset(dev->priv, 0, sizeof(struct iucv_priv));
- privptr = (struct iucv_priv *)(dev->priv);
-
-
- privptr->send_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
- if (privptr->send_buffer == NULL) {
- printk(KERN_INFO "%s: could not get pages for send buffer\n",
- dev->name);
- return -ENOMEM;
- }
- memset(privptr->send_buffer, 0, 8*PAGE_SIZE);
- privptr->send_buffer_len=8*PAGE_SIZE;
-
- privptr->receive_buffer = (u8*) __get_free_pages(GFP_KERNEL+GFP_DMA,8);
- if (privptr->receive_buffer == NULL) {
- printk(KERN_INFO "%s: could not get pages for receive buffer\n",
- dev->name);
- return -ENOMEM;
- }
- memset(privptr->receive_buffer, 0, 8*PAGE_SIZE);
- privptr->receive_buffer_len=8*PAGE_SIZE;
-
- /* now use the private fields ... */
- /* init pathid */
- privptr->pathid = -1;
-
- /* init private userid from global userid */
- memcpy(privptr->userid,iucv_userid[dev-iucv_devs],8);
-
-
- /* we can use only ONE buffer for external interrupt ! */
- rc=iucv_declare_buffer(privptr->command_buffer,
- (DCLBFR_T *)iucv_ext_int_buffer);
- if (rc!=0 && rc!=19) /* ignore existing buffer */
- {
- printk( "iucv:iucv_declare failed, rc: %X\n",rc);
- return -ENODEV;
- }
-
- rc = iucv_enable(privptr->command_buffer);
- if (rc!=0)
- {
- printk( "iucv:iucv_enable failed, rc: %x\n",rc);
- iucv_retrieve_buffer(privptr->command_buffer);
- return -ENODEV;
- }
+ my_ops = *ops;
+ /* Allocate handler table */
+ new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+ if (new_handler == NULL) {
#ifdef DEBUG
- printk( "iucv: iucv_init endend OK for device %s.\n",dev->name);
+ printk (KERN_DEBUG
+ "IUCV: returned NULL address for new handle \n");
#endif
- return 0;
-}
-
-
-/*
- * setup iucv devices
- *
- * string passed: iucv=userid1,...,useridn
- */
-#if LINUX_VERSION_CODE>=0x020300
-static int __init iucv_setup(char *str)
-#else
-__initfunc(void iucv_setup(char *str,int *ints))
+ return NULL;
+ }
+ /* fill in handler table */
+ memcpy (new_handler->user_data, pgmname, 16);
+ memcpy (new_handler->vmid, userid, 8);
+ memcpy (new_handler->mask, pgmmask, 24);
+ new_handler->pgm_data = pgm_data;
+ /* Convert from ASCII to EBCDIC */
+ if (new_handler->vmid) {
+ ASCEBC (new_handler->vmid, 8);
+ EBC_TOUPPER(new_handler->vmid, 8);
+ }
+ /* fill in handler table */
+ new_handler->interrupt_table = ops;
+ new_handler->size = ADDED_STOR;
+ /* Allocate storage for pathid table */
+ new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
+ memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
+ if (new_handler->start == NULL) {
+#ifdef DEBUG
+ printk (KERN_DEBUG
+ "IUCV: returned NULL address for pathid table,"
+ " exiting\n");
+#endif
+ return NULL;
+ }
+ new_handler->end = (*new_handler).start + ADDED_STOR;
+ new_handler->next = 0;
+ new_handler->prev = 0;
+ /* Place handler at beginning of chain */
+ spin_lock (&lock);
+ if (handler_anchor == NULL)
+ handler_anchor = new_handler;
+ else {
+ handler_anchor->prev = (ulong *) new_handler;
+ new_handler->next = (ulong *) handler_anchor;
+ handler_anchor = new_handler;
+#ifdef DEBUG
+ printk (KERN_DEBUG "adding a another handler to list\n");
+ printk (KERN_DEBUG "handler_anchor->prev is %p \n",
+ handler_anchor->prev);
+ printk (KERN_DEBUG "new_handler->next is %p \n",
+ new_handler->next);
+ printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
+#endif
+ }
+ spin_unlock (&lock);
+ if (declare_flag == NULL) {
+ rc = iucv_declare_buffer (iucv_external_int_buffer);
+ if (rc == 0) {
+ declare_flag = 1;
+ /* request the 0x4000 external interrupt */
+ rc =
+ register_external_interrupt (0x4000,
+ top_half_interrupt);
+ } else {
+ panic ("Registration failed");
+#ifdef DEBUG
+ printk (KERN_DEBUG "rc from declare buffer is: %i\n",
+ rc);
+#endif
+ }
+ }
+#ifdef DEBUG
+ printk (KERN_DEBUG "address of handle is %p ", new_handler);
+ printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler)));
+ printk (KERN_DEBUG "exit iucv_register_program\n");
+ printk (KERN_DEBUG "main_table is %p \n", main_table);
+ printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
+ printk (KERN_DEBUG "Handler is: \n");
+ prt_parm = (uchar *) new_handler;
+ for (i = 0; i < sizeof (handler); i++)
+ printk (KERN_DEBUG " %02x ", prt_parm[i]);
+ printk (KERN_DEBUG "\n");
#endif
+ return new_handler; /* send buffer address back */
+} /* end of register function */
+
+/**************************************************************/
+/* Name: iucv_unregister */
+/* Purpose: remove handler from chain and sever all paths */
+/* Input: handle - address of handler to be severed */
+/* Output: returns 0 */
+/**************************************************************/
+int
+iucv_unregister (iucv_handle_t handle)
{
- int result=0, i=0,j=0, k=0, device_present=0;
- char *s = str;
- net_device * dev ={0};
-
+ handler *temp_next = 0, *temp_prev = 0;
+ handler *Q = 0, *R;
+ handler_table_entry *H_T_E = 0;
+ ulong *S = 0; /*points to the beginning of block of h_t_e's*/
#ifdef DEBUG
- printk( "iucv: start registering device(s)... \n");
+ printk (KERN_DEBUG "enter iucv_unregister\n");
+ printk (KERN_DEBUG "address of handle is %p ", handle);
+ printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle)));
#endif
-
- /*
- * scan device userids
- */
-
- while(*s != 0x20 && *s != '\0'){
- if(*s == ','){
- /* fill userid up to 8 chars */
- for(k=i;k<8;k++){
- iucv_userid[j][k] = 0x40;
- } /* end for */
- /* new device */
- j++;
- s++; /* ignore current char */
- i=0;
- if (j>MAX_DEVICES) {
- printk("iucv: setup devices: max devices %d reached.\n",
- MAX_DEVICES);
- break;
- } /* end if */
- continue;
- } /* end if */
- iucv_ascii_userid[j][i] = (int)*s;
- iucv_userid[j][i] = _ascebc[(int)*s++];
- i++;
- } /* end while */
-
- /*
- * fill last userid up to 8 chars
- */
- for(k=i;k<8;k++) {
- iucv_userid[j][k] = 0x40;
- }
-
- /*
- * set device name and register
- */
-
- for (k=0;k<=j;k++) {
- memcpy(iucv_devs[k].name, "iucv0", 4);
- dev = &iucv_devs[k];
- dev->name[4] = k + '0';
-
-#ifdef DEBUGX
- printk("iucv: (ASCII- )Userid:%s\n",&iucv_ascii_userid[k][0]);
- printk("iucv: (ASCII-)Userid: ");
- for (i=0;i<8;i++) {
- printk( "%02X ",(int)iucv_ascii_userid[k][i]);
- }
- printk("\n");
- printk("iucv: (EBCDIC-)Userid: ");
- for (i=0;i<8;i++) {
- printk( "%02X ",(int)iucv_userid[k][i]);
- }
- printk("\n");
- printk("iucv: device name :%s\n",iucv_devs[k].name);
+ spin_lock (&lock);
+ Q = (handler *) handle;
+ /*
+ * Checking if handle is still registered: if yes, continue
+ * if not registered, return.
+ */
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ if (Q == R) {
+#ifdef DEBUG
+ printk (KERN_DEBUG "found a matching handler\n");
#endif
-
- if ( (result = register_netdev(iucv_devs + k)) )
- printk("iucv: error %i registering device \"%s\"\n",
- result, iucv_devs[k].name);
- else
- {
- device_present++;
- }
- } /* end for */
-
+ break;
+ }
+ if (!R) {
+ spin_unlock (&lock);
+ return (0);
+ }
+ S = Q->start;
#ifdef DEBUG
- printk( "iucv: end register devices, %d devices present\n",device_present);
+ printk (KERN_DEBUG "Q is handle? %p ", Q);
+ printk (KERN_DEBUG "Q->start is %p ", Q->start);
+ printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start));
+ printk (KERN_DEBUG "Q->end is %p ", Q->end);
+ printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end));
#endif
- /* return device_present ? 0 : -ENODEV; */
-#if LINUX_VERSION_CODE>=0x020300
- return 1;
-#else
- return;
+ while (S < (Q->end)) { /* index thru table */
+ if (*S) {
+ H_T_E = (handler_table_entry *) (*S);
+#ifdef DEBUG
+ printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E);
+ printk (KERN_DEBUG "Address of handle in H_T_E is %p",
+ (H_T_E->addrs));
#endif
-}
-
-#if LINUX_VERSION_CODE>=0x020300
-__setup("iucv=", iucv_setup);
+ if ((H_T_E->addrs) != handle) {
+ spin_unlock (&lock);
+ return (-2); /*handler addresses don't match */
+ } else {
+ spin_unlock (&lock);
+ iucv_sever (H_T_E->pathid, Q->user_data);
+ spin_lock (&lock);
+ }
+ }
+ S++; /* index by size of ulong */
+ }
+ kfree (Q->start);
+ temp_next = (handler *) Q->next; /* address of next handler on list */
+ temp_prev = (handler *) Q->prev; /* address of prev handler on list */
+ if ((temp_next != NULL) & (temp_prev != NULL)) {
+ (*temp_next).prev = (ulong *) temp_prev;
+ (*temp_prev).next = (ulong *) temp_next;
+ } else if ((temp_next != NULL) & (temp_prev == NULL)) {
+ (*temp_next).prev = NULL;
+ handler_anchor = temp_next;
+ } else if ((temp_next == NULL) & (temp_prev != NULL))
+ (*temp_prev).next = NULL;
+ else
+ handler_anchor = NULL;
+ if (handler_anchor == NULL)
+ iucv_retrieve_buffer ();
+ kfree (handle);
+ spin_unlock (&lock);
+#ifdef DEBUG
+ printk (KERN_DEBUG "exit iucv_unregister\n");
#endif
+ return 0;
+}
-
-/*-------------*/
-/* The devices */
-/*-------------*/
-char iucv_names[MAX_DEVICES*8]; /* MAX_DEVICES eight-byte buffers */
-net_device iucv_devs[MAX_DEVICES] = {
- {
- iucv_names, /* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+8,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+16,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+24,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+32,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+40,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+48,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+56,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+64,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- },
- {
- iucv_names+72,/* name -- set at load time */
- 0, 0, 0, 0, /* shmem addresses */
- 0x000, /* ioport */
- 0, /* irq line */
- 0, 0, 0, /* various flags: init to 0 */
- NULL, /* next ptr */
- iucv_init, /* init function, fill other fields with NULL's */
- }
-};
-
+EXPORT_SYMBOL (iucv_accept);
+EXPORT_SYMBOL (iucv_connect);
+EXPORT_SYMBOL (iucv_purge);
+EXPORT_SYMBOL (iucv_query);
+EXPORT_SYMBOL (iucv_quiesce);
+EXPORT_SYMBOL (iucv_receive);
+EXPORT_SYMBOL (iucv_receive_simple);
+EXPORT_SYMBOL (iucv_receive_array);
+EXPORT_SYMBOL (iucv_reject);
+EXPORT_SYMBOL (iucv_reply);
+EXPORT_SYMBOL (iucv_reply_array);
+EXPORT_SYMBOL (iucv_reply_prmmsg);
+EXPORT_SYMBOL (iucv_resume);
+EXPORT_SYMBOL (iucv_send);
+EXPORT_SYMBOL (iucv_send2way);
+EXPORT_SYMBOL (iucv_send2way_array);
+EXPORT_SYMBOL (iucv_send_array);
+EXPORT_SYMBOL (iucv_send2way_prmmsg);
+EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
+EXPORT_SYMBOL (iucv_send_prmmsg);
+EXPORT_SYMBOL (iucv_setmask);
+EXPORT_SYMBOL (iucv_sever);
+EXPORT_SYMBOL (iucv_register_program);
+EXPORT_SYMBOL (iucv_unregister);
--- /dev/null
+/*
+ * drivers/s390/net/netiucv.c
+ * Network driver for VM using iucv
+ *
+ * S/390 version
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Stefan Hegewald <hegewald@de.ibm.com>
+ * Hartmut Penner <hpenner@de.ibm.com>
+ *
+ *
+ * 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * Re-write: Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
+ * Uses iucv.c kernel module for IUCV services.
+ *
+ * --------------------------------------------------------------------------
+ * An IUCV frame consists of one or more packets preceded by a 16-bit
+ * header. The header contains the offset to the next packet header,
+ * measured from the beginning of the _frame_. If zero, there are no more
+ * packets in the frame. Consider a frame which contains a 10-byte packet
+ * followed by a 20-byte packet:
+ * +-----+----------------+-----+----------------------------+-----+
+ * |h'12'| 10-byte packet |h'34'| 20-byte packet |h'00'|
+ * +-----+----------------+-----+----------------------------+-----+
+ * Offset: 0 2 12 14 34
+ *
+ * This means that each header will always have a larger value than the
+ * previous one (except for the final zero header, of course).
+ *
+ * For outbound packets, we send ONE frame per packet. So, our frame is:
+ * AL2(packet length+2), packet, AL2(0)
+ * The maximum packet size is the MTU, so the maximum IUCV frame we send
+ * is MTU+4 bytes.
+ *
+ * For inbound frames, we don't care how long the frame is. We tear apart
+ * the frame, processing packets up to MTU size in length, until no more
+ * packets remain in the frame.
+ *
+ * --------------------------------------------------------------------------
+ * The code uses the 2.3.43 network driver interfaces. If compiled on an
+ * an older level of the kernel, the module provides its own macros.
+ * Doc is in Linux Weekly News (lwn.net) memo from David Miller, 9 Feb 2000.
+ * There are a few other places with 2.3-specific enhancements.
+ *
+ * --------------------------------------------------------------------------
+*/
+//#define DEBUG 1
+
+/* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */
+/* (See bottom of program.) */
+#define MAX_DEVICES 10 /* Allows "iucv0" to "iucv9" */
+#define MAX_VM_MTU 32764 /* 32K IUCV buffer, minus 4 */
+#define MAX_TX_Q 50 /* Maximum pending TX */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+MODULE_AUTHOR
+ ("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)");
+MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s");
+MODULE_PARM_DESC (iucv,
+ "Specify the userids associated with iucv0-iucv9:\n"
+ "iucv=userid1,userid2,...,userid10\n");
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/sched.h> /* task queues */
+#include <linux/malloc.h> /* kmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h> /* mark_bh */
+#include <linux/netdevice.h> /* struct net_device, etc. */
+#include <linux/if_arp.h> /* ARPHRD_SLIP */
+#include <linux/skbuff.h> /* skb */
+#include <linux/init.h> /* __setup() */
+#include <asm/io.h> /* virt_to_phys() */
+#include <asm/string.h> /* memset, memcpy, etc. */
+#include "iucv.h"
+#define min(a,b) (a < b) ? a : b
+
+#ifdef DEBUG
+#undef KERN_INFO
+#undef KERN_DEBUG
+#define KERN_INFO KERN_EMERG
+#define KERN_DEBUG KERN_EMERG
+#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+typedef struct net_device net_device;
+#else
+typedef struct device net_device;
+#endif
+
+static __inline__ int
+netif_is_busy (net_device * dev)
+{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45))
+ return (dev->tbusy);
+#else
+ return (test_bit (LINK_STATE_XOFF, &dev->flags));
+#endif
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,45))
+ /* Provide our own 2.3.45 interfaces */
+#define netif_enter_interrupt(dev) dev->interrupt=1
+#define netif_exit_interrupt(dev) dev->interrupt=0
+#define netif_start(dev) dev->start=1
+#define netif_stop(dev) dev->start=0
+
+static __inline__ void
+netif_stop_queue (net_device * dev)
+{
+ dev->tbusy = 1;
+}
+
+static __inline__ void
+netif_start_queue (net_device * dev)
+{
+ dev->tbusy = 0;
+}
+
+static __inline__ void
+netif_wake_queue (net_device * dev)
+{
+ dev->tbusy = 0;
+ mark_bh (NET_BH);
+}
+
+#else
+ /* As of 2.3.45, we don't do these things anymore */
+#define netif_enter_interrupt(dev)
+#define netif_exit_interrupt(dev)
+#define netif_start(dev)
+#define netif_stop(dev)
+#endif
+
+static int iucv_start (net_device *);
+static int iucv_stop (net_device *);
+static int iucv_change_mtu (net_device *, int);
+static int iucv_init (net_device *);
+static void iucv_rx (net_device *, uchar *, int);
+static int iucv_tx (struct sk_buff *, net_device *);
+
+static void connection_severed (iucv_ConnectionSevered *, ulong);
+static void connection_pending (iucv_ConnectionPending *, ulong);
+static void connection_complete (iucv_ConnectionComplete *, ulong);
+static void message_pending (iucv_MessagePending *, ulong);
+static void send_complete (iucv_MessageComplete *, ulong);
+
+void register_iucv_dev (int, char *);
+
+static iucv_interrupt_ops_t netiucv_ops = {
+ &connection_pending,
+ &connection_complete,
+ &connection_severed,
+ NULL, /* Quiesced */
+ NULL, /* Resumed */
+ &message_pending, /* Message pending */
+ &send_complete /* Message complete */
+};
+
+static char iucv_userid[MAX_DEVICES][8];
+net_device iucv_netdev[MAX_DEVICES];
+static char iucv_names[MAX_DEVICES][8];
+static char eodata[2] = { '\0', '\0' };
+
+/* This structure is private to each device. It contains the */
+/* information necessary to do IUCV operations. */
+struct iucv_priv {
+ struct net_device_stats stats;
+ net_device *dev;
+ iucv_handle_t handle;
+ uchar userid[9]; /* Printable userid */
+ uchar userid2[8]; /* Used for IUCV operations */
+
+ /* Note: atomic_compare_and_swap() return value is backwards */
+ /* from what you might think: FALSE=0=OK, TRUE=1=FAIL */
+ atomic_t state;
+#define FREE 0
+#define CONNECTING 1
+#define CONNECTED 2
+ u16 pathid;
+};
+
+struct iucvtag {
+ iucv_array_t iucvvec[3];
+ u16 framelen;
+ struct sk_buff *skb;
+};
+
+uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
+};
+
+/* This mask means the 16-byte IUCV "magic" and the origin userid must */
+/* match exactly as specified in order to give connection_pending() */
+/* control. */
+const char mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+#ifdef DEBUG
+/*--------------------------*/
+/* Dump buffer formatted */
+/*--------------------------*/
+static void
+dumpit (char *buf, int len)
+{
+ int i;
+ printk (KERN_DEBUG);
+ for (i = 0; i < len; i++) {
+ if (!(i % 32) && i != 0)
+ printk ("\n");
+ else if (!(i % 4) && i != 0)
+ printk (" ");
+ printk ("%02X", buf[i]);
+ }
+ if (len % 32)
+ printk ("\n");
+}
+#endif
+
+/*-----------------------------------------------------------------*/
+/* Open a connection to another Linux or VM TCP/IP stack. */
+/* Called by kernel. */
+/* */
+/* 1. Register a handler. (Up to now, any attempt by another stack */
+/* has been rejected by the IUCV handler.) We give the handler */
+/* the net_device* so that we can locate the dev associated */
+/* with the partner userid if he tries to connect to us or */
+/* if the connection is broken. */
+/* */
+/* 2. Connect to remote stack. If we get a connection pending */
+/* interrupt while we're in the middle of connecting, don't */
+/* worry. VM will sever its and use ours, because the DEVICE */
+/* is defined to be: */
+/* DEVICE devname IUCV 0 0 linuxvm A */
+/* or DEVICE devname IUCV 0 0 linuxvm B */
+/* In EBCDIC, "0" (0xF0) is greater than "A" (0xC1) or "B", so */
+/* win all races. We will sever any connects that occur while */
+/* we are connecting. The "0 0" is where we get iucvMagic from.*/
+/* */
+/* FIXME: If two Linux machines get into this race condition, */
+/* both will sever. Manual intervention required. */
+/* Need a better IUCV "hello"-like function that permits */
+/* some negotiation. But can't do that until VM TCP/IP */
+/* would support it. */
+/* */
+/* 3. Return 0 to indicate device ok. Anything else is an error. */
+/*-----------------------------------------------------------------*/
+static int
+iucv_start (net_device * dev)
+{
+ int rc, i;
+ uchar pri;
+ uchar unused = '\0';
+ struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+
+ pr_debug ("iucv_start(%s)\n", dev->name);
+
+ if (p == NULL) {
+ /* Allocate priv data */
+ p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv),
+ GFP_KERNEL);
+ if (p == NULL) {
+ printk (KERN_CRIT "%s: no memory for dev->priv.\n",
+ dev->name);
+ return -ENOMEM;
+ }
+ memset (p, 0, sizeof (struct iucv_priv));
+ dev->priv = p;
+ p->dev = dev;
+
+ memcpy (p->userid, iucv_userid[dev - iucv_netdev], 8); /* Save userid */
+ memcpy (p->userid2, p->userid, 8); /* Again, with feeling. */
+
+ for (i = 0; i < 8; i++) { /* Change userid to printable form */
+ if (p->userid[i] == ' ') {
+ p->userid[i] = '\0';
+ break;
+ }
+ }
+ p->userid[8] = '\0';
+ atomic_set (&p->state, FREE);
+ p->handle =
+ iucv_register_program (iucvMagic, p->userid2, (char *) mask,
+ &netiucv_ops, (ulong) dev);
+ if (p->handle <= 0) {
+ printk (KERN_ERR
+ "%s: iucv_register_program error, rc=%i\n",
+ dev->name, (int) p->handle);
+ dev->priv = NULL;
+ kfree (p);
+ return -ENODEV;
+ }
+ pr_debug ("state@ = %p\n", &p->state);
+ MOD_INC_USE_COUNT;
+ }
+
+ if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
+ pr_debug ("Other side connecting during start\n");
+ return 0;
+ }
+
+ rc =
+ iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2,
+ iucv_host, unused, unused, unused, unused, unused,
+ &pri, p->handle, (ulong) p);
+
+ /* Some errors are not fatal. In these cases we will report "OK". */
+ switch (rc) {
+ case 0: /* Wait for connection to complete */
+ pr_debug ("...waiting for connection to complete...");
+ return 0;
+ case 11: /* Wait for parter to connect */
+ printk (KERN_NOTICE "Device %s: "
+ "User %s is not available now.\n",
+ dev->name, p->userid);
+ atomic_set (&p->state, FREE);
+ return 0;
+ case 12: /* Wait for partner to connect */
+ printk (KERN_NOTICE "Device %s: "
+ "User %s is not ready to talk now.\n",
+ dev->name, p->userid);
+ atomic_set (&p->state, FREE);
+ return 0;
+ case 13: /* Fatal */
+ printk (KERN_ERR "Device %s: "
+ "You have too many IUCV connections."
+ "Check MAXCONN in CP directory.\n", dev->name);
+ break;
+ case 14: /* Fatal */
+ printk (KERN_ERR "Device %s: "
+ "User %s has too many IUCV connections."
+ "Check MAXCONN in CP directory.\n",
+ dev->name, p->userid);
+ break;
+ case 15: /* Fatal */
+ printk (KERN_ERR "Device %s: "
+ "No IUCV authorization found in CP directory.\n",
+ dev->name);
+ break;
+ default: /* Really fatal! Should not occur!! */
+ printk (KERN_ERR "%s: "
+ "return code %i from iucv_connect()\n", dev->name, rc);
+ }
+
+ rc = iucv_unregister (p->handle);
+ dev->priv = NULL;
+ kfree (p);
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+} /* end iucv_start() */
+
+/*********************************************************************/
+/* Our connection TO another stack has been accepted. */
+/*********************************************************************/
+static void
+connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
+{
+ struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+ pr_debug ("...%s connection complete... txq=%u\n",
+ p->dev->name, cci->ipmsglim);
+ atomic_set (&p->state, CONNECTED);
+ p->pathid = cci->ippathid;
+ p->dev->tx_queue_len = cci->ipmsglim;
+ netif_start (p->dev);
+ netif_start_queue (p->dev);
+ printk (KERN_INFO "%s: Connection to user %s is up\n",
+ p->dev->name, p->userid);
+} /* end connection_complete() */
+
+/*********************************************************************/
+/* A connection FROM another stack is pending. If we are in the */
+/* middle of connecting, sever the new connection. */
+/* */
+/* We only get here if we've done an iucv_register(), so we know */
+/* the remote user is the correct user. */
+/*********************************************************************/
+static void
+connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
+{
+ /* Only get this far if handler is set up, so we know userid is ok. */
+ /* and the device is started. */
+ /* pgm_data is different for this one. We get dev*, not priv*. */
+ net_device *dev = (net_device *) pgm_data;
+ struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+ int rc;
+ uchar udata[16];
+ uchar no = '\0';
+ uchar na;
+
+ /* If we're not waiting on a connect, reject the connection */
+ if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
+ iucv_sever (cpi->ippathid, udata);
+ return;
+ }
+
+ rc = iucv_accept (cpi->ippathid, /* Path id */
+ MAX_TX_Q, /* msglimit */
+ udata, /* user_Data */
+ no, /* will we send priority msgs? */
+ no, /* do we accept prmdata? */
+ no, /* quiece immediately? */
+ no, /* control path? */
+ &na, /* other side accept prmdata? */
+ p->handle, /* registration handle */
+ (ulong) p); /* private data */
+ if (rc != 0) {
+ atomic_set (&p->state, FREE);
+ printk (KERN_ERR "%s: iucv accept failed rc=%i\n",
+ p->dev->name, rc);
+ } else {
+ p->pathid = cpi->ippathid;
+ p->dev->tx_queue_len = cpi->ipmsglim;
+ netif_start (p->dev);
+ netif_start_queue (p->dev);
+ atomic_set (&p->state, CONNECTED);
+ printk (KERN_INFO "Device %s: Connection to user %s is up\n",
+ p->dev->name, p->userid);
+ }
+} /* end connection_pending() */
+
+/*********************************************************************/
+/* Our connection to another stack has been severed. */
+/*********************************************************************/
+static void
+connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data)
+{
+ struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+
+ printk (KERN_INFO "%s: Connection to user %s is down\n",
+ p->dev->name, p->userid);
+
+ if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0)
+ return; /* In case reconnect in progress already */
+
+ netif_stop_queue (p->dev);
+ netif_stop (p->dev);
+} /* end connection_severed() */
+
+/*-----------------------------------------------------*/
+/* STOP device. Called by kernel. */
+/*-----------------------------------------------------*/
+static int
+iucv_stop (net_device * dev)
+{
+ int rc = 0;
+ struct iucv_priv *p;
+ pr_debug ("%s: iucv_stop\n", dev->name);
+
+ netif_stop_queue (dev);
+ netif_stop (dev);
+
+ p = (struct iucv_priv *) (dev->priv);
+ if (p == NULL)
+ return 0;
+
+ rc = iucv_unregister (p->handle); /* Will sever connections */
+ dev->priv = NULL;
+ kfree (p);
+ MOD_DEC_USE_COUNT;
+ return 0;
+} /* end iucv_stop() */
+
+/*---------------------------------------------------------------------*/
+/* Inbound packets from other host are ready for receipt. Receive */
+/* them (they arrive as a single transmission), break them up into */
+/* separate packets, and send them to the "generic" packet processor. */
+/*---------------------------------------------------------------------*/
+static void
+message_pending (iucv_MessagePending * mpi, ulong pgm_data)
+{
+ struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+ int rc;
+ u32 buffer_length;
+ u16 packet_offset, prev_offset = 0;
+ void *buffer;
+
+ buffer_length = mpi->ln1msg2.ipbfln1f;
+ pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
+ buffer_length);
+
+ buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA);
+ if (buffer == NULL) {
+ p->stats.rx_dropped++;
+ return;
+ }
+
+ rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
+ buffer, buffer_length);
+
+ if (rc != 0 || buffer_length < 5) {
+ printk (KERN_INFO
+ "%s: iucv_receive error. rc=%X, length=%u\n",
+ p->dev->name, rc, buffer_length);
+ p->stats.rx_errors++;
+ kfree (buffer);
+ return;
+ }
+
+ packet_offset = *((u16 *) buffer);
+
+ while (packet_offset != 0) {
+ if (packet_offset <= prev_offset
+ || packet_offset > buffer_length - 2) {
+ printk (KERN_INFO "%s: bad inbound packet offset %u, "
+ "prev %u, total %u\n", p->dev->name,
+ packet_offset, prev_offset, buffer_length);
+ p->stats.rx_errors++;
+ break;
+ } else {
+ /* Kick the packet upstairs */
+ iucv_rx (p->dev,
+ buffer + prev_offset + 2,
+ packet_offset - prev_offset - 2);
+ prev_offset = packet_offset;
+ packet_offset = *((u16 *) (buffer + packet_offset));
+ }
+ }
+
+ kfree (buffer);
+ return;
+} /* end message_pending() */
+
+/*-------------------------------------------------------------*/
+/* Add meta-data to packet and send upstairs. */
+/*-------------------------------------------------------------*/
+static void
+iucv_rx (net_device * dev, uchar * buf, int len)
+{
+ struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+ struct sk_buff *skb;
+
+ pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len);
+#ifdef DEBUG
+ dumpit (buf, 20);
+#endif
+
+ if (len > p->dev->mtu) {
+ printk (KERN_INFO
+ "%s: inbound packet length %u exceeds MTU %i\n",
+ p->dev->name, len, p->dev->mtu);
+ p->stats.rx_errors++;
+ return;
+ }
+
+ skb = dev_alloc_skb (len);
+ if (!skb) {
+ p->stats.rx_dropped++;
+ return;
+ }
+
+ /* If not enough room, skb_put will panic */
+ memcpy (skb_put (skb, len), buf, len);
+
+ /* Write metadata, and then pass to the receive level. Since we */
+ /* are not an Ethernet device, we have special fields to set. */
+ /* This is all boilerplace, not to be messed with. */
+ skb->dev = p->dev; /* Set device */
+ skb->mac.raw = skb->data; /* Point to packet */
+ skb->pkt_type = PACKET_HOST; /* ..for this host. */
+ skb->protocol = htons (ETH_P_IP); /* IP packet */
+ skb->ip_summed = CHECKSUM_UNNECESSARY; /* No checksum */
+ p->stats.rx_packets++;
+ p->stats.rx_bytes += len;
+ netif_rx (skb);
+
+ return;
+} /* end iucv_rx() */
+
+/*-------------------------------------------------------------*/
+/* TRANSMIT a packet. Called by kernel. */
+/* This function deals with hw details of packet transmission. */
+/*-------------------------------------------------------------*/
+static int
+iucv_tx (struct sk_buff *skb, net_device * dev)
+{
+ int rc, pktlen;
+ struct iucvtag *tag;
+ struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+
+ if (skb == NULL) /* Nothing to do */
+ return 0;
+
+ if (netif_is_busy (dev)) {
+ p->stats.tx_dropped++;
+ dev_kfree_skb (skb);
+ printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n",
+ dev->name);
+ return -EBUSY;
+ }
+
+ netif_stop_queue (dev); /* transmission is busy */
+
+ dev->trans_start = jiffies; /* save the timestamp */
+
+ /* Tag contains data that must survive exit from this */
+ /* routine. MessageComplete exit will free the tag */
+ /* and any structures it points to. */
+ tag =
+ (struct iucvtag *) kmalloc (sizeof (struct iucvtag),
+ GFP_DMA | GFP_KERNEL);
+ if (!tag) {
+ p->stats.tx_dropped++;
+ dev_kfree_skb (skb);
+ return -ENOMEM;
+ }
+
+ pktlen = skb->len;
+ tag->framelen = (u16) pktlen + 2;
+ tag->skb = skb;
+ tag->iucvvec[0].address = &tag->framelen;
+ tag->iucvvec[0].length = 2;
+ tag->iucvvec[1].address = (void *) virt_to_phys (skb->data);
+ tag->iucvvec[1].length = pktlen;
+ tag->iucvvec[2].address = (void *) virt_to_phys (eodata);
+ tag->iucvvec[2].length = 2;
+ pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag);
+
+ /* Ok, now the packet is ready for transmission: send it. */
+ rc =
+ iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0,
+ tag->iucvvec, pktlen + 4);
+ if (rc == 0)
+ p->stats.tx_packets++;
+ else {
+ if (rc == 3) /* Exceeded MSGLIMIT */
+ p->stats.tx_dropped++;
+ else {
+ p->stats.tx_errors++;
+ printk (KERN_INFO "%s: iucv send failed, rc=%i\n",
+ p->dev->name, rc);
+ }
+ dev_kfree_skb (skb);
+ kfree (tag);
+ }
+
+ netif_wake_queue (p->dev);
+ return rc; /* zero == done; nonzero == fail */
+} /* end iucv_tx() */
+
+/*-----------------------------------------------------------*/
+/* SEND COMPLETE Called by IUCV handler. */
+/* Free SKB associated with this transmission and free */
+/* the IUCV buffer list and SKB pointer. */
+/*-----------------------------------------------------------*/
+static void
+send_complete (iucv_MessageComplete * mci, ulong pgm_data)
+{
+ struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag;
+ pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb);
+ dev_kfree_skb (tag->skb);
+ kfree (tag);
+} /* end send_complete() */
+
+/*-----------------------------------------------------------*/
+/* STATISTICS reporting. Called by kernel. */
+/*-----------------------------------------------------------*/
+static struct net_device_stats *
+iucv_stats (net_device * dev)
+{
+ struct iucv_priv *p = (struct iucv_priv *) dev->priv;
+ return &p->stats;
+} /* end iucv_stats() */
+
+/*-----------------------------------------------------------*/
+/* MTU change . Called by kernel. */
+/* IUCV can handle mtu sizes from 576 (the IP architectural */
+/* minimum) up to maximum supported by VM. I don't think IP */
+/* pays attention to new mtu until device is restarted. */
+/*-----------------------------------------------------------*/
+static int
+iucv_change_mtu (net_device * dev, int new_mtu)
+{
+ if ((new_mtu < 576) || (new_mtu > MAX_VM_MTU))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+} /* end iucv_change_mtu() */
+
+/*-----------------------------------------------------------*/
+/* INIT device. Called by kernel. */
+/* Called by register_netdev() in kernel. */
+/*-----------------------------------------------------------*/
+static int
+iucv_init (net_device * dev)
+{
+ dev->open = iucv_start;
+ dev->stop = iucv_stop;
+ dev->hard_start_xmit = iucv_tx;
+ dev->get_stats = iucv_stats;
+ dev->change_mtu = iucv_change_mtu;
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = MAX_TX_Q; /* Default - updated based on IUCV */
+ /* keep the default flags, just add NOARP and POINTOPOINT */
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ dev->mtu = 9216;
+
+ dev_init_buffers (dev);
+ pr_debug ("%s: iucv_init dev@=%p\n", dev->name, dev);
+ return 0;
+}
+
+#ifndef MODULE
+/*-----------------------------------------------------------------*/
+/* Process iucv=userid1,...,useridn kernel parameter. */
+/* */
+/* Each user id provided will be associated with device 'iucvnn'. */
+/* iucv_init will be called to initialize each device. */
+/*-----------------------------------------------------------------*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#define init_return(a) return a
+static int __init
+iucv_setup (char *iucv)
+#else
+#define init_return(a) return
+__initfunc (void iucv_setup (char *iucv, int *ints))
+#endif
+{
+ int i, devnumber;
+ char *s;
+ char temp_userid[9];
+
+ i = devnumber = 0;
+ memset (temp_userid, ' ', 8);
+ temp_userid[8] = '\0';
+
+ if (!iucv)
+ init_return (0);
+
+ for (s = iucv; *s != '\0'; s++) {
+ if (*s == ' ') /* Compress out blanks */
+ continue;
+
+ if (devnumber >= MAX_DEVICES) {
+ printk (KERN_ERR "More than %i IUCV hosts specified\n",
+ MAX_DEVICES);
+ init_return (-ENODEV);
+ }
+
+ if (*s != ',') {
+ temp_userid[i++] = *s;
+
+ if (i == 8 || *(s + 1) == ',' || *(s + 1) == '\0') {
+ register_iucv_dev (devnumber, temp_userid);
+ devnumber++;
+ i = 0;
+ memset (temp_userid, ' ', 8);
+ if (*(s + 1) != '\0')
+ *(s + 1) = ' ';
+ }
+ }
+ } /* while */
+
+ init_return (1);
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+__setup ("iucv=", iucv_setup);
+#endif
+#else /* BUILT AS MODULE */
+/*-------------------------------------------------------------------*/
+/* Process iucv=userid1,...,useridn module paramter. */
+/* */
+/* insmod passes the module an array of string pointers, each of */
+/* which points to a userid. The commas are stripped out by insmod. */
+/* MODULE_PARM defines the name of the array. (See start of module.)*/
+/* */
+/* Each user id provided will be associated with device 'iucvnn'. */
+/* iucv_init will be called to initialize each device. */
+/*-------------------------------------------------------------------*/
+char *iucv[MAX_DEVICES] = { NULL };
+int
+init_module (void)
+{
+ int i;
+ for (i = 0; i < MAX_DEVICES; i++) {
+ if (iucv[i] == NULL)
+ break;
+ register_iucv_dev (i, iucv[i]);
+ }
+ return 0;
+}
+
+void
+cleanup_module (void)
+{
+ int i;
+ for (i = 0; i < MAX_DEVICES; i++) {
+ if (iucv[i])
+ unregister_netdev (&iucv_netdev[i]);
+ }
+ return;
+}
+#endif /* MODULE */
+
+void
+register_iucv_dev (int devnumber, char *userid)
+{
+ int rc;
+ net_device *dev;
+
+ memset (iucv_userid[devnumber], ' ', 8);
+ memcpy (iucv_userid[devnumber], userid, min (strlen (userid), 8));
+ dev = &iucv_netdev[devnumber];
+ sprintf (dev->name, "iucv%i", devnumber);
+
+ pr_debug ("netiucv: registering %s\n", dev->name);
+
+ if ((rc = register_netdev (dev))) {
+ printk (KERN_ERR
+ "netiucv: register_netdev(%s) error %i\n",
+ dev->name, rc);
+ }
+ return;
+}
+
+/* These structures are static because setup() can be called very */
+/* early in kernel init if this module is built into the kernel. */
+/* Certainly no kmalloc() is available, probably no C runtime. */
+/* If support changed to be module only, this can all be done */
+/* dynamically. */
+static char iucv_names[MAX_DEVICES][8]; /* Allows "iucvXXX" plus null */
+net_device iucv_netdev[MAX_DEVICES] = {
+ {
+ &iucv_names[0][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[1][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[2][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[3][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[4][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[5][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[6][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[7][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[8][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ },
+ {
+ &iucv_names[9][0], /* Name filled in at load time */
+ 0, 0, 0, 0, /* shmem addresses */
+ 0x0000, /* I/O port */
+ 0, /* irq line */
+ 0, 0, 0, /* flags */
+ NULL, /* next device in list */
+ iucv_init, /* probe function, rest to null */
+ }
+};