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