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 | const 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: array of pointers to 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 | dma32_t 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 | dma32_t ipbfadr1; |
230 | u32 ipbfln1f; |
231 | u32 ipsrccls; |
232 | u32 ipmsgtag; |
233 | dma32_t 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 | unsigned long reg1 = virt_to_phys(address: parm); |
290 | int cc; |
291 | |
292 | asm volatile( |
293 | " lgr 0,%[reg0]\n" |
294 | " lgr 1,%[reg1]\n" |
295 | " .long 0xb2f01000\n" |
296 | " ipm %[cc]\n" |
297 | " srl %[cc],28\n" |
298 | : [cc] "=&d" (cc), "+m" (*parm) |
299 | : [reg0] "d" ((unsigned long)command), |
300 | [reg1] "d" (reg1) |
301 | : "cc" , "0" , "1" ); |
302 | return cc; |
303 | } |
304 | |
305 | static inline int iucv_call_b2f0(int command, union iucv_param *parm) |
306 | { |
307 | int ccode; |
308 | |
309 | ccode = __iucv_call_b2f0(command, parm); |
310 | return ccode == 1 ? parm->ctrl.iprcode : ccode; |
311 | } |
312 | |
313 | /* |
314 | * iucv_query_maxconn |
315 | * |
316 | * Determines the maximum number of connections that may be established. |
317 | * |
318 | * Returns the maximum number of connections or -EPERM is IUCV is not |
319 | * available. |
320 | */ |
321 | static int __iucv_query_maxconn(void *param, unsigned long *max_pathid) |
322 | { |
323 | unsigned long reg1 = virt_to_phys(address: param); |
324 | int cc; |
325 | |
326 | asm volatile ( |
327 | " lghi 0,%[cmd]\n" |
328 | " lgr 1,%[reg1]\n" |
329 | " .long 0xb2f01000\n" |
330 | " ipm %[cc]\n" |
331 | " srl %[cc],28\n" |
332 | " lgr %[reg1],1\n" |
333 | : [cc] "=&d" (cc), [reg1] "+&d" (reg1) |
334 | : [cmd] "K" (IUCV_QUERY) |
335 | : "cc" , "0" , "1" ); |
336 | *max_pathid = reg1; |
337 | return cc; |
338 | } |
339 | |
340 | static int iucv_query_maxconn(void) |
341 | { |
342 | unsigned long max_pathid; |
343 | void *param; |
344 | int ccode; |
345 | |
346 | param = kzalloc(size: sizeof(union iucv_param), GFP_KERNEL | GFP_DMA); |
347 | if (!param) |
348 | return -ENOMEM; |
349 | ccode = __iucv_query_maxconn(param, max_pathid: &max_pathid); |
350 | if (ccode == 0) |
351 | iucv_max_pathid = max_pathid; |
352 | kfree(objp: param); |
353 | return ccode ? -EPERM : 0; |
354 | } |
355 | |
356 | /** |
357 | * iucv_allow_cpu |
358 | * @data: unused |
359 | * |
360 | * Allow iucv interrupts on this cpu. |
361 | */ |
362 | static void iucv_allow_cpu(void *data) |
363 | { |
364 | int cpu = smp_processor_id(); |
365 | union iucv_param *parm; |
366 | |
367 | /* |
368 | * Enable all iucv interrupts. |
369 | * ipmask contains bits for the different interrupts |
370 | * 0x80 - Flag to allow nonpriority message pending interrupts |
371 | * 0x40 - Flag to allow priority message pending interrupts |
372 | * 0x20 - Flag to allow nonpriority message completion interrupts |
373 | * 0x10 - Flag to allow priority message completion interrupts |
374 | * 0x08 - Flag to allow IUCV control interrupts |
375 | */ |
376 | parm = iucv_param_irq[cpu]; |
377 | memset(parm, 0, sizeof(union iucv_param)); |
378 | parm->set_mask.ipmask = 0xf8; |
379 | iucv_call_b2f0(command: IUCV_SETMASK, parm); |
380 | |
381 | /* |
382 | * Enable all iucv control interrupts. |
383 | * ipmask contains bits for the different interrupts |
384 | * 0x80 - Flag to allow pending connections interrupts |
385 | * 0x40 - Flag to allow connection complete interrupts |
386 | * 0x20 - Flag to allow connection severed interrupts |
387 | * 0x10 - Flag to allow connection quiesced interrupts |
388 | * 0x08 - Flag to allow connection resumed interrupts |
389 | */ |
390 | memset(parm, 0, sizeof(union iucv_param)); |
391 | parm->set_mask.ipmask = 0xf8; |
392 | iucv_call_b2f0(command: IUCV_SETCONTROLMASK, parm); |
393 | /* Set indication that iucv interrupts are allowed for this cpu. */ |
394 | cpumask_set_cpu(cpu, dstp: &iucv_irq_cpumask); |
395 | } |
396 | |
397 | /** |
398 | * iucv_block_cpu |
399 | * @data: unused |
400 | * |
401 | * Block iucv interrupts on this cpu. |
402 | */ |
403 | static void iucv_block_cpu(void *data) |
404 | { |
405 | int cpu = smp_processor_id(); |
406 | union iucv_param *parm; |
407 | |
408 | /* Disable all iucv interrupts. */ |
409 | parm = iucv_param_irq[cpu]; |
410 | memset(parm, 0, sizeof(union iucv_param)); |
411 | iucv_call_b2f0(command: IUCV_SETMASK, parm); |
412 | |
413 | /* Clear indication that iucv interrupts are allowed for this cpu. */ |
414 | cpumask_clear_cpu(cpu, dstp: &iucv_irq_cpumask); |
415 | } |
416 | |
417 | /** |
418 | * iucv_declare_cpu |
419 | * @data: unused |
420 | * |
421 | * Declare a interrupt buffer on this cpu. |
422 | */ |
423 | static void iucv_declare_cpu(void *data) |
424 | { |
425 | int cpu = smp_processor_id(); |
426 | union iucv_param *parm; |
427 | int rc; |
428 | |
429 | if (cpumask_test_cpu(cpu, cpumask: &iucv_buffer_cpumask)) |
430 | return; |
431 | |
432 | /* Declare interrupt buffer. */ |
433 | parm = iucv_param_irq[cpu]; |
434 | memset(parm, 0, sizeof(union iucv_param)); |
435 | parm->db.ipbfadr1 = virt_to_dma32(iucv_irq_data[cpu]); |
436 | rc = iucv_call_b2f0(command: IUCV_DECLARE_BUFFER, parm); |
437 | if (rc) { |
438 | char *err = "Unknown" ; |
439 | switch (rc) { |
440 | case 0x03: |
441 | err = "Directory error" ; |
442 | break; |
443 | case 0x0a: |
444 | err = "Invalid length" ; |
445 | break; |
446 | case 0x13: |
447 | err = "Buffer already exists" ; |
448 | break; |
449 | case 0x3e: |
450 | err = "Buffer overlap" ; |
451 | break; |
452 | case 0x5c: |
453 | err = "Paging or storage error" ; |
454 | break; |
455 | } |
456 | pr_warn("Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n" , |
457 | cpu, rc, err); |
458 | return; |
459 | } |
460 | |
461 | /* Set indication that an iucv buffer exists for this cpu. */ |
462 | cpumask_set_cpu(cpu, dstp: &iucv_buffer_cpumask); |
463 | |
464 | if (iucv_nonsmp_handler == 0 || cpumask_empty(srcp: &iucv_irq_cpumask)) |
465 | /* Enable iucv interrupts on this cpu. */ |
466 | iucv_allow_cpu(NULL); |
467 | else |
468 | /* Disable iucv interrupts on this cpu. */ |
469 | iucv_block_cpu(NULL); |
470 | } |
471 | |
472 | /** |
473 | * iucv_retrieve_cpu |
474 | * @data: unused |
475 | * |
476 | * Retrieve interrupt buffer on this cpu. |
477 | */ |
478 | static void iucv_retrieve_cpu(void *data) |
479 | { |
480 | int cpu = smp_processor_id(); |
481 | union iucv_param *parm; |
482 | |
483 | if (!cpumask_test_cpu(cpu, cpumask: &iucv_buffer_cpumask)) |
484 | return; |
485 | |
486 | /* Block iucv interrupts. */ |
487 | iucv_block_cpu(NULL); |
488 | |
489 | /* Retrieve interrupt buffer. */ |
490 | parm = iucv_param_irq[cpu]; |
491 | iucv_call_b2f0(command: IUCV_RETRIEVE_BUFFER, parm); |
492 | |
493 | /* Clear indication that an iucv buffer exists for this cpu. */ |
494 | cpumask_clear_cpu(cpu, dstp: &iucv_buffer_cpumask); |
495 | } |
496 | |
497 | /* |
498 | * iucv_setmask_mp |
499 | * |
500 | * Allow iucv interrupts on all cpus. |
501 | */ |
502 | static void iucv_setmask_mp(void) |
503 | { |
504 | int cpu; |
505 | |
506 | cpus_read_lock(); |
507 | for_each_online_cpu(cpu) |
508 | /* Enable all cpus with a declared buffer. */ |
509 | if (cpumask_test_cpu(cpu, cpumask: &iucv_buffer_cpumask) && |
510 | !cpumask_test_cpu(cpu, cpumask: &iucv_irq_cpumask)) |
511 | smp_call_function_single(cpuid: cpu, func: iucv_allow_cpu, |
512 | NULL, wait: 1); |
513 | cpus_read_unlock(); |
514 | } |
515 | |
516 | /* |
517 | * iucv_setmask_up |
518 | * |
519 | * Allow iucv interrupts on a single cpu. |
520 | */ |
521 | static void iucv_setmask_up(void) |
522 | { |
523 | cpumask_t cpumask; |
524 | int cpu; |
525 | |
526 | /* Disable all cpu but the first in cpu_irq_cpumask. */ |
527 | cpumask_copy(dstp: &cpumask, srcp: &iucv_irq_cpumask); |
528 | cpumask_clear_cpu(cpu: cpumask_first(srcp: &iucv_irq_cpumask), dstp: &cpumask); |
529 | for_each_cpu(cpu, &cpumask) |
530 | smp_call_function_single(cpuid: cpu, func: iucv_block_cpu, NULL, wait: 1); |
531 | } |
532 | |
533 | /* |
534 | * iucv_enable |
535 | * |
536 | * This function makes iucv ready for use. It allocates the pathid |
537 | * table, declares an iucv interrupt buffer and enables the iucv |
538 | * interrupts. Called when the first user has registered an iucv |
539 | * handler. |
540 | */ |
541 | static int iucv_enable(void) |
542 | { |
543 | size_t alloc_size; |
544 | int cpu, rc; |
545 | |
546 | cpus_read_lock(); |
547 | rc = -ENOMEM; |
548 | alloc_size = iucv_max_pathid * sizeof(*iucv_path_table); |
549 | iucv_path_table = kzalloc(size: alloc_size, GFP_KERNEL); |
550 | if (!iucv_path_table) |
551 | goto out; |
552 | /* Declare per cpu buffers. */ |
553 | rc = -EIO; |
554 | for_each_online_cpu(cpu) |
555 | smp_call_function_single(cpuid: cpu, func: iucv_declare_cpu, NULL, wait: 1); |
556 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) |
557 | /* No cpu could declare an iucv buffer. */ |
558 | goto out; |
559 | cpus_read_unlock(); |
560 | return 0; |
561 | out: |
562 | kfree(objp: iucv_path_table); |
563 | iucv_path_table = NULL; |
564 | cpus_read_unlock(); |
565 | return rc; |
566 | } |
567 | |
568 | /* |
569 | * iucv_disable |
570 | * |
571 | * This function shuts down iucv. It disables iucv interrupts, retrieves |
572 | * the iucv interrupt buffer and frees the pathid table. Called after the |
573 | * last user unregister its iucv handler. |
574 | */ |
575 | static void iucv_disable(void) |
576 | { |
577 | cpus_read_lock(); |
578 | on_each_cpu(func: iucv_retrieve_cpu, NULL, wait: 1); |
579 | kfree(objp: iucv_path_table); |
580 | iucv_path_table = NULL; |
581 | cpus_read_unlock(); |
582 | } |
583 | |
584 | static int iucv_cpu_dead(unsigned int cpu) |
585 | { |
586 | kfree(objp: iucv_param_irq[cpu]); |
587 | iucv_param_irq[cpu] = NULL; |
588 | kfree(objp: iucv_param[cpu]); |
589 | iucv_param[cpu] = NULL; |
590 | kfree(objp: iucv_irq_data[cpu]); |
591 | iucv_irq_data[cpu] = NULL; |
592 | return 0; |
593 | } |
594 | |
595 | static int iucv_cpu_prepare(unsigned int cpu) |
596 | { |
597 | /* Note: GFP_DMA used to get memory below 2G */ |
598 | iucv_irq_data[cpu] = kmalloc_node(size: sizeof(struct iucv_irq_data), |
599 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
600 | if (!iucv_irq_data[cpu]) |
601 | goto out_free; |
602 | |
603 | /* Allocate parameter blocks. */ |
604 | iucv_param[cpu] = kmalloc_node(size: sizeof(union iucv_param), |
605 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
606 | if (!iucv_param[cpu]) |
607 | goto out_free; |
608 | |
609 | iucv_param_irq[cpu] = kmalloc_node(size: sizeof(union iucv_param), |
610 | GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); |
611 | if (!iucv_param_irq[cpu]) |
612 | goto out_free; |
613 | |
614 | return 0; |
615 | |
616 | out_free: |
617 | iucv_cpu_dead(cpu); |
618 | return -ENOMEM; |
619 | } |
620 | |
621 | static int iucv_cpu_online(unsigned int cpu) |
622 | { |
623 | if (!iucv_path_table) |
624 | return 0; |
625 | iucv_declare_cpu(NULL); |
626 | return 0; |
627 | } |
628 | |
629 | static int iucv_cpu_down_prep(unsigned int cpu) |
630 | { |
631 | cpumask_t cpumask; |
632 | |
633 | if (!iucv_path_table) |
634 | return 0; |
635 | |
636 | cpumask_copy(dstp: &cpumask, srcp: &iucv_buffer_cpumask); |
637 | cpumask_clear_cpu(cpu, dstp: &cpumask); |
638 | if (cpumask_empty(srcp: &cpumask)) |
639 | /* Can't offline last IUCV enabled cpu. */ |
640 | return -EINVAL; |
641 | |
642 | iucv_retrieve_cpu(NULL); |
643 | if (!cpumask_empty(srcp: &iucv_irq_cpumask)) |
644 | return 0; |
645 | smp_call_function_single(cpuid: cpumask_first(srcp: &iucv_buffer_cpumask), |
646 | func: iucv_allow_cpu, NULL, wait: 1); |
647 | return 0; |
648 | } |
649 | |
650 | /** |
651 | * iucv_sever_pathid |
652 | * @pathid: path identification number. |
653 | * @userdata: 16-bytes of user data. |
654 | * |
655 | * Sever an iucv path to free up the pathid. Used internally. |
656 | */ |
657 | static int iucv_sever_pathid(u16 pathid, u8 *userdata) |
658 | { |
659 | union iucv_param *parm; |
660 | |
661 | parm = iucv_param_irq[smp_processor_id()]; |
662 | memset(parm, 0, sizeof(union iucv_param)); |
663 | if (userdata) |
664 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
665 | parm->ctrl.ippathid = pathid; |
666 | return iucv_call_b2f0(command: IUCV_SEVER, parm); |
667 | } |
668 | |
669 | /** |
670 | * __iucv_cleanup_queue |
671 | * @dummy: unused dummy argument |
672 | * |
673 | * Nop function called via smp_call_function to force work items from |
674 | * pending external iucv interrupts to the work queue. |
675 | */ |
676 | static void __iucv_cleanup_queue(void *dummy) |
677 | { |
678 | } |
679 | |
680 | /** |
681 | * iucv_cleanup_queue |
682 | * |
683 | * Function called after a path has been severed to find all remaining |
684 | * work items for the now stale pathid. The caller needs to hold the |
685 | * iucv_table_lock. |
686 | */ |
687 | static void iucv_cleanup_queue(void) |
688 | { |
689 | struct iucv_irq_list *p, *n; |
690 | |
691 | /* |
692 | * When a path is severed, the pathid can be reused immediately |
693 | * on a iucv connect or a connection pending interrupt. Remove |
694 | * all entries from the task queue that refer to a stale pathid |
695 | * (iucv_path_table[ix] == NULL). Only then do the iucv connect |
696 | * or deliver the connection pending interrupt. To get all the |
697 | * pending interrupts force them to the work queue by calling |
698 | * an empty function on all cpus. |
699 | */ |
700 | smp_call_function(func: __iucv_cleanup_queue, NULL, wait: 1); |
701 | spin_lock_irq(lock: &iucv_queue_lock); |
702 | list_for_each_entry_safe(p, n, &iucv_task_queue, list) { |
703 | /* Remove stale work items from the task queue. */ |
704 | if (iucv_path_table[p->data.ippathid] == NULL) { |
705 | list_del(entry: &p->list); |
706 | kfree(objp: p); |
707 | } |
708 | } |
709 | spin_unlock_irq(lock: &iucv_queue_lock); |
710 | } |
711 | |
712 | /** |
713 | * iucv_register: |
714 | * @handler: address of iucv handler structure |
715 | * @smp: != 0 indicates that the handler can deal with out of order messages |
716 | * |
717 | * Registers a driver with IUCV. |
718 | * |
719 | * Returns 0 on success, -ENOMEM if the memory allocation for the pathid |
720 | * table failed, or -EIO if IUCV_DECLARE_BUFFER failed on all cpus. |
721 | */ |
722 | int iucv_register(struct iucv_handler *handler, int smp) |
723 | { |
724 | int rc; |
725 | |
726 | if (!iucv_available) |
727 | return -ENOSYS; |
728 | mutex_lock(&iucv_register_mutex); |
729 | if (!smp) |
730 | iucv_nonsmp_handler++; |
731 | if (list_empty(head: &iucv_handler_list)) { |
732 | rc = iucv_enable(); |
733 | if (rc) |
734 | goto out_mutex; |
735 | } else if (!smp && iucv_nonsmp_handler == 1) |
736 | iucv_setmask_up(); |
737 | INIT_LIST_HEAD(list: &handler->paths); |
738 | |
739 | spin_lock_bh(lock: &iucv_table_lock); |
740 | list_add_tail(new: &handler->list, head: &iucv_handler_list); |
741 | spin_unlock_bh(lock: &iucv_table_lock); |
742 | rc = 0; |
743 | out_mutex: |
744 | mutex_unlock(lock: &iucv_register_mutex); |
745 | return rc; |
746 | } |
747 | EXPORT_SYMBOL(iucv_register); |
748 | |
749 | /** |
750 | * iucv_unregister |
751 | * @handler: address of iucv handler structure |
752 | * @smp: != 0 indicates that the handler can deal with out of order messages |
753 | * |
754 | * Unregister driver from IUCV. |
755 | */ |
756 | void iucv_unregister(struct iucv_handler *handler, int smp) |
757 | { |
758 | struct iucv_path *p, *n; |
759 | |
760 | mutex_lock(&iucv_register_mutex); |
761 | spin_lock_bh(lock: &iucv_table_lock); |
762 | /* Remove handler from the iucv_handler_list. */ |
763 | list_del_init(entry: &handler->list); |
764 | /* Sever all pathids still referring to the handler. */ |
765 | list_for_each_entry_safe(p, n, &handler->paths, list) { |
766 | iucv_sever_pathid(pathid: p->pathid, NULL); |
767 | iucv_path_table[p->pathid] = NULL; |
768 | list_del(entry: &p->list); |
769 | iucv_path_free(path: p); |
770 | } |
771 | spin_unlock_bh(lock: &iucv_table_lock); |
772 | if (!smp) |
773 | iucv_nonsmp_handler--; |
774 | if (list_empty(head: &iucv_handler_list)) |
775 | iucv_disable(); |
776 | else if (!smp && iucv_nonsmp_handler == 0) |
777 | iucv_setmask_mp(); |
778 | mutex_unlock(lock: &iucv_register_mutex); |
779 | } |
780 | EXPORT_SYMBOL(iucv_unregister); |
781 | |
782 | static int iucv_reboot_event(struct notifier_block *this, |
783 | unsigned long event, void *ptr) |
784 | { |
785 | int i; |
786 | |
787 | if (cpumask_empty(srcp: &iucv_irq_cpumask)) |
788 | return NOTIFY_DONE; |
789 | |
790 | cpus_read_lock(); |
791 | on_each_cpu_mask(mask: &iucv_irq_cpumask, func: iucv_block_cpu, NULL, wait: 1); |
792 | preempt_disable(); |
793 | for (i = 0; i < iucv_max_pathid; i++) { |
794 | if (iucv_path_table[i]) |
795 | iucv_sever_pathid(pathid: i, NULL); |
796 | } |
797 | preempt_enable(); |
798 | cpus_read_unlock(); |
799 | iucv_disable(); |
800 | return NOTIFY_DONE; |
801 | } |
802 | |
803 | static struct notifier_block iucv_reboot_notifier = { |
804 | .notifier_call = iucv_reboot_event, |
805 | }; |
806 | |
807 | /** |
808 | * iucv_path_accept |
809 | * @path: address of iucv path structure |
810 | * @handler: address of iucv handler structure |
811 | * @userdata: 16 bytes of data reflected to the communication partner |
812 | * @private: private data passed to interrupt handlers for this path |
813 | * |
814 | * This function is issued after the user received a connection pending |
815 | * external interrupt and now wishes to complete the IUCV communication path. |
816 | * |
817 | * Returns the result of the CP IUCV call. |
818 | */ |
819 | int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, |
820 | u8 *userdata, void *private) |
821 | { |
822 | union iucv_param *parm; |
823 | int rc; |
824 | |
825 | local_bh_disable(); |
826 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
827 | rc = -EIO; |
828 | goto out; |
829 | } |
830 | /* Prepare parameter block. */ |
831 | parm = iucv_param[smp_processor_id()]; |
832 | memset(parm, 0, sizeof(union iucv_param)); |
833 | parm->ctrl.ippathid = path->pathid; |
834 | parm->ctrl.ipmsglim = path->msglim; |
835 | if (userdata) |
836 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
837 | parm->ctrl.ipflags1 = path->flags; |
838 | |
839 | rc = iucv_call_b2f0(command: IUCV_ACCEPT, parm); |
840 | if (!rc) { |
841 | path->private = private; |
842 | path->msglim = parm->ctrl.ipmsglim; |
843 | path->flags = parm->ctrl.ipflags1; |
844 | } |
845 | out: |
846 | local_bh_enable(); |
847 | return rc; |
848 | } |
849 | EXPORT_SYMBOL(iucv_path_accept); |
850 | |
851 | /** |
852 | * iucv_path_connect |
853 | * @path: address of iucv path structure |
854 | * @handler: address of iucv handler structure |
855 | * @userid: 8-byte user identification |
856 | * @system: 8-byte target system identification |
857 | * @userdata: 16 bytes of data reflected to the communication partner |
858 | * @private: private data passed to interrupt handlers for this path |
859 | * |
860 | * This function establishes an IUCV path. Although the connect may complete |
861 | * successfully, you are not able to use the path until you receive an IUCV |
862 | * Connection Complete external interrupt. |
863 | * |
864 | * Returns the result of the CP IUCV call. |
865 | */ |
866 | int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, |
867 | u8 *userid, u8 *system, u8 *userdata, |
868 | void *private) |
869 | { |
870 | union iucv_param *parm; |
871 | int rc; |
872 | |
873 | spin_lock_bh(lock: &iucv_table_lock); |
874 | iucv_cleanup_queue(); |
875 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
876 | rc = -EIO; |
877 | goto out; |
878 | } |
879 | parm = iucv_param[smp_processor_id()]; |
880 | memset(parm, 0, sizeof(union iucv_param)); |
881 | parm->ctrl.ipmsglim = path->msglim; |
882 | parm->ctrl.ipflags1 = path->flags; |
883 | if (userid) { |
884 | memcpy(parm->ctrl.ipvmid, userid, sizeof(parm->ctrl.ipvmid)); |
885 | ASCEBC(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid)); |
886 | EBC_TOUPPER(parm->ctrl.ipvmid, sizeof(parm->ctrl.ipvmid)); |
887 | } |
888 | if (system) { |
889 | memcpy(parm->ctrl.iptarget, system, |
890 | sizeof(parm->ctrl.iptarget)); |
891 | ASCEBC(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget)); |
892 | EBC_TOUPPER(parm->ctrl.iptarget, sizeof(parm->ctrl.iptarget)); |
893 | } |
894 | if (userdata) |
895 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
896 | |
897 | rc = iucv_call_b2f0(command: IUCV_CONNECT, parm); |
898 | if (!rc) { |
899 | if (parm->ctrl.ippathid < iucv_max_pathid) { |
900 | path->pathid = parm->ctrl.ippathid; |
901 | path->msglim = parm->ctrl.ipmsglim; |
902 | path->flags = parm->ctrl.ipflags1; |
903 | path->handler = handler; |
904 | path->private = private; |
905 | list_add_tail(new: &path->list, head: &handler->paths); |
906 | iucv_path_table[path->pathid] = path; |
907 | } else { |
908 | iucv_sever_pathid(pathid: parm->ctrl.ippathid, |
909 | userdata: iucv_error_pathid); |
910 | rc = -EIO; |
911 | } |
912 | } |
913 | out: |
914 | spin_unlock_bh(lock: &iucv_table_lock); |
915 | return rc; |
916 | } |
917 | EXPORT_SYMBOL(iucv_path_connect); |
918 | |
919 | /** |
920 | * iucv_path_quiesce: |
921 | * @path: address of iucv path structure |
922 | * @userdata: 16 bytes of data reflected to the communication partner |
923 | * |
924 | * This function temporarily suspends incoming messages on an IUCV path. |
925 | * You can later reactivate the path by invoking the iucv_resume function. |
926 | * |
927 | * Returns the result from the CP IUCV call. |
928 | */ |
929 | int iucv_path_quiesce(struct iucv_path *path, u8 *userdata) |
930 | { |
931 | union iucv_param *parm; |
932 | int rc; |
933 | |
934 | local_bh_disable(); |
935 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
936 | rc = -EIO; |
937 | goto out; |
938 | } |
939 | parm = iucv_param[smp_processor_id()]; |
940 | memset(parm, 0, sizeof(union iucv_param)); |
941 | if (userdata) |
942 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
943 | parm->ctrl.ippathid = path->pathid; |
944 | rc = iucv_call_b2f0(command: IUCV_QUIESCE, parm); |
945 | out: |
946 | local_bh_enable(); |
947 | return rc; |
948 | } |
949 | EXPORT_SYMBOL(iucv_path_quiesce); |
950 | |
951 | /** |
952 | * iucv_path_resume: |
953 | * @path: address of iucv path structure |
954 | * @userdata: 16 bytes of data reflected to the communication partner |
955 | * |
956 | * This function resumes incoming messages on an IUCV path that has |
957 | * been stopped with iucv_path_quiesce. |
958 | * |
959 | * Returns the result from the CP IUCV call. |
960 | */ |
961 | int iucv_path_resume(struct iucv_path *path, u8 *userdata) |
962 | { |
963 | union iucv_param *parm; |
964 | int rc; |
965 | |
966 | local_bh_disable(); |
967 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
968 | rc = -EIO; |
969 | goto out; |
970 | } |
971 | parm = iucv_param[smp_processor_id()]; |
972 | memset(parm, 0, sizeof(union iucv_param)); |
973 | if (userdata) |
974 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
975 | parm->ctrl.ippathid = path->pathid; |
976 | rc = iucv_call_b2f0(command: IUCV_RESUME, parm); |
977 | out: |
978 | local_bh_enable(); |
979 | return rc; |
980 | } |
981 | |
982 | /** |
983 | * iucv_path_sever |
984 | * @path: address of iucv path structure |
985 | * @userdata: 16 bytes of data reflected to the communication partner |
986 | * |
987 | * This function terminates an IUCV path. |
988 | * |
989 | * Returns the result from the CP IUCV call. |
990 | */ |
991 | int iucv_path_sever(struct iucv_path *path, u8 *userdata) |
992 | { |
993 | int rc; |
994 | |
995 | preempt_disable(); |
996 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
997 | rc = -EIO; |
998 | goto out; |
999 | } |
1000 | if (iucv_active_cpu != smp_processor_id()) |
1001 | spin_lock_bh(lock: &iucv_table_lock); |
1002 | rc = iucv_sever_pathid(pathid: path->pathid, userdata); |
1003 | iucv_path_table[path->pathid] = NULL; |
1004 | list_del_init(entry: &path->list); |
1005 | if (iucv_active_cpu != smp_processor_id()) |
1006 | spin_unlock_bh(lock: &iucv_table_lock); |
1007 | out: |
1008 | preempt_enable(); |
1009 | return rc; |
1010 | } |
1011 | EXPORT_SYMBOL(iucv_path_sever); |
1012 | |
1013 | /** |
1014 | * iucv_message_purge |
1015 | * @path: address of iucv path structure |
1016 | * @msg: address of iucv msg structure |
1017 | * @srccls: source class of message |
1018 | * |
1019 | * Cancels a message you have sent. |
1020 | * |
1021 | * Returns the result from the CP IUCV call. |
1022 | */ |
1023 | int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, |
1024 | u32 srccls) |
1025 | { |
1026 | union iucv_param *parm; |
1027 | int rc; |
1028 | |
1029 | local_bh_disable(); |
1030 | if (cpumask_empty(srcp: &iucv_buffer_cpumask)) { |
1031 | rc = -EIO; |
1032 | goto out; |
1033 | } |
1034 | parm = iucv_param[smp_processor_id()]; |
1035 | memset(parm, 0, sizeof(union iucv_param)); |
1036 | parm->purge.ippathid = path->pathid; |
1037 | parm->purge.ipmsgid = msg->id; |
1038 | parm->purge.ipsrccls = srccls; |
1039 | parm->purge.ipflags1 = IUCV_IPSRCCLS | IUCV_IPFGMID | IUCV_IPFGPID; |
1040 | rc = iucv_call_b2f0(command: IUCV_PURGE, parm); |
1041 | if (!rc) { |
1042 | msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; |
1043 | msg->tag = parm->purge.ipmsgtag; |
1044 | } |
1045 | out: |
1046 | local_bh_enable(); |
1047 | return rc; |
1048 | } |
1049 | EXPORT_SYMBOL(iucv_message_purge); |
1050 | |
1051 | /** |
1052 | * iucv_message_receive_iprmdata |
1053 | * @path: address of iucv path structure |
1054 | * @msg: address of iucv msg structure |
1055 | * @flags: how the message is received (IUCV_IPBUFLST) |
1056 | * @buffer: address of data buffer or address of struct iucv_array |
1057 | * @size: length of data buffer |
1058 | * @residual: |
1059 | * |
1060 | * Internal function used by iucv_message_receive and __iucv_message_receive |
1061 | * to receive RMDATA data stored in struct iucv_message. |
1062 | */ |
1063 | static int iucv_message_receive_iprmdata(struct iucv_path *path, |
1064 | struct iucv_message *msg, |
1065 | u8 flags, void *buffer, |
1066 | size_t size, size_t *residual) |
1067 | { |
1068 | struct iucv_array *array; |
1069 | u8 *rmmsg; |
1070 | size_t copy; |
1071 | |
1072 | /* |
1073 | * Message is 8 bytes long and has been stored to the |
1074 | * message descriptor itself. |
1075 | */ |
1076 | if (residual) |
1077 | *residual = abs(size - 8); |
1078 | rmmsg = msg->rmmsg; |
1079 | if (flags & IUCV_IPBUFLST) { |
1080 | /* Copy to struct iucv_array. */ |
1081 | size = (size < 8) ? size : 8; |
1082 | for (array = buffer; size > 0; array++) { |
1083 | copy = min_t(size_t, size, array->length); |
1084 | memcpy(dma32_to_virt(array->address), 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 = virt_to_dma32(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 = virt_to_dma32(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 = virt_to_dma32(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 = virt_to_dma32(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 = virt_to_dma32(buffer); |
1391 | parm->db.ipbfln1f = (u32) size; |
1392 | parm->db.ipbfadr2 = virt_to_dma32(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 | |