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