1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * CIO inject interface |
4 | * |
5 | * Copyright IBM Corp. 2021 |
6 | * Author(s): Vineeth Vijayan <vneethv@linux.ibm.com> |
7 | */ |
8 | |
9 | #define KMSG_COMPONENT "cio" |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
11 | |
12 | #include <linux/slab.h> |
13 | #include <linux/spinlock.h> |
14 | #include <linux/mm.h> |
15 | #include <linux/debugfs.h> |
16 | #include <asm/chpid.h> |
17 | |
18 | #include "cio_inject.h" |
19 | #include "cio_debug.h" |
20 | |
21 | static DEFINE_SPINLOCK(crw_inject_lock); |
22 | DEFINE_STATIC_KEY_FALSE(cio_inject_enabled); |
23 | static struct crw *crw_inject_data; |
24 | |
25 | /** |
26 | * crw_inject : Initiate the artificial CRW inject |
27 | * @crw: The data which needs to be injected as new CRW. |
28 | * |
29 | * The CRW handler is called, which will use the provided artificial |
30 | * data instead of the CRW from the underlying hardware. |
31 | * |
32 | * Return: 0 on success |
33 | */ |
34 | static int crw_inject(struct crw *crw) |
35 | { |
36 | int rc = 0; |
37 | struct crw *copy; |
38 | unsigned long flags; |
39 | |
40 | copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL); |
41 | if (!copy) |
42 | return -ENOMEM; |
43 | |
44 | spin_lock_irqsave(&crw_inject_lock, flags); |
45 | if (crw_inject_data) { |
46 | kfree(objp: copy); |
47 | rc = -EBUSY; |
48 | } else { |
49 | crw_inject_data = copy; |
50 | } |
51 | spin_unlock_irqrestore(lock: &crw_inject_lock, flags); |
52 | |
53 | if (!rc) |
54 | crw_handle_channel_report(); |
55 | |
56 | return rc; |
57 | } |
58 | |
59 | /** |
60 | * stcrw_get_injected: Copy the artificial CRW data to CRW struct. |
61 | * @crw: The target CRW pointer. |
62 | * |
63 | * Retrieve an injected CRW data. Return 0 on success, 1 if no |
64 | * injected-CRW is available. The function reproduces the return |
65 | * code of the actual STCRW function. |
66 | */ |
67 | int stcrw_get_injected(struct crw *crw) |
68 | { |
69 | int rc = 1; |
70 | unsigned long flags; |
71 | |
72 | spin_lock_irqsave(&crw_inject_lock, flags); |
73 | if (crw_inject_data) { |
74 | memcpy(crw, crw_inject_data, sizeof(*crw)); |
75 | kfree(objp: crw_inject_data); |
76 | crw_inject_data = NULL; |
77 | rc = 0; |
78 | } |
79 | spin_unlock_irqrestore(lock: &crw_inject_lock, flags); |
80 | |
81 | return rc; |
82 | } |
83 | |
84 | /* The debugfs write handler for crw_inject nodes operation */ |
85 | static ssize_t crw_inject_write(struct file *file, const char __user *buf, |
86 | size_t lbuf, loff_t *ppos) |
87 | { |
88 | u32 slct, oflw, chn, rsc, anc, erc, rsid; |
89 | struct crw crw; |
90 | char *buffer; |
91 | int rc; |
92 | |
93 | if (!static_branch_likely(&cio_inject_enabled)) { |
94 | pr_warn("CIO inject is not enabled - ignoring CRW inject\n" ); |
95 | return -EINVAL; |
96 | } |
97 | |
98 | buffer = vmemdup_user(buf, lbuf); |
99 | if (IS_ERR(ptr: buffer)) |
100 | return -ENOMEM; |
101 | |
102 | rc = sscanf(buffer, "%x %x %x %x %x %x %x" , &slct, &oflw, &chn, &rsc, &anc, |
103 | &erc, &rsid); |
104 | |
105 | kvfree(addr: buffer); |
106 | if (rc != 7) { |
107 | pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n" ); |
108 | return -EINVAL; |
109 | } |
110 | |
111 | memset(&crw, 0, sizeof(crw)); |
112 | crw.slct = slct; |
113 | crw.oflw = oflw; |
114 | crw.chn = chn; |
115 | crw.rsc = rsc; |
116 | crw.anc = anc; |
117 | crw.erc = erc; |
118 | crw.rsid = rsid; |
119 | |
120 | rc = crw_inject(crw: &crw); |
121 | if (rc) |
122 | return rc; |
123 | |
124 | return lbuf; |
125 | } |
126 | |
127 | /* Debugfs write handler for inject_enable node*/ |
128 | static ssize_t enable_inject_write(struct file *file, const char __user *buf, |
129 | size_t lbuf, loff_t *ppos) |
130 | { |
131 | unsigned long en = 0; |
132 | int rc; |
133 | |
134 | rc = kstrtoul_from_user(s: buf, count: lbuf, base: 10, res: &en); |
135 | if (rc) |
136 | return rc; |
137 | |
138 | switch (en) { |
139 | case 0: |
140 | static_branch_disable(&cio_inject_enabled); |
141 | break; |
142 | case 1: |
143 | static_branch_enable(&cio_inject_enabled); |
144 | break; |
145 | } |
146 | |
147 | return lbuf; |
148 | } |
149 | |
150 | static const struct file_operations crw_fops = { |
151 | .owner = THIS_MODULE, |
152 | .write = crw_inject_write, |
153 | }; |
154 | |
155 | static const struct file_operations cio_en_fops = { |
156 | .owner = THIS_MODULE, |
157 | .write = enable_inject_write, |
158 | }; |
159 | |
160 | static int __init cio_inject_init(void) |
161 | { |
162 | /* enable_inject node enables the static branching */ |
163 | debugfs_create_file(name: "enable_inject" , mode: 0200, parent: cio_debugfs_dir, |
164 | NULL, fops: &cio_en_fops); |
165 | |
166 | debugfs_create_file(name: "crw_inject" , mode: 0200, parent: cio_debugfs_dir, |
167 | NULL, fops: &crw_fops); |
168 | return 0; |
169 | } |
170 | |
171 | device_initcall(cio_inject_init); |
172 | |