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