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