📄 iucv.c
字号:
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(1, "entering"); iucv_debug(1, "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) { if (handle) printk(KERN_WARNING "%s: Handler not found in iucv_handler_table.\n", __FUNCTION__); else printk(KERN_WARNING "%s: NULL handle passed by application.\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) { if (msglim) *msglim = parm->ipmsglim; if (pgm_data) h->pgm_data = pgm_data; if (flags1_out) *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; } release_param(parm); iucv_debug(1, "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; iparml_control local_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(1, "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; } } spin_unlock_irqrestore (&iucv_lock, flags); if (!h) { if (handle) printk(KERN_WARNING "%s: Handler not found in iucv_handler_table.\n", __FUNCTION__); else printk(KERN_WARNING "%s: NULL handle passed by application.\n", __FUNCTION__); return -EINVAL; } if (pathid == NULL) { printk(KERN_WARNING "%s: NULL pathid pointer\n", __FUNCTION__); return -EINVAL; } parm = (iparml_control *)grab_param(); parm->ipmsglim = msglim_reqstd; if (user_data) memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); if (userid) { memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); } if (system_name) { memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); ASCEBC(parm->iptarget, sizeof(parm->iptarget)); EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); } /* In order to establish an IUCV connection, the procedure is: * * b2f0(CONNECT) * take the ippathid from the b2f0 call * register the handler to the ippathid * * Unfortunately, the ConnectionEstablished message gets sent after the * b2f0(CONNECT) call but before the register is handled. * * In order for this race condition to be eliminated, the IUCV Control * Interrupts must be disabled for the above procedure. * * David Kennedy <dkennedy@linuxcare.com> */ /* Enable everything but IUCV Control messages */ iucv_setmask(~(AllInterrupts)); messagesDisabled = 1; spin_lock_irqsave (&iucv_lock, flags); parm->ipflags1 = (__u8)flags1; b2f0_result = b2f0(CONNECT, parm); memcpy(&local_parm, parm, sizeof(local_parm)); release_param(parm); parm = &local_parm; if (!b2f0_result) add_pathid_result = __iucv_add_pathid(parm->ippathid, h); spin_unlock_irqrestore (&iucv_lock, flags); if (b2f0_result) { iucv_setmask(~0); messagesDisabled = 0; return b2f0_result; } *pathid = parm->ippathid; /* Enable everything again */ iucv_setmask(IUCVControlInterruptsFlag); if (msglim) *msglim = parm->ipmsglim; if (flags1_out) *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; if (add_pathid_result) { iucv_sever(*pathid, no_memory); printk(KERN_WARNING "%s: add_pathid failed with rc =" " %d\n", __FUNCTION__, add_pathid_result); return(add_pathid_result); } iucv_debug(1, "exiting"); return b2f0_result;}/** * iucv_purge: * @pathid: Path identification number * @msgid: Message ID of message to purge. * @srccls: Message class of the message to purge. * @audit: Pointer to an __u32. If not NULL, on return, information about * asynchronous errors that may have affected the normal completion * of this message ist stored at the given location. * * Cancels a message you have sent. * Returns: return code from CP */intiucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit){ iparml_purge *parm; ulong b2f0_result = 0; iucv_debug(1, "entering"); iucv_debug(1, "pathid = %d", pathid); parm = (iparml_purge *)grab_param(); parm->ipmsgid = msgid; parm->ippathid = pathid; parm->ipsrccls = srccls; parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); b2f0_result = b2f0(PURGE, parm); if (!b2f0_result && audit) { memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); /* parm->ipaudit has only 3 bytes */ *audit >>= 8; } release_param(parm); iucv_debug(1, "b2f0_result = %ld", b2f0_result); iucv_debug(1, "exiting"); return b2f0_result;}/** * iucv_query_generic: * @want_maxconn: Flag, describing which value is to be returned. * * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). * * Returns: The buffersize, if want_maxconn is 0; the maximum number of * connections, if want_maxconn is 1 or an error-code < 0 on failure. */static intiucv_query_generic(int want_maxconn){ iparml_purge *parm = (iparml_purge *)grab_param(); int bufsize, maxconn; int ccode; /** * Call b2f0 and store R0 (max buffer size), * R1 (max connections) and CC. */ asm volatile ( "LRA 1,0(%4)\n\t" "LR 0,%3\n\t" ".long 0xb2f01000\n\t" "IPM %0\n\t" "SRL %0,28\n\t" "ST 0,%1\n\t" "ST 1,%2\n\t" : "=d" (ccode), "=m" (bufsize), "=m" (maxconn) : "d" (QUERY), "a" (parm) : "0", "1", "cc" ); release_param(parm); if (ccode) return -EPERM; if (want_maxconn) return maxconn; return bufsize;}/** * iucv_query_maxconn: * * Determines the maximum number of connections thay may be established. * * Returns: Maximum number of connections that can be. */ulongiucv_query_maxconn(void){ return iucv_query_generic(1);}/** * iucv_query_bufsize: * * Determines the size of the external interrupt buffer. * * Returns: Size of external interrupt buffer. */ulongiucv_query_bufsize (void){ return iucv_query_generic(0);}/** * iucv_quiesce: * @pathid: Path identification number * @user_data: 16-byte user data * * Temporarily suspends incoming messages on an IUCV path. * You can later reactivate the path by invoking the iucv_resume function. * Returns: return code from CP */intiucv_quiesce (__u16 pathid, __u8 user_data[16]){ iparml_control *parm; ulong b2f0_result = 0; iucv_debug(1, "entering"); iucv_debug(1, "pathid = %d", pathid); parm = (iparml_control *)grab_param(); memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); parm->ippathid = pathid; b2f0_result = b2f0(QUIESCE, parm); release_param(parm); iucv_debug(1, "b2f0_result = %ld", b2f0_result); iucv_debug(1, "exiting"); return b2f0_result;}/** * iucv_receive: * @pathid: Path identification number. * @buffer: Address of buffer to receive. Must be below 2G. * @buflen: Length of buffer to receive. * @msgid: Specifies the message ID. * @trgcls: Specifies target class. * @flags1_out: Receives options for path on return. * - IPNORPY (0x10) Specifies whether a reply is required * - IPPRTY (0x20) Specifies if you want to send priority message * - IPRMDATA (0x80) Specifies the data is contained in the parameter list * @residual_buffer: Receives the address of buffer updated by the number * of bytes you have received on return. * @residual_length: On return, receives one of the following values: * - 0 If the receive buffer is the same length as * the message. * - Remaining bytes in buffer If the receive buffer is longer than the * message. * - Remaining bytes in message If the receive buffer is shorter than the * message. * * This function receives messages that are being sent to you over established * paths. * Returns: return code from CP IUCV call; If the receive buffer is shorter * than the message, always 5 * -EINVAL - buffer address is pointing to NULL */intiucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, void *buffer, ulong buflen, int *flags1_out, ulong * residual_buffer, ulong * residual_length){ iparml_db *parm; ulong b2f0_result; int moved = 0; /* number of bytes moved from parmlist to buffer */ iucv_debug(2, "entering"); if (!buffer) return -EINVAL; parm = (iparml_db *)grab_param(); parm->ipbfadr1 = (__u32) (addr_t) buffer; parm->ipbfln1f = (__u32) ((ulong) buflen); parm->ipmsgid = msgid; parm->ippathid = pathid; parm->iptrgcls = trgcls; parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); b2f0_result = b2f0(RECEIVE, parm); if (!b2f0_result || b2f0_result == 5) { if (flags1_out) { iucv_debug(2, "*flags1_out = %d", *flags1_out); *flags1_out = (parm->ipflags1 & (~0x07)); iucv_debug(2, "*flags1_out = %d", *flags1_out); } if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ if (residual_length) *residual_length = parm->ipbfln1f; if (residual_buffer) *residual_buffer = parm->ipbfadr1; } else { moved = min_t (unsigned long, buflen, 8); memcpy ((char *) buffer, (char *) &parm->ipbfadr1, moved); if (buflen < 8) b2f0_result = 5; if (residual_length) *residual_length = abs (buflen - 8); if (residual_buffer) *residual_buffer = (ulong) (buffer + moved); } } release_param(parm); iucv_debug(2, "exiting"); return b2f0_result;}/* * Name: iucv_receive_array * Purpose: This function receives messages that are being sent to you * over established paths. * Input: pathid - path identification number * buffer - address of array of buffers * buflen - total length of buffers * msgid - specifies the message ID. * trgcls - specifies target class * Output:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -