1 /* 2 * S/390 common I/O routines -- blacklisting of specific devices 3 * 4 * Copyright IBM Corp. 1999, 2002 5 * Author(s): Ingo Adlung (adlung@de.ibm.com) 6 * Cornelia Huck (cornelia.huck@de.ibm.com) 7 * Arnd Bergmann (arndb@de.ibm.com) 8 */ 9 10 #define KMSG_COMPONENT "cio" 11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 12 13 #include <linux/init.h> 14 #include <linux/vmalloc.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 #include "device.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 int blacklist_range(range_action action, unsigned int from_ssid, 48 unsigned int to_ssid, unsigned int from, 49 unsigned int to, int msgtrigger) 50 { 51 if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { 52 if (msgtrigger) 53 pr_warning("0.%x.%04x to 0.%x.%04x is not a valid " 54 "range for cio_ignore\n", from_ssid, from, 55 to_ssid, to); 56 57 return 1; 58 } 59 60 while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) && 61 (from <= to))) { 62 if (action == add) 63 set_bit(from, bl_dev[from_ssid]); 64 else 65 clear_bit(from, bl_dev[from_ssid]); 66 from++; 67 if (from > __MAX_SUBCHANNEL) { 68 from_ssid++; 69 from = 0; 70 } 71 } 72 73 return 0; 74 } 75 76 static int pure_hex(char **cp, unsigned int *val, int min_digit, 77 int max_digit, int max_val) 78 { 79 int diff; 80 81 diff = 0; 82 *val = 0; 83 84 while (diff <= max_digit) { 85 int value = hex_to_bin(**cp); 86 87 if (value < 0) 88 break; 89 *val = *val * 16 + value; 90 (*cp)++; 91 diff++; 92 } 93 94 if ((diff < min_digit) || (diff > max_digit) || (*val > max_val)) 95 return 1; 96 97 return 0; 98 } 99 100 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, 101 unsigned int *devno, int msgtrigger) 102 { 103 char *str_work; 104 int val, rc, ret; 105 106 rc = 1; 107 108 if (*str == '\0') 109 goto out; 110 111 /* old style */ 112 str_work = str; 113 val = simple_strtoul(str, &str_work, 16); 114 115 if (*str_work == '\0') { 116 if (val <= __MAX_SUBCHANNEL) { 117 *devno = val; 118 *ssid = 0; 119 *cssid = 0; 120 rc = 0; 121 } 122 goto out; 123 } 124 125 /* new style */ 126 str_work = str; 127 ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID); 128 if (ret || (str_work[0] != '.')) 129 goto out; 130 str_work++; 131 ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID); 132 if (ret || (str_work[0] != '.')) 133 goto out; 134 str_work++; 135 ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL); 136 if (ret || (str_work[0] != '\0')) 137 goto out; 138 139 rc = 0; 140 out: 141 if (rc && msgtrigger) 142 pr_warning("%s is not a valid device for the cio_ignore " 143 "kernel parameter\n", str); 144 145 return rc; 146 } 147 148 static int blacklist_parse_parameters(char *str, range_action action, 149 int msgtrigger) 150 { 151 unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to; 152 int rc, totalrc; 153 char *parm; 154 range_action ra; 155 156 totalrc = 0; 157 158 while ((parm = strsep(&str, ","))) { 159 rc = 0; 160 ra = action; 161 if (*parm == '!') { 162 if (ra == add) 163 ra = free; 164 else 165 ra = add; 166 parm++; 167 } 168 if (strcmp(parm, "all") == 0) { 169 from_cssid = 0; 170 from_ssid = 0; 171 from = 0; 172 to_cssid = __MAX_CSSID; 173 to_ssid = __MAX_SSID; 174 to = __MAX_SUBCHANNEL; 175 } else { 176 rc = parse_busid(strsep(&parm, "-"), &from_cssid, 177 &from_ssid, &from, msgtrigger); 178 if (!rc) { 179 if (parm != NULL) 180 rc = parse_busid(parm, &to_cssid, 181 &to_ssid, &to, 182 msgtrigger); 183 else { 184 to_cssid = from_cssid; 185 to_ssid = from_ssid; 186 to = from; 187 } 188 } 189 } 190 if (!rc) { 191 rc = blacklist_range(ra, from_ssid, to_ssid, from, to, 192 msgtrigger); 193 if (rc) 194 totalrc = -EINVAL; 195 } else 196 totalrc = -EINVAL; 197 } 198 199 return totalrc; 200 } 201 202 static int __init 203 blacklist_setup (char *str) 204 { 205 CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 206 if (blacklist_parse_parameters(str, add, 1)) 207 return 0; 208 return 1; 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 /* 229 * Function: blacklist_parse_proc_parameters 230 * parse the stuff which is piped to /proc/cio_ignore 231 */ 232 static int blacklist_parse_proc_parameters(char *buf) 233 { 234 int rc; 235 char *parm; 236 237 parm = strsep(&buf, " "); 238 239 if (strcmp("free", parm) == 0) 240 rc = blacklist_parse_parameters(buf, free, 0); 241 else if (strcmp("add", parm) == 0) 242 rc = blacklist_parse_parameters(buf, add, 0); 243 else if (strcmp("purge", parm) == 0) 244 return ccw_purge_blacklisted(); 245 else 246 return -EINVAL; 247 248 css_schedule_reprobe(); 249 250 return rc; 251 } 252 253 /* Iterator struct for all devices. */ 254 struct ccwdev_iter { 255 int devno; 256 int ssid; 257 int in_range; 258 }; 259 260 static void * 261 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 262 { 263 struct ccwdev_iter *iter = s->private; 264 265 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 266 return NULL; 267 memset(iter, 0, sizeof(*iter)); 268 iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 269 iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 270 return iter; 271 } 272 273 static void 274 cio_ignore_proc_seq_stop(struct seq_file *s, void *it) 275 { 276 } 277 278 static void * 279 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 280 { 281 struct ccwdev_iter *iter; 282 283 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 284 return NULL; 285 iter = it; 286 if (iter->devno == __MAX_SUBCHANNEL) { 287 iter->devno = 0; 288 iter->ssid++; 289 if (iter->ssid > __MAX_SSID) 290 return NULL; 291 } else 292 iter->devno++; 293 (*offset)++; 294 return iter; 295 } 296 297 static int 298 cio_ignore_proc_seq_show(struct seq_file *s, void *it) 299 { 300 struct ccwdev_iter *iter; 301 302 iter = it; 303 if (!is_blacklisted(iter->ssid, iter->devno)) 304 /* Not blacklisted, nothing to output. */ 305 return 0; 306 if (!iter->in_range) { 307 /* First device in range. */ 308 if ((iter->devno == __MAX_SUBCHANNEL) || 309 !is_blacklisted(iter->ssid, iter->devno + 1)) 310 /* Singular device. */ 311 return seq_printf(s, "0.%x.%04x\n", 312 iter->ssid, iter->devno); 313 iter->in_range = 1; 314 return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 315 } 316 if ((iter->devno == __MAX_SUBCHANNEL) || 317 !is_blacklisted(iter->ssid, iter->devno + 1)) { 318 /* Last device in range. */ 319 iter->in_range = 0; 320 return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 321 } 322 return 0; 323 } 324 325 static ssize_t 326 cio_ignore_write(struct file *file, const char __user *user_buf, 327 size_t user_len, loff_t *offset) 328 { 329 char *buf; 330 ssize_t rc, ret, i; 331 332 if (*offset) 333 return -EINVAL; 334 if (user_len > 65536) 335 user_len = 65536; 336 buf = vzalloc(user_len + 1); /* maybe better use the stack? */ 337 if (buf == NULL) 338 return -ENOMEM; 339 340 if (strncpy_from_user (buf, user_buf, user_len) < 0) { 341 rc = -EFAULT; 342 goto out_free; 343 } 344 345 i = user_len - 1; 346 while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) { 347 buf[i] = '\0'; 348 i--; 349 } 350 ret = blacklist_parse_proc_parameters(buf); 351 if (ret) 352 rc = ret; 353 else 354 rc = user_len; 355 356 out_free: 357 vfree (buf); 358 return rc; 359 } 360 361 static const struct seq_operations cio_ignore_proc_seq_ops = { 362 .start = cio_ignore_proc_seq_start, 363 .stop = cio_ignore_proc_seq_stop, 364 .next = cio_ignore_proc_seq_next, 365 .show = cio_ignore_proc_seq_show, 366 }; 367 368 static int 369 cio_ignore_proc_open(struct inode *inode, struct file *file) 370 { 371 return seq_open_private(file, &cio_ignore_proc_seq_ops, 372 sizeof(struct ccwdev_iter)); 373 } 374 375 static const struct file_operations cio_ignore_proc_fops = { 376 .open = cio_ignore_proc_open, 377 .read = seq_read, 378 .llseek = seq_lseek, 379 .release = seq_release_private, 380 .write = cio_ignore_write, 381 }; 382 383 static int 384 cio_ignore_proc_init (void) 385 { 386 struct proc_dir_entry *entry; 387 388 entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, 389 &cio_ignore_proc_fops); 390 if (!entry) 391 return -ENOENT; 392 return 0; 393 } 394 395 __initcall (cio_ignore_proc_init); 396 397 #endif /* CONFIG_PROC_FS */ 398