📄 iucv.c
字号:
if (!iucv_param[cpu]) return NOTIFY_BAD; break; case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); iucv_irq_data[cpu] = NULL; break; case CPU_ONLINE: case CPU_ONLINE_FROZEN: case CPU_DOWN_FAILED: case CPU_DOWN_FAILED_FROZEN: smp_call_function_single(cpu, iucv_declare_cpu, NULL, 0, 1); break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: cpumask = iucv_buffer_cpumask; cpu_clear(cpu, cpumask); if (cpus_empty(cpumask)) /* Can't offline last IUCV enabled cpu. */ return NOTIFY_BAD; smp_call_function_single(cpu, iucv_retrieve_cpu, NULL, 0, 1); if (cpus_empty(iucv_irq_cpumask)) smp_call_function_single(first_cpu(iucv_buffer_cpumask), iucv_allow_cpu, NULL, 0, 1); break; } return NOTIFY_OK;}static struct notifier_block __cpuinitdata iucv_cpu_notifier = { .notifier_call = iucv_cpu_notify,};/** * iucv_sever_pathid * @pathid: path identification number. * @userdata: 16-bytes of user data. * * Sever an iucv path to free up the pathid. Used internally. */static int iucv_sever_pathid(u16 pathid, u8 userdata[16]){ union iucv_param *parm; parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = pathid; return iucv_call_b2f0(IUCV_SEVER, parm);}#ifdef CONFIG_SMP/** * __iucv_cleanup_queue * @dummy: unused dummy argument * * Nop function called via smp_call_function to force work items from * pending external iucv interrupts to the work queue. */static void __iucv_cleanup_queue(void *dummy){}#endif/** * iucv_cleanup_queue * * Function called after a path has been severed to find all remaining * work items for the now stale pathid. The caller needs to hold the * iucv_table_lock. */static void iucv_cleanup_queue(void){ struct iucv_irq_list *p, *n; /* * When a path is severed, the pathid can be reused immediatly * on a iucv connect or a connection pending interrupt. Remove * all entries from the task queue that refer to a stale pathid * (iucv_path_table[ix] == NULL). Only then do the iucv connect * or deliver the connection pending interrupt. To get all the * pending interrupts force them to the work queue by calling * an empty function on all cpus. */ smp_call_function(__iucv_cleanup_queue, NULL, 0, 1); spin_lock_irq(&iucv_queue_lock); list_for_each_entry_safe(p, n, &iucv_task_queue, list) { /* Remove stale work items from the task queue. */ if (iucv_path_table[p->data.ippathid] == NULL) { list_del(&p->list); kfree(p); } } spin_unlock_irq(&iucv_queue_lock);}/** * iucv_register: * @handler: address of iucv handler structure * @smp: != 0 indicates that the handler can deal with out of order messages * * Registers a driver with IUCV. * * Returns 0 on success, -ENOMEM if the memory allocation for the pathid * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus. */int iucv_register(struct iucv_handler *handler, int smp){ int rc; if (!iucv_available) return -ENOSYS; mutex_lock(&iucv_register_mutex); if (!smp) iucv_nonsmp_handler++; if (list_empty(&iucv_handler_list)) { rc = iucv_enable(); if (rc) goto out_mutex; } else if (!smp && iucv_nonsmp_handler == 1) iucv_setmask_up(); INIT_LIST_HEAD(&handler->paths); spin_lock_irq(&iucv_table_lock); list_add_tail(&handler->list, &iucv_handler_list); spin_unlock_irq(&iucv_table_lock); rc = 0;out_mutex: mutex_unlock(&iucv_register_mutex); return rc;}EXPORT_SYMBOL(iucv_register);/** * iucv_unregister * @handler: address of iucv handler structure * @smp: != 0 indicates that the handler can deal with out of order messages * * Unregister driver from IUCV. */void iucv_unregister(struct iucv_handler *handler, int smp){ struct iucv_path *p, *n; mutex_lock(&iucv_register_mutex); spin_lock_bh(&iucv_table_lock); /* Remove handler from the iucv_handler_list. */ list_del_init(&handler->list); /* Sever all pathids still refering to the handler. */ list_for_each_entry_safe(p, n, &handler->paths, list) { iucv_sever_pathid(p->pathid, NULL); iucv_path_table[p->pathid] = NULL; list_del(&p->list); iucv_path_free(p); } spin_unlock_bh(&iucv_table_lock); if (!smp) iucv_nonsmp_handler--; if (list_empty(&iucv_handler_list)) iucv_disable(); else if (!smp && iucv_nonsmp_handler == 0) iucv_setmask_mp(); mutex_unlock(&iucv_register_mutex);}EXPORT_SYMBOL(iucv_unregister);/** * iucv_path_accept * @path: address of iucv path structure * @handler: address of iucv handler structure * @userdata: 16 bytes of data reflected to the communication partner * @private: private data passed to interrupt handlers for this path * * This function is issued after the user received a connection pending * external interrupt and now wishes to complete the IUCV communication path. * * Returns the result of the CP IUCV call. */int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, u8 userdata[16], void *private){ union iucv_param *parm; int rc; local_bh_disable(); /* Prepare parameter block. */ parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ippathid = path->pathid; parm->ctrl.ipmsglim = path->msglim; if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ipflags1 = path->flags; rc = iucv_call_b2f0(IUCV_ACCEPT, parm); if (!rc) { path->private = private; path->msglim = parm->ctrl.ipmsglim; path->flags = parm->ctrl.ipflags1; } local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_path_accept);/** * iucv_path_connect * @path: address of iucv path structure * @handler: address of iucv handler structure * @userid: 8-byte user identification * @system: 8-byte target system identification * @userdata: 16 bytes of data reflected to the communication partner * @private: private data passed to interrupt handlers for this path * * 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 the result of the CP IUCV call. */int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, u8 userid[8], u8 system[8], u8 userdata[16], void *private){ union iucv_param *parm; int rc; BUG_ON(in_atomic()); spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ipmsglim = path->msglim; parm->ctrl.ipflags1 = path->flags; if (userid) { memcpy(parm->ctrl.ipvmid, userid, sizeof(parm->ctrl.ipvmid)); ASCEBC(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid)); EBC_TOUPPER(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid)); } if (system) { memcpy(parm->ctrl.iptarget, system, sizeof(parm->ctrl.iptarget)); ASCEBC(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget)); EBC_TOUPPER(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget)); } if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); rc = iucv_call_b2f0(IUCV_CONNECT, parm); if (!rc) { if (parm->ctrl.ippathid < iucv_max_pathid) { path->pathid = parm->ctrl.ippathid; path->msglim = parm->ctrl.ipmsglim; path->flags = parm->ctrl.ipflags1; path->handler = handler; path->private = private; list_add_tail(&path->list, &handler->paths); iucv_path_table[path->pathid] = path; } else { iucv_sever_pathid(parm->ctrl.ippathid, iucv_error_pathid); rc = -EIO; } } spin_unlock_bh(&iucv_table_lock); return rc;}EXPORT_SYMBOL(iucv_path_connect);/** * iucv_path_quiesce: * @path: address of iucv path structure * @userdata: 16 bytes of data reflected to the communication partner * * This function temporarily suspends incoming messages on an IUCV path. * You can later reactivate the path by invoking the iucv_resume function. * * Returns the result from the CP IUCV call. */int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_QUIESCE, parm); local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_path_quiesce);/** * iucv_path_resume: * @path: address of iucv path structure * @userdata: 16 bytes of data reflected to the communication partner * * This function resumes incoming messages on an IUCV path that has * been stopped with iucv_path_quiesce. * * Returns the result from the CP IUCV call. */int iucv_path_resume(struct iucv_path *path, u8 userdata[16]){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); parm->ctrl.ippathid = path->pathid; rc = iucv_call_b2f0(IUCV_RESUME, parm); local_bh_enable(); return rc;}/** * iucv_path_sever * @path: address of iucv path structure * @userdata: 16 bytes of data reflected to the communication partner * * This function terminates an IUCV path. * * Returns the result from the CP IUCV call. */int iucv_path_sever(struct iucv_path *path, u8 userdata[16]){ int rc; preempt_disable(); if (iucv_active_cpu != smp_processor_id()) spin_lock_bh(&iucv_table_lock); rc = iucv_sever_pathid(path->pathid, userdata); if (!rc) { iucv_path_table[path->pathid] = NULL; list_del_init(&path->list); } if (iucv_active_cpu != smp_processor_id()) spin_unlock_bh(&iucv_table_lock); preempt_enable(); return rc;}EXPORT_SYMBOL(iucv_path_sever);/** * iucv_message_purge * @path: address of iucv path structure * @msg: address of iucv msg structure * @srccls: source class of message * * Cancels a message you have sent. * * Returns the result from the CP IUCV call. */int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, u32 srccls){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->purge.ippathid = path->pathid; parm->purge.ipmsgid = msg->id; parm->purge.ipsrccls = srccls; parm->purge.ipflags1 = IUCV_IPSRCCLS | IUCV_IPFGMID | IUCV_IPFGPID; rc = iucv_call_b2f0(IUCV_PURGE, parm); if (!rc) { msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; msg->tag = parm->purge.ipmsgtag; } local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_message_purge);/** * iucv_message_receive * @path: address of iucv path structure * @msg: address of iucv msg structure * @flags: how the message is received (IUCV_IPBUFLST) * @buffer: address of data buffer or address of struct iucv_array * @size: length of data buffer * @residual: * * This function receives messages that are being sent to you over * established paths. This function will deal with RMDATA messages * embedded in struct iucv_message as well. * * Returns the result from the CP IUCV call. */int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, u8 flags, void *buffer, size_t size, size_t *residual){ union iucv_param *parm; struct iucv_array *array; u8 *rmmsg; size_t copy; int rc; if (msg->flags & IUCV_IPRMDATA) { /* * Message is 8 bytes long and has been stored to the * message descriptor itself. */ rc = (size < 8) ? 5 : 0; if (residual) *residual = abs(size - 8); rmmsg = msg->rmmsg; if (flags & IUCV_IPBUFLST) { /* Copy to struct iucv_array. */ size = (size < 8) ? size : 8; for (array = buffer; size > 0; array++) { copy = min_t(size_t, size, array->length); memcpy((u8 *)(addr_t) array->address, rmmsg, copy); rmmsg += copy; size -= copy; } } else { /* Copy to direct buffer. */ memcpy(buffer, rmmsg, min_t(size_t, size, 8)); } return 0; } local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = (u32)(addr_t) buffer; parm->db.ipbfln1f = (u32) size; parm->db.ipmsgid = msg->id; parm->db.ippathid = path->pathid; parm->db.iptrgcls = msg->class; parm->db.ipflags1 = (flags | IUCV_IPFGPID | IUCV_IPFGMID | IUCV_IPTRGCLS); rc = iucv_call_b2f0(IUCV_RECEIVE, parm); if (!rc || rc == 5) { msg->flags = parm->db.ipflags1; if (residual) *residual = parm->db.ipbfln1f; } local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_message_receive);/** * iucv_message_reject * @path: address of iucv path structure * @msg: address of iucv msg structure * * The reject function refuses a specified message. Between the time you * are notified of a message and the time that you complete the message, * the message may be rejected. * * Returns the result from the CP IUCV call. */int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ippathid = path->pathid; parm->db.ipmsgid = msg->id; parm->db.iptrgcls = msg->class; parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); rc = iucv_call_b2f0(IUCV_REJECT, parm); local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_message_reject);/** * iucv_message_reply * @path: address of iucv path structure * @msg: address of iucv msg structure * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) * @reply: address of reply data buffer or address of struct iucv_array * @size: length of reply data buffer * * This function responds to the two-way messages that you receive. You * must identify completely the message to which you wish to reply. ie, * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into * the parameter list. * * Returns the result from the CP IUCV call. */int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, u8 flags, void *reply, size_t size){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { parm->dpl.ippathid = path->pathid; parm->dpl.ipflags1 = flags; parm->dpl.ipmsgid = msg->id; parm->dpl.iptrgcls = msg->class; memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8)); } else { parm->db.ipbfadr1 = (u32)(addr_t) reply; parm->db.ipbfln1f = (u32) size; parm->db.ippathid = path->pathid; parm->db.ipflags1 = flags; parm->db.ipmsgid = msg->id; parm->db.iptrgcls = msg->class; } rc = iucv_call_b2f0(IUCV_REPLY, parm); local_bh_enable(); return rc;}EXPORT_SYMBOL(iucv_message_reply);/** * iucv_message_send * @path: address of iucv path structure * @msg: address of iucv msg structure * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) * @srccls: source class of message * @buffer: address of send buffer or address of struct iucv_array * @size: length of send buffer * * This function transmits data to another application. Data to be * transmitted is in a buffer and this is a one-way message and the * receiver will not reply to the message. * * Returns the result from the CP IUCV call. */int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, u8 flags, u32 srccls, void *buffer, size_t size){ union iucv_param *parm; int rc; local_bh_disable(); parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { /* Message of 8 bytes can be placed into the parameter list. */ parm->dpl.ippathid = path->pathid; parm->dpl.ipflags1 = flags | IUCV_IPNORPY; parm->dpl.iptrgcls = msg->class; parm->dpl.ipsrccls = srccls; parm->dpl.ipmsgtag = msg->tag; memcpy(parm->dpl.iprmmsg, buffer, 8); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -