⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iucv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 + -