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