^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * IUCV base infrastructure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright IBM Corp. 2001, 2009
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Author(s):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Original source:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Xenia Tkatschow (xenia@us.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * 2Gb awareness and general cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Rewritten for af_iucv:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Martin Schwidefsky <schwidefsky@de.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * PM functions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Ursula Braun (ursula.braun@de.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Documentation used:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * The original source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * CP Programming Service, IBM document # SC24-5760
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define KMSG_COMPONENT "iucv"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/kernel_stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/cpu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <net/iucv/iucv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/ebcdic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * FLAGS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * All flags are defined in the field IPFLAGS1 of each function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * and can be found in CP Programming Services.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * IPSRCCLS - Indicates you have specified a source class.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * IPTRGCLS - Indicates you have specified a target class.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * IPFGPID - Indicates you have specified a pathid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * IPFGMID - Indicates you have specified a message ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * IPNORPY - Indicates a one-way message. No reply expected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * IPALL - Indicates that all paths are affected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define IUCV_IPSRCCLS 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define IUCV_IPTRGCLS 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define IUCV_IPFGPID 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define IUCV_IPFGMID 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define IUCV_IPNORPY 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define IUCV_IPALL 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int iucv_bus_match(struct device *dev, struct device_driver *drv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct bus_type iucv_bus = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .name = "iucv",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .match = iucv_bus_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) EXPORT_SYMBOL(iucv_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct device *iucv_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) EXPORT_SYMBOL(iucv_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int iucv_available;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* General IUCV interrupt structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct iucv_irq_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u32 res2[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct iucv_irq_list {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct iucv_irq_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static struct iucv_irq_data *iucv_irq_data[NR_CPUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static cpumask_t iucv_buffer_cpumask = { CPU_BITS_NONE };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static cpumask_t iucv_irq_cpumask = { CPU_BITS_NONE };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Queue of interrupt buffers lock for delivery via the tasklet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * (fast but can't call smp_call_function).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static LIST_HEAD(iucv_task_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * The tasklet for fast delivery of iucv interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static void iucv_tasklet_fn(unsigned long);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static DECLARE_TASKLET_OLD(iucv_tasklet, iucv_tasklet_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Queue of interrupt buffers for delivery via a work queue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * (slower but can call smp_call_function).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static LIST_HEAD(iucv_work_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * The work element to deliver path pending interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static void iucv_work_fn(struct work_struct *work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static DECLARE_WORK(iucv_work, iucv_work_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * Spinlock protecting task and work queue.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static DEFINE_SPINLOCK(iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) enum iucv_command_codes {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) IUCV_QUERY = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) IUCV_RETRIEVE_BUFFER = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) IUCV_SEND = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) IUCV_RECEIVE = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) IUCV_REPLY = 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) IUCV_REJECT = 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) IUCV_PURGE = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) IUCV_ACCEPT = 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) IUCV_CONNECT = 11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) IUCV_DECLARE_BUFFER = 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) IUCV_QUIESCE = 13,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) IUCV_RESUME = 14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) IUCV_SEVER = 15,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) IUCV_SETMASK = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) IUCV_SETCONTROLMASK = 17,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * Error messages that are used with the iucv_sever function. They get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * converted to EBCDIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static char iucv_error_no_listener[16] = "NO LISTENER";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static char iucv_error_no_memory[16] = "NO MEMORY";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static char iucv_error_pathid[16] = "INVALID PATHID";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * iucv_handler_list: List of registered handlers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static LIST_HEAD(iucv_handler_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * iucv_path_table: an array of iucv_path structures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static struct iucv_path **iucv_path_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static unsigned long iucv_max_pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * iucv_lock: spinlock protecting iucv_handler_list and iucv_pathid_table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static DEFINE_SPINLOCK(iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * iucv_active_cpu: contains the number of the cpu executing the tasklet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * or the work handler. Needed for iucv_path_sever called from tasklet.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static int iucv_active_cpu = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) * Mutex and wait queue for iucv_register/iucv_unregister.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static DEFINE_MUTEX(iucv_register_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Counter for number of non-smp capable handlers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static int iucv_nonsmp_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * IUCV control data structure. Used by iucv_path_accept, iucv_path_connect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * iucv_path_quiesce and iucv_path_sever.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct iucv_cmd_control {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) u8 iprcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) u16 ipmsglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) u16 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) u8 ipvmid[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u8 iptarget[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) } __attribute__ ((packed,aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * Data in parameter list iucv structure. Used by iucv_message_send,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * iucv_message_send2way and iucv_message_reply.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct iucv_cmd_dpl {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) u8 iprcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) u32 ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) u32 iptrgcls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) u8 iprmmsg[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) u32 ipsrccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) u32 ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) u32 ipbfadr2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) u32 ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) u32 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) } __attribute__ ((packed,aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * Data in buffer iucv structure. Used by iucv_message_receive,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * iucv_message_reject, iucv_message_send, iucv_message_send2way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * and iucv_declare_cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) struct iucv_cmd_db {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) u8 iprcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) u32 ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) u32 iptrgcls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) u32 ipbfadr1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) u32 ipbfln1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) u32 ipsrccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) u32 ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) u32 ipbfadr2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) u32 ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) u32 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) } __attribute__ ((packed,aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * Purge message iucv structure. Used by iucv_message_purge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct iucv_cmd_purge {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) u8 iprcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) u32 ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) u8 ipaudit[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) u8 res1[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) u32 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) u32 ipsrccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) u32 ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) u32 res3[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) } __attribute__ ((packed,aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * Set mask iucv structure. Used by iucv_enable_cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) struct iucv_cmd_set_mask {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) u8 ipmask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) u8 res1[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u8 iprcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) u32 res2[9];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) } __attribute__ ((packed,aligned(8)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) union iucv_param {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct iucv_cmd_control ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct iucv_cmd_dpl dpl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct iucv_cmd_db db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct iucv_cmd_purge purge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct iucv_cmd_set_mask set_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * Anchor for per-cpu IUCV command parameter block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static union iucv_param *iucv_param[NR_CPUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static union iucv_param *iucv_param_irq[NR_CPUS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * iucv_call_b2f0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * @code: identifier of IUCV call to CP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * @parm: pointer to a struct iucv_parm block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * Calls CP to execute IUCV commands.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * Returns the result of the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static inline int __iucv_call_b2f0(int command, union iucv_param *parm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) register unsigned long reg0 asm ("0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) register unsigned long reg1 asm ("1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) reg0 = command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) reg1 = (unsigned long)parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) " .long 0xb2f01000\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) " ipm %0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) " srl %0,28\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) : "=d" (ccode), "=m" (*parm), "+d" (reg0), "+a" (reg1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) : "m" (*parm) : "cc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static inline int iucv_call_b2f0(int command, union iucv_param *parm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) int ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ccode = __iucv_call_b2f0(command, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return ccode == 1 ? parm->ctrl.iprcode : ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * iucv_query_maxconn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * Determines the maximum number of connections that may be established.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * Returns the maximum number of connections or -EPERM is IUCV is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) static int __iucv_query_maxconn(void *param, unsigned long *max_pathid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) register unsigned long reg0 asm ("0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) register unsigned long reg1 asm ("1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) reg0 = IUCV_QUERY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) reg1 = (unsigned long) param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) asm volatile (
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) " .long 0xb2f01000\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) " ipm %0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) " srl %0,28\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) *max_pathid = reg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int iucv_query_maxconn(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) unsigned long max_pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) void *param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) int ccode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) param = kzalloc(sizeof(union iucv_param), GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (!param)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ccode = __iucv_query_maxconn(param, &max_pathid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (ccode == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) iucv_max_pathid = max_pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) kfree(param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return ccode ? -EPERM : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) * iucv_allow_cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * @data: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * Allow iucv interrupts on this cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) static void iucv_allow_cpu(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) * Enable all iucv interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * ipmask contains bits for the different interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * 0x80 - Flag to allow nonpriority message pending interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) * 0x40 - Flag to allow priority message pending interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * 0x20 - Flag to allow nonpriority message completion interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * 0x10 - Flag to allow priority message completion interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * 0x08 - Flag to allow IUCV control interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) parm = iucv_param_irq[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) parm->set_mask.ipmask = 0xf8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) iucv_call_b2f0(IUCV_SETMASK, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * Enable all iucv control interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * ipmask contains bits for the different interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * 0x80 - Flag to allow pending connections interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * 0x40 - Flag to allow connection complete interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * 0x20 - Flag to allow connection severed interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * 0x10 - Flag to allow connection quiesced interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * 0x08 - Flag to allow connection resumed interrupts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) parm->set_mask.ipmask = 0xf8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) iucv_call_b2f0(IUCV_SETCONTROLMASK, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* Set indication that iucv interrupts are allowed for this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) cpumask_set_cpu(cpu, &iucv_irq_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * iucv_block_cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * @data: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * Block iucv interrupts on this cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static void iucv_block_cpu(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /* Disable all iucv interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) parm = iucv_param_irq[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) iucv_call_b2f0(IUCV_SETMASK, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) /* Clear indication that iucv interrupts are allowed for this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) cpumask_clear_cpu(cpu, &iucv_irq_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) * iucv_declare_cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) * @data: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) * Declare a interrupt buffer on this cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static void iucv_declare_cpu(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) /* Declare interrupt buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) parm = iucv_param_irq[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) char *err = "Unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) switch (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) case 0x03:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) err = "Directory error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) case 0x0a:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) err = "Invalid length";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case 0x13:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) err = "Buffer already exists";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) case 0x3e:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) err = "Buffer overlap";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) case 0x5c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) err = "Paging or storage error";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) pr_warn("Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) cpu, rc, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) /* Set indication that an iucv buffer exists for this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) cpumask_set_cpu(cpu, &iucv_buffer_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (iucv_nonsmp_handler == 0 || cpumask_empty(&iucv_irq_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* Enable iucv interrupts on this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) iucv_allow_cpu(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* Disable iucv interrupts on this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) iucv_block_cpu(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * iucv_retrieve_cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * @data: unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * Retrieve interrupt buffer on this cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) static void iucv_retrieve_cpu(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (!cpumask_test_cpu(cpu, &iucv_buffer_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) /* Block iucv interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) iucv_block_cpu(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /* Retrieve interrupt buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) parm = iucv_param_irq[cpu];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) /* Clear indication that an iucv buffer exists for this cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) cpumask_clear_cpu(cpu, &iucv_buffer_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * iucv_setmask_smp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * Allow iucv interrupts on all cpus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) static void iucv_setmask_mp(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) get_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) for_each_online_cpu(cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* Enable all cpus with a declared buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if (cpumask_test_cpu(cpu, &iucv_buffer_cpumask) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) !cpumask_test_cpu(cpu, &iucv_irq_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) smp_call_function_single(cpu, iucv_allow_cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * iucv_setmask_up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * Allow iucv interrupts on a single cpu.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static void iucv_setmask_up(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) cpumask_t cpumask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) int cpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) /* Disable all cpu but the first in cpu_irq_cpumask. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) cpumask_copy(&cpumask, &iucv_irq_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) cpumask_clear_cpu(cpumask_first(&iucv_irq_cpumask), &cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) for_each_cpu(cpu, &cpumask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) smp_call_function_single(cpu, iucv_block_cpu, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * iucv_enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) * This function makes iucv ready for use. It allocates the pathid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * table, declares an iucv interrupt buffer and enables the iucv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * interrupts. Called when the first user has registered an iucv
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) static int iucv_enable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) size_t alloc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) int cpu, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) get_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) alloc_size = iucv_max_pathid * sizeof(struct iucv_path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) iucv_path_table = kzalloc(alloc_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (!iucv_path_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* Declare per cpu buffers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) for_each_online_cpu(cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) smp_call_function_single(cpu, iucv_declare_cpu, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (cpumask_empty(&iucv_buffer_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /* No cpu could declare an iucv buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) kfree(iucv_path_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) iucv_path_table = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * iucv_disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) * This function shuts down iucv. It disables iucv interrupts, retrieves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * the iucv interrupt buffer and frees the pathid table. Called after the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * last user unregister its iucv handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static void iucv_disable(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) get_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) on_each_cpu(iucv_retrieve_cpu, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) kfree(iucv_path_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) iucv_path_table = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static int iucv_cpu_dead(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) kfree(iucv_param_irq[cpu]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) iucv_param_irq[cpu] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) kfree(iucv_param[cpu]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) iucv_param[cpu] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) kfree(iucv_irq_data[cpu]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) iucv_irq_data[cpu] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static int iucv_cpu_prepare(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /* Note: GFP_DMA used to get memory below 2G */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (!iucv_irq_data[cpu])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /* Allocate parameter blocks. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (!iucv_param[cpu])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (!iucv_param_irq[cpu])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) iucv_cpu_dead(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static int iucv_cpu_online(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (!iucv_path_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) iucv_declare_cpu(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static int iucv_cpu_down_prep(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) cpumask_t cpumask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (!iucv_path_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) cpumask_copy(&cpumask, &iucv_buffer_cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) cpumask_clear_cpu(cpu, &cpumask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) if (cpumask_empty(&cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) /* Can't offline last IUCV enabled cpu. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) iucv_retrieve_cpu(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (!cpumask_empty(&iucv_irq_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) smp_call_function_single(cpumask_first(&iucv_buffer_cpumask),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) iucv_allow_cpu, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) * iucv_sever_pathid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * @pathid: path identification number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * @userdata: 16-bytes of user data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) * Sever an iucv path to free up the pathid. Used internally.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) static int iucv_sever_pathid(u16 pathid, u8 *userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) parm = iucv_param_irq[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) parm->ctrl.ippathid = pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) return iucv_call_b2f0(IUCV_SEVER, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * __iucv_cleanup_queue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * @dummy: unused dummy argument
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * Nop function called via smp_call_function to force work items from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * pending external iucv interrupts to the work queue.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) static void __iucv_cleanup_queue(void *dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) * iucv_cleanup_queue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * Function called after a path has been severed to find all remaining
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) * work items for the now stale pathid. The caller needs to hold the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) static void iucv_cleanup_queue(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct iucv_irq_list *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * When a path is severed, the pathid can be reused immediately
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * on a iucv connect or a connection pending interrupt. Remove
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * all entries from the task queue that refer to a stale pathid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * (iucv_path_table[ix] == NULL). Only then do the iucv connect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * or deliver the connection pending interrupt. To get all the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * pending interrupts force them to the work queue by calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * an empty function on all cpus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) smp_call_function(__iucv_cleanup_queue, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) spin_lock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) list_for_each_entry_safe(p, n, &iucv_task_queue, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) /* Remove stale work items from the task queue. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (iucv_path_table[p->data.ippathid] == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) list_del(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) spin_unlock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * iucv_register:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) * @handler: address of iucv handler structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) * @smp: != 0 indicates that the handler can deal with out of order messages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) * Registers a driver with IUCV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) * Returns 0 on success, -ENOMEM if the memory allocation for the pathid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) int iucv_register(struct iucv_handler *handler, int smp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (!iucv_available)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) return -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) mutex_lock(&iucv_register_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) if (!smp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) iucv_nonsmp_handler++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) if (list_empty(&iucv_handler_list)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) rc = iucv_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) goto out_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) } else if (!smp && iucv_nonsmp_handler == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) iucv_setmask_up();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) INIT_LIST_HEAD(&handler->paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) spin_lock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) list_add_tail(&handler->list, &iucv_handler_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) spin_unlock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) out_mutex:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) mutex_unlock(&iucv_register_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) EXPORT_SYMBOL(iucv_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) * iucv_unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) * @handler: address of iucv handler structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) * @smp: != 0 indicates that the handler can deal with out of order messages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) * Unregister driver from IUCV.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) void iucv_unregister(struct iucv_handler *handler, int smp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) struct iucv_path *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) mutex_lock(&iucv_register_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) spin_lock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) /* Remove handler from the iucv_handler_list. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) list_del_init(&handler->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) /* Sever all pathids still referring to the handler. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) list_for_each_entry_safe(p, n, &handler->paths, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) iucv_sever_pathid(p->pathid, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) iucv_path_table[p->pathid] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) list_del(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) iucv_path_free(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) spin_unlock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (!smp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) iucv_nonsmp_handler--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) if (list_empty(&iucv_handler_list))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) iucv_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) else if (!smp && iucv_nonsmp_handler == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) iucv_setmask_mp();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) mutex_unlock(&iucv_register_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) EXPORT_SYMBOL(iucv_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) static int iucv_reboot_event(struct notifier_block *this,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) unsigned long event, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) if (cpumask_empty(&iucv_irq_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) get_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) on_each_cpu_mask(&iucv_irq_cpumask, iucv_block_cpu, NULL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) for (i = 0; i < iucv_max_pathid; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (iucv_path_table[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) iucv_sever_pathid(i, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) put_online_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) iucv_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) static struct notifier_block iucv_reboot_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) .notifier_call = iucv_reboot_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) * iucv_path_accept
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) * @handler: address of iucv handler structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) * @userdata: 16 bytes of data reflected to the communication partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) * @private: private data passed to interrupt handlers for this path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) * This function is issued after the user received a connection pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) * external interrupt and now wishes to complete the IUCV communication path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) * Returns the result of the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) u8 *userdata, void *private)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) /* Prepare parameter block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) parm->ctrl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) parm->ctrl.ipmsglim = path->msglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) if (userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) parm->ctrl.ipflags1 = path->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) rc = iucv_call_b2f0(IUCV_ACCEPT, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) path->private = private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) path->msglim = parm->ctrl.ipmsglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) path->flags = parm->ctrl.ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) EXPORT_SYMBOL(iucv_path_accept);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) * iucv_path_connect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) * @handler: address of iucv handler structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * @userid: 8-byte user identification
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) * @system: 8-byte target system identification
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * @userdata: 16 bytes of data reflected to the communication partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * @private: private data passed to interrupt handlers for this path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * This function establishes an IUCV path. Although the connect may complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * successfully, you are not able to use the path until you receive an IUCV
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) * Connection Complete external interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) * Returns the result of the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) u8 *userid, u8 *system, u8 *userdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) void *private)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) spin_lock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) iucv_cleanup_queue();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) parm->ctrl.ipmsglim = path->msglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) parm->ctrl.ipflags1 = path->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) if (userid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) memcpy(parm->ctrl.ipvmid, userid, sizeof(parm->ctrl.ipvmid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) ASCEBC(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) EBC_TOUPPER(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) if (system) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) memcpy(parm->ctrl.iptarget, system,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) sizeof(parm->ctrl.iptarget));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) ASCEBC(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) EBC_TOUPPER(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) if (userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) rc = iucv_call_b2f0(IUCV_CONNECT, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (parm->ctrl.ippathid < iucv_max_pathid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) path->pathid = parm->ctrl.ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) path->msglim = parm->ctrl.ipmsglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) path->flags = parm->ctrl.ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) path->handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) path->private = private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) list_add_tail(&path->list, &handler->paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) iucv_path_table[path->pathid] = path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) iucv_sever_pathid(parm->ctrl.ippathid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) iucv_error_pathid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) spin_unlock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) EXPORT_SYMBOL(iucv_path_connect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) * iucv_path_quiesce:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) * @userdata: 16 bytes of data reflected to the communication partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) * This function temporarily suspends incoming messages on an IUCV path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) * You can later reactivate the path by invoking the iucv_resume function.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) int iucv_path_quiesce(struct iucv_path *path, u8 *userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) parm->ctrl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) EXPORT_SYMBOL(iucv_path_quiesce);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * iucv_path_resume:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) * @userdata: 16 bytes of data reflected to the communication partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) * This function resumes incoming messages on an IUCV path that has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * been stopped with iucv_path_quiesce.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) int iucv_path_resume(struct iucv_path *path, u8 *userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) if (userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) parm->ctrl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) rc = iucv_call_b2f0(IUCV_RESUME, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) * iucv_path_sever
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) * @userdata: 16 bytes of data reflected to the communication partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) * This function terminates an IUCV path.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) int iucv_path_sever(struct iucv_path *path, u8 *userdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) preempt_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (iucv_active_cpu != smp_processor_id())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) spin_lock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) rc = iucv_sever_pathid(path->pathid, userdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) iucv_path_table[path->pathid] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) list_del_init(&path->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (iucv_active_cpu != smp_processor_id())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) spin_unlock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) EXPORT_SYMBOL(iucv_path_sever);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) * iucv_message_purge
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * @srccls: source class of message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * Cancels a message you have sent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) u32 srccls)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) parm->purge.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) parm->purge.ipmsgid = msg->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) parm->purge.ipsrccls = srccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) parm->purge.ipflags1 = IUCV_IPSRCCLS | IUCV_IPFGMID | IUCV_IPFGPID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) rc = iucv_call_b2f0(IUCV_PURGE, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) if (!rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) msg->tag = parm->purge.ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) EXPORT_SYMBOL(iucv_message_purge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) * iucv_message_receive_iprmdata
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) * @flags: how the message is received (IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) * @buffer: address of data buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) * @size: length of data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) * @residual:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) * Internal function used by iucv_message_receive and __iucv_message_receive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) * to receive RMDATA data stored in struct iucv_message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) static int iucv_message_receive_iprmdata(struct iucv_path *path,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) u8 flags, void *buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) size_t size, size_t *residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) struct iucv_array *array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) u8 *rmmsg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) size_t copy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) * Message is 8 bytes long and has been stored to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) * message descriptor itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) *residual = abs(size - 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) rmmsg = msg->rmmsg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (flags & IUCV_IPBUFLST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) /* Copy to struct iucv_array. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) size = (size < 8) ? size : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) for (array = buffer; size > 0; array++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) copy = min_t(size_t, size, array->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) memcpy((u8 *)(addr_t) array->address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) rmmsg, copy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) rmmsg += copy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) size -= copy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) /* Copy to direct buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) memcpy(buffer, rmmsg, min_t(size_t, size, 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) * __iucv_message_receive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * @flags: how the message is received (IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) * @buffer: address of data buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) * @size: length of data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) * @residual:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) * This function receives messages that are being sent to you over
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) * established paths. This function will deal with RMDATA messages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * embedded in struct iucv_message as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * Locking: no locking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) u8 flags, void *buffer, size_t size, size_t *residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (msg->flags & IUCV_IPRMDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) return iucv_message_receive_iprmdata(path, msg, flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) buffer, size, residual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) if (cpumask_empty(&iucv_buffer_cpumask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) parm->db.ipbfadr1 = (u32)(addr_t) buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) parm->db.ipbfln1f = (u32) size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) parm->db.ipmsgid = msg->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) parm->db.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) parm->db.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) parm->db.ipflags1 = (flags | IUCV_IPFGPID |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) IUCV_IPFGMID | IUCV_IPTRGCLS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) rc = iucv_call_b2f0(IUCV_RECEIVE, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) if (!rc || rc == 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) msg->flags = parm->db.ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) if (residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) *residual = parm->db.ipbfln1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) EXPORT_SYMBOL(__iucv_message_receive);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) * iucv_message_receive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) * @flags: how the message is received (IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) * @buffer: address of data buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) * @size: length of data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) * @residual:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) * This function receives messages that are being sent to you over
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) * established paths. This function will deal with RMDATA messages
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) * embedded in struct iucv_message as well.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) * Locking: local_bh_enable/local_bh_disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) u8 flags, void *buffer, size_t size, size_t *residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (msg->flags & IUCV_IPRMDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return iucv_message_receive_iprmdata(path, msg, flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) buffer, size, residual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) rc = __iucv_message_receive(path, msg, flags, buffer, size, residual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) EXPORT_SYMBOL(iucv_message_receive);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) * iucv_message_reject
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) * The reject function refuses a specified message. Between the time you
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) * are notified of a message and the time that you complete the message,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) * the message may be rejected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) parm->db.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) parm->db.ipmsgid = msg->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) parm->db.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) rc = iucv_call_b2f0(IUCV_REJECT, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) EXPORT_SYMBOL(iucv_message_reject);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) * iucv_message_reply
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) * @flags: how the reply is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) * @reply: address of reply data buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) * @size: length of reply data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) * This function responds to the two-way messages that you receive. You
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * must identify completely the message to which you wish to reply. ie,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) * pathid, msgid, and trgcls. Prmmsg signifies the data is moved into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) * the parameter list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) u8 flags, void *reply, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) if (flags & IUCV_IPRMDATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) parm->dpl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) parm->dpl.ipflags1 = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) parm->dpl.ipmsgid = msg->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) parm->dpl.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) memcpy(parm->dpl.iprmmsg, reply, min_t(size_t, size, 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) parm->db.ipbfadr1 = (u32)(addr_t) reply;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) parm->db.ipbfln1f = (u32) size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) parm->db.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) parm->db.ipflags1 = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) parm->db.ipmsgid = msg->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) parm->db.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) rc = iucv_call_b2f0(IUCV_REPLY, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) EXPORT_SYMBOL(iucv_message_reply);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) * __iucv_message_send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) * @srccls: source class of message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) * @buffer: address of send buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) * @size: length of send buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) * This function transmits data to another application. Data to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) * transmitted is in a buffer and this is a one-way message and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) * receiver will not reply to the message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) * Locking: no locking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) u8 flags, u32 srccls, void *buffer, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) if (flags & IUCV_IPRMDATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) /* Message of 8 bytes can be placed into the parameter list. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) parm->dpl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) parm->dpl.ipflags1 = flags | IUCV_IPNORPY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) parm->dpl.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) parm->dpl.ipsrccls = srccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) parm->dpl.ipmsgtag = msg->tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) memcpy(parm->dpl.iprmmsg, buffer, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) parm->db.ipbfadr1 = (u32)(addr_t) buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) parm->db.ipbfln1f = (u32) size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) parm->db.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) parm->db.ipflags1 = flags | IUCV_IPNORPY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) parm->db.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) parm->db.ipsrccls = srccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) parm->db.ipmsgtag = msg->tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) rc = iucv_call_b2f0(IUCV_SEND, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) msg->id = parm->db.ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) EXPORT_SYMBOL(__iucv_message_send);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) * iucv_message_send
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) * @srccls: source class of message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) * @buffer: address of send buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * @size: length of send buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) * This function transmits data to another application. Data to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * transmitted is in a buffer and this is a one-way message and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) * receiver will not reply to the message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) * Locking: local_bh_enable/local_bh_disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) u8 flags, u32 srccls, void *buffer, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) rc = __iucv_message_send(path, msg, flags, srccls, buffer, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) EXPORT_SYMBOL(iucv_message_send);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) * iucv_message_send2way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) * @path: address of iucv path structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) * @msg: address of iucv msg structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) * @flags: how the message is sent and the reply is received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) * (IUCV_IPRMDATA, IUCV_IPBUFLST, IUCV_IPPRTY, IUCV_ANSLST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) * @srccls: source class of message
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) * @buffer: address of send buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) * @size: length of send buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) * @ansbuf: address of answer buffer or address of struct iucv_array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) * @asize: size of reply buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) * This function transmits data to another application. Data to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) * transmitted is in a buffer. The receiver of the send is expected to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) * reply to the message and a buffer is provided into which IUCV moves
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) * the reply to this message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) * Returns the result from the CP IUCV call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) u8 flags, u32 srccls, void *buffer, size_t size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) void *answer, size_t asize, size_t *residual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) union iucv_param *parm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) local_bh_disable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) if (cpumask_empty(&iucv_buffer_cpumask)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) rc = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) parm = iucv_param[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) memset(parm, 0, sizeof(union iucv_param));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) if (flags & IUCV_IPRMDATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) parm->dpl.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) parm->dpl.ipflags1 = path->flags; /* priority message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) parm->dpl.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) parm->dpl.ipsrccls = srccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) parm->dpl.ipmsgtag = msg->tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) parm->dpl.ipbfadr2 = (u32)(addr_t) answer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) parm->dpl.ipbfln2f = (u32) asize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) memcpy(parm->dpl.iprmmsg, buffer, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) parm->db.ippathid = path->pathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) parm->db.ipflags1 = path->flags; /* priority message */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) parm->db.iptrgcls = msg->class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) parm->db.ipsrccls = srccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) parm->db.ipmsgtag = msg->tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) parm->db.ipbfadr1 = (u32)(addr_t) buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) parm->db.ipbfln1f = (u32) size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) parm->db.ipbfadr2 = (u32)(addr_t) answer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) parm->db.ipbfln2f = (u32) asize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) rc = iucv_call_b2f0(IUCV_SEND, parm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) if (!rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) msg->id = parm->db.ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) local_bh_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) EXPORT_SYMBOL(iucv_message_send2way);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) * iucv_path_pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) * Process connection pending work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) struct iucv_path_pending {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) u16 ipmsglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) u16 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) u8 ipvmid[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) u32 res3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) u8 res4[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) static void iucv_path_pending(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) struct iucv_path_pending *ipp = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) struct iucv_handler *handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) struct iucv_path *path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) char *error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) BUG_ON(iucv_path_table[ipp->ippathid]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) /* New pathid, handler found. Create a new path struct. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) error = iucv_error_no_memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) path = iucv_path_alloc(ipp->ipmsglim, ipp->ipflags1, GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) if (!path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) goto out_sever;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) path->pathid = ipp->ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) iucv_path_table[path->pathid] = path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) EBCASC(ipp->ipvmid, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) /* Call registered handler until one is found that wants the path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) list_for_each_entry(handler, &iucv_handler_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) if (!handler->path_pending)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) * Add path to handler to allow a call to iucv_path_sever
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) * inside the path_pending function. If the handler returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) * an error remove the path from the handler again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) list_add(&path->list, &handler->paths);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) path->handler = handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) if (!handler->path_pending(path, ipp->ipvmid, ipp->ipuser))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) list_del(&path->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) path->handler = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) /* No handler wanted the path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) iucv_path_table[path->pathid] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) iucv_path_free(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) error = iucv_error_no_listener;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) out_sever:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) iucv_sever_pathid(ipp->ippathid, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) * iucv_path_complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) * Process connection complete work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) struct iucv_path_complete {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) u16 ipmsglim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) u16 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) u8 res2[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) u32 res3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) u8 res4[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) static void iucv_path_complete(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) struct iucv_path_complete *ipc = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) struct iucv_path *path = iucv_path_table[ipc->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) if (path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) path->flags = ipc->ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) if (path && path->handler && path->handler->path_complete)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) path->handler->path_complete(path, ipc->ipuser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) * iucv_path_severed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) * Process connection severed work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) struct iucv_path_severed {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) u8 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) u32 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) u8 res3[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) u32 res4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) u8 res5[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) static void iucv_path_severed(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) struct iucv_path_severed *ips = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) struct iucv_path *path = iucv_path_table[ips->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) if (!path || !path->handler) /* Already severed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) if (path->handler->path_severed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) path->handler->path_severed(path, ips->ipuser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) iucv_sever_pathid(path->pathid, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) iucv_path_table[path->pathid] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) list_del(&path->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) iucv_path_free(path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) * iucv_path_quiesced
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) * Process connection quiesced work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) struct iucv_path_quiesced {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) u8 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) u32 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) u8 res3[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) u32 res4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) u8 res5[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) static void iucv_path_quiesced(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) struct iucv_path_quiesced *ipq = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) struct iucv_path *path = iucv_path_table[ipq->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) if (path && path->handler && path->handler->path_quiesced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) path->handler->path_quiesced(path, ipq->ipuser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) * iucv_path_resumed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) * Process connection resumed work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) struct iucv_path_resumed {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) u8 res1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) u32 res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) u8 res3[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) u8 ipuser[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) u32 res4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) u8 res5[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) static void iucv_path_resumed(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) struct iucv_path_resumed *ipr = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) struct iucv_path *path = iucv_path_table[ipr->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) if (path && path->handler && path->handler->path_resumed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) path->handler->path_resumed(path, ipr->ipuser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) * iucv_message_complete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) * Process message complete work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) struct iucv_message_complete {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) u32 ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) u32 ipaudit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) u8 iprmmsg[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) u32 ipsrccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) u32 ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) u32 res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) u32 ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) u8 res2[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) static void iucv_message_complete(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) struct iucv_message_complete *imc = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) struct iucv_path *path = iucv_path_table[imc->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) struct iucv_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) if (path && path->handler && path->handler->message_complete) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) msg.flags = imc->ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) msg.id = imc->ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) msg.audit = imc->ipaudit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) memcpy(msg.rmmsg, imc->iprmmsg, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) msg.class = imc->ipsrccls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) msg.tag = imc->ipmsgtag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) msg.length = imc->ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) path->handler->message_complete(path, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) * iucv_message_pending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) * @data: Pointer to external interrupt buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) * Process message pending work item. Called from tasklet while holding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) * iucv_table_lock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) struct iucv_message_pending {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) u16 ippathid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) u8 ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) u8 iptype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) u32 ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) u32 iptrgcls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) u32 iprmmsg1_u32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) u8 iprmmsg1[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) } ln1msg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) union {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) u32 ipbfln1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) u8 iprmmsg2[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) } ln1msg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) u32 res1[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) u32 ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) u8 ippollfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) u8 res2[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) static void iucv_message_pending(struct iucv_irq_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) struct iucv_message_pending *imp = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) struct iucv_path *path = iucv_path_table[imp->ippathid];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) struct iucv_message msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) if (path && path->handler && path->handler->message_pending) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) msg.flags = imp->ipflags1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) msg.id = imp->ipmsgid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) msg.class = imp->iptrgcls;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) if (imp->ipflags1 & IUCV_IPRMDATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) memcpy(msg.rmmsg, imp->ln1msg1.iprmmsg1, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664) msg.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) msg.length = imp->ln1msg2.ipbfln1f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) msg.reply_size = imp->ipbfln2f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) path->handler->message_pending(path, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) * iucv_tasklet_fn:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) * This tasklet loops over the queue of irq buffers created by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) * iucv_external_interrupt, calls the appropriate action handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) * and then frees the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) static void iucv_tasklet_fn(unsigned long ignored)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) typedef void iucv_irq_fn(struct iucv_irq_data *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) static iucv_irq_fn *irq_fn[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) [0x02] = iucv_path_complete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) [0x03] = iucv_path_severed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) [0x04] = iucv_path_quiesced,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) [0x05] = iucv_path_resumed,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) [0x06] = iucv_message_complete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) [0x07] = iucv_message_complete,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) [0x08] = iucv_message_pending,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) [0x09] = iucv_message_pending,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) LIST_HEAD(task_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) struct iucv_irq_list *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) /* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (!spin_trylock(&iucv_table_lock)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) tasklet_schedule(&iucv_tasklet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) iucv_active_cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) spin_lock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) list_splice_init(&iucv_task_queue, &task_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) spin_unlock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) list_for_each_entry_safe(p, n, &task_queue, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) list_del_init(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) irq_fn[p->data.iptype](&p->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) iucv_active_cpu = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) spin_unlock(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) * iucv_work_fn:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) * This work function loops over the queue of path pending irq blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) * created by iucv_external_interrupt, calls the appropriate action
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) * handler and then frees the buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) static void iucv_work_fn(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) LIST_HEAD(work_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) struct iucv_irq_list *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) /* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) spin_lock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) iucv_active_cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) spin_lock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) list_splice_init(&iucv_work_queue, &work_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) spin_unlock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) iucv_cleanup_queue();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) list_for_each_entry_safe(p, n, &work_queue, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) list_del_init(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) iucv_path_pending(&p->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) iucv_active_cpu = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) spin_unlock_bh(&iucv_table_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) * iucv_external_interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) * @code: irq code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) * Handles external interrupts coming in from CP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) static void iucv_external_interrupt(struct ext_code ext_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) unsigned int param32, unsigned long param64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) struct iucv_irq_data *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) struct iucv_irq_list *work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) inc_irq_stat(IRQEXT_IUC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) p = iucv_irq_data[smp_processor_id()];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) if (p->ippathid >= iucv_max_pathid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) WARN_ON(p->ippathid >= iucv_max_pathid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) iucv_sever_pathid(p->ippathid, iucv_error_no_listener);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) BUG_ON(p->iptype < 0x01 || p->iptype > 0x09);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) if (!work) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) pr_warn("iucv_external_interrupt: out of memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) memcpy(&work->data, p, sizeof(work->data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) spin_lock(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) if (p->iptype == 0x01) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) /* Path pending interrupt. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) list_add_tail(&work->list, &iucv_work_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) schedule_work(&iucv_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) /* The other interrupts. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) list_add_tail(&work->list, &iucv_task_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) tasklet_schedule(&iucv_tasklet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) spin_unlock(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) struct iucv_interface iucv_if = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) .message_receive = iucv_message_receive,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) .__message_receive = __iucv_message_receive,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) .message_reply = iucv_message_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) .message_reject = iucv_message_reject,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) .message_send = iucv_message_send,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) .__message_send = __iucv_message_send,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794) .message_send2way = iucv_message_send2way,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) .message_purge = iucv_message_purge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) .path_accept = iucv_path_accept,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) .path_connect = iucv_path_connect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) .path_quiesce = iucv_path_quiesce,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) .path_resume = iucv_path_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) .path_sever = iucv_path_sever,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) .iucv_register = iucv_register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) .iucv_unregister = iucv_unregister,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) .bus = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) .root = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) EXPORT_SYMBOL(iucv_if);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) static enum cpuhp_state iucv_online;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) * iucv_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) * Allocates and initializes various data structures.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) static int __init iucv_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) if (!MACHINE_IS_VM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) rc = -EPROTONOSUPPORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) ctl_set_bit(0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) rc = iucv_query_maxconn();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) goto out_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) rc = register_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) goto out_ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) iucv_root = root_device_register("iucv");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) if (IS_ERR(iucv_root)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) rc = PTR_ERR(iucv_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) goto out_int;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) rc = cpuhp_setup_state(CPUHP_NET_IUCV_PREPARE, "net/iucv:prepare",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) iucv_cpu_prepare, iucv_cpu_dead);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) goto out_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "net/iucv:online",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) iucv_cpu_online, iucv_cpu_down_prep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) if (rc < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) goto out_prep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) iucv_online = rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) rc = register_reboot_notifier(&iucv_reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) goto out_remove_hp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) ASCEBC(iucv_error_no_listener, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) ASCEBC(iucv_error_no_memory, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) ASCEBC(iucv_error_pathid, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) iucv_available = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) rc = bus_register(&iucv_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) goto out_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) iucv_if.root = iucv_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) iucv_if.bus = &iucv_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) out_reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) unregister_reboot_notifier(&iucv_reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) out_remove_hp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) cpuhp_remove_state(iucv_online);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) out_prep:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) cpuhp_remove_state(CPUHP_NET_IUCV_PREPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) out_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) root_device_unregister(iucv_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) out_int:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) out_ctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) ctl_clear_bit(0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) * iucv_exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) * Frees everything allocated from iucv_init.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) static void __exit iucv_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) struct iucv_irq_list *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) spin_lock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) list_for_each_entry_safe(p, n, &iucv_task_queue, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) list_for_each_entry_safe(p, n, &iucv_work_queue, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) spin_unlock_irq(&iucv_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) unregister_reboot_notifier(&iucv_reboot_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) cpuhp_remove_state_nocalls(iucv_online);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) cpuhp_remove_state(CPUHP_NET_IUCV_PREPARE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) root_device_unregister(iucv_root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) bus_unregister(&iucv_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) subsys_initcall(iucv_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) module_exit(iucv_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) MODULE_LICENSE("GPL");