iucv.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:64k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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