📄 iucv.c
字号:
spin_lock_irqsave (&iucv_lock, flags); list_del(&handler->list); spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug("exiting"); return;}/** * b2f0: * @code: identifier of IUCV call to CP. * @parm: pointer to 40 byte iparml area passed to CP * * Calls CP to execute IUCV commands. * * Returns: return code from CP's IUCV call */static __inline__ ulongb2f0(__u32 code, void *parm){ iucv_debug("iparml before b2f0 call:"); iucv_dumpit(parm, sizeof(iucv_param)); asm volatile ( "LRA 1,0(%1)\n\t" "LR 0,%0\n\t" ".long 0xb2f01000" : : "d" (code), "a" (parm) : "0", "1" ); iucv_debug("iparml after b2f0 call:"); iucv_dumpit(parm, sizeof(iucv_param)); return (unsigned long)*((__u8 *)(parm + 3));}/* * Name: iucv_add_pathid * Purpose: Adds a path id to the system. * Input: pathid - pathid that is going to be entered into system * handle - address of handler that the pathid will be associated * with. * pgm_data - token passed in by application. * Output: 0: successful addition of pathid * - EINVAL - pathid entry is being used by another application * - ENOMEM - storage allocation for a new pathid table failed*/static intiucv_add_pathid(__u16 pathid, handler *handler){ ulong flags; iucv_debug("entering"); iucv_debug("handler is pointing to %p", handler); if (pathid > (max_connections - 1)) return -EINVAL; spin_lock_irqsave (&iucv_lock, flags); if (iucv_pathid_table[pathid]) { spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug("pathid entry is %p", iucv_pathid_table[pathid]); printk(KERN_WARNING "%s: Pathid being used, error.\n", __FUNCTION__); return -EINVAL; } iucv_pathid_table[pathid] = handler; spin_unlock_irqrestore (&iucv_lock, flags); iucv_debug("exiting"); return 0;} /* end of add_pathid function */static voidiucv_remove_pathid(__u16 pathid){ ulong flags; if (pathid > (max_connections - 1)) return; spin_lock_irqsave (&iucv_lock, flags); iucv_pathid_table[pathid] = NULL; spin_unlock_irqrestore (&iucv_lock, flags);}/* * Name: iucv_declare_buffer * Purpose: Specifies the guests real address of an external * interrupt. * Input: void * Output: iprcode - return code from b2f0 call*/intiucv_declare_buffer (void){ ulong b2f0_result; iparml_db *parm = (iparml_db *)grab_param(); parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); b2f0_result = b2f0(DECLARE_BUFFER, parm); release_param(parm); iucv_debug("Address of EIB = %p", iucv_external_int_buffer); iucv_debug("exiting"); return b2f0_result;}/** * iucv_retrieve_buffer: * * Terminates all use of IUCV. * Returns: return code from CP */intiucv_retrieve_buffer (void){ ulong b2f0_result = 0; iparml_control *parm = (iparml_control *)grab_param(); iucv_debug("entering"); b2f0_result = b2f0(RETRIEVE_BUFFER, parm); release_param(parm); if (b2f0_result == 0) { kfree(iucv_pathid_table); iucv_pathid_table = NULL; declare_flag = 0; } iucv_debug("exiting"); return b2f0_result;}/** * iucv_register_program: * @pgmname: user identification * @userid: machine identification * @pgmmask: Indicates which bits in the pgmname and userid combined will be * used to determine who is given control. * @ops: Address of interrupt handler table. * @pgm_data: Application data to be passed to interrupt handlers. * * Registers an application with IUCV. * Returns: * The address of handler, or NULL on failure. * NOTE on pgmmask: * If pgmname, userid and pgmmask are provided, pgmmask is entered into the * handler as is. * If pgmmask is NULL, the internal mask is set to all 0xff's * When userid is NULL, the first 8 bytes of the internal mask are forced * to 0x00. * If pgmmask and userid are NULL, the first 8 bytes of the internal mask * are forced to 0x00 and the last 16 bytes to 0xff. */iucv_handle_tiucv_register_program (__u8 pgmname[16], __u8 userid[8], __u8 pgmmask[24], iucv_interrupt_ops_t * ops, void *pgm_data){ ulong rc = 0; /* return code from function calls */ handler *new_handler; iucv_debug("entering"); if (ops == NULL) { /* interrupt table is not defined */ printk(KERN_WARNING "%s: Interrupt table is not defined, " "exiting\n", __FUNCTION__); return NULL; } if (!pgmname) { printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); return NULL; } /* Allocate handler entry */ new_handler = (handler *)kmalloc(sizeof(handler), GFP_KERNEL); if (new_handler == NULL) { printk(KERN_WARNING "%s: storage allocation for new handler " "failed.\n", __FUNCTION__); return NULL; } if (!iucv_pathid_table) { if (iucv_init()) { kfree(new_handler); return NULL; } max_connections = iucv_query_maxconn(); iucv_pathid_table = kmalloc(max_connections * sizeof(handler *), GFP_KERNEL); if (iucv_pathid_table == NULL) { printk(KERN_WARNING "%s: iucv_pathid_table storage " "allocation failed\n", __FUNCTION__); return NULL; } memset (iucv_pathid_table, 0, max_connections * sizeof(handler *)); } memset(new_handler, 0, sizeof (handler)); memcpy(new_handler->id.user_data, pgmname, sizeof (new_handler->id.user_data)); if (userid) { memcpy (new_handler->id.userid, userid, sizeof (new_handler->id.userid)); ASCEBC (new_handler->id.userid, sizeof (new_handler->id.userid)); EBC_TOUPPER (new_handler->id.userid, sizeof (new_handler->id.userid)); if (pgmmask) { memcpy (new_handler->id.mask, pgmmask, sizeof (new_handler->id.mask)); } else { memset (new_handler->id.mask, 0xFF, sizeof (new_handler->id.mask)); } } else { if (pgmmask) { memcpy (new_handler->id.mask, pgmmask, sizeof (new_handler->id.mask)); } else { memset (new_handler->id.mask, 0xFF, sizeof (new_handler->id.mask)); } memset (new_handler->id.mask, 0x00, sizeof (new_handler->id.userid)); } /* fill in the rest of handler */ new_handler->pgm_data = pgm_data; new_handler->interrupt_table = ops; /* * Check if someone else is registered with same pgmname, userid * and mask. If someone is already registered with same pgmname, * userid and mask, registration will fail and NULL will be returned * to the application. * If identical handler not found, then handler is added to list. */ rc = iucv_add_handler(new_handler); if (rc) { printk(KERN_WARNING "%s: Someone already registered with same " "pgmname, userid, pgmmask\n", __FUNCTION__); kfree (new_handler); return NULL; } if (declare_flag == 0) { rc = iucv_declare_buffer(); if (rc) { iucv_remove_handler(new_handler); kfree(new_handler); printk(KERN_WARNING "%s: iucv_declare_buffer " "returned %ld\n", __FUNCTION__, rc); return NULL; } /* request the 0x4000 external interrupt */ rc = register_external_interrupt (0x4000, iucv_irq_handler); if (rc) { iucv_remove_handler(new_handler); iucv_retrieve_buffer(); kfree (new_handler); printk(KERN_WARNING "%s: " "register_external_interrupt returned %ld\n", __FUNCTION__, rc); return NULL; } declare_flag = 1; } iucv_debug("exiting"); return new_handler;} /* end of register function *//** * iucv_unregister_program: * @handle: address of handler * * Unregister application with IUCV. * Returns: * Always 0 */intiucv_unregister_program (iucv_handle_t handle){ handler *h = (handler *)handle; int i; ulong flags; iucv_debug("entering"); iucv_debug("address of handler is %p", h); /** * First, walk thru iucv_pathid_table and sever any pathid which is * still pointing to the handler to be removed. */ spin_lock_irqsave (&iucv_lock, flags); for (i = 0; i < max_connections; i++) if (iucv_pathid_table[i] == h) { spin_unlock_irqrestore (&iucv_lock, flags); iucv_sever(i, h->id.user_data); spin_lock_irqsave(&iucv_lock, flags); } spin_unlock_irqrestore (&iucv_lock, flags); iucv_remove_handler(h); kfree(h); iucv_debug("exiting"); return 0;}/** * iucv_accept: * @pathid: Path identification number * @msglim_reqstd: The number of outstanding messages requested. * @user_data: Data specified by the iucv_connect function. * @flags1: Contains options for this path. * - IPPRTY (0x20) Specifies if you want to send priority message. * - IPRMDATA (0x80) Specifies whether your program can handle a message * in the parameter list. * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being * established. * @handle: Address of handler. * @pgm_data: Application data passed to interrupt handlers. * @flags1_out: Pointer to an int. If not NULL, on return the options for * the path are stored at the given location: * - IPPRTY (0x20) Indicates you may send a priority message. * @msglim: Pointer to an __u16. If not NULL, on return the maximum * number of outstanding messages is stored at the given * location. * * This function is issued after the user receives a Connection Pending external * interrupt and now wishes to complete the IUCV communication path. * Returns: * return code from CP */intiucv_accept(__u16 pathid, __u16 msglim_reqstd, __u8 user_data[16], int flags1, iucv_handle_t handle, void *pgm_data, int *flags1_out, __u16 * msglim){ ulong b2f0_result = 0; ulong flags; struct list_head *lh; handler *h = NULL; iparml_control *parm; iucv_debug("entering"); iucv_debug("pathid = %d", pathid); /* Checking if handle is valid */ spin_lock_irqsave (&iucv_lock, flags); list_for_each(lh, &iucv_handler_table) { if ((handler *)handle == list_entry(lh, handler, list)) { h = (handler *)handle; break; } } spin_unlock_irqrestore (&iucv_lock, flags); if (!h) { printk(KERN_WARNING "%s: NULL handle passed by application " "or handler not found in iucv_handler_table\n", __FUNCTION__); return -EINVAL; } parm = (iparml_control *)grab_param(); parm->ippathid = pathid; parm->ipmsglim = msglim_reqstd; if (user_data) memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); parm->ipflags1 = (__u8)flags1; b2f0_result = b2f0(ACCEPT, parm); if (b2f0_result == 0) { if (pgm_data) h->pgm_data = pgm_data; if (flags1_out) *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; } release_param(parm); iucv_debug("exiting"); return b2f0_result;}/** * iucv_connect: * @pathid: Path identification number * @msglim_reqstd: Number of outstanding messages requested * @user_data: 16-byte user data * @userid: 8-byte of user identification * @system_name: 8-byte identifying the system name * @flags1: Specifies options for this path: * - IPPRTY (0x20) Specifies if you want to send priority message. * - IPRMDATA (0x80) Specifies whether your program can handle a message * in the parameter list. * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being * established. * - IPLOCAL (0x01) Allows an application to force the partner to be on the * local system. If local is specified then target class * cannot be specified. * @flags1_out: Pointer to an int. If not NULL, on return the options for * the path are stored at the given location: * - IPPRTY (0x20) Indicates you may send a priority message. * @msglim: Pointer to an __u16. If not NULL, on return the maximum * number of outstanding messages is stored at the given * location. * @handle: Address of handler. * @pgm_data: Application data to be passed to interrupt handlers. * * This function establishes an IUCV path. Although the connect may complete * successfully, you are not able to use the path until you receive an IUCV * Connection Complete external interrupt. * Returns: return code from CP, or one of the following * - ENOMEM * - return code from iucv_declare_buffer * - EINVAL - invalid handle passed by application * - EINVAL - pathid address is NULL * - ENOMEM - pathid table storage allocation failed * - return code from internal function add_pathid */intiucv_connect (__u16 *pathid, __u16 msglim_reqstd, __u8 user_data[16], __u8 userid[8], __u8 system_name[8], int flags1, int *flags1_out, __u16 * msglim, iucv_handle_t handle, void *pgm_data){ iparml_control *parm; struct list_head *lh; ulong b2f0_result = 0; ulong flags; int add_pathid_result = 0; handler *h = NULL; __u8 no_memory[16] = "NO MEMORY"; iucv_debug("entering"); /* Checking if handle is valid */ spin_lock_irqsave (&iucv_lock, flags); list_for_each(lh, &iucv_handler_table) { if ((handler *)handle == list_entry(lh, handler, list)) { h = (handler *)handle; break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -