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