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