File: /usr/src/linux/drivers/s390/net/iucv.c

1     /*                                                                                             
2      *   drivers/s390/net/iucv.c
3      *    Support for VM IUCV functions for use by other part of the
4      *    kernel or loadable modules.
5      *
6      *  S390 version
7      *    Copyright (C) 2000 IBM Corporation
8      *    Author(s): Alan Altmark (Alan_Altmark@us.ibm.com)
9      *               Xenia Tkatschow (xenia@us.ibm.com)
10      * Functionality:                                                    
11      * To explore any of the IUCV functions, one must first register     
12      * their program using iucv_register(). Once your program has        
13      * successfully completed a register, it can use the other functions.
14      * For furthur reference on all IUCV functionality, refer to the     
15      * CP Programming Services book, also available on the web            
16      * thru www.ibm.com/s390/vm/pubs , manual # SC24-5760.               
17      *                                                                    
18      *      Definition of Return Codes                                    
19      *      -All positive return codes including zero are reflected back 
20      *       from CP and the definition can be found in CP Programming    
21      *       Services book.                  
22      *      - (-ENOMEM) Out of memory
23      *      - (-EINVAL) Invalid value                             
24     */
25     /* #define DEBUG 1 */
26     #include <linux/module.h>
27     #include <linux/config.h>
28     #include <linux/version.h>
29     #include <linux/spinlock.h>
30     #include <linux/kernel.h>
31     #include <linux/malloc.h>
32     #include <linux/init.h>
33     #include <linux/tqueue.h>
34     #include <linux/interrupt.h>
35     #include <asm/atomic.h>
36     #include "iucv.h"
37     #include <asm/io.h>
38     #include <asm/irq.h>
39     #include <asm/s390_ext.h>
40     #include <asm/ebcdic.h>
41     
42     #ifdef DEBUG
43     #undef KERN_INFO
44     #undef KERN_DEBUG
45     #define KERN_INFO KERN_EMERG
46     #define KERN_DEBUG KERN_EMERG
47     #endif
48     
49     #undef NULL
50     #define NULL 0
51     
52     #define PRRTY_PRMTD    0x01	/* priority permitted */
53     #define RPY_RQRD       0x01	/* reply required */
54     #define ADDED_STOR  64		/* ADDITIONAL STORAGE FOR PATHID @'S */
55     #define BUFFER_SIZE 40		/* Size of 31-bit iparml */
56     
57     /* FLAGS:
58      * All flags are defined in the field IPFLAGS1 of each function
59      * and can be found in CP Programming Services.
60      * IPSRCCLS - Indicates you have specified a source class
61      * IPFGMCL  - Indicates you have specified a target class
62      * IPFGPID  - Indicates you have specified a pathid
63      * IPFGMID  - Indicates you have specified a message ID
64      * IPANSLST - Indicates that you are using an address list for
65      *            reply data
66      * IPBUFLST - Indicates that you are using an address list for
67      *            message data
68      */
69     
70     #define IPSRCCLS 	0x01
71     #define IPFGMCL         0x01
72     #define IPFGPID         0x02
73     #define IPFGMID         0x04
74     #define IPANSLST        0x08
75     #define IPBUFLST        0x40
76     
77     static uchar iucv_external_int_buffer[40];
78     
79     /* Spin Lock declaration */
80     struct tq_struct short_task;	/* automatically initialized to zero */
81     static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;
82     
83     /* General IUCV interrupt structure */
84     typedef struct {
85     	u16 ippathid;
86     	uchar res1;
87     	uchar iptype;
88     	u32 res2;
89     	uchar ipvmid[8];
90     	uchar res3[24];
91     } iucv_GeneralInterrupt;
92     
93     /***************INTERRUPT HANDLING DEFINITIONS***************/
94     typedef struct _iucv_packet {
95     	struct _iucv_packet *next;
96     	uchar data[40];
97     } iucv_packet;
98     struct tq_struct short_task;
99     
100     static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
101     
102     iucv_packet *iucv_packets_head, *iucv_packets_tail;
103     
104     static atomic_t bh_scheduled = ATOMIC_INIT (0);
105     
106     /* 
107      *Internal function prototypes 
108      */
109     
110     static ulong iucv_vmsize (void);
111     
112     int iucv_declare_buffer (void);
113     
114     int iucv_retrieve_buffer (void);
115     
116     static int iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data);
117     
118     static void iucv_remove_pathid (u16 pathid);
119     
120     void bottom_half_interrupt (void);
121     
122     static void do_int (iucv_GeneralInterrupt *);
123     
124     inline void top_half_interrupt (struct pt_regs *regs, __u16 code);
125     /************FUNCTION ID'S****************************/
126     
127     #define ACCEPT          10
128     #define CONNECT         11
129     #define DECLARE_BUFFER  12
130     #define PURGE           9
131     #define QUERY           0
132     #define QUIESCE         13
133     #define RECEIVE         5
134     #define REJECT          8
135     #define REPLY           6
136     #define RESUME          14
137     #define RETRIEVE_BUFFER 2
138     #define SEND            4
139     #define SETMASK         16
140     #define SEVER           15
141     
142     /*                                                               
143      * Structure: handler                                            
144      * members: next - is a pointer to next handler on chain         
145      *          prev - is a pointer to prev handler on chain         
146      *          structure: id                                        
147      *             vmid - 8 char array of machine identification     
148      *             user_data - 16 char array for user identification 
149      *             mask - 24 char array used to compare the 2 previous  
150      *          interrupt_table - vector of interrupt functions.     
151      *          pathid_head - pointer to start of user_pathid_table  
152      *          pathid_tail - pointer to end of user_pathid_table    
153      *          entries -  ulong, size of user_pathid_table          
154      *          pgm_data -  ulong, application data that is passed   
155      *                      to the interrupt handlers                
156     */
157     typedef struct {
158     	ulong *next;
159     	ulong *prev;
160     	struct {
161     		uchar userid[8];
162     		uchar user_data[16];
163     		uchar mask[24];
164     	} id;
165     	iucv_interrupt_ops_t *interrupt_table;
166     	ulong *pathid_head;
167     	ulong *pathid_tail;
168     	ulong entries;
169     	void *pgm_data;
170     } handler;
171     
172     /*                                                         
173      * Structure: handler_table_entry                          
174      * members: addrs - pointer to a handler                   
175      *          pathid - ushort containing path identification 
176      *          pgm_data - ulong, application data that is     
177      *                     passed to the interrupt handlers    
178      *          ops - pointer to iucv interrupt vector         
179      */
180     
181     typedef struct {
182     	handler *addrs;
183     	u16 pathid;
184     	void *pgm_data;
185     	iucv_interrupt_ops_t *ops;
186     } handler_table_entry;
187     
188     /* 
189      * Internal function prototypes 
190      */
191     
192     static int iucv_add_handler (handler * new_handler);
193     
194     static void iucv_remove_handler (handler * users_handler);
195     
196     /* handler_anchor: points to first handler on chain */
197     /* handler_tail: points to last handler on chain */
198     /* handler_table_anchor: points to beginning of handler_table_entries*/
199     
200     static handler *handler_anchor = NULL;
201     
202     static handler *handler_tail = NULL;
203     
204     static handler_table_entry *handler_table_anchor = NULL;
205     
206     /* declare_flag: is 0 when iucv_declare_buffer has not been called */
207     
208     static ulong declare_flag = 0;
209     
210     /****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
211     /* Data struct 1: iparml_control                                      
212      * Used for iucv_accept                                               
213      *          iucv_connect                                              
214      *          iucv_quiesce                                              
215      *          iucv_resume                                               
216      *          iucv_sever                                                
217      *          iucv_retrieve_buffer                                      
218      * Data struct 2: iparml_dpl     (data in parameter list)             
219      * Used for iucv_send_prmmsg                                          
220      *          iucv_send2way_prmmsg                                      
221      *          iucv_send2way_prmmsg_array                                
222      *          iucv_reply_prmmsg                                         
223      * Data struct 3: iparml_db       (data in a buffer)                  
224      * Used for iucv_receive                                              
225      *          iucv_receive_array                                        
226      *          iucv_reject                                               
227      *          iucv_reply                                                
228      *          iucv_reply_array                
229      *          iucv_send                       
230      *          iucv_send_array                 
231      *          iucv_send2way                   
232      *          iucv_send2way_array             
233      *          iucv_declare_buffer             
234      * Data struct 4: iparml_purge              
235      * Used for iucv_purge                      
236      *          iucv_query                      
237      * Data struct 5: iparml_set_mask           
238      * Used for iucv_set_mask                   
239     */
240     
241     typedef struct {
242     	u16 ippathid;
243     	uchar ipflags1;
244     	uchar iprcode;
245     	u16 ipmsglim;
246     	u16 res1;
247     	uchar ipvmid[8];
248     	uchar ipuser[16];
249     	uchar iptarget[8];
250     } iparml_control;
251     
252     typedef struct {
253     	u16 ippathid;
254     	uchar ipflags1;
255     	uchar iprcode;
256     	u32 ipmsgid;
257     	u32 iptrgcls;
258     	uchar iprmmsg[8];
259     	u32 ipsrccls;
260     	u32 ipmsgtag;
261     	u32 ipbfadr2;
262     	u32 ipbfln2f;
263     	u32 res;
264     } iparml_dpl;
265     
266     typedef struct {
267     	u16 ippathid;
268     	uchar ipflags1;
269     	uchar iprcode;
270     	u32 ipmsgid;
271     	u32 iptrgcls;
272     	u32 ipbfadr1;
273     	u32 ipbfln1f;
274     	u32 ipsrccls;
275     	u32 ipmsgtag;
276     	u32 ipbfadr2;
277     	u32 ipbfln2f;
278     	u32 res;
279     } iparml_db;
280     
281     typedef struct {
282     	u16 ippathid;
283     	uchar ipflags1;
284     	uchar iprcode;
285     	u32 ipmsgid;
286     	uchar ipaudit[3];
287     	uchar res1[5];
288     	u32 res2;
289     	u32 ipsrccls;
290     	u32 ipmsgtag;
291     	u32 res3[3];
292     } iparml_purge;
293     
294     typedef struct {
295     	uchar ipmask;
296     	uchar res1[2];
297     	uchar iprcode;
298     	u32 res2[9];
299     } iparml_set_mask;
300     
301     /*********************INTERNAL FUNCTIONS*****************************/
302     
303     static ulong
304     iucv_vmsize (void)
305     {
306     	extern unsigned long memory_size;
307     	return memory_size;
308     }
309     
310     /*
311      * Name: dumpit                                                     
312      * Purpose: print to the console buffers of a given length          
313      * Input: buf - (* uchar) - pointer to buffer to be printed         
314      *        len - int - length of buffer being printed                
315      * Output: void                                                     
316      */
317     
318     #ifdef DEBUG
319     
320     static void
321     iucv_dumpit (uchar * buf, int len)
322     {
323     	int i;
324     	for (i = 0; i < len; i++) {
325     		if (!(i % 16) && i != 0)
326     			printk ("\n");
327     		else if (!(i % 4) && i != 0)
328     			printk (" ");
329     		printk ("%02X", buf[i]);
330     	}
331     	if (len % 16)
332     		printk ("\n");
333     	return;
334     }
335     
336     #else
337     static void
338     iucv_dumpit (uchar * buf, int len)
339     {
340     }
341     
342     #endif
343     
344     /*
345      * Name iucv_add_handler
346      * Purpose: Place new handle on handler_anchor chain, if identical handler is not
347      *	    found. Handlers are ordered with largest mask integer value first.
348      * Input: new_handler - handle that is being entered into chain
349      * Return: int
350      *	   0 - handler added
351      *	   1 - identical handler found, handler not added to chain
352     */
353     int
354     iucv_add_handler (handler * new_handler)
355     {
356     	handler *R = new_handler;
357     	int rc = 1, comp = 0;	/* return code (rc = 1 not added) or (rc = 0 added) */
358     	ulong flags;
359     	pr_debug ("iucv_add_handler: entering\n");
360     	iucv_dumpit ((uchar *) new_handler, sizeof (handler));
361     	spin_lock_irqsave (&iucv_lock, flags);
362     	if (handler_anchor == NULL) {
363     		/* add to beginning of chain */
364     		handler_anchor = handler_tail = new_handler;
365     		rc = 0;
366     	} else
367     		for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
368     			comp = memcmp ((void *) &(new_handler->id),
369     				       (void *) &(R->id), sizeof (R->id));
370     			pr_debug ("comp = %d\n", comp);
371     			if (comp == 0)	/* identicle handler found */
372     				break;	/* break out of for loop */
373     			else if (comp > 0) {	/* new_handler > R */
374     				pr_debug
375     				    ("iucv_add_handler: Found a place to add,"
376     				     "R is\n");
377     				iucv_dumpit ((uchar *) R, sizeof (handler));
378     				if ((R->prev != NULL)) {
379     					/* add to middle of chain */
380     					pr_debug
381     					    ("iucv_add_handler: added to middle\n");
382     					new_handler->prev = R->prev;
383     					new_handler->next = (ulong *) R;
384     					((handler *) (R->prev))->next =
385     					    (ulong *) new_handler;
386     					R->prev = (ulong *) new_handler;
387     					rc = 0;
388     					break;	/* break out of FOR loop */
389     				} else {	/* R->prev == NULL */
390     					/* add to start of chain;  */
391     					pr_debug ("iucv_add_handler:"
392     						  "added to beginning\n");
393     					R->prev = (ulong *) new_handler;
394     					new_handler->next = (ulong *) R;
395     					handler_anchor = new_handler;
396     					rc = 0;
397     					break;	/* break out of FOR loop */
398     				}
399     			}	/* end of else if */
400     		}		/* end of for loop */
401     	if (R == NULL) {
402     		/* add to end of chain */
403     		pr_debug ("iucv_add_handler: added to end\n");
404     		handler_tail->next = (ulong *) new_handler;
405     		new_handler->prev = (ulong *) handler_tail;
406     		handler_tail = new_handler;
407     		rc = 0;
408     	}
409     	spin_unlock_irqrestore (&iucv_lock, flags);
410     
411     	pr_debug ("Current Chain of handlers is\n");
412     	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
413     		iucv_dumpit ((uchar *) R, (int) sizeof (handler));
414     
415     	pr_debug ("iucv_add_handler: exiting\n");
416     	return rc;
417     }
418     
419     /* 
420      * Name: iucv_remove_handler
421      * Purpose: Remove handler when application unregisters.
422      * Input: users_handler - handler to be removed
423      * Output: void
424     */
425     void
426     iucv_remove_handler (handler * users_handler)
427     {
428     	handler *R;		/* used for Debugging */
429     	pr_debug ("iucv_remove_handler: entering\n");
430     	if ((users_handler->next != NULL) & (users_handler->prev != NULL)) {
431     		/* remove from middle of chain */
432     		((handler *) (users_handler->next))->prev =
433     		    (ulong *) users_handler->prev;
434     		((handler *) (users_handler->prev))->next =
435     		    (ulong *) users_handler->next;
436     	} else if ((users_handler->next != NULL) &
437     		   (users_handler->prev == NULL)) {
438     		/* remove from start of chain */
439     		((handler *) (users_handler->next))->prev = NULL;
440     		handler_anchor = (handler *) users_handler->next;
441     	} else if ((users_handler->next == NULL) &
442     		   (users_handler->prev != NULL)) {
443     		/* remove from end of chain */
444     		((handler *) (users_handler->prev))->next = NULL;
445     		handler_tail = (handler *) users_handler->prev;
446     	} else {
447     		handler_anchor = NULL;
448     		handler_tail = NULL;
449     	}
450     
451     	pr_debug ("Current Chain of handlers is\n");
452     	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
453     		iucv_dumpit ((uchar *) R, (int) sizeof (handler));
454     
455     	pr_debug ("iucv_remove_handler: exiting\n");
456     	return;
457     }
458     
459     /*
460      * Name: b2f0
461      * Purpose: This function calls CP to execute IUCV commands.
462      * Input: code -  identifier of IUCV call to CP.
463      *        parm -  pointer to 40 byte iparml area
464      *               passed to CP
465      * Output: iprcode- return code from CP's IUCV call
466      * NOTE: Assembler code performing IUCV call
467     */
468     inline ulong
469     b2f0 (u32 code, void *parm)
470     {
471     	uchar *iprcode;
472     	pr_debug ("iparml before b2f0 call\n");
473     	iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
474     	asm volatile ("LRA   1,0(%1)\n\t"
475     		      "LR    0,%0\n\t"
476     		      ".long 0xb2f01000"::"d" (code), "a" (parm):"0", "1");
477     	pr_debug ("iparml after b2f0 call\n");
478     	iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
479     	iprcode = (uchar *) (parm + 3);
480     	return (ulong) (*iprcode);
481     }
482     
483     /*
484      * Name: iucv_add_pathid                                            
485      * Purpose: Adds a path id to the system.                       
486      * Input: pathid -  pathid that is going to be entered into system              
487      *        handle -  address of handler that the pathid will be associated
488      *		   with.
489      *        pgm_data - token passed in by application.                
490      * Output: 0: successful addition of pathid
491      *	   - EINVAL - pathid entry is being used by another application
492      *	   - ENOMEM - storage allocation for a new pathid table failed      
493     */
494     int
495     iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data)
496     {
497     	ulong add_flag = 0;
498     	ulong old_size = 0, new_size = 0;
499     	ulong flags;
500     	uchar *to, *from;	/* pointer for copying the table */
501     	handler_table_entry *P = 0;	/*P is a pointer to the users H_T_E */
502     	handler *users_handler = 0;
503     	ulong *X = 0;		/* Points to array of pointers to H-T_E */
504     
505     	pr_debug ("iucv_add_pathid: entering\n");
506     
507     	users_handler = (handler *) handle;
508     
509     	pr_debug ("iucv_add_pathid: users_handler is pointing to %p ",
510     		  users_handler);
511     
512     	spin_lock_irqsave (&iucv_lock, flags);
513     
514     	/*
515     	 * P points to the users handler table entry (H_T_E) in which all entries in
516     	 * that structure should be NULL. If they're not NULL, then there
517     	 * is a bad pointer and it will return(-EINVAL) immediately, otherwise users
518     	 * data will be entered into H_T_E.
519     	 */
520     
521     	P = handler_table_anchor + pathid;	/* index into users handler table */
522     
523     	pr_debug ("handler_table_anchor is %p\n", handler_table_anchor);
524     	pr_debug ("P=handler_table_anchor+pathid = %p\n", P);
525     
526     	if (P->addrs) {
527     		pr_debug ("iucv_add_pathid: P = %p \n", P);
528     		pr_debug ("iucv_add_pathid: P->addrs is %p \n", P->addrs);
529     		spin_unlock_irqrestore (&iucv_lock, flags);
530     		/* This message should be sent to syslog */
531     		printk (KERN_WARNING "iucv_add_pathid: Pathid being used,"
532     			"error.\n");
533     		return (-EINVAL);
534     	}
535     
536     	P->addrs = handle;
537     	P->pathid = pathid;
538     
539     	/*
540     	 * pgm_data provided in iucv_register may be overwritten on a connect, accept. 
541     	 */
542     
543     	if (pgm_data)
544     		P->pgm_data = pgm_data;
545     	else
546     		P->pgm_data = users_handler->pgm_data;
547     
548     	/*
549     	 * Address of pathid's iucv_interrupt_ops is taken from the associated handler
550     	 * and added here for quicker access to the interrupt tables during interrupt
551     	 * handling.
552     	 */
553     
554     	P->ops = (P->addrs)->interrupt_table;
555     
556     	pr_debug ("Complete users H_T_E is\n");
557     	iucv_dumpit ((uchar *) P, sizeof (handler_table_entry));
558     
559     	/*
560     	 * Step thru the table of addresses of pathid's to find the first
561     	 * available entry (NULL). If an entry is found, add the pathid,
562     	 * unlock and exit. If an available entry is not found, allocate a
563     	 * new, larger table, copy over the old table to the new table. De-allocate the
564     	 * old table and enter the new pathid.
565     	 */
566     
567     	pr_debug ("iucv_add_pathid: address of handle is %p\n", handle);
568     	pr_debug ("iucv_add_pathid: &(users_handler->pathid_head) is %p\n",
569     		  &(users_handler->pathid_head));
570     	pr_debug ("iucv_add_pathid: &(users_handler->pathid_tail) is %p\n",
571     		  &(users_handler->pathid_tail));
572     	pr_debug ("iucv_add_pathid: start of pathid table is %p\n",
573     		  (users_handler->pathid_head));
574     	pr_debug ("iucv_add_pathid: end of pathid table is %p\n",
575     		  (users_handler->pathid_tail));
576     	iucv_dumpit ((uchar *) users_handler->pathid_head,
577     		     (int) (users_handler->pathid_tail -
578     			    users_handler->pathid_head));
579     
580     	for (X = (users_handler->pathid_head);
581     	     X <
582     	     (users_handler->pathid_head +
583     	      users_handler->entries * sizeof (ulong)); X++)
584     		if (*X == NULL) {
585     			pr_debug ("adding pathid, %p = P\n", P);
586     			*X = (ulong) P;
587     			add_flag = 1;
588     			break;	/* breaks out of for loop */
589     		}
590     
591     	pr_debug ("Addresses of HTE's are\n");
592     	iucv_dumpit ((uchar *) users_handler->pathid_head,
593     		     users_handler->entries * sizeof (ulong));
594     
595     	if (add_flag == 0) {	/* element not added to list: must get a new table */
596     		X = users_handler->pathid_head;
597     		old_size = users_handler->entries;
598     		new_size = old_size + ADDED_STOR;	/*number of entries of new table */
599     		from = (uchar *) (users_handler->pathid_head);	/*address of old table */
600     		users_handler->pathid_head =
601     		    kmalloc (new_size * sizeof (ulong), GFP_ATOMIC);
602     
603     		if (users_handler->pathid_head == NULL) {
604     			users_handler->pathid_head = X;	/*setting old condition */
605     			spin_unlock_irqrestore (&iucv_lock, flags);
606     			printk (KERN_WARNING
607     				"iucv_add_pathid: storage allocation"
608     				"failed for new pathid table \n ");
609     			memset (P, 0, sizeof (handler_table_entry));
610     			return -ENOMEM;
611     		}
612     
613     		memset (users_handler->pathid_head, 0,
614     			new_size * sizeof (ulong));
615     		to = (uchar *) (users_handler->pathid_head);	/* address of new table */
616     		/* copy old table to new  */
617     		memcpy (to, from, old_size * (sizeof (ulong)));
618     
619     		pr_debug ("iucv: add_pathid: Getting a new pathid table\n");
620     		pr_debug ("iucv: add_pathid: to is %p \n", to);
621     		pr_debug ("iucv: add_pathid: from is %p \n", from);
622     
623     		users_handler->entries = new_size;	/* storing new size of table */
624     		users_handler->pathid_tail =
625     		    (users_handler->pathid_head) + (users_handler->entries);
626     		X = users_handler->pathid_head + old_size;
627     		*X = (ulong) P;	/* adding element to new table */
628     
629     		pr_debug ("iucv: add_pathid: users_handler->entries is %u \n",
630     			  (int) (users_handler->entries));
631     		pr_debug
632     		    ("iucv: add_pathid: users_handler->pathid_tail is %p\n",
633     		     users_handler->pathid_tail);
634     		pr_debug ("users_handler->pathid_head is %p \n",
635     			  users_handler->pathid_head);
636     		pr_debug ("iucv: add_pathid: X is %p \n", X);
637     		pr_debug ("iucv: add_pathid: *X is %u \n", (int) (*X));
638     		pr_debug ("Addresses of HTE's after getting new table is\n");
639     		iucv_dumpit ((uchar *) users_handler->pathid_head,
640     			     users_handler->entries * sizeof (ulong));
641     		pr_debug ("New handler is\n");
642     		iucv_dumpit ((uchar *) users_handler, sizeof (handler));
643     
644     		kfree (from);	/* free old table */
645     	}
646     	spin_unlock_irqrestore (&iucv_lock, flags);
647     	pr_debug ("iucv_dd_pathid: exiting\n");
648     	return (0);
649     }				/* end of add_pathid function */
650     
651     /*
652      * Name: iucv_declare_buffer                                    
653      * Purpose: Specifies the guests real address of an external  
654      *          interrupt.                                        
655      * Input: void                             
656      * Output: iprcode - return code from b2f0 call               
657     */
658     int
659     iucv_declare_buffer (void)
660     {
661     	iparml_db parm;
662     	ulong b2f0_result;
663     	pr_debug ("iucv_declare_buffer: entering\n");
664     	memset (&parm, 0, sizeof (parm));
665     	parm.ipbfadr1 = virt_to_phys ((uchar *) iucv_external_int_buffer);
666     	b2f0_result = b2f0 (DECLARE_BUFFER, &parm);
667     	pr_debug ("iucv_declare_buffer: Address of EIB = %p\n",
668     		  iucv_external_int_buffer);
669     	pr_debug ("iucv_declare_buffer: exiting\n");
670     	return b2f0_result;
671     }
672     
673     /*
674      * Name: iucv_retrieve_buffer
675      * Purpose: Terminates all use of IUCV.
676      * Input: void
677      * Output:
678      *      b2f0_result: return code from CP
679     */
680     int
681     iucv_retrieve_buffer (void)
682     {
683     	iparml_control parm;
684     	ulong b2f0_result = 0;
685     	pr_debug ("iucv_retrieve_buffer: entering\n");
686     	memset (&parm, 0, sizeof (parm));
687     	b2f0_result = b2f0 (RETRIEVE_BUFFER, &parm);
688     	if (b2f0_result == NULL) {
689     		kfree (handler_table_anchor);
690     		handler_table_anchor = NULL;
691     		declare_flag = 0;
692     	}
693     	pr_debug ("iucv_retrieve_buffer: exiting\n");
694     	return b2f0_result;
695     }
696     
697     /*
698      * Name: iucv_register_program
699      * Purpose: Registers an application with IUCV.   
700      * Input: prmname - user identification
701      *        userid  - machine identification
702      *        pgmmask - indicates which bits in the prmname and userid combined will be used
703      *	   to determine who is given control
704      *        ops - address of vector of interrupt handlers
705      *        pgm_data- application data passed to interrupt handlers
706      * Output: NA
707      * Return: type: iucv_handle_t
708      *          address of handler
709      *         (0) - registration failed
710      *	       - Machine size > 2GB
711      *	       - new_handler kmalloc failed
712      * 	       - pgmname was not provided
713      *	       - pathid_table kmalloc failed
714      *             - application with identical pgmname, userid, and pgmmask is registered
715      * 	       - iucv_declare_buffer failed
716      * NOTE: pgmmask
717      *	When pgmname, userid, pgmmask is provided, mask is entered into the handler
718      *	as is.
719      *	When pgmname, userid is provided, pgmmask is all 0xff's
720      *	When pgmname, pgmmask is provided, the first 8 bytes = 0x00 and the last 16
721      *      bytes are as provided by pgmmask. 
722      *	When pgmname is provided is provided, the first 8 bytes = 0x00 and the last
723      *	16 bytes are 0xff.   
724     */
725     
726     iucv_handle_t
727     iucv_register_program (uchar pgmname[16],
728     		       uchar userid[8],
729     		       uchar pgmmask[24],
730     		       iucv_interrupt_ops_t * ops, void *pgm_data)
731     {
732     	ulong rc = 0;		/* return code from function calls */
733     	ulong machine_size = 0;	/* size of virtual machine */
734     	static u32 maxconn1;
735     	handler *new_handler = NULL;
736     
737     	pr_debug ("iucv_register_program:entering\n");
738     
739     	if (ops == NULL) {
740     		/* interrupt table is not defined */
741     		printk (KERN_WARNING "iucv_register_program:"
742     			"Interrupt table is not defined, exiting\n");
743     		return NULL;
744     	}
745     
746     	if (declare_flag == 0) {
747     		/* check size of virtual machine */
748     		if ((machine_size = iucv_vmsize ()) > 0x100000000) {	/* 2GB */
749     			printk (KERN_WARNING "iucv_register_progam: Virtual"
750     				"storage = %lx hex," "exiting\n", machine_size);
751     			return NULL;
752     		}
753     
754     		pr_debug ("machine_size is %lx\n", machine_size);
755     
756     		maxconn1 = iucv_query_maxconn ();
757     		handler_table_anchor = kmalloc (maxconn1 * sizeof
758     						(handler_table_entry),
759     						GFP_KERNEL);
760     
761     		if (handler_table_anchor == NULL) {
762     			printk (KERN_WARNING "iucv_register_program:"
763     				"handler_table_anchor"
764     				"storage allocation failed\n");
765     			return NULL;
766     		}
767     
768     		memset (handler_table_anchor, 0,
769     			maxconn1 * sizeof (handler_table_entry));
770     
771     	}
772     	/* Allocate handler table */
773     	new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
774     	if (new_handler == NULL) {
775     		printk (KERN_WARNING "iucv_register_program: storage allocation"
776     			"for new handler failed. \n ");
777     		return NULL;
778     	}
779     	memset (new_handler, 0, sizeof (handler));
780     	if (pgmname) {
781     		memcpy (new_handler->id.user_data, pgmname,
782     			sizeof (new_handler->id.user_data));
783     		if (userid) {
784     			memcpy (new_handler->id.userid, userid,
785     				sizeof (new_handler->id.userid));
786     			ASCEBC (new_handler->id.userid,
787     				sizeof (new_handler->id.userid));
788     			EBC_TOUPPER (new_handler->id.userid,
789     				     sizeof (new_handler->id.userid));
790     
791     			if (pgmmask) {
792     				memcpy (new_handler->id.mask, pgmmask,
793     					sizeof (new_handler->id.mask));
794     			} else {
795     				memset (new_handler->id.mask, 0xFF,
796     					sizeof (new_handler->id.mask));
797     			}
798     		} else {
799     			if (pgmmask) {
800     				memcpy (new_handler->id.mask, pgmmask,
801     					sizeof (new_handler->id.mask));
802     			} else {
803     				memset (new_handler->id.mask, 0xFF,
804     					sizeof (new_handler->id.mask));
805     			}
806     			memset (new_handler->id.mask, 0x00,
807     				sizeof (new_handler->id.userid));
808     		}
809     	} else {
810     		kfree (new_handler);
811     		printk (KERN_WARNING "iucv_register_program: pgmname not"
812     			"provided\n");
813     		return NULL;
814     	}
815     	/* fill in the rest of handler */
816     	new_handler->pgm_data = pgm_data;
817     	new_handler->interrupt_table = ops;
818     	new_handler->entries = ADDED_STOR;
819     	/* Allocate storage for pathid table */
820     	new_handler->pathid_head =
821     	    kmalloc (new_handler->entries * sizeof (ulong), GFP_KERNEL);
822     	if (new_handler->pathid_head == NULL) {
823     		printk (KERN_WARNING "iucv_register_program: storage allocation"
824     			"failed\n");
825     		kfree (new_handler);
826     		return NULL;
827     	}
828     
829     	memset (new_handler->pathid_head, 0,
830     		new_handler->entries * sizeof (ulong));
831     	new_handler->pathid_tail =
832     	    new_handler->pathid_head + new_handler->entries;
833     	/* 
834     	 * Check if someone else is registered with same pgmname, userid, and mask. 
835     	 * If someone is already registered with same pgmname, userid, and mask 
836     	 * registration will fail and NULL will be returned to the application. 
837     	 * If identical handler not found, then handler is added to list.
838     	 */
839     	rc = iucv_add_handler (new_handler);
840     	if (rc) {
841     		printk (KERN_WARNING "iucv_register_program: Someone already"
842     			"registered with same pgmname, userid, pgmmask\n");
843     		kfree (new_handler->pathid_head);
844     		kfree (new_handler);
845     		return NULL;
846     	}
847     
848     	if (declare_flag == 0) {
849     		rc = iucv_declare_buffer ();
850     		if (rc) {
851     			kfree (handler_table_anchor);
852     			kfree (new_handler->pathid_head);
853     			kfree (new_handler);
854     			handler_table_anchor = NULL;
855     			printk (KERN_WARNING "iucv_register_program: rc from"
856     				"iucv_declare_buffer is:% ld \n ", rc);
857     			return NULL;
858     		}
859     		/* request the 0x4000 external interrupt */
860     		rc = register_external_interrupt (0x4000, top_half_interrupt);
861     		if (rc) {
862     			iucv_retrieve_buffer ();
863     			kfree (new_handler->pathid_head);
864     			kfree (new_handler);
865     			printk (KERN_WARNING "iucv_register_program: rc from"
866     				"register_external_interrupt is:% ld \n ", rc);
867     			return NULL;
868     
869     		}
870     		declare_flag = 1;
871     	}
872     	pr_debug ("iucv_register_program: exiting\n");
873     	return new_handler;
874     }				/* end of register function */
875     
876     /*
877      * Name: iucv_unregister_program
878      * Purpose: Unregister application with IUCV.
879      * Input: handle address of handler
880      * Output: NA
881      * Return: (0) - Normal return
882      *         (-EINVAL)- Matching handler was not found
883     */
884     
885     int
886     iucv_unregister_program (iucv_handle_t handle)
887     {
888     	handler *users_handler = 0, *R;
889     	handler_table_entry *H_T_E = 0;
890     	ulong *S = 0;		/*points to the beginning of block of h_t_e's */
891     	ulong flags;
892     	u16 pathid_sever = 0;
893     	pr_debug ("iucv_unregister_program: entering\n");
894     	pr_debug ("iucv_unregister_program: address of handle is %p\n", handle);
895     	spin_lock_irqsave (&iucv_lock, flags);
896     	users_handler = (handler *) handle;
897     	/* 
898     	 * Checking if handle is still registered: if yes, continue
899     	 *  if not registered, return.
900     	 */
901     	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
902     		if (users_handler == R) {
903     			pr_debug ("iucv_unregister_program: found a matching"
904     				  "handler\n");
905     			break;
906     		}
907     	if (!R) {
908     		pr_debug ("You are not registered\n");
909     		spin_unlock_irqrestore (&iucv_lock, flags);
910     		return (0);
911     	}
912     	S = users_handler->pathid_head;
913     	while (S < (users_handler->pathid_tail)) {	/* index thru table */
914     		if (*S) {
915     			H_T_E = (handler_table_entry *) (*S);
916     
917     			pr_debug ("iucv_unregister_program: pointer to H_T_E is"
918     				  "%p\n", H_T_E);
919     			pr_debug
920     			    ("iucv_unregister_program: address of handle in"
921     			     "H_T_E is %p", (H_T_E->addrs));
922     			pathid_sever = H_T_E->pathid;
923     			spin_unlock_irqrestore (&iucv_lock, flags);
924     			iucv_sever (pathid_sever, users_handler->id.user_data);
925     			spin_lock_irqsave (&iucv_lock, flags);
926     		}
927     
928     		S++;		/* index by address */
929     	}
930     
931     	kfree (users_handler->pathid_head);
932     	iucv_remove_handler (users_handler);
933     	spin_unlock_irqrestore (&iucv_lock, flags);
934     	kfree (handle);
935     	pr_debug ("iucv_unregister_program: exiting\n");
936     	return 0;
937     }
938     
939     /*
940      * Name: iucv_accept
941      * Purpose: This function is issued after the user receives a Connection Pending external
942      *          interrupt and now wishes to complete the IUCV communication path.
943      * Input:  pathid - u16 , path identification number   
944      *         msglim_reqstd - u16, The number of outstanding messages requested.
945      *         user_data - uchar[16], Data specified by the iucv_connect function.
946      *	   flags1 - int, Contains options for this path.
947      *           -IPPRTY - 0x20- Specifies if you want to send priority message.
948      *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
949      *            	in  the parameter list.
950      *           -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
951      *		established.
952      *         handle - iucv_handle_t, Address of handler.
953      *         pgm_data - ulong, Application data passed to interrupt handlers.
954      *	   flags1_out - int *, Options for path.
955      *           IPPRTY - 0x20 - Indicates you may send a priority message.
956      *         priority_permitted -uchar *, Indicates you may send priority messages.
957      *         msglim - *u16, Number of outstanding messages.
958      * Output: b2f0_result - return code from CP
959     */
960     int
961     iucv_accept (u16 pathid, u16 msglim_reqstd,
962     	     uchar user_data[16], int flags1,
963     	     iucv_handle_t handle, void *pgm_data,
964     	     int *flags1_out, u16 * msglim)
965     {
966     	iparml_control parm;
967     	ulong b2f0_result = 0;
968     	ulong flags;
969     	handler *R = NULL;
970     	pr_debug ("iucv_accept: entering \n");
971     	pr_debug ("iucv_accept: pathid = %d\n", pathid);
972     
973     	/* Checking if handle is valid  */
974     	spin_lock_irqsave (&iucv_lock, flags);
975     
976     	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
977     		if (R == handle)
978     			break;
979     
980     	spin_unlock_irqrestore (&iucv_lock, flags);
981     	if (R == NULL) {
982     		printk (KERN_WARNING "iucv_connect: NULL handle passed by"
983     			"application\n");
984     		return -EINVAL;
985     	}
986     
987     	memset (&parm, 0, sizeof (parm));
988     	parm.ippathid = pathid;
989     	parm.ipmsglim = msglim_reqstd;
990     	if (user_data)
991     		memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
992     	parm.ipflags1 = (uchar) flags1;
993     	b2f0_result = b2f0 (ACCEPT, &parm);
994     
995     	if (b2f0_result == 0) {
996     		if (pgm_data)
997     			(handler_table_anchor + pathid)->pgm_data = pgm_data;
998     		if (parm.ipflags1 & IPPRTY)
999     			if (flags1_out) {
1000     				pr_debug ("*flags1_out = %d\n", *flags1_out);
1001     				*flags1_out = 0;
1002     				*flags1_out |= IPPRTY;
1003     				pr_debug (" *flags1_out = %d\n", *flags1_out);
1004     			}
1005     	}
1006     
1007     	pr_debug ("iucv_accept: exiting\n");
1008     	return b2f0_result;
1009     }
1010     
1011     /*
1012      * Name: iucv_connect                                         
1013      * Purpose: This function establishes an IUCV path. Although the connect may complete
1014      *	    successfully, you are not able to use the path until you receive an IUCV 
1015      *          Connection Complete external interrupt.            
1016      * Input: pathid - u16 *, path identification number          
1017      *        msglim_reqstd - u16, number of outstanding messages requested       
1018      *        user_data - uchar[16], 16-byte user data                    
1019      *        userid - uchar[8], 8-byte of user identification                        
1020      *        system_name - uchar[8], 8-byte identifying the system name 
1021      *        flags1 - int, Contains options for this path.
1022      *          -IPPRTY - 0x20- Specifies if you want to send priority message.
1023      *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
1024      *               in  the parameter list.
1025      *          -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
1026      *              established.
1027      *          -IPLOCAL - 0X01, allows an application to force the partner to be on the
1028      *              local system. If local is specified then target class cannot be
1029      *              specified.  
1030      *         flags1_out - int *, Options for path. 
1031      *           IPPRTY - 0x20 - Indicates you may send a priority message.
1032      *        msglim - * u16, number of outstanding messages
1033      *        handle - iucv_handle_t, address of handler                         
1034      *        pgm_data - *void, application data passed to interrupt handlers                  
1035      * Output: b2f0_result - return code from CP
1036      *         -ENOMEM
1037      *         rc - return code from iucv_declare_buffer
1038      *         -EINVAL - invalid handle passed by application 
1039      *         -EINVAL - pathid address is NULL 
1040      *	   -ENOMEM - pathid table storage allocation failed
1041      *         add_pathid_result - return code from internal function add_pathid             
1042     */
1043     int
1044     iucv_connect (u16 * pathid, u16 msglim_reqstd,
1045     	      uchar user_data[16], uchar userid[8],
1046     	      uchar system_name[8], int flags1,
1047     	      int *flags1_out, u16 * msglim,
1048     	      iucv_handle_t handle, void *pgm_data)
1049     {
1050     	iparml_control parm;
1051     	ulong b2f0_result = 0;
1052     	ulong flags;
1053     	int add_pathid_result = 0;
1054     	handler *R = NULL;
1055     	uchar no_memory[16] = "NO MEMORY";
1056     
1057     	pr_debug ("iucv_connect: entering \n");
1058     
1059     	/* Checking if handle is valid  */
1060     	spin_lock_irqsave (&iucv_lock, flags);
1061     
1062     	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
1063     		if (R == handle)
1064     			break;
1065     
1066     	spin_unlock_irqrestore (&iucv_lock, flags);
1067     
1068     	if (R == NULL) {
1069     		printk (KERN_WARNING "iucv_connect: NULL handle passed by"
1070     			"application\n");
1071     		return -EINVAL;
1072     	}
1073     
1074     	if (pathid == NULL) {
1075     		printk (KERN_WARNING "iucv_connect: NULL pathid pointer\n");
1076     		return -EINVAL;
1077     	}
1078     	memset (&parm, 0, sizeof (iparml_control));
1079     	parm.ipmsglim = msglim_reqstd;
1080     
1081     	if (user_data)
1082     		memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
1083     
1084     	if (userid) {
1085     		memcpy (parm.ipvmid, userid, sizeof (parm.ipvmid));
1086     		ASCEBC (parm.ipvmid, sizeof (parm.ipvmid));
1087     		EBC_TOUPPER (parm.ipvmid, sizeof (parm.ipvmid));
1088     	}
1089     
1090     	if (system_name) {
1091     		memcpy (parm.iptarget, system_name, sizeof (parm.iptarget));
1092     		ASCEBC (parm.iptarget, sizeof (parm.iptarget));
1093     		EBC_TOUPPER (parm.iptarget, sizeof (parm.iptarget));
1094     	}
1095     
1096     	parm.ipflags1 = (uchar) flags1;
1097     	b2f0_result = b2f0 (CONNECT, &parm);
1098     	if (b2f0_result)
1099     		return b2f0_result;
1100     
1101     	add_pathid_result = iucv_add_pathid (parm.ippathid, handle, pgm_data);
1102     	if (add_pathid_result) {
1103     
1104     		iucv_sever (parm.ippathid, no_memory);
1105     		printk (KERN_WARNING "iucv_connect: add_pathid failed with rc ="
1106     			"%d\n", add_pathid_result);
1107     		return (add_pathid_result);
1108     	}
1109     
1110     	*pathid = parm.ippathid;
1111     
1112     	if (msglim)
1113     		*msglim = parm.ipmsglim;
1114     
1115     	if (parm.ipflags1 & IPPRTY)
1116     		if (flags1_out) {
1117     			*flags1_out = 0;
1118     			*flags1_out |= IPPRTY;
1119     		}
1120     
1121     	pr_debug ("iucv_connect: exiting\n");
1122     	return b2f0_result;
1123     }
1124     
1125     /*
1126      * Name: iucv_purge                                           
1127      * Purpose: Cancels a message you have sent.                   
1128      * Input: pathid -   address of pathid                                  
1129      *        msgid  -   address of message identification             
1130      *        srccls -   address of source message class                     
1131      *        audit  -  contains information about                              
1132      *                 asynchronous error that may have affected                           
1133      *                 the normal completion of this message.                  
1134      * Output:b2f0_result - return code from CP                   
1135     */
1136     int
1137     iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3])
1138     {
1139     	iparml_purge parm;
1140     	ulong b2f0_result = 0;
1141     	pr_debug ("iucv_purge: entering\n");
1142     	pr_debug ("iucv_purge: pathid = %d \n", pathid);
1143     	memset (&parm, 0, sizeof (parm));
1144     	parm.ipmsgid = msgid;
1145     	parm.ippathid = pathid;
1146     	parm.ipsrccls = srccls;
1147     	parm.ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
1148     	b2f0_result = b2f0 (PURGE, &parm);
1149     
1150     	if ((b2f0_result == 0) && (audit))
1151     		memcpy (audit, parm.ipaudit, sizeof (parm.ipaudit));
1152     
1153     	pr_debug ("iucv_purge: b2f0_result = %ld \n", b2f0_result);
1154     	pr_debug ("iucv_purge: exiting\n");
1155     	return b2f0_result;
1156     }
1157     
1158     /*
1159      * Name: iucv_query_maxconn                                            
1160      * Purpose: Determines the maximum number of connections thay may be established.
1161      * Output: maxconn - ulong: Maximum number of connections that can be.     
1162     */
1163     ulong
1164     iucv_query_maxconn (void)
1165     {
1166     	iparml_purge parm;	/* DOESN'T MATTER WHICH IPARML IS USED    */
1167     	static u32 maxconn1, bufsize1;
1168     
1169     	pr_debug ("iucv_query_maxconn: entering\n");
1170     
1171     	memset (&parm, 0, sizeof (parm));
1172     
1173     	/* Assembler instruction calling b2f0  and storing R0 and R1 */
1174     	asm volatile ("LRA   1,0(%3)\n\t"
1175     		      "LR    0,%2\n\t"
1176     		      ".long 0xb2f01000\n\t"
1177     		      "ST    0,%0\n\t"
1178     		      "ST    1,%1\n\t":"=m" (bufsize1),
1179     		      "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
1180     
1181     	pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
1182     	pr_debug ("iucv_query_maxconn: exiting\n");
1183     
1184     	return maxconn1;
1185     }
1186     
1187     /*
1188      * Name: iucv_query_bufsize
1189      * Purpose: Determines the size of the external interrupt buffer.
1190      * Output: bufsize - ulong: Size of external interrupt buffer.
1191      */
1192     ulong
1193     iucv_query_bufsize (void)
1194     {
1195     	iparml_purge parm;	/* DOESN'T MATTER WHICH IPARML IS USED    */
1196     	static u32 maxconn1, bufsize1;
1197     
1198     	pr_debug ("iucv_query_bufsize: entering\n");
1199     	pr_debug ("iucv_query_maxconn: entering\n");
1200     
1201     	memset (&parm, 0, sizeof (parm));
1202     
1203     	/* Assembler instruction calling b2f0  and storing R0 and R1 */
1204     	asm volatile ("LRA   1,0(%3)\n\t"
1205     		      "LR    0,%2\n\t"
1206     		      ".long 0xb2f01000\n\t"
1207     		      "ST    0,%0\n\t"
1208     		      "ST    1,%1\n\t":"=m" (bufsize1),
1209     		      "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
1210     
1211     	pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
1212     	pr_debug ("iucv_query_bufsize: exiting\n");
1213     
1214     	return bufsize1;
1215     }
1216     
1217     /*
1218      * Name: iucv_quiesce                                         
1219      * Purpose: temporarily suspends incoming messages on an IUCV path.
1220      *          You can later reactivate the path by invoking the iucv_resume function        
1221      * Input: pathid - u16, path identification number                             
1222      *        user_data - uchar[16], 16-byte user data                      
1223      * Output: b2f0_result - return code from CP               
1224      */
1225     int
1226     iucv_quiesce (u16 pathid, uchar user_data[16])
1227     {
1228     	iparml_control parm;
1229     	ulong b2f0_result = 0;
1230     
1231     	pr_debug ("iucv_quiesce: entering \n");
1232     	pr_debug ("iucv_quiesce: pathid = %d\n", pathid);
1233     
1234     	memset (&parm, 0, sizeof (parm));
1235     	memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
1236     	parm.ippathid = pathid;
1237     
1238     	b2f0_result = b2f0 (QUIESCE, &parm);
1239     
1240     	pr_debug ("iucv_quiesce: b2f0_result = %ld\n", b2f0_result);
1241     	pr_debug ("iucv_quiesce: exiting\n");
1242     
1243     	return b2f0_result;
1244     }
1245     
1246     /*
1247      * Name: iucv_receive
1248      * Purpose: This function receives messages that are being sent to you
1249      *          over established paths. 
1250      * Input:
1251      *        pathid - path identification number
1252      *        buffer - address of buffer to receive
1253      *        buflen - length of buffer to receive
1254      *        msgid - specifies the message ID.
1255      *        trgcls - specifies target class
1256      * Output:
1257      *	 flags1_out: Options for path.
1258      *         IPNORPY - 0x10 specifies whether a reply is required
1259      *         IPPRTY - 0x20 specifies if you want to send priority message
1260      *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
1261      *       residual_buffer - address of buffer updated by the number
1262      *                         of bytes you have received.
1263      *       residual_length - 
1264      *		Contains one of the following values, if the receive buffer is:
1265      *		 The same length as the message, this field is zero.
1266      *		 Longer than the message, this field contains the number of
1267      *		  bytes remaining in the buffer.
1268      *		 Shorter than the message, this field contains the residual
1269      *		  count (that is, the number of bytes remaining in the
1270      *		  message that does not fit into the buffer. In this
1271      *		  case b2f0_result = 5. 
1272      * Return: b2f0_result - return code from CP IUCV call.
1273      *         (-EINVAL) - buffer address is pointing to NULL
1274      */
1275     int
1276     iucv_receive (u16 pathid, u32 msgid, u32 trgcls,
1277     	      void *buffer, ulong buflen,
1278     	      int *flags1_out, ulong * residual_buffer, ulong * residual_length)
1279     {
1280     	iparml_db parm;
1281     	ulong b2f0_result;
1282     	int moved = 0;		/* number of bytes moved from parmlist to buffer */
1283     	pr_debug ("iucv_receive: entering\n");
1284     
1285     	if (!buffer)
1286     		return -EINVAL;
1287     
1288     	memset (&parm, 0, sizeof (parm));
1289     	parm.ipbfadr1 = (u32) buffer;
1290     	parm.ipbfln1f = (u32) ((ulong) buflen);
1291     	parm.ipmsgid = msgid;
1292     	parm.ippathid = pathid;
1293     	parm.iptrgcls = trgcls;
1294     	parm.ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
1295     
1296     	b2f0_result = b2f0 (RECEIVE, &parm);
1297     
1298     	if (b2f0_result == 0 || b2f0_result == 5) {
1299     		if (flags1_out) {
1300     			pr_debug ("*flags1_out = %d\n", *flags1_out);
1301     			*flags1_out = (parm.ipflags1 & (~0x07));
1302     			pr_debug ("*flags1_out = %d\n", *flags1_out);
1303     		}
1304     
1305     		if (!(parm.ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
1306     			if (residual_length)
1307     				*residual_length = parm.ipbfln1f;
1308     
1309     			if (residual_buffer)
1310     				*residual_buffer = parm.ipbfadr1;
1311     		} else {
1312     			moved = min_t(unsigned int, buflen, 8);
1313     
1314     			memcpy ((char *) buffer,
1315     				(char *) &parm.ipbfadr1, moved);
1316     
1317     			if (buflen < 8)
1318     				b2f0_result = 5;
1319     
1320     			if (residual_length)
1321     				*residual_length = abs (buflen - 8);
1322     
1323     			if (residual_buffer)
1324     				*residual_buffer = (ulong) (buffer + moved);
1325     		}
1326     	}
1327     	pr_debug ("iucv_receive: exiting \n");
1328     	return b2f0_result;
1329     }
1330     
1331     /*
1332      * Name: iucv_receive_array
1333      * Purpose: This function receives messages that are being sent to you
1334      *          over established paths. 
1335      * Input: pathid - path identification number
1336      *        buffer - address of array of buffers
1337      *        buflen - total length of buffers
1338      *        msgid - specifies the message ID.
1339      *        trgcls - specifies target class
1340      * Output:
1341      *        flags1_out: Options for path.
1342      *          IPNORPY - 0x10 specifies whether a reply is required
1343      *          IPPRTY - 0x20 specifies if you want to send priority message
1344      *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
1345      *       residual_buffer - address points to the current list entry IUCV
1346      *                         is working on.
1347      *       residual_length -
1348      *              Contains one of the following values, if the receive buffer is:
1349      *               The same length as the message, this field is zero.
1350      *               Longer than the message, this field contains the number of
1351      *                bytes remaining in the buffer.
1352      *               Shorter than the message, this field contains the residual
1353      *                count (that is, the number of bytes remaining in the
1354      *                message that does not fit into the buffer. In this case
1355      *		  b2f0_result = 5.
1356      * Return: b2f0_result - return code from CP
1357      *         (-EINVAL) - buffer address is NULL
1358      */
1359     int
1360     iucv_receive_array (u16 pathid,
1361     		    u32 msgid, u32 trgcls,
1362     		    iucv_array_t * buffer, ulong buflen,
1363     		    int *flags1_out,
1364     		    ulong * residual_buffer, ulong * residual_length)
1365     {
1366     	iparml_db parm;
1367     	ulong b2f0_result;
1368     	int i = 0, moved = 0, need_to_move = 8, dyn_len;
1369     	pr_debug ("iucv_receive_array: entering\n");
1370     
1371     	if (!buffer)
1372     		return -EINVAL;
1373     
1374     	memset (&parm, 0, sizeof (parm));
1375     	parm.ipbfadr1 = (u32) ((ulong) buffer);
1376     	parm.ipbfln1f = (u32) buflen;
1377     	parm.ipmsgid = msgid;
1378     	parm.ippathid = pathid;
1379     	parm.iptrgcls = trgcls;
1380     	parm.ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
1381     
1382     	b2f0_result = b2f0 (RECEIVE, &parm);
1383     
1384     	if (b2f0_result == 0 || b2f0_result == 5) {
1385     
1386     		if (flags1_out) {
1387     			pr_debug ("*flags1_out = %d\n", *flags1_out);
1388     			*flags1_out = (parm.ipflags1 & (~0x07));
1389     			pr_debug ("*flags1_out = %d\n", *flags1_out);
1390     		}
1391     
1392     		if (!(parm.ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
1393     
1394     			if (residual_length)
1395     				*residual_length = parm.ipbfln1f;
1396     
1397     			if (residual_buffer)
1398     				*residual_buffer = parm.ipbfadr1;
1399     
1400     		} else {
1401     			/* copy msg from parmlist to users array. */
1402     
1403     			while ((moved < 8) && (moved < buflen)) {
1404     				dyn_len =
1405     				    min_t(unsigned int,
1406     					(buffer + i)->length, need_to_move);
1407     
1408     				memcpy ((char *)((ulong)((buffer + i)->address)),
1409     					((char *) &parm.ipbfadr1) + moved,
1410     					dyn_len);
1411     
1412     				moved += dyn_len;
1413     				need_to_move -= dyn_len;
1414     
1415     				(buffer + i)->address =
1416     				    	(u32)  
1417     				((ulong)(uchar *) ((ulong)(buffer + i)->address) 
1418     						+ dyn_len);
1419     
1420     				(buffer + i)->length -= dyn_len;
1421     				i++;
1422     			}
1423     
1424     			if (need_to_move)	/* buflen < 8 bytes */
1425     				b2f0_result = 5;
1426     
1427     			if (residual_length)
1428     				*residual_length = abs (buflen - 8);
1429     
1430     			if (residual_buffer) {
1431     				if (moved == 0)
1432     					*residual_buffer = (ulong) buffer;
1433     				else
1434     					*residual_buffer =
1435     					    (ulong) (buffer + (i - 1));
1436     			}
1437     
1438     		}
1439     	}
1440     
1441     	pr_debug ("iucv_receive_array: exiting\n");
1442     	return b2f0_result;
1443     }
1444     
1445     /*
1446      * Name: iucv_reject                                          
1447      * Purpose: Refuses a specified message. Between the time you are notified of a 
1448      *          message and the time that you complete the message, the message may
1449      *          be rejected.                                 
1450      * Input: pathid - u16, path identification number.                            
1451      *        msgid  - u32, specifies the message ID.
1452      *        trgcls - u32, specifies target class.                
1453      * Output: b2f0_result - return code from CP
1454      * NOTE: see b2f0 output list                                 
1455     */
1456     int
1457     iucv_reject (u16 pathid, u32 msgid, u32 trgcls)
1458     {
1459     	iparml_db parm;
1460     	ulong b2f0_result = 0;
1461     
1462     	pr_debug ("iucv_reject: entering \n");
1463     	pr_debug ("iucv_reject: pathid = %d\n", pathid);
1464     
1465     	memset (&parm, 0, sizeof (parm));
1466     	parm.ippathid = pathid;
1467     	parm.ipmsgid = msgid;
1468     	parm.iptrgcls = trgcls;
1469     	parm.ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
1470     
1471     	b2f0_result = b2f0 (REJECT, &parm);
1472     
1473     	pr_debug ("iucv_reject: b2f0_result = %ld\n", b2f0_result);
1474     	pr_debug ("iucv_reject: exiting\n");
1475     
1476     	return b2f0_result;
1477     }
1478     
1479     /* 
1480      * Name: iucv_reply
1481      * Purpose: This function responds to the two-way messages that you
1482      *          receive. You must identify completely the message to
1483      *          which you wish to reply. ie, pathid, msgid, and trgcls.
1484      * Input: pathid - path identification number
1485      *        msgid - specifies the message ID. 
1486      *        trgcls - specifies target class
1487      *        flags1 - option for path
1488      *                 IPPRTY- 0x20 - specifies if you want to send priority message
1489      *        buffer - address of reply buffer
1490      *        buflen - length of reply buffer
1491      * Output: ipbfadr2 - Address of buffer updated by the number
1492      *                    of bytes you have moved.
1493      *         ipbfln2f - Contains on the the following values
1494      *              If the answer buffer is the same length as the reply, this field
1495      *               contains zero.
1496      *              If the answer buffer is longer than the reply, this field contains
1497      *               the number of bytes remaining in the buffer.
1498      *              If the answer buffer is shorter than the reply, this field contains
1499      *               a residual count (that is, the number of bytes remianing in the
1500      *               reply that does not fit into the buffer. In this
1501      *                case b2f0_result = 5.
1502      * Return: b2f0_result - return code from CP
1503      *         (-EINVAL) - buffer address is NULL
1504      */
1505     int
1506     iucv_reply (u16 pathid,
1507     	    u32 msgid, u32 trgcls,
1508     	    int flags1,
1509     	    void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
1510     {
1511     	iparml_db parm;
1512     	ulong b2f0_result;
1513     
1514     	pr_debug ("iucv_reply: entering\n");
1515     
1516     	if (!buffer)
1517     		return -EINVAL;
1518     
1519     	memset (&parm, 0, sizeof (parm));
1520     	parm.ipbfadr2 = (u32) ((ulong) buffer);
1521     	parm.ipbfln2f = (u32) buflen;	/* length of message */
1522     	parm.ippathid = pathid;
1523     	parm.ipmsgid = msgid;
1524     	parm.iptrgcls = trgcls;
1525     	parm.ipflags1 = (uchar) flags1;	/* priority message */
1526     
1527     	b2f0_result = b2f0 (REPLY, &parm);
1528     
1529     	if ((b2f0_result == 0) || (b2f0_result == 5)) {
1530     		if (ipbfadr2)
1531     			*ipbfadr2 = parm.ipbfadr2;
1532     		if (ipbfln2f)
1533     			*ipbfln2f = parm.ipbfln2f;
1534     	}
1535     
1536     	pr_debug ("iucv_reply: exiting\n");
1537     
1538     	return b2f0_result;
1539     }
1540     
1541     /*
1542      * Name: iucv_reply_array
1543      * Purpose: This function responds to the two-way messages that you
1544      *          receive. You must identify completely the message to   
1545      *          which you wish to reply. ie, pathid, msgid, and trgcls.
1546      *          The array identifies a list of addresses and lengths of
1547      *          discontiguous buffers that contains the reply data.
1548      * Input: pathid - path identification number
1549      *        msgid - specifies the message ID. 
1550      *        trgcls - specifies target class 
1551      *        flags1 - option for path
1552      *                 IPPRTY- specifies if you want to send priority message
1553      *        buffer - address of array of reply buffers
1554      *        buflen - total length of reply buffers
1555      * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
1556      *         ipbfln2f - Contains on the the following values
1557      *              If the answer buffer is the same length as the reply, this field
1558      *               contains zero.
1559      *              If the answer buffer is longer than the reply, this field contains
1560      *               the number of bytes remaining in the buffer.
1561      *              If the answer buffer is shorter than the reply, this field contains
1562      *               a residual count (that is, the number of bytes remianing in the
1563      *               reply that does not fit into the buffer. In this
1564      *               case b2f0_result = 5.
1565      * Return: b2f0_result - return code from CP
1566      *             (-EINVAL) - buffer address is NULL
1567     */
1568     int
1569     iucv_reply_array (u16 pathid,
1570     		  u32 msgid, u32 trgcls,
1571     		  int flags1,
1572     		  iucv_array_t * buffer,
1573     		  ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
1574     {
1575     	iparml_db parm;
1576     	ulong b2f0_result;
1577     
1578     	pr_debug ("iucv_reply_array: entering\n");
1579     
1580     	if (!buffer)
1581     		return -EINVAL;
1582     
1583     	memset (&parm, 0, sizeof (parm));
1584     	parm.ipbfadr2 = (u32) ((ulong) buffer);
1585     	parm.ipbfln2f = buflen;	/* length of message */
1586     	parm.ippathid = pathid;
1587     	parm.ipmsgid = msgid;
1588     	parm.iptrgcls = trgcls;
1589     	parm.ipflags1 = (IPANSLST | flags1);
1590     
1591     	b2f0_result = b2f0 (REPLY, &parm);
1592     
1593     	if ((b2f0_result == 0) || (b2f0_result == 5)) {
1594     
1595     		if (ipbfadr2)
1596     			*ipbfadr2 = parm.ipbfadr2;
1597     		if (ipbfln2f)
1598     			*ipbfln2f = parm.ipbfln2f;
1599     	}
1600     
1601     	pr_debug ("iucv_reply_array: exiting\n");
1602     
1603     	return b2f0_result;
1604     }
1605     
1606     /*
1607      * Name: iucv_reply_prmmsg
1608      * Purpose: This function responds to the two-way messages that you
1609      *          receive. You must identify completely the message to
1610      *          which you wish to reply. ie, pathid, msgid, and trgcls.
1611      *          Prmmsg signifies the data is moved into the
1612      *          parameter list.
1613      * Input: pathid - path identification number
1614      *        msgid - specifies the message ID. 
1615      *        trgcls - specifies target class
1616      *        flags1 - option for path
1617      *                 IPPRTY- specifies if you want to send priority message
1618      *        prmmsg - 8-bytes of data to be placed into the parameter
1619      *                 list.
1620      * Output: NA
1621      * Return: b2f0_result - return code from CP
1622     */
1623     int
1624     iucv_reply_prmmsg (u16 pathid,
1625     		   u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8])
1626     {
1627     	iparml_dpl parm;
1628     	ulong b2f0_result;
1629     
1630     	pr_debug ("iucv_reply_prmmsg: entering\n");
1631     
1632     	memset (&parm, 0, sizeof (parm));
1633     	parm.ippathid = pathid;
1634     	parm.ipmsgid = msgid;
1635     	parm.iptrgcls = trgcls;
1636     	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
1637     	parm.ipflags1 = (IPRMDATA | flags1);
1638     
1639     	b2f0_result = b2f0 (REPLY, &parm);
1640     
1641     	pr_debug ("iucv_reply_prmmsg: exiting\n");
1642     
1643     	return b2f0_result;
1644     }
1645     
1646     /*
1647      * Name: iucv_resume                                          
1648      * Purpose: This function restores communication over a quiesced path.       
1649      * Input: pathid - u16, path identification number                             
1650      *        user_data - uchar[16], 16-byte of user data                     
1651      * Output: b2f0_result - return code from CP               
1652      */
1653     int
1654     iucv_resume (u16 pathid, uchar user_data[16])
1655     {
1656     	iparml_control parm;
1657     	ulong b2f0_result = 0;
1658     
1659     	pr_debug ("iucv_resume: entering\n");
1660     	pr_debug ("iucv_resume: pathid = %d\n", pathid);
1661     
1662     	memset (&parm, 0, sizeof (parm));
1663     	memcpy (parm.ipuser, user_data, sizeof (*user_data));
1664     	parm.ippathid = pathid;
1665     
1666     	b2f0_result = b2f0 (RESUME, &parm);
1667     
1668     	pr_debug ("iucv_resume: exiting \n");
1669     
1670     	return b2f0_result;
1671     }
1672     
1673     /*
1674      * Name: iucv_send                                             
1675      * Purpose: sends messages                                    
1676      * Input: pathid - ushort, pathid                            
1677      *        msgid  - ulong *, id of message returned to caller   
1678      *        trgcls - ulong, target message class              
1679      *        srccls - ulong, source message class              
1680      *        msgtag - ulong, message tag                    
1681      *	  flags1  - Contains options for this path.
1682      *		IPPRTY - Ox20 - specifies if you want to send a priority message.
1683      *        buffer - pointer to buffer                           
1684      *        buflen - ulong, length of buffer                     
1685      * Output: b2f0_result - return code from b2f0 call               
1686      *         msgid - returns message id                         
1687      */
1688     int
1689     iucv_send (u16 pathid, u32 * msgid,
1690     	   u32 trgcls, u32 srccls,
1691     	   u32 msgtag, int flags1, void *buffer, ulong buflen)
1692     {
1693     	iparml_db parm;
1694     	ulong b2f0_result;
1695     
1696     	pr_debug ("iucv_send: entering\n");
1697     
1698     	if (!buffer)
1699     		return -EINVAL;
1700     
1701     	memset (&parm, 0, sizeof (parm));
1702     	parm.ipbfadr1 = (u32) ((ulong) buffer);
1703     	parm.ippathid = pathid;
1704     	parm.iptrgcls = trgcls;
1705     	parm.ipbfln1f = (u32) buflen;	/* length of message */
1706     	parm.ipsrccls = srccls;
1707     	parm.ipmsgtag = msgtag;
1708     	parm.ipflags1 = (IPNORPY | flags1);	/* one way priority message */
1709     
1710     	b2f0_result = b2f0 (SEND, &parm);
1711     
1712     	if ((b2f0_result == 0) && (msgid))
1713     		*msgid = parm.ipmsgid;
1714     
1715     	pr_debug ("iucv_send: exiting\n");
1716     
1717     	return b2f0_result;
1718     }
1719     
1720     /*
1721      * Name: iucv_send_array
1722      * Purpose: This function transmits data to another application.
1723      *          The contents of buffer is the address of the array of
1724      *          addresses and lengths of discontiguous buffers that hold
1725      *          the message text. This is a one-way message and the
1726      *          receiver will not reply to the message.
1727      * Input: pathid - path identification number
1728      *        trgcls - specifies target class
1729      *        srccls - specifies the source message class
1730      *        msgtag - specifies a tag to be associated witht the message
1731      *        flags1 - option for path
1732      *                 IPPRTY- specifies if you want to send priority message
1733      *        buffer - address of array of send buffers
1734      *        buflen - total length of send buffers
1735      * Output: msgid - specifies the message ID.
1736      * Return: b2f0_result - return code from CP 
1737      *         (-EINVAL) - buffer address is NULL
1738      */
1739     int
1740     iucv_send_array (u16 pathid,
1741     		 u32 * msgid,
1742     		 u32 trgcls,
1743     		 u32 srccls,
1744     		 u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
1745     {
1746     	iparml_db parm;
1747     	ulong b2f0_result;
1748     
1749     	pr_debug ("iucv_send_array: entering\n");
1750     
1751     	if (!buffer)
1752     		return -EINVAL;
1753     
1754     	memset (&parm, 0, sizeof (parm));
1755     	parm.ippathid = pathid;
1756     	parm.iptrgcls = trgcls;
1757     	parm.ipbfadr1 = (u32) ((ulong) buffer);
1758     	parm.ipbfln1f = (u32) buflen;	/* length of message */
1759     	parm.ipsrccls = srccls;
1760     	parm.ipmsgtag = msgtag;
1761     	parm.ipflags1 = (IPNORPY | IPBUFLST | flags1);
1762     	b2f0_result = b2f0 (SEND, &parm);
1763     
1764     	if ((b2f0_result == 0) && (msgid))
1765     		*msgid = parm.ipmsgid;
1766     	pr_debug ("iucv_send_array: exiting\n");
1767     	return b2f0_result;
1768     }
1769     
1770     /*
1771      * Name: iucv_send_prmmsg
1772      * Purpose: This function transmits data to another application. 
1773      *          Prmmsg specifies that the 8-bytes of data are to be moved
1774      *          into the parameter list. This is a one-way message and the
1775      *          receiver will not reply to the message.
1776      * Input: pathid - path identification number
1777      *        trgcls - specifies target class
1778      *        srccls - specifies the source message class
1779      *        msgtag - specifies a tag to be associated with the message
1780      *        flags1 - option for path
1781      *                 IPPRTY- specifies if you want to send priority message
1782      *        prmmsg - 8-bytes of data to be placed into parameter list
1783      * Output: msgid - specifies the message ID.   
1784      * Return: b2f0_result - return code from CP
1785     */
1786     int
1787     iucv_send_prmmsg (u16 pathid,
1788     		  u32 * msgid,
1789     		  u32 trgcls,
1790     		  u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8])
1791     {
1792     	iparml_dpl parm;
1793     	ulong b2f0_result;
1794     
1795     	pr_debug ("iucv_send_prmmsg: entering\n");
1796     
1797     	memset (&parm, 0, sizeof (parm));
1798     	parm.ippathid = pathid;
1799     	parm.iptrgcls = trgcls;
1800     	parm.ipsrccls = srccls;
1801     	parm.ipmsgtag = msgtag;
1802     	parm.ipflags1 = (IPRMDATA | IPNORPY | flags1);
1803     	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
1804     
1805     	b2f0_result = b2f0 (SEND, &parm);
1806     
1807     	if ((b2f0_result == 0) && (msgid))
1808     		*msgid = parm.ipmsgid;
1809     
1810     	pr_debug ("iucv_send_prmmsg: exiting\n");
1811     	return b2f0_result;
1812     }
1813     
1814     /*
1815      * Name: iucv_send2way
1816      * Purpose: This function transmits data to another application.
1817      *          Data to be transmitted is in a buffer. The receiver
1818      *          of the send is expected to reply to the message and
1819      *          a buffer is provided into which IUCV moves the reply 
1820      *          to this message.
1821      * Input: pathid - path identification number
1822      *        trgcls - specifies target class
1823      *        srccls - specifies the source message class
1824      *        msgtag - specifies a tag associated with the message
1825      *        flags1 - option for path
1826      *                 IPPRTY- specifies if you want to send priority message
1827      *        buffer - address of send buffer
1828      *        buflen - length of send buffer
1829      *        ansbuf - address of buffer to reply with
1830      *        anslen - length of buffer to reply with
1831      * Output: msgid - specifies the message ID.
1832      * Return: b2f0_result - return code from CP
1833      *         (-EINVAL) - buffer or ansbuf address is NULL
1834      */
1835     int
1836     iucv_send2way (u16 pathid,
1837     	       u32 * msgid,
1838     	       u32 trgcls,
1839     	       u32 srccls,
1840     	       u32 msgtag,
1841     	       int flags1,
1842     	       void *buffer, ulong buflen, void *ansbuf, ulong anslen)
1843     {
1844     	iparml_db parm;
1845     	ulong b2f0_result;
1846     	pr_debug ("iucv_send2way: entering\n");
1847     
1848     	if (!buffer || !ansbuf)
1849     		return -EINVAL;
1850     
1851     	memset (&parm, 0, sizeof (parm));
1852     	parm.ippathid = pathid;
1853     	parm.iptrgcls = trgcls;
1854     	parm.ipbfadr1 = (u32) ((ulong) buffer);
1855     	parm.ipbfln1f = (u32) buflen;	/* length of message */
1856     	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
1857     	parm.ipbfln2f = (u32) anslen;
1858     	parm.ipsrccls = srccls;
1859     	parm.ipmsgtag = msgtag;
1860     	parm.ipflags1 = flags1;	/* priority message */
1861     
1862     	b2f0_result = b2f0 (SEND, &parm);
1863     
1864     	if ((b2f0_result == 0) && (msgid))
1865     		*msgid = parm.ipmsgid;
1866     
1867     	pr_debug ("iucv_send2way: exiting\n");
1868     
1869     	return b2f0_result;
1870     }
1871     
1872     /*
1873      * Name: iucv_send2way_array
1874      * Purpose: This function transmits data to another application.
1875      *          The contents of buffer is the address of the array of
1876      *          addresses and lengths of discontiguous buffers that hold
1877      *          the message text. The receiver of the send is expected to
1878      *          reply to the message and a buffer is provided into which
1879      *          IUCV moves the reply to this message.
1880      * Input: pathid - path identification number
1881      *        trgcls - specifies target class
1882      *        srccls - specifies the source message class
1883      *        msgtag - spcifies a tag to be associated with the message
1884      *        flags1 - option for path
1885      *                 IPPRTY- specifies if you want to send priority message
1886      *        buffer - address of array of send buffers
1887      *        buflen - total length of send buffers
1888      *        ansbuf - address of buffer to reply with                       
1889      *        anslen - length of buffer to reply with     
1890      * Output: msgid - specifies the message ID.
1891      * Return: b2f0_result - return code from CP
1892      *         (-EINVAL) - buffer address is NULL
1893      */
1894     int
1895     iucv_send2way_array (u16 pathid,
1896     		     u32 * msgid,
1897     		     u32 trgcls,
1898     		     u32 srccls,
1899     		     u32 msgtag,
1900     		     int flags1,
1901     		     iucv_array_t * buffer,
1902     		     ulong buflen, iucv_array_t * ansbuf, ulong anslen)
1903     {
1904     	iparml_db parm;
1905     	ulong b2f0_result;
1906     
1907     	pr_debug ("iucv_send2way_array: entering\n");
1908     
1909     	if (!buffer || !ansbuf)
1910     		return -EINVAL;
1911     
1912     	memset (&parm, 0, sizeof (parm));
1913     	parm.ippathid = pathid;
1914     	parm.iptrgcls = trgcls;
1915     	parm.ipbfadr1 = (u32) ((ulong) buffer);
1916     	parm.ipbfln1f = (u32) buflen;	/* length of message */
1917     	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
1918     	parm.ipbfln2f = (u32) anslen;
1919     	parm.ipsrccls = srccls;
1920     	parm.ipmsgtag = msgtag;
1921     	parm.ipflags1 = (IPBUFLST | IPANSLST | flags1);
1922     	b2f0_result = b2f0 (SEND, &parm);
1923     	if ((b2f0_result == 0) && (msgid))
1924     		*msgid = parm.ipmsgid;
1925     	pr_debug ("iucv_send2way_array: exiting\n");
1926     	return b2f0_result;
1927     }
1928     
1929     /*
1930      * Name: iucv_send2way_prmmsg
1931      * Purpose: This function transmits data to another application.
1932      *          Prmmsg specifies that the 8-bytes of data are to be moved
1933      *          into the parameter list. This is a two-way message and the
1934      *          receiver of the message is expected to reply. A buffer
1935      *          is provided into which IUCV moves the reply to this
1936      *          message.
1937      * Input: pathid - path identification number  
1938      *        trgcls - specifies target class
1939      *        srccls - specifies the source message class
1940      *        msgtag - specifies a tag to be associated with the message
1941      *        flags1 - option for path
1942      *                 IPPRTY- specifies if you want to send priority message
1943      *        prmmsg - 8-bytes of data to be placed in parameter list
1944      *        ansbuf - address of buffer to reply with                       
1945      *        anslen - length of buffer to reply with     
1946      * Output: msgid - specifies the message ID.
1947      * Return: b2f0_result - return code from CP
1948      *         (-EINVAL) - buffer address is NULL
1949     */
1950     int
1951     iucv_send2way_prmmsg (u16 pathid,
1952     		      u32 * msgid,
1953     		      u32 trgcls,
1954     		      u32 srccls,
1955     		      u32 msgtag,
1956     		      ulong flags1, uchar prmmsg[8], void *ansbuf, ulong anslen)
1957     {
1958     	iparml_dpl parm;
1959     	ulong b2f0_result;
1960     	pr_debug ("iucv_send2way_prmmsg: entering\n");
1961     
1962     	if (!ansbuf)
1963     		return -EINVAL;
1964     
1965     	memset (&parm, 0, sizeof (parm));
1966     	parm.ippathid = pathid;
1967     	parm.iptrgcls = trgcls;
1968     	parm.ipsrccls = srccls;
1969     	parm.ipmsgtag = msgtag;
1970     	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
1971     	parm.ipbfln2f = (u32) anslen;
1972     	parm.ipflags1 = (IPRMDATA | flags1);	/* message in prmlist */
1973     	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
1974     
1975     	b2f0_result = b2f0 (SEND, &parm);
1976     
1977     	if ((b2f0_result == 0) && (msgid))
1978     		*msgid = parm.ipmsgid;
1979     
1980     	pr_debug ("iucv_send2way_prmmsg: exiting\n");
1981     
1982     	return b2f0_result;
1983     }
1984     
1985     /*
1986      * Name: iucv_send2way_prmmsg_array
1987      * Purpose: This function transmits data to another application.
1988      *          Prmmsg specifies that the 8-bytes of data are to be moved
1989      *          into the parameter list. This is a two-way message and the
1990      *          receiver of the message is expected to reply. A buffer
1991      *          is provided into which IUCV moves the reply to this
1992      *          message. The contents of ansbuf is the address of the
1993      *          array of addresses and lengths of discontiguous buffers
1994      *          that contain the reply.
1995      * Input: pathid - path identification number
1996      *        trgcls - specifies target class
1997      *        srccls - specifies the source message class   
1998      *        msgtag - specifies a tag to be associated with the message
1999      *        flags1 - option for path
2000      *                 IPPRTY- specifies if you want to send priority message
2001      *        prmmsg - 8-bytes of data to be placed into the parameter list
2002      *        ansbuf - address of buffer to reply with                       
2003      *        anslen - length of buffer to reply with     
2004      * Output: msgid - specifies the message ID.
2005      * Return: b2f0_result - return code from CP
2006      *         (-EINVAL) - ansbuf address is NULL
2007      */
2008     int
2009     iucv_send2way_prmmsg_array (u16 pathid,
2010     			    u32 * msgid,
2011     			    u32 trgcls,
2012     			    u32 srccls,
2013     			    u32 msgtag,
2014     			    int flags1,
2015     			    uchar prmmsg[8],
2016     			    iucv_array_t * ansbuf, ulong anslen)
2017     {
2018     	iparml_dpl parm;
2019     	ulong b2f0_result;
2020     
2021     	pr_debug ("iucv_send2way_prmmsg_array: entering\n");
2022     
2023     	if (!ansbuf)
2024     		return -EINVAL;
2025     
2026     	memset (&parm, 0, sizeof (parm));
2027     	parm.ippathid = pathid;
2028     	parm.iptrgcls = trgcls;
2029     	parm.ipsrccls = srccls;
2030     	parm.ipmsgtag = msgtag;
2031     	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
2032     	parm.ipbfln2f = (u32) anslen;
2033     	parm.ipflags1 = (IPRMDATA | IPANSLST | flags1);
2034     	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
2035     	b2f0_result = b2f0 (SEND, &parm);
2036     	if ((b2f0_result == 0) && (msgid))
2037     		*msgid = parm.ipmsgid;
2038     	pr_debug ("iucv_send2way_prmmsg_array: exiting\n");
2039     	return b2f0_result;
2040     }
2041     
2042     /*
2043      * Name: iucv_setmask
2044      * Purpose: This function enables or disables the following IUCV   
2045      *          external interruptions: Nonpriority and priority message
2046      *          interrupts, nonpriority and priority reply interrupts.
2047      * Input: SetMaskFlag - options for interrupts
2048      *           0x80 - Nonpriority_MessagePendingInterruptsFlag
2049      *           0x40 - Priority_MessagePendingInterruptsFlag
2050      *           0x20 - Nonpriority_MessageCompletionInterruptsFlag
2051      *           0x10 - Priority_MessageCompletionInterruptsFlag
2052      * Output: NA
2053      * Return: b2f0_result - return code from CP
2054     */
2055     int
2056     iucv_setmask (int SetMaskFlag)
2057     {
2058     	iparml_set_mask parm;
2059     	ulong b2f0_result = 0;
2060     	pr_debug ("iucv_setmask: entering \n");
2061     
2062     	memset (&parm, 0, sizeof (parm));
2063     	parm.ipmask = (uchar) SetMaskFlag;
2064     
2065     	b2f0_result = b2f0 (SETMASK, &parm);
2066     
2067     	pr_debug ("iucv_setmask: b2f0_result = %ld\n", b2f0_result);
2068     	pr_debug ("iucv_setmask: exiting\n");
2069     
2070     	return b2f0_result;
2071     }
2072     
2073     /*
2074      * Name: iucv_sever                                           
2075      * Purpose: This function terminates an iucv path         
2076      * Input: pathid - u16, path identification number                             
2077      *        user_data - uchar[16], 16-byte of user data                     
2078      * Output: b2f0_result - return code from CP          
2079      *         -EINVAL - NULL address found for handler                                 
2080      */
2081     int
2082     iucv_sever (u16 pathid, uchar user_data[16])
2083     {
2084     	iparml_control parm;
2085     	ulong b2f0_result = 0;
2086     	pr_debug ("iucv_sever: entering\n");
2087     	memset (&parm, 0, sizeof (parm));
2088     	memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
2089     	parm.ippathid = pathid;
2090     
2091     	b2f0_result = b2f0 (SEVER, &parm);
2092     
2093     	if (!b2f0_result)
2094     		iucv_remove_pathid (pathid);
2095     
2096     	pr_debug ("iucv_sever: exiting \n");
2097     	return b2f0_result;
2098     }
2099     
2100     static void
2101     iucv_remove_pathid (u16 pathid)
2102     {
2103     	handler_table_entry *users_hte = NULL;	/*users handler_table_entry */
2104     	handler *users_handler = NULL;
2105     	ulong *users_pathid = NULL;
2106     	ulong flags;
2107     	spin_lock_irqsave (&iucv_lock, flags);
2108     	users_hte = handler_table_anchor + (int) pathid;
2109     
2110     	if ((users_hte->addrs) == NULL) {
2111     		spin_unlock_irqrestore (&iucv_lock, flags);
2112     		return;		/* wild pointer has been found */
2113     	}
2114     
2115     	users_handler = users_hte->addrs;
2116     
2117     	pr_debug ("iucv_sever: pathid is %d\n", pathid);
2118     	pr_debug ("iucv_sever: H_T_E is %p\n", users_hte);
2119     	pr_debug ("iucv_sever: address of handler is %p\n", users_handler);
2120     	pr_debug ("iucv_sever: below is pathid table\n");
2121     	iucv_dumpit ((uchar *) users_handler->pathid_head,
2122     		     (int) users_handler->entries * sizeof (ulong));
2123     
2124     /*
2125      * Searching the pathid address table for matching address, once    
2126      * found, NULL the handler_table_entry field and then zero the H_T_E fields.               
2127      */
2128     
2129     	for (users_pathid = (users_handler->pathid_head);
2130     	     users_pathid < (users_handler->pathid_tail); users_pathid++)
2131     
2132     		if (*users_pathid == (ulong) users_hte) {
2133     			pr_debug ("iucv_sever: found a path to remove from"
2134     				  "table\n");
2135     			pr_debug ("iucv_sever: removing %d \n",
2136     				  (int) (*users_pathid)); *users_pathid = NULL;
2137     
2138     			memset (users_hte, 0, sizeof (handler_table_entry));
2139     		}
2140     	spin_unlock_irqrestore (&iucv_lock, flags);
2141     	return;
2142     }
2143     
2144     /*
2145      * Interrupt Handling Functions
2146      * 	top_half_interrupt
2147      * 	bottom_half_interrupt
2148      * 	do_int
2149      */
2150     
2151     /*
2152      * Name: top_half_interrupt                                         
2153      * Purpose: Handles interrupts coming in from CP.  Places the interrupt on a queue and  
2154      * 	    calls bottom_half_interrupt          
2155      * Input: external interrupt buffer                                
2156      * Output: void                                                    
2157      */
2158     
2159     inline void
2160     top_half_interrupt (struct pt_regs *regs, __u16 code)
2161     {
2162     	iucv_packet *pkt;
2163     	int cpu = smp_processor_id();
2164     
2165     	irq_enter(cpu, 0x4000);
2166     
2167     	pkt = (iucv_packet *) kmalloc (sizeof (iucv_packet), GFP_ATOMIC);
2168     	if (pkt == NULL) {
2169     		printk (KERN_WARNING
2170     			"iucv:top_half_interrupt: out of memory\n");
2171     		irq_exit(cpu, 0x4000);
2172     		return;
2173     	}
2174     
2175     	memcpy (pkt->data, iucv_external_int_buffer, BUFFER_SIZE);
2176     
2177     	pr_debug ("TH: Got INT: %08x\n", *(int *) (pkt->data + 4));
2178     
2179     	/* put new packet on the list */
2180     	spin_lock (&iucv_packets_lock);
2181     	pkt->next = NULL;
2182     
2183     	if (iucv_packets_tail != NULL)
2184     		iucv_packets_tail->next = pkt;
2185     	else
2186     		iucv_packets_head = pkt;
2187     
2188     	iucv_packets_tail = pkt;
2189     	spin_unlock (&iucv_packets_lock);
2190     
2191     	if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
2192     		short_task.routine = (void *) bottom_half_interrupt;
2193     		queue_task (&short_task, &tq_immediate);
2194     		mark_bh (IMMEDIATE_BH);
2195     	}
2196     	irq_exit(cpu, 0x4000);
2197     	return;
2198     }
2199     
2200     /*
2201      * Name: bottom_half_interrupt                                      
2202      * Purpose: Handle interrupt at a more safer time                  
2203      * Input: void                                                     
2204      * Output: void                                                    
2205      */
2206     void
2207     bottom_half_interrupt (void)
2208     {
2209     	iucv_packet *iucv_packet_list;
2210     	iucv_packet *tmp;
2211     	ulong flags;
2212     	atomic_set (&bh_scheduled, 0);
2213     
2214     	spin_lock_irqsave (&iucv_packets_lock, flags);
2215     	iucv_packet_list = iucv_packets_head;
2216     	iucv_packets_head = iucv_packets_tail = NULL;
2217     	spin_unlock_irqrestore (&iucv_packets_lock, flags);
2218     
2219     	/* now process all the request in the iucv_packet_list */
2220     	pr_debug ("BH: Process all packets\n");
2221     	while (iucv_packet_list != NULL) {
2222     		pr_debug ("BH:>  %08x\n",
2223     			  *(int *) (iucv_packet_list->data + 4));
2224     
2225     		do_int ((iucv_GeneralInterrupt *) iucv_packet_list->data);
2226     
2227     		pr_debug ("BH:<  %08x\n",
2228     			  *(int *) (iucv_packet_list->data + 4));
2229     		tmp = iucv_packet_list;
2230     		iucv_packet_list = iucv_packet_list->next;
2231     		kfree (tmp);
2232     	}
2233     	pr_debug ("BH: Done\n");
2234     	return;
2235     }
2236     
2237     /*
2238      * Name: do_int                                                     
2239      * Purpose: Handles the interrupts in a more safe environment             
2240      * Input: int_buf - pointer to copy of external interrupt buffer  
2241      * Output: void                                                     
2242      */
2243     void
2244     do_int (iucv_GeneralInterrupt * int_buf)
2245     {
2246     	handler_table_entry *P = 0;
2247     	ulong flags;
2248     	handler *Q = 0, *R;
2249     	iucv_interrupt_ops_t *interrupt = 0;	/* interrupt addresses */
2250     	uchar temp_buff1[24], temp_buff2[24];	/* masked handler id. */
2251     	int add_pathid_result = 0, j = 0;
2252     	uchar no_listener[16] = "NO LISTENER";
2253     
2254     	pr_debug ("IUCV: BHI: -  Entered do_int "
2255     		  "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
2256     	pr_debug ("BHI:External Interrupt Buffer\n");
2257     	iucv_dumpit ((uchar *) int_buf, sizeof (iucv_GeneralInterrupt));
2258     
2259     	ASCEBC (no_listener, 16);
2260     	if (int_buf->iptype != 01) {
2261     		spin_lock_irqsave (&iucv_lock, flags);
2262     		P = handler_table_anchor + int_buf->ippathid;
2263     		Q = P->addrs;
2264     		interrupt = P->ops;	/* interrupt functions */
2265     
2266     		pr_debug ("iucv: do_int: Handler\n");
2267     		iucv_dumpit ((uchar *) Q, sizeof (handler));
2268     		spin_unlock_irqrestore (&iucv_lock, flags);
2269     	}
2270     	/* end of if statement */
2271     	switch (int_buf->iptype) {
2272     	case 0x01:		/* connection pending */
2273     		spin_lock_irqsave (&iucv_lock, flags);
2274     		for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
2275     			memcpy (temp_buff1, &(int_buf->ipvmid), 24);
2276     			memcpy (temp_buff2, &(R->id.userid), 24);
2277     			for (j = 0; j < 24; j++) {
2278     				temp_buff1[j] =
2279     				    (temp_buff1[j]) & (R->id.mask)[j];
2280     				temp_buff2[j] =
2281     				    (temp_buff2[j]) & (R->id.mask)[j];
2282     			}
2283     
2284     			pr_debug ("iucv:do_int: temp_buff1\n");
2285     			iucv_dumpit (temp_buff1, sizeof (temp_buff1));
2286     			pr_debug ("iucv:do_int: temp_buff2\n");
2287     			iucv_dumpit (temp_buff2, sizeof (temp_buff2));
2288     
2289     			if (memcmp ((void *) temp_buff1,
2290     				    (void *) temp_buff2, 24) == 0) {
2291     
2292     				pr_debug
2293     				    ("iucv:do_int: found a matching handler\n");
2294     				break;
2295     			}
2296     		}
2297     		spin_unlock_irqrestore (&iucv_lock, flags);
2298     
2299     		if (R) {
2300     			/* ADD PATH TO PATHID TABLE */
2301     			add_pathid_result = iucv_add_pathid (int_buf->ippathid,
2302     							     R, R->pgm_data);
2303     			if (add_pathid_result == NULL) {
2304     				interrupt = R->interrupt_table;
2305     				if (interrupt->ConnectionPending) {
2306     
2307     					EBCASC (int_buf->ipvmid, 8);
2308     
2309     					(interrupt->ConnectionPending)
2310     					    ((iucv_ConnectionPending *) int_buf,
2311     					     (R->pgm_data));
2312     				} else {
2313     					iucv_sever (int_buf->ippathid,
2314     						    no_listener);
2315     				}
2316     			} /* end of if(add_p...... */
2317     			else {
2318     				iucv_sever (int_buf->ippathid, no_listener);
2319     				pr_debug ("iucv:do_int:add_pathid failed"
2320     					  "with rc = %d\n",
2321     					  (int) add_pathid_result);
2322     			}
2323     		} else
2324     			iucv_sever (int_buf->ippathid, no_listener);
2325     		break;
2326     
2327     	case 0x02:		/*connection complete */
2328     		if (Q) {
2329     			if (interrupt->ConnectionComplete)
2330     				(interrupt->ConnectionComplete)
2331     				    ((iucv_ConnectionComplete *) int_buf, (P->pgm_data));
2332     			else
2333     				pr_debug ("iucv:do_int:"
2334     					  "ConnectionComplete not called\n");
2335     		}
2336     		
2337     		break;
2338     
2339     	case 0x03:		/* connection severed */
2340     		if (Q) {
2341     			if (interrupt->ConnectionSevered)
2342     				(interrupt->ConnectionSevered)
2343     				    ((iucv_ConnectionSevered *) int_buf,
2344     				     (P->pgm_data));
2345     
2346     			else
2347     				iucv_sever (int_buf->ippathid, no_listener);
2348     		} else
2349     			iucv_sever (int_buf->ippathid, no_listener);
2350     		break;
2351     
2352     	case 0x04:		/* connection quiesced */
2353     		if (Q) {
2354     			if (interrupt->ConnectionQuiesced)
2355     				(interrupt->ConnectionQuiesced)
2356     				    ((iucv_ConnectionQuiesced *) int_buf,
2357     				     (P->pgm_data));
2358     			else
2359     				pr_debug ("iucv:do_int:"
2360     					  "ConnectionQuiesced not called\n");
2361     		}
2362     		break;
2363     
2364     	case 0x05:		/* connection resumed */
2365     		if (Q) {
2366     			if (interrupt->ConnectionResumed)
2367     				(interrupt->ConnectionResumed)
2368     				    ((iucv_ConnectionResumed *) int_buf, (P->pgm_data));
2369     			else
2370     				pr_debug ("iucv:do_int:"
2371     					  "ConnectionResumed not called\n");
2372     		}
2373     		break;
2374     
2375     	case 0x06:		/* priority message complete */
2376     	case 0x07:		/* nonpriority message complete */
2377     		if (Q) {
2378     			if (interrupt->MessageComplete)
2379     				(interrupt->MessageComplete)
2380     				    ((iucv_MessageComplete *) int_buf, (P->pgm_data));
2381     			else
2382     				pr_debug ("iucv:do_int:"
2383     					  "MessageComplete not called\n");
2384     		}
2385     		break;
2386     
2387     	case 0x08:		/* priority message pending  */
2388     	case 0x09:		/* nonpriority message pending  */
2389     		if (Q) {
2390     			if (interrupt->MessagePending)
2391     				(interrupt->MessagePending)
2392     				    ((iucv_MessagePending *) int_buf, (P->pgm_data));
2393     			else
2394     				pr_debug ("iucv:do_int:"
2395     					  "MessagePending not called\n");
2396     		}
2397     		break;
2398     	default:		/* unknown iucv type */
2399     		printk (KERN_WARNING "iucv:do_int: unknown iucv interrupt \n");
2400     		break;
2401     	}			/* end switch */
2402     
2403     	pr_debug ("BH:-  Exiting do_int "
2404     		  "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
2405     
2406     	return;
2407     }
2408     /* end of function call */
2409     
2410     EXPORT_SYMBOL (iucv_accept);
2411     EXPORT_SYMBOL (iucv_connect);
2412     EXPORT_SYMBOL (iucv_purge);
2413     EXPORT_SYMBOL (iucv_query_maxconn);
2414     EXPORT_SYMBOL (iucv_query_bufsize);
2415     EXPORT_SYMBOL (iucv_quiesce);
2416     EXPORT_SYMBOL (iucv_receive);
2417     EXPORT_SYMBOL (iucv_receive_array);
2418     EXPORT_SYMBOL (iucv_reject);
2419     EXPORT_SYMBOL (iucv_reply);
2420     EXPORT_SYMBOL (iucv_reply_array);
2421     EXPORT_SYMBOL (iucv_reply_prmmsg);
2422     EXPORT_SYMBOL (iucv_resume);
2423     EXPORT_SYMBOL (iucv_send);
2424     EXPORT_SYMBOL (iucv_send2way);
2425     EXPORT_SYMBOL (iucv_send2way_array);
2426     EXPORT_SYMBOL (iucv_send_array);
2427     EXPORT_SYMBOL (iucv_send2way_prmmsg);
2428     EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
2429     EXPORT_SYMBOL (iucv_send_prmmsg);
2430     EXPORT_SYMBOL (iucv_setmask);
2431     EXPORT_SYMBOL (iucv_sever);
2432     EXPORT_SYMBOL (iucv_register_program);
2433     EXPORT_SYMBOL (iucv_unregister_program);
2434