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 #include <linux/config.h> 13 #include <linux/init.h> 14 #include <linux/vmalloc.h> 15 #include <linux/slab.h> 16 #include <linux/proc_fs.h> 17 #include <linux/seq_file.h> 18 #include <linux/ctype.h> 19 #include <linux/device.h> 20 21 #include <asm/cio.h> 22 #include <asm/uaccess.h> 23 24 #include "blacklist.h" 25 #include "cio.h" 26 #include "cio_debug.h" 27 #include "css.h" 28 29 /* 30 * "Blacklisting" of certain devices: 31 * Device numbers given in the commandline as cio_ignore=... won't be known 32 * to Linux. 33 * 34 * These can be single devices or ranges of devices 35 */ 36 37 /* 65536 bits for each set to indicate if a devno is blacklisted or not */ 38 #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ 39 (8*sizeof(long))) 40 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS]; 41 typedef enum {add, free} range_action; 42 43 /* 44 * Function: blacklist_range 45 * (Un-)blacklist the devices from-to 46 */ 47 static inline void 48 blacklist_range (range_action action, unsigned int from, unsigned int to, 49 unsigned int ssid) 50 { 51 if (!to) 52 to = from; 53 54 if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) { 55 printk (KERN_WARNING "Invalid blacklist range " 56 "0.%x.%04x to 0.%x.%04x, skipping\n", 57 ssid, from, ssid, to); 58 return; 59 } 60 for (; from <= to; from++) { 61 if (action == add) 62 set_bit (from, bl_dev[ssid]); 63 else 64 clear_bit (from, bl_dev[ssid]); 65 } 66 } 67 68 /* 69 * Function: blacklist_busid 70 * Get devno/busid from given string. 71 * Shamelessly grabbed from dasd_devmap.c. 72 */ 73 static inline int 74 blacklist_busid(char **str, int *id0, int *ssid, int *devno) 75 { 76 int val, old_style; 77 char *sav; 78 79 sav = *str; 80 81 /* check for leading '0x' */ 82 old_style = 0; 83 if ((*str)[0] == '0' && (*str)[1] == 'x') { 84 *str += 2; 85 old_style = 1; 86 } 87 if (!isxdigit((*str)[0])) /* We require at least one hex digit */ 88 goto confused; 89 val = simple_strtoul(*str, str, 16); 90 if (old_style || (*str)[0] != '.') { 91 *id0 = *ssid = 0; 92 if (val < 0 || val > 0xffff) 93 goto confused; 94 *devno = val; 95 if ((*str)[0] != ',' && (*str)[0] != '-' && 96 (*str)[0] != '\n' && (*str)[0] != '\0') 97 goto confused; 98 return 0; 99 } 100 /* New style x.y.z busid */ 101 if (val < 0 || val > 0xff) 102 goto confused; 103 *id0 = val; 104 (*str)++; 105 if (!isxdigit((*str)[0])) /* We require at least one hex digit */ 106 goto confused; 107 val = simple_strtoul(*str, str, 16); 108 if (val < 0 || val > 0xff || (*str)++[0] != '.') 109 goto confused; 110 *ssid = val; 111 if (!isxdigit((*str)[0])) /* We require at least one hex digit */ 112 goto confused; 113 val = simple_strtoul(*str, str, 16); 114 if (val < 0 || val > 0xffff) 115 goto confused; 116 *devno = val; 117 if ((*str)[0] != ',' && (*str)[0] != '-' && 118 (*str)[0] != '\n' && (*str)[0] != '\0') 119 goto confused; 120 return 0; 121 confused: 122 strsep(str, ",\n"); 123 printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav); 124 return 1; 125 } 126 127 static inline int 128 blacklist_parse_parameters (char *str, range_action action) 129 { 130 unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid; 131 132 while (*str != 0 && *str != '\n') { 133 range_action ra = action; 134 while(*str == ',') 135 str++; 136 if (*str == '!') { 137 ra = !action; 138 ++str; 139 } 140 141 /* 142 * Since we have to parse the proc commands and the 143 * kernel arguments we have to check four cases 144 */ 145 if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 || 146 strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) { 147 int j; 148 149 str += 3; 150 for (j=0; j <= __MAX_SSID; j++) 151 blacklist_range(ra, 0, __MAX_SUBCHANNEL, j); 152 } else { 153 int rc; 154 155 rc = blacklist_busid(&str, &from_id0, 156 &from_ssid, &from); 157 if (rc) 158 continue; 159 to = from; 160 to_id0 = from_id0; 161 to_ssid = from_ssid; 162 if (*str == '-') { 163 str++; 164 rc = blacklist_busid(&str, &to_id0, 165 &to_ssid, &to); 166 if (rc) 167 continue; 168 } 169 if (*str == '-') { 170 printk(KERN_WARNING "invalid cio_ignore " 171 "parameter '%s'\n", 172 strsep(&str, ",\n")); 173 continue; 174 } 175 if ((from_id0 != to_id0) || 176 (from_ssid != to_ssid)) { 177 printk(KERN_WARNING "invalid cio_ignore range " 178 "%x.%x.%04x-%x.%x.%04x\n", 179 from_id0, from_ssid, from, 180 to_id0, to_ssid, to); 181 continue; 182 } 183 pr_debug("blacklist_setup: adding range " 184 "from %x.%x.%04x to %x.%x.%04x\n", 185 from_id0, from_ssid, from, to_id0, to_ssid, to); 186 blacklist_range (ra, from, to, to_ssid); 187 } 188 } 189 return 1; 190 } 191 192 /* Parsing the commandline for blacklist parameters, e.g. to blacklist 193 * bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of: 194 * - cio_ignore=1234-1236 195 * - cio_ignore=0x1234-0x1235,1236 196 * - cio_ignore=0x1234,1235-1236 197 * - cio_ignore=1236 cio_ignore=1234-0x1236 198 * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235 199 * - cio_ignore=0.0.1234-0.0.1236 200 * - cio_ignore=0.0.1234,0x1235,1236 201 * - ... 202 */ 203 static int __init 204 blacklist_setup (char *str) 205 { 206 CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 207 return blacklist_parse_parameters (str, add); 208 } 209 210 __setup ("cio_ignore=", blacklist_setup); 211 212 /* Checking if devices are blacklisted */ 213 214 /* 215 * Function: is_blacklisted 216 * Returns 1 if the given devicenumber can be found in the blacklist, 217 * otherwise 0. 218 * Used by validate_subchannel() 219 */ 220 int 221 is_blacklisted (int ssid, int devno) 222 { 223 return test_bit (devno, bl_dev[ssid]); 224 } 225 226 #ifdef CONFIG_PROC_FS 227 static int 228 __s390_redo_validation(struct subchannel_id schid, void *data) 229 { 230 int ret; 231 struct subchannel *sch; 232 233 sch = get_subchannel_by_schid(schid); 234 if (sch) { 235 /* Already known. */ 236 put_device(&sch->dev); 237 return 0; 238 } 239 ret = css_probe_device(schid); 240 if (ret == -ENXIO) 241 return ret; /* We're through. */ 242 if (ret == -ENOMEM) 243 /* Stop validation for now. Bad, but no need for a panic. */ 244 return ret; 245 return 0; 246 } 247 248 /* 249 * Function: s390_redo_validation 250 * Look for no longer blacklisted devices 251 * FIXME: there must be a better way to do this */ 252 static inline void 253 s390_redo_validation (void) 254 { 255 CIO_TRACE_EVENT (0, "redoval"); 256 257 for_each_subchannel(__s390_redo_validation, NULL); 258 } 259 260 /* 261 * Function: blacklist_parse_proc_parameters 262 * parse the stuff which is piped to /proc/cio_ignore 263 */ 264 static inline void 265 blacklist_parse_proc_parameters (char *buf) 266 { 267 if (strncmp (buf, "free ", 5) == 0) { 268 blacklist_parse_parameters (buf + 5, free); 269 } else if (strncmp (buf, "add ", 4) == 0) { 270 /* 271 * We don't need to check for known devices since 272 * css_probe_device will handle this correctly. 273 */ 274 blacklist_parse_parameters (buf + 4, add); 275 } else { 276 printk (KERN_WARNING "cio_ignore: Parse error; \n" 277 KERN_WARNING "try using 'free all|<devno-range>," 278 "<devno-range>,...'\n" 279 KERN_WARNING "or 'add <devno-range>," 280 "<devno-range>,...'\n"); 281 return; 282 } 283 284 s390_redo_validation (); 285 } 286 287 /* Iterator struct for all devices. */ 288 struct ccwdev_iter { 289 int devno; 290 int ssid; 291 int in_range; 292 }; 293 294 static void * 295 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 296 { 297 struct ccwdev_iter *iter; 298 299 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 300 return NULL; 301 iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL); 302 if (!iter) 303 return ERR_PTR(-ENOMEM); 304 iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 305 iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 306 return iter; 307 } 308 309 static void 310 cio_ignore_proc_seq_stop(struct seq_file *s, void *it) 311 { 312 if (!IS_ERR(it)) 313 kfree(it); 314 } 315 316 static void * 317 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 318 { 319 struct ccwdev_iter *iter; 320 321 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 322 return NULL; 323 iter = it; 324 if (iter->devno == __MAX_SUBCHANNEL) { 325 iter->devno = 0; 326 iter->ssid++; 327 if (iter->ssid > __MAX_SSID) 328 return NULL; 329 } else 330 iter->devno++; 331 (*offset)++; 332 return iter; 333 } 334 335 static int 336 cio_ignore_proc_seq_show(struct seq_file *s, void *it) 337 { 338 struct ccwdev_iter *iter; 339 340 iter = it; 341 if (!is_blacklisted(iter->ssid, iter->devno)) 342 /* Not blacklisted, nothing to output. */ 343 return 0; 344 if (!iter->in_range) { 345 /* First device in range. */ 346 if ((iter->devno == __MAX_SUBCHANNEL) || 347 !is_blacklisted(iter->ssid, iter->devno + 1)) 348 /* Singular device. */ 349 return seq_printf(s, "0.%x.%04x\n", 350 iter->ssid, iter->devno); 351 iter->in_range = 1; 352 return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 353 } 354 if ((iter->devno == __MAX_SUBCHANNEL) || 355 !is_blacklisted(iter->ssid, iter->devno + 1)) { 356 /* Last device in range. */ 357 iter->in_range = 0; 358 return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 359 } 360 return 0; 361 } 362 363 static ssize_t 364 cio_ignore_write(struct file *file, const char __user *user_buf, 365 size_t user_len, loff_t *offset) 366 { 367 char *buf; 368 369 if (*offset) 370 return -EINVAL; 371 if (user_len > 65536) 372 user_len = 65536; 373 buf = vmalloc (user_len + 1); /* maybe better use the stack? */ 374 if (buf == NULL) 375 return -ENOMEM; 376 if (strncpy_from_user (buf, user_buf, user_len) < 0) { 377 vfree (buf); 378 return -EFAULT; 379 } 380 buf[user_len] = '\0'; 381 382 blacklist_parse_proc_parameters (buf); 383 384 vfree (buf); 385 return user_len; 386 } 387 388 static struct seq_operations cio_ignore_proc_seq_ops = { 389 .start = cio_ignore_proc_seq_start, 390 .stop = cio_ignore_proc_seq_stop, 391 .next = cio_ignore_proc_seq_next, 392 .show = cio_ignore_proc_seq_show, 393 }; 394 395 static int 396 cio_ignore_proc_open(struct inode *inode, struct file *file) 397 { 398 return seq_open(file, &cio_ignore_proc_seq_ops); 399 } 400 401 static struct file_operations cio_ignore_proc_fops = { 402 .open = cio_ignore_proc_open, 403 .read = seq_read, 404 .llseek = seq_lseek, 405 .release = seq_release, 406 .write = cio_ignore_write, 407 }; 408 409 static int 410 cio_ignore_proc_init (void) 411 { 412 struct proc_dir_entry *entry; 413 414 entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, 415 &proc_root); 416 if (!entry) 417 return -ENOENT; 418 419 entry->proc_fops = &cio_ignore_proc_fops; 420 421 return 0; 422 } 423 424 __initcall (cio_ignore_proc_init); 425 426 #endif /* CONFIG_PROC_FS */ 427