xref: /openbmc/linux/drivers/s390/cio/blacklist.c (revision 63dc02bd)
1 /*
2  *  drivers/s390/cio/blacklist.c
3  *   S/390 common I/O routines -- blacklisting of specific devices
4  *
5  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
6  *			      IBM Corporation
7  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
8  *		 Cornelia Huck (cornelia.huck@de.ibm.com)
9  *		 Arnd Bergmann (arndb@de.ibm.com)
10  */
11 
12 #define KMSG_COMPONENT "cio"
13 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14 
15 #include <linux/init.h>
16 #include <linux/vmalloc.h>
17 #include <linux/proc_fs.h>
18 #include <linux/seq_file.h>
19 #include <linux/ctype.h>
20 #include <linux/device.h>
21 
22 #include <asm/cio.h>
23 #include <asm/uaccess.h>
24 
25 #include "blacklist.h"
26 #include "cio.h"
27 #include "cio_debug.h"
28 #include "css.h"
29 #include "device.h"
30 
31 /*
32  * "Blacklisting" of certain devices:
33  * Device numbers given in the commandline as cio_ignore=... won't be known
34  * to Linux.
35  *
36  * These can be single devices or ranges of devices
37  */
38 
39 /* 65536 bits for each set to indicate if a devno is blacklisted or not */
40 #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
41 			 (8*sizeof(long)))
42 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
43 typedef enum {add, free} range_action;
44 
45 /*
46  * Function: blacklist_range
47  * (Un-)blacklist the devices from-to
48  */
49 static int blacklist_range(range_action action, unsigned int from_ssid,
50 			   unsigned int to_ssid, unsigned int from,
51 			   unsigned int to, int msgtrigger)
52 {
53 	if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
54 		if (msgtrigger)
55 			pr_warning("0.%x.%04x to 0.%x.%04x is not a valid "
56 				   "range for cio_ignore\n", from_ssid, from,
57 				   to_ssid, to);
58 
59 		return 1;
60 	}
61 
62 	while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
63 	       (from <= to))) {
64 		if (action == add)
65 			set_bit(from, bl_dev[from_ssid]);
66 		else
67 			clear_bit(from, bl_dev[from_ssid]);
68 		from++;
69 		if (from > __MAX_SUBCHANNEL) {
70 			from_ssid++;
71 			from = 0;
72 		}
73 	}
74 
75 	return 0;
76 }
77 
78 static int pure_hex(char **cp, unsigned int *val, int min_digit,
79 		    int max_digit, int max_val)
80 {
81 	int diff;
82 
83 	diff = 0;
84 	*val = 0;
85 
86 	while (diff <= max_digit) {
87 		int value = hex_to_bin(**cp);
88 
89 		if (value < 0)
90 			break;
91 		*val = *val * 16 + value;
92 		(*cp)++;
93 		diff++;
94 	}
95 
96 	if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
97 		return 1;
98 
99 	return 0;
100 }
101 
102 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
103 		       unsigned int *devno, int msgtrigger)
104 {
105 	char *str_work;
106 	int val, rc, ret;
107 
108 	rc = 1;
109 
110 	if (*str == '\0')
111 		goto out;
112 
113 	/* old style */
114 	str_work = str;
115 	val = simple_strtoul(str, &str_work, 16);
116 
117 	if (*str_work == '\0') {
118 		if (val <= __MAX_SUBCHANNEL) {
119 			*devno = val;
120 			*ssid = 0;
121 			*cssid = 0;
122 			rc = 0;
123 		}
124 		goto out;
125 	}
126 
127 	/* new style */
128 	str_work = str;
129 	ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
130 	if (ret || (str_work[0] != '.'))
131 		goto out;
132 	str_work++;
133 	ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
134 	if (ret || (str_work[0] != '.'))
135 		goto out;
136 	str_work++;
137 	ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
138 	if (ret || (str_work[0] != '\0'))
139 		goto out;
140 
141 	rc = 0;
142 out:
143 	if (rc && msgtrigger)
144 		pr_warning("%s is not a valid device for the cio_ignore "
145 			   "kernel parameter\n", str);
146 
147 	return rc;
148 }
149 
150 static int blacklist_parse_parameters(char *str, range_action action,
151 				      int msgtrigger)
152 {
153 	unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
154 	int rc, totalrc;
155 	char *parm;
156 	range_action ra;
157 
158 	totalrc = 0;
159 
160 	while ((parm = strsep(&str, ","))) {
161 		rc = 0;
162 		ra = action;
163 		if (*parm == '!') {
164 			if (ra == add)
165 				ra = free;
166 			else
167 				ra = add;
168 			parm++;
169 		}
170 		if (strcmp(parm, "all") == 0) {
171 			from_cssid = 0;
172 			from_ssid = 0;
173 			from = 0;
174 			to_cssid = __MAX_CSSID;
175 			to_ssid = __MAX_SSID;
176 			to = __MAX_SUBCHANNEL;
177 		} else {
178 			rc = parse_busid(strsep(&parm, "-"), &from_cssid,
179 					 &from_ssid, &from, msgtrigger);
180 			if (!rc) {
181 				if (parm != NULL)
182 					rc = parse_busid(parm, &to_cssid,
183 							 &to_ssid, &to,
184 							 msgtrigger);
185 				else {
186 					to_cssid = from_cssid;
187 					to_ssid = from_ssid;
188 					to = from;
189 				}
190 			}
191 		}
192 		if (!rc) {
193 			rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
194 					     msgtrigger);
195 			if (rc)
196 				totalrc = -EINVAL;
197 		} else
198 			totalrc = -EINVAL;
199 	}
200 
201 	return totalrc;
202 }
203 
204 static int __init
205 blacklist_setup (char *str)
206 {
207 	CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
208 	if (blacklist_parse_parameters(str, add, 1))
209 		return 0;
210 	return 1;
211 }
212 
213 __setup ("cio_ignore=", blacklist_setup);
214 
215 /* Checking if devices are blacklisted */
216 
217 /*
218  * Function: is_blacklisted
219  * Returns 1 if the given devicenumber can be found in the blacklist,
220  * otherwise 0.
221  * Used by validate_subchannel()
222  */
223 int
224 is_blacklisted (int ssid, int devno)
225 {
226 	return test_bit (devno, bl_dev[ssid]);
227 }
228 
229 #ifdef CONFIG_PROC_FS
230 /*
231  * Function: blacklist_parse_proc_parameters
232  * parse the stuff which is piped to /proc/cio_ignore
233  */
234 static int blacklist_parse_proc_parameters(char *buf)
235 {
236 	int rc;
237 	char *parm;
238 
239 	parm = strsep(&buf, " ");
240 
241 	if (strcmp("free", parm) == 0)
242 		rc = blacklist_parse_parameters(buf, free, 0);
243 	else if (strcmp("add", parm) == 0)
244 		rc = blacklist_parse_parameters(buf, add, 0);
245 	else if (strcmp("purge", parm) == 0)
246 		return ccw_purge_blacklisted();
247 	else
248 		return -EINVAL;
249 
250 	css_schedule_reprobe();
251 
252 	return rc;
253 }
254 
255 /* Iterator struct for all devices. */
256 struct ccwdev_iter {
257 	int devno;
258 	int ssid;
259 	int in_range;
260 };
261 
262 static void *
263 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
264 {
265 	struct ccwdev_iter *iter = s->private;
266 
267 	if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
268 		return NULL;
269 	memset(iter, 0, sizeof(*iter));
270 	iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
271 	iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
272 	return iter;
273 }
274 
275 static void
276 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
277 {
278 }
279 
280 static void *
281 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
282 {
283 	struct ccwdev_iter *iter;
284 
285 	if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
286 		return NULL;
287 	iter = it;
288 	if (iter->devno == __MAX_SUBCHANNEL) {
289 		iter->devno = 0;
290 		iter->ssid++;
291 		if (iter->ssid > __MAX_SSID)
292 			return NULL;
293 	} else
294 		iter->devno++;
295 	(*offset)++;
296 	return iter;
297 }
298 
299 static int
300 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
301 {
302 	struct ccwdev_iter *iter;
303 
304 	iter = it;
305 	if (!is_blacklisted(iter->ssid, iter->devno))
306 		/* Not blacklisted, nothing to output. */
307 		return 0;
308 	if (!iter->in_range) {
309 		/* First device in range. */
310 		if ((iter->devno == __MAX_SUBCHANNEL) ||
311 		    !is_blacklisted(iter->ssid, iter->devno + 1))
312 			/* Singular device. */
313 			return seq_printf(s, "0.%x.%04x\n",
314 					  iter->ssid, iter->devno);
315 		iter->in_range = 1;
316 		return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
317 	}
318 	if ((iter->devno == __MAX_SUBCHANNEL) ||
319 	    !is_blacklisted(iter->ssid, iter->devno + 1)) {
320 		/* Last device in range. */
321 		iter->in_range = 0;
322 		return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
323 	}
324 	return 0;
325 }
326 
327 static ssize_t
328 cio_ignore_write(struct file *file, const char __user *user_buf,
329 		 size_t user_len, loff_t *offset)
330 {
331 	char *buf;
332 	ssize_t rc, ret, i;
333 
334 	if (*offset)
335 		return -EINVAL;
336 	if (user_len > 65536)
337 		user_len = 65536;
338 	buf = vzalloc(user_len + 1); /* maybe better use the stack? */
339 	if (buf == NULL)
340 		return -ENOMEM;
341 
342 	if (strncpy_from_user (buf, user_buf, user_len) < 0) {
343 		rc = -EFAULT;
344 		goto out_free;
345 	}
346 
347 	i = user_len - 1;
348 	while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
349 		buf[i] = '\0';
350 		i--;
351 	}
352 	ret = blacklist_parse_proc_parameters(buf);
353 	if (ret)
354 		rc = ret;
355 	else
356 		rc = user_len;
357 
358 out_free:
359 	vfree (buf);
360 	return rc;
361 }
362 
363 static const struct seq_operations cio_ignore_proc_seq_ops = {
364 	.start = cio_ignore_proc_seq_start,
365 	.stop  = cio_ignore_proc_seq_stop,
366 	.next  = cio_ignore_proc_seq_next,
367 	.show  = cio_ignore_proc_seq_show,
368 };
369 
370 static int
371 cio_ignore_proc_open(struct inode *inode, struct file *file)
372 {
373 	return seq_open_private(file, &cio_ignore_proc_seq_ops,
374 				sizeof(struct ccwdev_iter));
375 }
376 
377 static const struct file_operations cio_ignore_proc_fops = {
378 	.open    = cio_ignore_proc_open,
379 	.read    = seq_read,
380 	.llseek  = seq_lseek,
381 	.release = seq_release_private,
382 	.write   = cio_ignore_write,
383 };
384 
385 static int
386 cio_ignore_proc_init (void)
387 {
388 	struct proc_dir_entry *entry;
389 
390 	entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
391 			    &cio_ignore_proc_fops);
392 	if (!entry)
393 		return -ENOENT;
394 	return 0;
395 }
396 
397 __initcall (cio_ignore_proc_init);
398 
399 #endif /* CONFIG_PROC_FS */
400