iucv.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:61k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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