cregit-Linux how code gets into the kernel

Release 4.15 net/iucv/iucv.c

Directory: net/iucv
/*
 * IUCV base infrastructure.
 *
 * Copyright IBM Corp. 2001, 2009
 *
 * Author(s):
 *    Original source:
 *      Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
 *      Xenia Tkatschow (xenia@us.ibm.com)
 *    2Gb awareness and general cleanup:
 *      Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
 *    Rewritten for af_iucv:
 *      Martin Schwidefsky <schwidefsky@de.ibm.com>
 *    PM functions:
 *      Ursula Braun (ursula.braun@de.ibm.com)
 *
 * Documentation used:
 *    The original source
 *    CP Programming Service, IBM document # SC24-5760
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#define KMSG_COMPONENT "iucv"

#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/cpu.h>
#include <linux/reboot.h>
#include <net/iucv/iucv.h>
#include <linux/atomic.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/smp.h>

/*
 * FLAGS:
 * All flags are defined in the field IPFLAGS1 of each function
 * and can be found in CP Programming Services.
 * IPSRCCLS - Indicates you have specified a source class.
 * IPTRGCLS - Indicates you have specified a target class.
 * IPFGPID  - Indicates you have specified a pathid.
 * IPFGMID  - Indicates you have specified a message ID.
 * IPNORPY  - Indicates a one-way message. No reply expected.
 * IPALL    - Indicates that all paths are affected.
 */

#define IUCV_IPSRCCLS	0x01

#define IUCV_IPTRGCLS	0x01

#define IUCV_IPFGPID	0x02

#define IUCV_IPFGMID	0x04

#define IUCV_IPNORPY	0x10

#define IUCV_IPALL	0x80


static int iucv_bus_match(struct device *dev, struct device_driver *drv) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky19100.00%1100.00%
Total19100.00%1100.00%

