1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * S/390 common I/O routines -- blacklisting of specific devices 4 * 5 * Copyright IBM Corp. 1999, 2013 6 * Author(s): Ingo Adlung (adlung@de.ibm.com) 7 * Cornelia Huck (cornelia.huck@de.ibm.com) 8 * Arnd Bergmann (arndb@de.ibm.com) 9 */ 10 11 #define pr_fmt(fmt) "cio: " 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 <linux/uaccess.h> 21 #include <asm/cio.h> 22 #include <asm/ipl.h> 23 24 #include "blacklist.h" 25 #include "cio.h" 26 #include "cio_debug.h" 27 #include "css.h" 28 #include "device.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 int blacklist_range(range_action action, unsigned int from_ssid, 49 unsigned int to_ssid, unsigned int from, 50 unsigned int to, int msgtrigger) 51 { 52 if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { 53 if (msgtrigger) 54 pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n", 55 from_ssid, from, 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_warn("%s is not a valid device for the cio_ignore kernel parameter\n", 143 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 if (strcmp(parm, "ipldev") == 0) { 176 if (ipl_info.type == IPL_TYPE_CCW) { 177 from_cssid = 0; 178 from_ssid = ipl_info.data.ccw.dev_id.ssid; 179 from = ipl_info.data.ccw.dev_id.devno; 180 } else if (ipl_info.type == IPL_TYPE_FCP || 181 ipl_info.type == IPL_TYPE_FCP_DUMP) { 182 from_cssid = 0; 183 from_ssid = ipl_info.data.fcp.dev_id.ssid; 184 from = ipl_info.data.fcp.dev_id.devno; 185 } else { 186 continue; 187 } 188 to_cssid = from_cssid; 189 to_ssid = from_ssid; 190 to = from; 191 } else if (strcmp(parm, "condev") == 0) { 192 if (console_devno == -1) 193 continue; 194 195 from_cssid = to_cssid = 0; 196 from_ssid = to_ssid = 0; 197 from = to = console_devno; 198 } else { 199 rc = parse_busid(strsep(&parm, "-"), &from_cssid, 200 &from_ssid, &from, msgtrigger); 201 if (!rc) { 202 if (parm != NULL) 203 rc = parse_busid(parm, &to_cssid, 204 &to_ssid, &to, 205 msgtrigger); 206 else { 207 to_cssid = from_cssid; 208 to_ssid = from_ssid; 209 to = from; 210 } 211 } 212 } 213 if (!rc) { 214 rc = blacklist_range(ra, from_ssid, to_ssid, from, to, 215 msgtrigger); 216 if (rc) 217 totalrc = -EINVAL; 218 } else 219 totalrc = -EINVAL; 220 } 221 222 return totalrc; 223 } 224 225 static int __init 226 blacklist_setup (char *str) 227 { 228 CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 229 if (blacklist_parse_parameters(str, add, 1)) 230 return 0; 231 return 1; 232 } 233 234 __setup ("cio_ignore=", blacklist_setup); 235 236 /* Checking if devices are blacklisted */ 237 238 /* 239 * Function: is_blacklisted 240 * Returns 1 if the given devicenumber can be found in the blacklist, 241 * otherwise 0. 242 * Used by validate_subchannel() 243 */ 244 int 245 is_blacklisted (int ssid, int devno) 246 { 247 return test_bit (devno, bl_dev[ssid]); 248 } 249 250 #ifdef CONFIG_PROC_FS 251 /* 252 * Function: blacklist_parse_proc_parameters 253 * parse the stuff which is piped to /proc/cio_ignore 254 */ 255 static int blacklist_parse_proc_parameters(char *buf) 256 { 257 int rc; 258 char *parm; 259 260 parm = strsep(&buf, " "); 261 262 if (strcmp("free", parm) == 0) { 263 rc = blacklist_parse_parameters(buf, free, 0); 264 /* 265 * Evaluate the subchannels without an online device. This way, 266 * no path-verification will be triggered on those subchannels 267 * and it avoids unnecessary delays. 268 */ 269 css_schedule_eval_cond(CSS_EVAL_NOT_ONLINE, 0); 270 } else if (strcmp("add", parm) == 0) 271 rc = blacklist_parse_parameters(buf, add, 0); 272 else if (strcmp("purge", parm) == 0) 273 return ccw_purge_blacklisted(); 274 else 275 return -EINVAL; 276 277 278 return rc; 279 } 280 281 /* Iterator struct for all devices. */ 282 struct ccwdev_iter { 283 int devno; 284 int ssid; 285 int in_range; 286 }; 287 288 static void * 289 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 290 { 291 struct ccwdev_iter *iter = s->private; 292 293 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 294 return NULL; 295 memset(iter, 0, sizeof(*iter)); 296 iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 297 iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 298 return iter; 299 } 300 301 static void 302 cio_ignore_proc_seq_stop(struct seq_file *s, void *it) 303 { 304 } 305 306 static void * 307 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 308 { 309 struct ccwdev_iter *iter; 310 loff_t p = *offset; 311 312 (*offset)++; 313 if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 314 return NULL; 315 iter = it; 316 if (iter->devno == __MAX_SUBCHANNEL) { 317 iter->devno = 0; 318 iter->ssid++; 319 if (iter->ssid > __MAX_SSID) 320 return NULL; 321 } else 322 iter->devno++; 323 return iter; 324 } 325 326 static int 327 cio_ignore_proc_seq_show(struct seq_file *s, void *it) 328 { 329 struct ccwdev_iter *iter; 330 331 iter = it; 332 if (!is_blacklisted(iter->ssid, iter->devno)) 333 /* Not blacklisted, nothing to output. */ 334 return 0; 335 if (!iter->in_range) { 336 /* First device in range. */ 337 if ((iter->devno == __MAX_SUBCHANNEL) || 338 !is_blacklisted(iter->ssid, iter->devno + 1)) { 339 /* Singular device. */ 340 seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 341 return 0; 342 } 343 iter->in_range = 1; 344 seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 345 return 0; 346 } 347 if ((iter->devno == __MAX_SUBCHANNEL) || 348 !is_blacklisted(iter->ssid, iter->devno + 1)) { 349 /* Last device in range. */ 350 iter->in_range = 0; 351 seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 352 } 353 return 0; 354 } 355 356 static ssize_t 357 cio_ignore_write(struct file *file, const char __user *user_buf, 358 size_t user_len, loff_t *offset) 359 { 360 char *buf; 361 ssize_t rc, ret, i; 362 363 if (*offset) 364 return -EINVAL; 365 if (user_len > 65536) 366 user_len = 65536; 367 buf = vzalloc(user_len + 1); /* maybe better use the stack? */ 368 if (buf == NULL) 369 return -ENOMEM; 370 371 if (strncpy_from_user (buf, user_buf, user_len) < 0) { 372 rc = -EFAULT; 373 goto out_free; 374 } 375 376 i = user_len - 1; 377 while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) { 378 buf[i] = '\0'; 379 i--; 380 } 381 ret = blacklist_parse_proc_parameters(buf); 382 if (ret) 383 rc = ret; 384 else 385 rc = user_len; 386 387 out_free: 388 vfree (buf); 389 return rc; 390 } 391 392 static const struct seq_operations cio_ignore_proc_seq_ops = { 393 .start = cio_ignore_proc_seq_start, 394 .stop = cio_ignore_proc_seq_stop, 395 .next = cio_ignore_proc_seq_next, 396 .show = cio_ignore_proc_seq_show, 397 }; 398 399 static int 400 cio_ignore_proc_open(struct inode *inode, struct file *file) 401 { 402 return seq_open_private(file, &cio_ignore_proc_seq_ops, 403 sizeof(struct ccwdev_iter)); 404 } 405 406 static const struct proc_ops cio_ignore_proc_ops = { 407 .proc_open = cio_ignore_proc_open, 408 .proc_read = seq_read, 409 .proc_lseek = seq_lseek, 410 .proc_release = seq_release_private, 411 .proc_write = cio_ignore_write, 412 }; 413 414 static int 415 cio_ignore_proc_init (void) 416 { 417 struct proc_dir_entry *entry; 418 419 entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, 420 &cio_ignore_proc_ops); 421 if (!entry) 422 return -ENOENT; 423 return 0; 424 } 425 426 __initcall (cio_ignore_proc_init); 427 428 #endif /* CONFIG_PROC_FS */ 429