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

📄 iucv.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
}/** * release_param - Release a parameter buffer. * @p: A pointer to a struct iucv_param, previously obtained by calling *     grab_param(). * * This function marks the specified parameter buffer "unused". */static __inline__ voidrelease_param(void *p){	atomic_set(&((iucv_param *)p)->in_use, 0);}/** * iucv_add_handler: - Add a new handler * @new_handler: handle that is being entered into chain. * * Places new handle on iucv_handler_table, if identical handler is not * found. * * Returns: 0 on success, !0 on failure (handler already in chain). */static intiucv_add_handler (handler *new){	ulong flags;	iucv_debug(1, "entering");	iucv_dumpit("handler:", new, sizeof(handler));	spin_lock_irqsave (&iucv_lock, flags);	if (!list_empty(&iucv_handler_table)) {		struct list_head *lh;		/**		 * Search list for handler with identical id. If one		 * is found, the new handler is _not_ added.		 */		list_for_each(lh, &iucv_handler_table) {			handler *h = list_entry(lh, handler, list);			if (!memcmp(&new->id, &h->id, sizeof(h->id))) {				iucv_debug(1, "ret 1");				spin_unlock_irqrestore (&iucv_lock, flags);				return 1;			}		}	}	/**	 * If we get here, no handler was found.	 */	INIT_LIST_HEAD(&new->list);	list_add(&new->list, &iucv_handler_table);	spin_unlock_irqrestore (&iucv_lock, flags);	iucv_debug(1, "exiting");	return 0;}/** * 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_dumpit("iparml before b2f0 call:", 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_dumpit("iparml after b2f0 call:", 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 int__iucv_add_pathid(__u16 pathid, handler *handler){	iucv_debug(1, "entering");	iucv_debug(1, "handler is pointing to %p", handler);	if (pathid > (max_connections - 1))		return -EINVAL;	if (iucv_pathid_table[pathid]) {		iucv_debug(1, "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;	iucv_debug(1, "exiting");	return 0;}				/* end of add_pathid function */static intiucv_add_pathid(__u16 pathid, handler *handler){	ulong flags;	int rc;	spin_lock_irqsave (&iucv_lock, flags);	rc = __iucv_add_pathid(pathid, handler);	spin_unlock_irqrestore (&iucv_lock, flags);	return rc;}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);}/** * iucv_declare_buffer_cpuid * Register at VM for subsequent IUCV operations. This is executed * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). */static voidiucv_declare_buffer_cpuid (void *result){	iparml_db *parm;	parm = (iparml_db *)grab_param();	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);	if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)		*((ulong *)result) = parm->iprcode;	release_param(parm);}/** * iucv_retrieve_buffer_cpuid: * Unregister IUCV usage at VM. This is always executed on the same * cpu that registered the buffer to VM. * Called from iucv_retrieve_buffer(). */static voidiucv_retrieve_buffer_cpuid (void *cpu){	iparml_control *parm;	parm = (iparml_control *)grab_param();	b2f0(RETRIEVE_BUFFER, parm);	release_param(parm);}/** * Name: iucv_declare_buffer * Purpose: Specifies the guests real address of an external *          interrupt. * Input: void * Output: iprcode - return code from b2f0 call */static intiucv_declare_buffer (void){	unsigned long flags;	ulong b2f0_result;	iucv_debug(1, "entering");	b2f0_result = -ENODEV;	spin_lock_irqsave (&iucv_lock, flags);	if (iucv_cpuid == -1) {		/* Reserve any cpu for use by iucv. */		iucv_cpuid = smp_get_cpu(CPU_MASK_ALL);		spin_unlock_irqrestore (&iucv_lock, flags);		smp_call_function_on(iucv_declare_buffer_cpuid,			&b2f0_result, 0, 1, iucv_cpuid);		if (b2f0_result) {			smp_put_cpu(iucv_cpuid);			iucv_cpuid = -1;		}		iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);	} else {		spin_unlock_irqrestore (&iucv_lock, flags);		b2f0_result = 0;	}	iucv_debug(1, "exiting");	return b2f0_result;}/** * iucv_retrieve_buffer: * * Terminates all use of IUCV. * Returns: return code from CP */static intiucv_retrieve_buffer (void){	iucv_debug(1, "entering");	if (iucv_cpuid != -1) {		smp_call_function_on(iucv_retrieve_buffer_cpuid,				     0, 0, 1, iucv_cpuid);		/* Release the cpu reserved by iucv_declare_buffer. */		smp_put_cpu(iucv_cpuid);		iucv_cpuid = -1;	}	iucv_debug(1, "exiting");	return 0;}/** * iucv_remove_handler: * @users_handler: handler to be removed * * Remove handler when application unregisters. */static voidiucv_remove_handler(handler *handler){	unsigned long flags;	if ((!iucv_pathid_table) || (!handler))		return;	iucv_debug(1, "entering");	spin_lock_irqsave (&iucv_lock, flags);	list_del(&handler->list);	if (list_empty(&iucv_handler_table)) {		if (register_flag) {			unregister_external_interrupt(0x4000, iucv_irq_handler);			register_flag = 0;		}	}	spin_unlock_irqrestore (&iucv_lock, flags);	iucv_debug(1, "exiting");	return;}/** * 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(1, "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_ATOMIC);	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_ATOMIC);		if (iucv_pathid_table == NULL) {			printk(KERN_WARNING "%s: iucv_pathid_table storage "			       "allocation failed\n", __FUNCTION__);			kfree(new_handler);			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.userid, 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;	}	rc = iucv_declare_buffer();	if (rc) {		char *err = "Unknown";		iucv_remove_handler(new_handler);		kfree(new_handler);		switch(rc) {		case 0x03:			err = "Directory error";			break;		case 0x0a:			err = "Invalid length";			break;		case 0x13:			err = "Buffer already exists";			break;		case 0x3e:			err = "Buffer overlap";			break;		case 0x5c:			err = "Paging or storage error";			break;		}		printk(KERN_WARNING "%s: iucv_declare_buffer "		       "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err);		return NULL;	}	if (!register_flag) {		/* request the 0x4000 external interrupt */		rc = register_external_interrupt (0x4000, iucv_irq_handler);		if (rc) {			iucv_remove_handler(new_handler);			kfree (new_handler);			printk(KERN_WARNING "%s: "			       "register_external_interrupt returned %ld\n",			       __FUNCTION__, rc);			return NULL;		}		register_flag = 1;	}	iucv_debug(1, "exiting");	return new_handler;}				/* end of register function *//** * iucv_unregister_program: * @handle: address of handler * * Unregister application with IUCV. * Returns: *   0 on success, -EINVAL, if specified handle is invalid. */intiucv_unregister_program (iucv_handle_t handle){	handler *h = NULL;	struct list_head *lh;	int i;	ulong flags;	iucv_debug(1, "entering");	iucv_debug(1, "address of handler is %p", h);	/* 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;		}	}	if (!h) {		spin_unlock_irqrestore (&iucv_lock, flags);		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;	}	/**	 * First, walk thru iucv_pathid_table and sever any pathid which is	 * still pointing to the handler to be removed.	 */	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(1, "exiting");

⌨️ 快捷键说明

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