enum iucv_pm_states { IUCV_PM_INITIAL = 0, IUCV_PM_FREEZING = 1, IUCV_PM_THAWING = 2, IUCV_PM_RESTORING = 3, }; static enum iucv_pm_states iucv_pm_state; static int iucv_pm_prepare(struct device *); static void iucv_pm_complete(struct device *); static int iucv_pm_freeze(struct device *); static int iucv_pm_thaw(struct device *); static int iucv_pm_restore(struct device *); static const struct dev_pm_ops iucv_pm_ops = { .prepare = iucv_pm_prepare, .complete = iucv_pm_complete, .freeze = iucv_pm_freeze, .thaw = iucv_pm_thaw, .restore = iucv_pm_restore, }; struct bus_type iucv_bus = { .name = "iucv", .match = iucv_bus_match, .pm = &iucv_pm_ops, }; EXPORT_SYMBOL(iucv_bus); struct device *iucv_root; EXPORT_SYMBOL(iucv_root); static int iucv_available; /* General IUCV interrupt structure */ struct iucv_irq_data { u16 ippathid; u8 ipflags1; u8 iptype; u32 res2[8]; }; struct iucv_irq_list { struct list_head list; struct iucv_irq_data data; }; static struct iucv_irq_data *iucv_irq_data[NR_CPUS]; static cpumask_t iucv_buffer_cpumask = { CPU_BITS_NONE }; static cpumask_t iucv_irq_cpumask = { CPU_BITS_NONE }; /* * Queue of interrupt buffers lock for delivery via the tasklet * (fast but can't call smp_call_function). */ static LIST_HEAD(iucv_task_queue); /* * The tasklet for fast delivery of iucv interrupts. */ static void iucv_tasklet_fn(unsigned long); static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_fn,0); /* * Queue of interrupt buffers for delivery via a work queue * (slower but can call smp_call_function). */ static LIST_HEAD(iucv_work_queue); /* * The work element to deliver path pending interrupts. */ static void iucv_work_fn(struct work_struct *work); static DECLARE_WORK(iucv_work, iucv_work_fn); /* * Spinlock protecting task and work queue. */ static DEFINE_SPINLOCK(iucv_queue_lock); enum iucv_command_codes { IUCV_QUERY = 0, IUCV_RETRIEVE_BUFFER = 2, IUCV_SEND = 4, IUCV_RECEIVE = 5, IUCV_REPLY = 6, IUCV_REJECT = 8, IUCV_PURGE = 9, IUCV_ACCEPT = 10, IUCV_CONNECT = 11, IUCV_DECLARE_BUFFER = 12, IUCV_QUIESCE = 13, IUCV_RESUME = 14, IUCV_SEVER = 15, IUCV_SETMASK = 16, IUCV_SETCONTROLMASK = 17, }; /* * Error messages that are used with the iucv_sever function. They get * converted to EBCDIC. */ static char iucv_error_no_listener[16] = "NO LISTENER"; static char iucv_error_no_memory[16] = "NO MEMORY"; static char iucv_error_pathid[16] = "INVALID PATHID"; /* * iucv_handler_list: List of registered handlers. */ static LIST_HEAD(iucv_handler_list); /* * iucv_path_table: an array of iucv_path structures. */ static struct iucv_path **iucv_path_table; static unsigned long iucv_max_pathid; /* * iucv_lock: spinlock protecting iucv_handler_list and iucv_pathid_table */ static DEFINE_SPINLOCK(iucv_table_lock); /* * iucv_active_cpu: contains the number of the cpu executing the tasklet * or the work handler. Needed for iucv_path_sever called from tasklet. */ static int iucv_active_cpu = -1; /* * Mutex and wait queue for iucv_register/iucv_unregister. */ static DEFINE_MUTEX(iucv_register_mutex); /* * Counter for number of non-smp capable handlers. */ static int iucv_nonsmp_handler; /* * IUCV control data structure. Used by iucv_path_accept, iucv_path_connect, * iucv_path_quiesce and iucv_path_sever. */ struct iucv_cmd_control { u16 ippathid; u8 ipflags1; u8 iprcode; u16 ipmsglim; u16 res1; u8 ipvmid[8]; u8 ipuser[16]; u8 iptarget[8]; } __attribute__ ((packed,aligned(8))); /* * Data in parameter list iucv structure. Used by iucv_message_send, * iucv_message_send2way and iucv_message_reply. */ struct iucv_cmd_dpl { u16 ippathid; u8 ipflags1; u8 iprcode; u32 ipmsgid; u32 iptrgcls; u8 iprmmsg[8]; u32 ipsrccls; u32 ipmsgtag; u32 ipbfadr2; u32 ipbfln2f; u32 res; } __attribute__ ((packed,aligned(8))); /* * Data in buffer iucv structure. Used by iucv_message_receive, * iucv_message_reject, iucv_message_send, iucv_message_send2way * and iucv_declare_cpu. */ struct iucv_cmd_db { u16 ippathid; u8 ipflags1; u8 iprcode; u32 ipmsgid; u32 iptrgcls; u32 ipbfadr1; u32 ipbfln1f; u32 ipsrccls; u32 ipmsgtag; u32 ipbfadr2; u32 ipbfln2f; u32 res; } __attribute__ ((packed,aligned(8))); /* * Purge message iucv structure. Used by iucv_message_purge. */ struct iucv_cmd_purge { u16 ippathid; u8 ipflags1; u8 iprcode; u32 ipmsgid; u8 ipaudit[3]; u8 res1[5]; u32 res2; u32 ipsrccls; u32 ipmsgtag; u32 res3[3]; } __attribute__ ((packed,aligned(8))); /* * Set mask iucv structure. Used by iucv_enable_cpu. */ struct iucv_cmd_set_mask { u8 ipmask; u8 res1[2]; u8 iprcode; u32 res2[9]; } __attribute__ ((packed,aligned(8))); union iucv_param { struct iucv_cmd_control ctrl; struct iucv_cmd_dpl dpl; struct iucv_cmd_db db; struct iucv_cmd_purge purge; struct iucv_cmd_set_mask set_mask; }; /* * Anchor for per-cpu IUCV command parameter block. */ static union iucv_param *iucv_param[NR_CPUS]; static union iucv_param *iucv_param_irq[NR_CPUS]; /** * iucv_call_b2f0 * @code: identifier of IUCV call to CP. * @parm: pointer to a struct iucv_parm block * * Calls CP to execute IUCV commands. * * Returns the result of the CP IUCV call. */
static inline int __iucv_call_b2f0(int command, union iucv_param *parm) { register unsigned long reg0 asm ("0"); register unsigned long reg1 asm ("1"); int ccode; reg0 = command; reg1 = (unsigned long)parm; asm volatile( " .long 0xb2f01000\n" " ipm %0\n" " srl %0,28\n" : "=d" (ccode), "=m" (*parm), "+d" (reg0), "+a" (reg1) : "m" (*parm) : "cc"); return ccode; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky4685.19%150.00%
Heiko Carstens814.81%150.00%
Total54100.00%2100.00%


static inline int iucv_call_b2f0(int command, union iucv_param *parm) { int ccode; ccode = __iucv_call_b2f0(command, parm); return ccode == 1 ? parm->ctrl.iprcode : ccode; }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens2767.50%150.00%
Martin Schwidefsky1332.50%150.00%
Total40100.00%2100.00%

/** * iucv_query_maxconn * * Determines the maximum number of connections that may be established. * * Returns the maximum number of connections or -EPERM is IUCV is not * available. */
static int __iucv_query_maxconn(void *param, unsigned long *max_pathid) { register unsigned long reg0 asm ("0"); register unsigned long reg1 asm ("1"); int ccode; reg0 = IUCV_QUERY; reg1 = (unsigned long) param; asm volatile ( " .long 0xb2f01000\n" " ipm %0\n" " srl %0,28\n" : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); *max_pathid = reg1; return ccode; }

Contributors

PersonTokensPropCommitsCommitProp
Heiko Carstens3559.32%150.00%
Martin Schwidefsky2440.68%150.00%
Total59100.00%2100.00%


static int iucv_query_maxconn(void) { unsigned long max_pathid; void *param; int ccode; param = kzalloc(sizeof(union iucv_param), GFP_KERNEL | GFP_DMA); if (!param) return -ENOMEM; ccode = __iucv_query_maxconn(param, &max_pathid); if (ccode == 0) iucv_max_pathid = max_pathid; kfree(param); return ccode ? -EPERM : 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky5775.00%150.00%
Heiko Carstens1925.00%150.00%
Total76100.00%2100.00%

/** * iucv_allow_cpu * @data: unused * * Allow iucv interrupts on this cpu. */
static void iucv_allow_cpu(void *data) { int cpu = smp_processor_id(); union iucv_param *parm; /* * Enable all iucv interrupts. * ipmask contains bits for the different interrupts * 0x80 - Flag to allow nonpriority message pending interrupts * 0x40 - Flag to allow priority message pending interrupts * 0x20 - Flag to allow nonpriority message completion interrupts * 0x10 - Flag to allow priority message completion interrupts * 0x08 - Flag to allow IUCV control interrupts */ parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); /* * Enable all iucv control interrupts. * ipmask contains bits for the different interrupts * 0x80 - Flag to allow pending connections interrupts * 0x40 - Flag to allow connection complete interrupts * 0x20 - Flag to allow connection severed interrupts * 0x10 - Flag to allow connection quiesced interrupts * 0x08 - Flag to allow connection resumed interrupts */ memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Set indication that iucv interrupts are allowed for this cpu. */ cpumask_set_cpu(cpu, &iucv_irq_cpumask); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky6063.16%120.00%
Ursula Braun3031.58%240.00%
Christoph Lameter33.16%120.00%
Motohiro Kosaki22.11%120.00%
Total95100.00%5100.00%

/** * iucv_block_cpu * @data: unused * * Block iucv interrupts on this cpu. */
static void iucv_block_cpu(void *data) { int cpu = smp_processor_id(); union iucv_param *parm; /* Disable all iucv interrupts. */ parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); iucv_call_b2f0(IUCV_SETMASK, parm); /* Clear indication that iucv interrupts are allowed for this cpu. */ cpumask_clear_cpu(cpu, &iucv_irq_cpumask); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky5289.66%125.00%
Christoph Lameter35.17%125.00%
Motohiro Kosaki23.45%125.00%
Ursula Braun11.72%125.00%
Total58100.00%4100.00%

/** * iucv_block_cpu_almost * @data: unused * * Allow connection-severed interrupts only on this cpu. */
static void iucv_block_cpu_almost(void *data) { int cpu = smp_processor_id(); union iucv_param *parm; /* Allow iucv control interrupts only */ parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0x08; iucv_call_b2f0(IUCV_SETMASK, parm); /* Allow iucv-severed interrupt only */ memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0x20; iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); /* Clear indication that iucv interrupts are allowed for this cpu. */ cpumask_clear_cpu(cpu, &iucv_irq_cpumask); }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun9397.89%150.00%
Motohiro Kosaki22.11%150.00%
Total95100.00%2100.00%

/** * iucv_declare_cpu * @data: unused * * Declare a interrupt buffer on this cpu. */
static void iucv_declare_cpu(void *data) { int cpu = smp_processor_id(); union iucv_param *parm; int rc; if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask)) return; /* Declare interrupt buffer. */ parm = iucv_param_irq[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); if (rc) { char *err = "Unknown"; 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; } pr_warn("Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n", cpu, rc, err); return; } /* Set indication that an iucv buffer exists for this cpu. */ cpumask_set_cpu(cpu, &iucv_buffer_cpumask); if (iucv_nonsmp_handler == 0 || cpumask_empty(&iucv_irq_cpumask)) /* Enable iucv interrupts on this cpu. */ iucv_allow_cpu(NULL); else /* Disable iucv interrupts on this cpu. */ iucv_block_cpu(NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky17092.90%120.00%
Motohiro Kosaki63.28%120.00%
Christoph Lameter42.19%120.00%
Joe Perches21.09%120.00%
Ursula Braun10.55%120.00%
Total183100.00%5100.00%

/** * iucv_retrieve_cpu * @data: unused * * Retrieve interrupt buffer on this cpu. */
static void iucv_retrieve_cpu(void *data) { int cpu = smp_processor_id(); union iucv_param *parm; if (!cpumask_test_cpu(cpu, &iucv_buffer_cpumask)) return; /* Block iucv interrupts. */ iucv_block_cpu(NULL); /* Retrieve interrupt buffer. */ parm = iucv_param_irq[cpu]; iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ cpumask_clear_cpu(cpu, &iucv_buffer_cpumask); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky5688.89%125.00%
Motohiro Kosaki46.35%125.00%
Christoph Lameter23.17%125.00%
Ursula Braun11.59%125.00%
Total63100.00%4100.00%

/** * iucv_setmask_smp * * Allow iucv interrupts on all cpus. */
static void iucv_setmask_mp(void) { int cpu; get_online_cpus(); for_each_online_cpu(cpu) /* Enable all cpus with a declared buffer. */ if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask) && !cpumask_test_cpu(cpu, &iucv_irq_cpumask)) smp_call_function_single(cpu, iucv_allow_cpu, NULL, 1); put_online_cpus(); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky4382.69%240.00%
Heiko Carstens59.62%240.00%
Motohiro Kosaki47.69%120.00%
Total52100.00%5100.00%

/** * iucv_setmask_up * * Allow iucv interrupts on a single cpu. */
static void iucv_setmask_up(void) { cpumask_t cpumask; int cpu; /* Disable all cpu but the first in cpu_irq_cpumask. */ cpumask_copy(&cpumask, &iucv_irq_cpumask); cpumask_clear_cpu(cpumask_first(&iucv_irq_cpumask), &cpumask); for_each_cpu(cpu, &cpumask) smp_call_function_single(cpu, iucv_block_cpu, NULL, 1); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky3871.70%133.33%
Motohiro Kosaki1222.64%133.33%
Heiko Carstens35.66%133.33%
Total53100.00%3100.00%

/** * iucv_enable * * This function makes iucv ready for use. It allocates the pathid * table, declares an iucv interrupt buffer and enables the iucv * interrupts. Called when the first user has registered an iucv * handler. */
static int iucv_enable(void) { size_t alloc_size; int cpu, rc; get_online_cpus(); rc = -ENOMEM; alloc_size = iucv_max_pathid * sizeof(struct iucv_path); iucv_path_table = kzalloc(alloc_size, GFP_KERNEL); if (!iucv_path_table) goto out; /* Declare per cpu buffers. */ rc = -EIO; for_each_online_cpu(cpu) smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1); if (cpumask_empty(&iucv_buffer_cpumask)) /* No cpu could declare an iucv buffer. */ goto out; put_online_cpus(); return 0; out: kfree(iucv_path_table); iucv_path_table = NULL; put_online_cpus(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky8781.31%120.00%
Heiko Carstens1816.82%360.00%
Motohiro Kosaki21.87%120.00%
Total107100.00%5100.00%

/** * iucv_disable * * This function shuts down iucv. It disables iucv interrupts, retrieves * the iucv interrupt buffer and frees the pathid table. Called after the * last user unregister its iucv handler. */
static void iucv_disable(void) { get_online_cpus(); on_each_cpu(iucv_retrieve_cpu, NULL, 1); kfree(iucv_path_table); iucv_path_table = NULL; put_online_cpus(); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky2268.75%133.33%
Heiko Carstens1031.25%266.67%
Total32100.00%3100.00%


static int iucv_cpu_dead(unsigned int cpu) { kfree(iucv_param_irq[cpu]); iucv_param_irq[cpu] = NULL; kfree(iucv_param[cpu]); iucv_param[cpu] = NULL; kfree(iucv_irq_data[cpu]); iucv_irq_data[cpu] = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Srivatsa S. Bhat4882.76%133.33%
Sebastian Andrzej Siewior610.34%133.33%
Martin Schwidefsky46.90%133.33%
Total58100.00%3100.00%


static int iucv_cpu_prepare(unsigned int 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]) 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]) goto out_free; iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param), GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); if (!iucv_param_irq[cpu]) goto out_free; return 0; out_free: iucv_cpu_dead(cpu); return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun3527.34%120.00%
Christoph Lameter3325.78%120.00%
Martin Schwidefsky3023.44%120.00%
Srivatsa S. Bhat2721.09%120.00%
Sebastian Andrzej Siewior32.34%120.00%
Total128100.00%5100.00%


