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

📄 iucv.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		parm->db.ipbfadr1 = (u32)(addr_t) buffer;		parm->db.ipbfln1f = (u32) size;		parm->db.ippathid = path->pathid;		parm->db.ipflags1 = flags | IUCV_IPNORPY;		parm->db.iptrgcls = msg->class;		parm->db.ipsrccls = srccls;		parm->db.ipmsgtag = msg->tag;	}	rc = iucv_call_b2f0(IUCV_SEND, parm);	if (!rc)		msg->id = parm->db.ipmsgid;	local_bh_enable();	return rc;}EXPORT_SYMBOL(iucv_message_send);/** * iucv_message_send2way * @path: address of iucv path structure * @msg: address of iucv msg structure * @flags: how the message is sent and the reply is received *	   (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST) * @srccls: source class of message * @buffer: address of send buffer or address of struct iucv_array * @size: length of send buffer * @ansbuf: address of answer buffer or address of struct iucv_array * @asize: size of reply buffer * * This function transmits data to another application. Data to be * transmitted is in a buffer. The receiver of the send is expected to * reply to the message and a buffer is provided into which IUCV moves * the reply to this message. * * Returns the result from the CP IUCV call. */int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,			  u8 flags, u32 srccls, void *buffer, size_t size,			  void *answer, size_t asize, size_t *residual){	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 = path->flags;	/* priority message */		parm->dpl.iptrgcls = msg->class;		parm->dpl.ipsrccls = srccls;		parm->dpl.ipmsgtag = msg->tag;		parm->dpl.ipbfadr2 = (u32)(addr_t) answer;		parm->dpl.ipbfln2f = (u32) asize;		memcpy(parm->dpl.iprmmsg, buffer, 8);	} else {		parm->db.ippathid = path->pathid;		parm->db.ipflags1 = path->flags;	/* priority message */		parm->db.iptrgcls = msg->class;		parm->db.ipsrccls = srccls;		parm->db.ipmsgtag = msg->tag;		parm->db.ipbfadr1 = (u32)(addr_t) buffer;		parm->db.ipbfln1f = (u32) size;		parm->db.ipbfadr2 = (u32)(addr_t) answer;		parm->db.ipbfln2f = (u32) asize;	}	rc = iucv_call_b2f0(IUCV_SEND, parm);	if (!rc)		msg->id = parm->db.ipmsgid;	local_bh_enable();	return rc;}EXPORT_SYMBOL(iucv_message_send2way);/** * iucv_path_pending * @data: Pointer to external interrupt buffer * * Process connection pending work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_path_pending {	u16 ippathid;	u8  ipflags1;	u8  iptype;	u16 ipmsglim;	u16 res1;	u8  ipvmid[8];	u8  ipuser[16];	u32 res3;	u8  ippollfg;	u8  res4[3];} __attribute__ ((packed));static void iucv_path_pending(struct iucv_irq_data *data){	struct iucv_path_pending *ipp = (void *) data;	struct iucv_handler *handler;	struct iucv_path *path;	char *error;	BUG_ON(iucv_path_table[ipp->ippathid]);	/* New pathid, handler found. Create a new path struct. */	error = iucv_error_no_memory;	path = iucv_path_alloc(ipp->ipmsglim, ipp->ipflags1, GFP_ATOMIC);	if (!path)		goto out_sever;	path->pathid = ipp->ippathid;	iucv_path_table[path->pathid] = path;	EBCASC(ipp->ipvmid, 8);	/* Call registered handler until one is found that wants the path. */	list_for_each_entry(handler, &iucv_handler_list, list) {		if (!handler->path_pending)			continue;		/*		 * Add path to handler to allow a call to iucv_path_sever		 * inside the path_pending function. If the handler returns		 * an error remove the path from the handler again.		 */		list_add(&path->list, &handler->paths);		path->handler = handler;		if (!handler->path_pending(path, ipp->ipvmid, ipp->ipuser))			return;		list_del(&path->list);		path->handler = NULL;	}	/* No handler wanted the path. */	iucv_path_table[path->pathid] = NULL;	iucv_path_free(path);	error = iucv_error_no_listener;out_sever:	iucv_sever_pathid(ipp->ippathid, error);}/** * iucv_path_complete * @data: Pointer to external interrupt buffer * * Process connection complete work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_path_complete {	u16 ippathid;	u8  ipflags1;	u8  iptype;	u16 ipmsglim;	u16 res1;	u8  res2[8];	u8  ipuser[16];	u32 res3;	u8  ippollfg;	u8  res4[3];} __attribute__ ((packed));static void iucv_path_complete(struct iucv_irq_data *data){	struct iucv_path_complete *ipc = (void *) data;	struct iucv_path *path = iucv_path_table[ipc->ippathid];	if (path && path->handler && path->handler->path_complete)		path->handler->path_complete(path, ipc->ipuser);}/** * iucv_path_severed * @data: Pointer to external interrupt buffer * * Process connection severed work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_path_severed {	u16 ippathid;	u8  res1;	u8  iptype;	u32 res2;	u8  res3[8];	u8  ipuser[16];	u32 res4;	u8  ippollfg;	u8  res5[3];} __attribute__ ((packed));static void iucv_path_severed(struct iucv_irq_data *data){	struct iucv_path_severed *ips = (void *) data;	struct iucv_path *path = iucv_path_table[ips->ippathid];	if (!path || !path->handler)	/* Already severed */		return;	if (path->handler->path_severed)		path->handler->path_severed(path, ips->ipuser);	else {		iucv_sever_pathid(path->pathid, NULL);		iucv_path_table[path->pathid] = NULL;		list_del_init(&path->list);		iucv_path_free(path);	}}/** * iucv_path_quiesced * @data: Pointer to external interrupt buffer * * Process connection quiesced work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_path_quiesced {	u16 ippathid;	u8  res1;	u8  iptype;	u32 res2;	u8  res3[8];	u8  ipuser[16];	u32 res4;	u8  ippollfg;	u8  res5[3];} __attribute__ ((packed));static void iucv_path_quiesced(struct iucv_irq_data *data){	struct iucv_path_quiesced *ipq = (void *) data;	struct iucv_path *path = iucv_path_table[ipq->ippathid];	if (path && path->handler && path->handler->path_quiesced)		path->handler->path_quiesced(path, ipq->ipuser);}/** * iucv_path_resumed * @data: Pointer to external interrupt buffer * * Process connection resumed work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_path_resumed {	u16 ippathid;	u8  res1;	u8  iptype;	u32 res2;	u8  res3[8];	u8  ipuser[16];	u32 res4;	u8  ippollfg;	u8  res5[3];} __attribute__ ((packed));static void iucv_path_resumed(struct iucv_irq_data *data){	struct iucv_path_resumed *ipr = (void *) data;	struct iucv_path *path = iucv_path_table[ipr->ippathid];	if (path && path->handler && path->handler->path_resumed)		path->handler->path_resumed(path, ipr->ipuser);}/** * iucv_message_complete * @data: Pointer to external interrupt buffer * * Process message complete work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_message_complete {	u16 ippathid;	u8  ipflags1;	u8  iptype;	u32 ipmsgid;	u32 ipaudit;	u8  iprmmsg[8];	u32 ipsrccls;	u32 ipmsgtag;	u32 res;	u32 ipbfln2f;	u8  ippollfg;	u8  res2[3];} __attribute__ ((packed));static void iucv_message_complete(struct iucv_irq_data *data){	struct iucv_message_complete *imc = (void *) data;	struct iucv_path *path = iucv_path_table[imc->ippathid];	struct iucv_message msg;	if (path && path->handler && path->handler->message_complete) {		msg.flags = imc->ipflags1;		msg.id = imc->ipmsgid;		msg.audit = imc->ipaudit;		memcpy(msg.rmmsg, imc->iprmmsg, 8);		msg.class = imc->ipsrccls;		msg.tag = imc->ipmsgtag;		msg.length = imc->ipbfln2f;		path->handler->message_complete(path, &msg);	}}/** * iucv_message_pending * @data: Pointer to external interrupt buffer * * Process message pending work item. Called from tasklet while holding * iucv_table_lock. */struct iucv_message_pending {	u16 ippathid;	u8  ipflags1;	u8  iptype;	u32 ipmsgid;	u32 iptrgcls;	union {		u32 iprmmsg1_u32;		u8  iprmmsg1[4];	} ln1msg1;	union {		u32 ipbfln1f;		u8  iprmmsg2[4];	} ln1msg2;	u32 res1[3];	u32 ipbfln2f;	u8  ippollfg;	u8  res2[3];} __attribute__ ((packed));static void iucv_message_pending(struct iucv_irq_data *data){	struct iucv_message_pending *imp = (void *) data;	struct iucv_path *path = iucv_path_table[imp->ippathid];	struct iucv_message msg;	if (path && path->handler && path->handler->message_pending) {		msg.flags = imp->ipflags1;		msg.id = imp->ipmsgid;		msg.class = imp->iptrgcls;		if (imp->ipflags1 & IUCV_IPRMDATA) {			memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8);			msg.length = 8;		} else			msg.length = imp->ln1msg2.ipbfln1f;		msg.reply_size = imp->ipbfln2f;		path->handler->message_pending(path, &msg);	}}/** * iucv_tasklet_fn: * * This tasklet loops over the queue of irq buffers created by * iucv_external_interrupt, calls the appropriate action handler * and then frees the buffer. */static void iucv_tasklet_fn(unsigned long ignored){	typedef void iucv_irq_fn(struct iucv_irq_data *);	static iucv_irq_fn *irq_fn[] = {		[0x02] = iucv_path_complete,		[0x03] = iucv_path_severed,		[0x04] = iucv_path_quiesced,		[0x05] = iucv_path_resumed,		[0x06] = iucv_message_complete,		[0x07] = iucv_message_complete,		[0x08] = iucv_message_pending,		[0x09] = iucv_message_pending,	};	struct list_head task_queue = LIST_HEAD_INIT(task_queue);	struct iucv_irq_list *p, *n;	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */	if (!spin_trylock(&iucv_table_lock)) {		tasklet_schedule(&iucv_tasklet);		return;	}	iucv_active_cpu = smp_processor_id();	spin_lock_irq(&iucv_queue_lock);	list_splice_init(&iucv_task_queue, &task_queue);	spin_unlock_irq(&iucv_queue_lock);	list_for_each_entry_safe(p, n, &task_queue, list) {		list_del_init(&p->list);		irq_fn[p->data.iptype](&p->data);		kfree(p);	}	iucv_active_cpu = -1;	spin_unlock(&iucv_table_lock);}/** * iucv_work_fn: * * This work function loops over the queue of path pending irq blocks * created by iucv_external_interrupt, calls the appropriate action * handler and then frees the buffer. */static void iucv_work_fn(struct work_struct *work){	typedef void iucv_irq_fn(struct iucv_irq_data *);	struct list_head work_queue = LIST_HEAD_INIT(work_queue);	struct iucv_irq_list *p, *n;	/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */	spin_lock_bh(&iucv_table_lock);	iucv_active_cpu = smp_processor_id();	spin_lock_irq(&iucv_queue_lock);	list_splice_init(&iucv_work_queue, &work_queue);	spin_unlock_irq(&iucv_queue_lock);	iucv_cleanup_queue();	list_for_each_entry_safe(p, n, &work_queue, list) {		list_del_init(&p->list);		iucv_path_pending(&p->data);		kfree(p);	}	iucv_active_cpu = -1;	spin_unlock_bh(&iucv_table_lock);}/** * iucv_external_interrupt * @code: irq code * * Handles external interrupts coming in from CP. * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn(). */static void iucv_external_interrupt(u16 code){	struct iucv_irq_data *p;	struct iucv_irq_list *work;	p = iucv_irq_data[smp_processor_id()];	if (p->ippathid >= iucv_max_pathid) {		printk(KERN_WARNING "iucv_do_int: Got interrupt with "		       "pathid %d > max_connections (%ld)\n",		       p->ippathid, iucv_max_pathid - 1);		iucv_sever_pathid(p->ippathid, iucv_error_no_listener);		return;	}	if (p->iptype  < 0x01 || p->iptype > 0x09) {		printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");		return;	}	work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);	if (!work) {		printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");		return;	}	memcpy(&work->data, p, sizeof(work->data));	spin_lock(&iucv_queue_lock);	if (p->iptype == 0x01) {		/* Path pending interrupt. */		list_add_tail(&work->list, &iucv_work_queue);		schedule_work(&iucv_work);	} else {		/* The other interrupts. */		list_add_tail(&work->list, &iucv_task_queue);		tasklet_schedule(&iucv_tasklet);	}	spin_unlock(&iucv_queue_lock);}/** * iucv_init * * Allocates and initializes various data structures. */static int __init iucv_init(void){	int rc;	int cpu;	if (!MACHINE_IS_VM) {		rc = -EPROTONOSUPPORT;		goto out;	}	rc = iucv_query_maxconn();	if (rc)		goto out;	rc = register_external_interrupt(0x4000, iucv_external_interrupt);	if (rc)		goto out;	rc = bus_register(&iucv_bus);	if (rc)		goto out_int;	iucv_root = s390_root_dev_register("iucv");	if (IS_ERR(iucv_root)) {		rc = PTR_ERR(iucv_root);		goto out_bus;	}	for_each_online_cpu(cpu) {		/* Note: GFP_DMA used to get memory below 2G */		iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),				     GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));		if (!iucv_irq_data[cpu]) {			rc = -ENOMEM;			goto out_free;		}		/* Allocate parameter blocks. */		iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),				  GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));		if (!iucv_param[cpu]) {			rc = -ENOMEM;			goto out_free;		}	}	register_hotcpu_notifier(&iucv_cpu_notifier);	ASCEBC(iucv_error_no_listener, 16);	ASCEBC(iucv_error_no_memory, 16);	ASCEBC(iucv_error_pathid, 16);	iucv_available = 1;	return 0;out_free:	for_each_possible_cpu(cpu) {		kfree(iucv_param[cpu]);		iucv_param[cpu] = NULL;		kfree(iucv_irq_data[cpu]);		iucv_irq_data[cpu] = NULL;	}	s390_root_dev_unregister(iucv_root);out_bus:	bus_unregister(&iucv_bus);out_int:	unregister_external_interrupt(0x4000, iucv_external_interrupt);out:	return rc;}/** * iucv_exit * * Frees everything allocated from iucv_init. */static void __exit iucv_exit(void){	struct iucv_irq_list *p, *n;	int cpu;	spin_lock_irq(&iucv_queue_lock);	list_for_each_entry_safe(p, n, &iucv_task_queue, list)		kfree(p);	list_for_each_entry_safe(p, n, &iucv_work_queue, list)		kfree(p);	spin_unlock_irq(&iucv_queue_lock);	unregister_hotcpu_notifier(&iucv_cpu_notifier);	for_each_possible_cpu(cpu) {		kfree(iucv_param[cpu]);		iucv_param[cpu] = NULL;		kfree(iucv_irq_data[cpu]);		iucv_irq_data[cpu] = NULL;	}	s390_root_dev_unregister(iucv_root);	bus_unregister(&iucv_bus);	unregister_external_interrupt(0x4000, iucv_external_interrupt);}subsys_initcall(iucv_init);module_exit(iucv_exit);MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -