📄 iucv.c
字号:
}/** * 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 + -