xref: /openbmc/linux/drivers/s390/cio/blacklist.c (revision e190bfe5)
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 	unsigned int value;
83 
84 	diff = 0;
85 	*val = 0;
86 
87 	while (isxdigit(**cp) && (diff <= max_digit)) {
88 
89 		if (isdigit(**cp))
90 			value = **cp - '0';
91 		else
92 			value = tolower(**cp) - 'a' + 10;
93 		*val = *val * 16 + value;
94 		(*cp)++;
95 		diff++;
96 	}
97 
98 	if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
99 		return 1;
100 
101 	return 0;
102 }
103 
104 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
105 		       unsigned int *devno, int msgtrigger)
106 {
107 	char *str_work;
108 	int val, rc, ret;
109 
110 	rc = 1;
111 
112 	if (*str == '\0')
113 		goto out;
114 
115 	/* old style */
116 	str_work = str;
117 	val = simple_strtoul(str, &str_work, 16);
118 
119 	if (*str_work == '\0') {
120 		if (val <= __MAX_SUBCHANNEL) {
121 			*devno = val;
122 			*ssid = 0;
123 			*cssid = 0;
124 			rc = 0;
125 		}
126 		goto out;
127 	}
128 
129 	/* new style */
130 	str_work = str;
131 	ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
132 	if (ret || (str_work[0] != '.'))
133 		goto out;
134 	str_work++;
135 	ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
136 	if (ret || (str_work[0] != '.'))
137 		goto out;
138 	str_work++;
139 	ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
140 	if (ret || (str_work[0] != '\0'))
141 		goto out;
142 
143 	rc = 0;
144 out:
145 	if (rc && msgtrigger)
146 		pr_warning("%s is not a valid device for the cio_ignore "
147 			   "kernel parameter\n", str);
148 
149 	return rc;
150 }
151 
152 static int blacklist_parse_parameters(char *str, range_action action,
153 				      int msgtrigger)
154 {
155 	unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
156 	int rc, totalrc;
157 	char *parm;
158 	range_action ra;
159 
160 	totalrc = 0;
161 
162 	while ((parm = strsep(&str, ","))) {
163 		rc = 0;
164 		ra = action;
165 		if (*parm == '!') {
166 			if (ra == add)
167 				ra = free;
168 			else
169 				ra = add;
170 			parm++;
171 		}
172 		if (strcmp(parm, "all") == 0) {
173 			from_cssid = 0;
174 			from_ssid = 0;
175 			from = 0;
176 			to_cssid = __MAX_CSSID;
177 			to_ssid = __MAX_SSID;
178 			to = __MAX_SUBCHANNEL;
179 		} else {
180 			rc = parse_busid(strsep(&parm, "-"), &from_cssid,
181 					 &from_ssid, &from, msgtrigger);
182 			if (!rc) {
183 				if (parm != NULL)
184 					rc = parse_busid(parm, &to_cssid,
185 							 &to_ssid, &to,
186 							 msgtrigger);
187 				else {
188 					to_cssid = from_cssid;
189 					to_ssid = from_ssid;
190 					to = from;
191 				}
192 			}
193 		}
194 		if (!rc) {
195 			rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
196 					     msgtrigger);
197 			if (rc)
198 				totalrc = -EINVAL;
199 		} else
200 			totalrc = -EINVAL;
201 	}
202 
203 	return totalrc;
204 }
205 
206 static int __init
207 blacklist_setup (char *str)
208 {
209 	CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
210 	if (blacklist_parse_parameters(str, add, 1))
211 		return 0;
212 	return 1;
213 }
214 
215 __setup ("cio_ignore=", blacklist_setup);
216 
217 /* Checking if devices are blacklisted */
218 
219 /*
220  * Function: is_blacklisted
221  * Returns 1 if the given devicenumber can be found in the blacklist,
222  * otherwise 0.
223  * Used by validate_subchannel()
224  */
225 int
226 is_blacklisted (int ssid, int devno)
227 {
228 	return test_bit (devno, bl_dev[ssid]);
229 }
230 
231 #ifdef CONFIG_PROC_FS
232 /*
233  * Function: blacklist_parse_proc_parameters
234  * parse the stuff which is piped to /proc/cio_ignore
235  */
236 static int blacklist_parse_proc_parameters(char *buf)
237 {
238 	int rc;
239 	char *parm;
240 
241 	parm = strsep(&buf, " ");
242 
243 	if (strcmp("free", parm) == 0)
244 		rc = blacklist_parse_parameters(buf, free, 0);
245 	else if (strcmp("add", parm) == 0)
246 		rc = blacklist_parse_parameters(buf, add, 0);
247 	else if (strcmp("purge", parm) == 0)
248 		return ccw_purge_blacklisted();
249 	else
250 		return -EINVAL;
251 
252 	css_schedule_reprobe();
253 
254 	return rc;
255 }
256 
257 /* Iterator struct for all devices. */
258 struct ccwdev_iter {
259 	int devno;
260 	int ssid;
261 	int in_range;
262 };
263 
264 static void *
265 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
266 {
267 	struct ccwdev_iter *iter = s->private;
268 
269 	if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
270 		return NULL;
271 	memset(iter, 0, sizeof(*iter));
272 	iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
273 	iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
274 	return iter;
275 }
276 
277 static void
278 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
279 {
280 }
281 
282 static void *
283 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
284 {
285 	struct ccwdev_iter *iter;
286 
287 	if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
288 		return NULL;
289 	iter = it;
290 	if (iter->devno == __MAX_SUBCHANNEL) {
291 		iter->devno = 0;
292 		iter->ssid++;
293 		if (iter->ssid > __MAX_SSID)
294 			return NULL;
295 	} else
296 		iter->devno++;
297 	(*offset)++;
298 	return iter;
299 }
300 
301 static int
302 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
303 {
304 	struct ccwdev_iter *iter;
305 
306 	iter = it;
307 	if (!is_blacklisted(iter->ssid, iter->devno))
308 		/* Not blacklisted, nothing to output. */
309 		return 0;
310 	if (!iter->in_range) {
311 		/* First device in range. */
312 		if ((iter->devno == __MAX_SUBCHANNEL) ||
313 		    !is_blacklisted(iter->ssid, iter->devno + 1))
314 			/* Singular device. */
315 			return seq_printf(s, "0.%x.%04x\n",
316 					  iter->ssid, iter->devno);
317 		iter->in_range = 1;
318 		return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
319 	}
320 	if ((iter->devno == __MAX_SUBCHANNEL) ||
321 	    !is_blacklisted(iter->ssid, iter->devno + 1)) {
322 		/* Last device in range. */
323 		iter->in_range = 0;
324 		return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
325 	}
326 	return 0;
327 }
328 
329 static ssize_t
330 cio_ignore_write(struct file *file, const char __user *user_buf,
331 		 size_t user_len, loff_t *offset)
332 {
333 	char *buf;
334 	ssize_t rc, ret, i;
335 
336 	if (*offset)
337 		return -EINVAL;
338 	if (user_len > 65536)
339 		user_len = 65536;
340 	buf = vmalloc (user_len + 1); /* maybe better use the stack? */
341 	if (buf == NULL)
342 		return -ENOMEM;
343 	memset(buf, 0, user_len + 1);
344 
345 	if (strncpy_from_user (buf, user_buf, user_len) < 0) {
346 		rc = -EFAULT;
347 		goto out_free;
348 	}
349 
350 	i = user_len - 1;
351 	while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
352 		buf[i] = '\0';
353 		i--;
354 	}
355 	ret = blacklist_parse_proc_parameters(buf);
356 	if (ret)
357 		rc = ret;
358 	else
359 		rc = user_len;
360 
361 out_free:
362 	vfree (buf);
363 	return rc;
364 }
365 
366 static const struct seq_operations cio_ignore_proc_seq_ops = {
367 	.start = cio_ignore_proc_seq_start,
368 	.stop  = cio_ignore_proc_seq_stop,
369 	.next  = cio_ignore_proc_seq_next,
370 	.show  = cio_ignore_proc_seq_show,
371 };
372 
373 static int
374 cio_ignore_proc_open(struct inode *inode, struct file *file)
375 {
376 	return seq_open_private(file, &cio_ignore_proc_seq_ops,
377 				sizeof(struct ccwdev_iter));
378 }
379 
380 static const struct file_operations cio_ignore_proc_fops = {
381 	.open    = cio_ignore_proc_open,
382 	.read    = seq_read,
383 	.llseek  = seq_lseek,
384 	.release = seq_release_private,
385 	.write   = cio_ignore_write,
386 };
387 
388 static int
389 cio_ignore_proc_init (void)
390 {
391 	struct proc_dir_entry *entry;
392 
393 	entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
394 			    &cio_ignore_proc_fops);
395 	if (!entry)
396 		return -ENOENT;
397 	return 0;
398 }
399 
400 __initcall (cio_ignore_proc_init);
401 
402 #endif /* CONFIG_PROC_FS */
403