static int iucv_cpu_online(unsigned int cpu) { if (!iucv_path_table) return 0; iucv_declare_cpu(NULL); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sebastian Andrzej Siewior1142.31%120.00%
Heiko Carstens519.23%120.00%
Srivatsa S. Bhat519.23%120.00%
Martin Schwidefsky415.38%120.00%
Ursula Braun13.85%120.00%
Total26100.00%5100.00%


static int iucv_cpu_down_prep(unsigned int cpu) { cpumask_t cpumask; if (!iucv_path_table) return 0; cpumask_copy(&cpumask, &iucv_buffer_cpumask); cpumask_clear_cpu(cpu, &cpumask); if (cpumask_empty(&cpumask)) /* Can't offline last IUCV enabled cpu. */ return -EINVAL; iucv_retrieve_cpu(NULL); if (!cpumask_empty(&iucv_irq_cpumask)) return 0; smp_call_function_single(cpumask_first(&iucv_buffer_cpumask), iucv_allow_cpu, NULL, 1); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky3945.35%116.67%
Sebastian Andrzej Siewior2124.42%116.67%
Motohiro Kosaki1416.28%116.67%
Heiko Carstens1011.63%233.33%
Akinobu Mita22.33%116.67%
Total86100.00%6100.00%

/** * 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) { union iucv_param *parm; parm = iucv_param_irq[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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky7594.94%125.00%
Christoph Lameter22.53%125.00%
Ursula Braun22.53%250.00%
Total79100.00%4100.00%

/** * __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) { }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky9100.00%2100.00%
Total9100.00%2100.00%

/** * 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 immediately * 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, 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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky7898.73%266.67%
Lucas De Marchi11.27%133.33%
Total79100.00%3100.00%

/** * 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_bh(&iucv_table_lock); list_add_tail(&handler->list, &iucv_handler_list); spin_unlock_bh(&iucv_table_lock); rc = 0; out_mutex: mutex_unlock(&iucv_register_mutex); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky11898.33%150.00%
Ursula Braun-Krahl21.67%150.00%
Total120100.00%2100.00%

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 referring 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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky12999.23%150.00%
Lucas De Marchi10.77%150.00%
Total130100.00%2100.00%

EXPORT_SYMBOL(iucv_unregister);
static int iucv_reboot_event(struct notifier_block *this, unsigned long event, void *ptr) { int i; if (cpumask_empty(&iucv_irq_cpumask)) return NOTIFY_DONE; get_online_cpus(); on_each_cpu_mask(&iucv_irq_cpumask, iucv_block_cpu, NULL, 1); preempt_disable(); for (i = 0; i < iucv_max_pathid; i++) { if (iucv_path_table[i]) iucv_sever_pathid(i, NULL); } preempt_enable(); put_online_cpus(); iucv_disable(); return NOTIFY_DONE; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun7783.70%150.00%
Hendrik Brueckner1516.30%150.00%
Total92100.00%2100.00%

static struct notifier_block iucv_reboot_notifier = { .notifier_call = iucv_reboot_event, }; /** * 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, void *private) { union iucv_param *parm; int rc; local_bh_disable(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } /* 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; } out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky15587.08%120.00%
Ursula Braun1910.67%240.00%
Christoph Lameter21.12%120.00%
Motohiro Kosaki21.12%120.00%
Total178100.00%5100.00%

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, u8 *system, u8 *userdata, void *private) { union iucv_param *parm; int rc; spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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; } } out: spin_unlock_bh(&iucv_table_lock); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky35293.37%233.33%
Ursula Braun215.57%233.33%
Christoph Lameter20.53%116.67%
Motohiro Kosaki20.53%116.67%
Total377100.00%6100.00%

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) { union iucv_param *parm; int rc; local_bh_disable(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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); out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky9280.00%120.00%
Ursula Braun1916.52%240.00%
Christoph Lameter21.74%120.00%
Motohiro Kosaki21.74%120.00%
Total115100.00%5100.00%

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) { union iucv_param *parm; int rc; local_bh_disable(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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); out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky9280.00%120.00%
Ursula Braun1916.52%240.00%
Motohiro Kosaki21.74%120.00%
Christoph Lameter21.74%120.00%
Total115100.00%5100.00%

/** * 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) { int rc; preempt_disable(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } if (iucv_active_cpu != smp_processor_id()) spin_lock_bh(&iucv_table_lock); rc = iucv_sever_pathid(path->pathid, userdata); iucv_path_table[path->pathid] = NULL; list_del_init(&path->list); if (iucv_active_cpu != smp_processor_id()) spin_unlock_bh(&iucv_table_lock); out: preempt_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky7979.00%240.00%
Ursula Braun1919.00%240.00%
Motohiro Kosaki22.00%120.00%
Total100100.00%5100.00%

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(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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; } out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky14086.42%125.00%
Ursula Braun1811.11%125.00%
Motohiro Kosaki21.23%125.00%
Christoph Lameter21.23%125.00%
Total162100.00%4100.00%

EXPORT_SYMBOL(iucv_message_purge); /** * iucv_message_receive_iprmdata * @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: * * Internal function used by iucv_message_receive and __iucv_message_receive * to receive RMDATA data stored in struct iucv_message. */
static int iucv_message_receive_iprmdata(struct iucv_path *path, struct iucv_message *msg, u8 flags, void *buffer, size_t size, size_t *residual) { struct iucv_array *array; u8 *rmmsg; size_t copy; /* * Message is 8 bytes long and has been stored to the * message descriptor itself. */ 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; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky15898.14%150.00%
Hendrik Brueckner31.86%150.00%
Total161100.00%2100.00%

/** * __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. * * Locking: no locking * * 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; int rc; if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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; } out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky13360.73%120.00%
Hendrik Brueckner6429.22%120.00%
Ursula Braun188.22%120.00%
Motohiro Kosaki20.91%120.00%
Christoph Lameter20.91%120.00%
Total219100.00%5100.00%

EXPORT_SYMBOL(__iucv_message_receive); /** * 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. * * Locking: local_bh_enable/local_bh_disable * * 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) { int rc; if (msg->flags & IUCV_IPRMDATA) return iucv_message_receive_iprmdata(path, msg, flags, buffer, size, residual); local_bh_disable(); rc = __iucv_message_receive(path, msg, flags, buffer, size, residual); local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Hendrik Brueckner7591.46%150.00%
Martin Schwidefsky78.54%150.00%
Total82100.00%2100.00%

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(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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); out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky10482.54%125.00%
Ursula Braun1814.29%125.00%
Motohiro Kosaki21.59%125.00%
Christoph Lameter21.59%125.00%
Total126100.00%4100.00%

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(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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); out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky20290.18%125.00%
Ursula Braun188.04%125.00%
Motohiro Kosaki20.89%125.00%
Christoph Lameter20.89%125.00%
Total224100.00%4100.00%

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. * * Locking: no locking * * 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; if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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 { 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; out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky22389.20%120.00%
Ursula Braun187.20%120.00%
Hendrik Brueckner52.00%120.00%
Motohiro Kosaki20.80%120.00%
Christoph Lameter20.80%120.00%
Total250100.00%5100.00%

EXPORT_SYMBOL(__iucv_message_send); /** * 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. * * Locking: local_bh_enable/local_bh_disable * * 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) { int rc; local_bh_disable(); rc = __iucv_message_send(path, msg, flags, srccls, buffer, size); local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Hendrik Brueckner5087.72%150.00%
Martin Schwidefsky712.28%150.00%
Total57100.00%2100.00%

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(); if (cpumask_empty(&iucv_buffer_cpumask)) { rc = -EIO; goto out; } 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; out: local_bh_enable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky29693.08%125.00%
Ursula Braun185.66%125.00%
Christoph Lameter20.63%125.00%
Motohiro Kosaki20.63%125.00%
Total318100.00%4100.00%

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]; } __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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky202100.00%1100.00%
Total202100.00%1100.00%

/** * 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]; } __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->flags = ipc->ipflags1; if (path && path->handler && path->handler->path_complete) path->handler->path_complete(path, ipc->ipuser); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky6183.56%266.67%
Hendrik Brueckner1216.44%133.33%
Total73100.00%3100.00%

/** * 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]; } __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(&path->list); iucv_path_free(path); } }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky10099.01%266.67%
Ursula Braun10.99%133.33%
Total101100.00%3100.00%

/** * 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]; } __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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky61100.00%2100.00%
Total61100.00%2100.00%

/** * 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]; } __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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky61100.00%2100.00%
Total61100.00%2100.00%

/** * 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]; } __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); } }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky127100.00%2100.00%
Total127100.00%2100.00%

/** * 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]; } __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); } }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky140100.00%2100.00%
Total140100.00%2100.00%

/** * 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, }; LIST_HEAD(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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky16991.85%250.00%
Ursula Braun-Krahl137.07%125.00%
Cheng Renquan21.09%125.00%
Total184100.00%4100.00%

/** * 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) { LIST_HEAD(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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky10298.08%266.67%
Cheng Renquan21.92%133.33%
Total104100.00%3100.00%

/** * 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(struct ext_code ext_code, unsigned int param32, unsigned long param64) { struct iucv_irq_data *p; struct iucv_irq_list *work; inc_irq_stat(IRQEXT_IUC); p = iucv_irq_data[smp_processor_id()]; if (p->ippathid >= iucv_max_pathid) { WARN_ON(p->ippathid >= iucv_max_pathid); iucv_sever_pathid(p->ippathid, iucv_error_no_listener); return; } BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); if (!work) { pr_warn("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); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky17492.06%333.33%
Heiko Carstens84.23%333.33%
Ursula Braun-Krahl42.12%111.11%
Christoph Lameter21.06%111.11%
Joe Perches10.53%111.11%
Total189100.00%9100.00%


static int iucv_pm_prepare(struct device *dev) { int rc = 0; #ifdef CONFIG_PM_DEBUG printk(KERN_INFO "iucv_pm_prepare\n"); #endif if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) rc = dev->driver->pm->prepare(dev); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun63100.00%1100.00%
Total63100.00%1100.00%


static void iucv_pm_complete(struct device *dev) { #ifdef CONFIG_PM_DEBUG printk(KERN_INFO "iucv_pm_complete\n"); #endif if (dev->driver && dev->driver->pm && dev->driver->pm->complete) dev->driver->pm->complete(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun53100.00%1100.00%
Total53100.00%1100.00%

/** * iucv_path_table_empty() - determine if iucv path table is empty * * Returns 0 if there are still iucv pathes defined * 1 if there are no iucv pathes defined */
int iucv_path_table_empty(void) { int i; for (i = 0; i < iucv_max_pathid; i++) { if (iucv_path_table[i]) return 0; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun38100.00%1100.00%
Total38100.00%1100.00%

/** * iucv_pm_freeze() - Freeze PM callback * @dev: iucv-based device * * disable iucv interrupts * invoke callback function of the iucv-based driver * shut down iucv, if no iucv-pathes are established anymore */
static int iucv_pm_freeze(struct device *dev) { int cpu; struct iucv_irq_list *p, *n; int rc = 0; #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_freeze\n"); #endif if (iucv_pm_state != IUCV_PM_FREEZING) { for_each_cpu(cpu, &iucv_irq_cpumask) smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); cancel_work_sync(&iucv_work); list_for_each_entry_safe(p, n, &iucv_work_queue, list) { list_del_init(&p->list); iucv_sever_pathid(p->data.ippathid, iucv_error_no_listener); kfree(p); } } iucv_pm_state = IUCV_PM_FREEZING; if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) rc = dev->driver->pm->freeze(dev); if (iucv_path_table_empty()) iucv_disable(); return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun15198.69%375.00%
Motohiro Kosaki21.31%125.00%
Total153100.00%4100.00%

/** * iucv_pm_thaw() - Thaw PM callback * @dev: iucv-based device * * make iucv ready for use again: allocate path table, declare interrupt buffers * and enable iucv interrupts * invoke callback function of the iucv-based driver */
static int iucv_pm_thaw(struct device *dev) { int rc = 0; #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_thaw\n"); #endif iucv_pm_state = IUCV_PM_THAWING; if (!iucv_path_table) { rc = iucv_enable(); if (rc) goto out; } if (cpumask_empty(&iucv_irq_cpumask)) { if (iucv_nonsmp_handler) /* enable interrupts on one cpu */ iucv_allow_cpu(NULL); else /* enable interrupts on all cpus */ iucv_setmask_mp(); } if (dev->driver && dev->driver->pm && dev->driver->pm->thaw) rc = dev->driver->pm->thaw(dev); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun11198.23%266.67%
Motohiro Kosaki21.77%133.33%
Total113100.00%3100.00%

/** * iucv_pm_restore() - Restore PM callback * @dev: iucv-based device * * make iucv ready for use again: allocate path table, declare interrupt buffers * and enable iucv interrupts * invoke callback function of the iucv-based driver */
static int iucv_pm_restore(struct device *dev) { int rc = 0; #ifdef CONFIG_PM_DEBUG printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); #endif if ((iucv_pm_state != IUCV_PM_RESTORING) && iucv_path_table) pr_warn("Suspending Linux did not completely close all IUCV connections\n"); iucv_pm_state = IUCV_PM_RESTORING; if (cpumask_empty(&iucv_irq_cpumask)) { rc = iucv_query_maxconn(); rc = iucv_enable(); if (rc) goto out; } if (dev->driver && dev->driver->pm && dev->driver->pm->restore) rc = dev->driver->pm->restore(dev); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Ursula Braun10996.46%250.00%
Motohiro Kosaki21.77%125.00%
Joe Perches21.77%125.00%
Total113100.00%4100.00%

struct iucv_interface iucv_if = { .message_receive = iucv_message_receive, .__message_receive = __iucv_message_receive, .message_reply = iucv_message_reply, .message_reject = iucv_message_reject, .message_send = iucv_message_send, .__message_send = __iucv_message_send, .message_send2way = iucv_message_send2way, .message_purge = iucv_message_purge, .path_accept = iucv_path_accept, .path_connect = iucv_path_connect, .path_quiesce = iucv_path_quiesce, .path_resume = iucv_path_resume, .path_sever = iucv_path_sever, .iucv_register = iucv_register, .iucv_unregister = iucv_unregister, .bus = NULL, .root = NULL, }; EXPORT_SYMBOL(iucv_if); static enum cpuhp_state iucv_online; /** * iucv_init * * Allocates and initializes various data structures. */
static int __init iucv_init(void) { int rc; if (!MACHINE_IS_VM) { rc = -EPROTONOSUPPORT; goto out; } ctl_set_bit(0, 1); rc = iucv_query_maxconn(); if (rc) goto out_ctl; rc = register_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt); if (rc) goto out_ctl; iucv_root = root_device_register("iucv"); if (IS_ERR(iucv_root)) { rc = PTR_ERR(iucv_root); goto out_int; } rc = cpuhp_setup_state(CPUHP_NET_IUCV_PREPARE, "net/iucv:prepare", iucv_cpu_prepare, iucv_cpu_dead); if (rc) goto out_dev; rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "net/iucv:online", iucv_cpu_online, iucv_cpu_down_prep); if (rc < 0) goto out_prep; iucv_online = rc; rc = register_reboot_notifier(&iucv_reboot_notifier); if (rc) goto out_remove_hp; ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_memory, 16); ASCEBC(iucv_error_pathid, 16); iucv_available = 1; rc = bus_register(&iucv_bus); if (rc) goto out_reboot; iucv_if.root = iucv_root; iucv_if.bus = &iucv_bus; return 0; out_reboot: unregister_reboot_notifier(&iucv_reboot_notifier); out_remove_hp: cpuhp_remove_state(iucv_online); out_prep: cpuhp_remove_state(CPUHP_NET_IUCV_PREPARE); out_dev: root_device_unregister(iucv_root); out_int: unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt); out_ctl: ctl_clear_bit(0, 1); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky14556.42%215.38%
Sebastian Andrzej Siewior3814.79%215.38%
Ursula Braun2610.12%215.38%
Cornelia Huck238.95%17.69%
Frank Blaschka135.06%17.69%
Thomas Huth41.56%17.69%
Christoph Lameter41.56%17.69%
Mark McLoughlin20.78%17.69%
Srivatsa S. Bhat10.39%17.69%
Heiko Carstens10.39%17.69%
Total257100.00%13100.00%

/** * iucv_exit * * Frees everything allocated from iucv_init. */
static void __exit iucv_exit(void) { struct iucv_irq_list *p, *n; 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_reboot_notifier(&iucv_reboot_notifier); cpuhp_remove_state_nocalls(iucv_online); cpuhp_remove_state(CPUHP_NET_IUCV_PREPARE); root_device_unregister(iucv_root); bus_unregister(&iucv_bus); unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt); }

Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky7681.72%222.22%
Ursula Braun88.60%222.22%
Sebastian Andrzej Siewior44.30%111.11%
Thomas Huth22.15%111.11%
Christoph Lameter11.08%111.11%
Heiko Carstens11.08%111.11%
Mark McLoughlin11.08%111.11%
Total93100.00%9100.00%

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");

Overall Contributors

PersonTokensPropCommitsCommitProp
Martin Schwidefsky564072.53%49.09%
Ursula Braun114814.76%613.64%
Hendrik Brueckner2393.07%36.82%
Heiko Carstens2242.88%1022.73%
Frank Blaschka1091.40%12.27%
Sebastian Andrzej Siewior881.13%24.55%
Motohiro Kosaki821.05%12.27%
Srivatsa S. Bhat811.04%12.27%
Christoph Lameter801.03%12.27%
Ursula Braun-Krahl300.39%49.09%
Cornelia Huck230.30%12.27%
Eric Dumazet70.09%12.27%
Thomas Huth60.08%12.27%
Joe Perches50.06%12.27%
Cheng Renquan40.05%12.27%
Mark McLoughlin30.04%12.27%
Lucas De Marchi20.03%12.27%
Akinobu Mita20.03%12.27%
Robert P. J. Day10.01%12.27%
Arun Sharma10.01%12.27%
Alexey Dobriyan10.01%12.27%
Total7776100.00%44100.00%
Directory: net/iucv
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.