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 KMSG_COMPONENT "cio" 12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 14 #include <linux/init.h> 15 #include <linux/vmalloc.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 <linux/uaccess.h> 22 #include <asm/cio.h> 23 #include <asm/ipl.h> 24 25 #include "blacklist.h" 26 #include "cio.h" 27 #include "cio_debug.h" 28 #include "css.h" 29 #include "device.h" 30 31 /* 32 * "Blacklisting" of certain devices: 33 * Device numbers given in the commandline as cio_ignore=... won't be known 34 * to Linux. 35 * 36 * These can be single devices or ranges of devices 37 */ 38 39 /* 65536 bits for each set to indicate if a devno is blacklisted or not */ 40 #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ 41 (8*sizeof(long))) 42 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS]; 43 typedef enum {add, free} range_action; 44 45 /* 46 * Function: blacklist_range 47 * (Un-)blacklist the devices from-to 48 */ 49 static int blacklist_range(range_action action, unsigned int from_ssid, 50 unsigned int to_ssid, unsigned int from, 51 unsigned int to, int msgtrigger) 52 { 53 if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { 54 if (msgtrigger) 55 pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n", 56 from_ssid, from, to_ssid, to); 57 58 return 1; 59 } 60 61 while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) && 62 (from <= to))) { 63 if (action == add) 64 set_bit(from, bl_dev[from_ssid]); 65 else 66 clear_bit(from, bl_dev[from_ssid]); 67 from++; 68 if (from > __MAX_SUBCHANNEL) { 69 from_ssid++; 70 from = 0; 71 } 72 } 73 74 return 0; 75 } 76 77 static int pure_hex(char **cp, unsigned int *val, int min_digit, 78 int max_digit, int max_val) 79 { 80 int diff; 81 82 diff = 0; 83 *val = 0; 84 85 while (diff <= max_digit) { 86 int value = hex_to_bin(**cp); 87 88 if (value < 0) 89 break; 90 *val = *val * 16 + value; 91 (*cp)++; 92 diff++; 93 } 94 95 if ((diff < min_digit) || (diff > max_digit) || (*val > max_val)) 96 return 1; 97 98 return 0; 99 } 100 101 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, 102 unsigned int *devno, int msgtrigger) 103 { 104 char *str_work; 105 int val, rc, ret; 106 107 rc = 1; 108 109 if (*str == '\0') 110 goto out; 111 112 /* old style */ 113 str_work = str; 114 val = simple_strtoul(str, &str_work, 16); 115 116 if (*str_work == '\0') { 117 if (val <= __MAX_SUBCHANNEL) { 118 *devno = val; 119 *ssid = 0; 120 *cssid = 0; 121 rc = 0; 122 } 123 goto out; 124 } 125 126 /* new style */ 127 str_work = str; 128 ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID); 129 if (ret || (str_work[0] != '.')) 130 goto out; 131 str_work++; 132 ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID); 133 if (ret || (str_work[0] != '.')) 134 goto out; 135 str_work++; 136 ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL); 137 if (ret || (str_work[0] != '\0')) 138 goto out; 139 140 rc = 0; 141 out: 142 if (rc && msgtrigger) 143 pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n", 144 str); 145 146 return rc; 147 } 148 149 static int blacklist_parse_parameters(char *str, range_action action, 150 int msgtrigger) 151 { 152 unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to; 153 int rc, totalrc; 154 char *parm; 155 range_action ra; 156 157 totalrc = 0; 158 159 while ((parm = strsep(&str, ","))) { 160 rc = 0; 161 ra = action; 162 if (*parm == '!') { 163 if (ra == add) 164 ra = free; 165 else 166 ra = add; 167 parm++; 168 } 169 if (strcmp(parm, "all") == 0) { 170 from_cssid = 0; 171 from_ssid = 0; 172 from = 0; 173 to_cssid = __MAX_CSSID; 174 to_ssid = __MAX_SSID; 175 to = __MAX_SUBCHANNEL; 176 } else if (strcmp(parm, "ipldev") == 0) { 177 if (ipl_info.type == IPL_TYPE_CCW) { 178 from_cssid = 0; 179 from_ssid = ipl_info.data.ccw.dev_id.ssid; 180 from = ipl_info.data.ccw.dev_id.devno; 181 } else if (ipl_info.type == IPL_TYPE_FCP || 182 ipl_info.type == IPL_TYPE_FCP_DUMP) { 183 from_cssid = 0; 184 from_ssid = ipl_info.data.fcp.dev_id.ssid; 185 from = ipl_info.data.fcp.dev_id.devno; 186 } else { 187 continue; 188 } 189 to_cssid = from_cssid; 190 to_ssid = from_ssid; 191 to = from; 192 } else if (strcmp(parm, "condev") == 0) { 193 if (console_devno == -1) 194 continue; 195 196 from_cssid = to_cssid = 0; 197 from_ssid = to_ssid = 0; 198 from = to = console_devno; 199 } else { 200 rc = parse_busid(strsep(&parm, "-"), &from_cssid, 201 &from_ssid, &from, msgtrigger); 202 if (!rc) { 203 if (parm != NULL) 204 rc = parse_busid(parm, &to_cssid, 205 &to_ssid, &to, 206 msgtrigger); 207 else { 208 to_cssid = from_cssid; 209 to_ssid = from_ssid; 210 to = from; 211 } 212 } 213 } 214 if (!rc) { 215 rc = blacklist_range(ra, from_ssid, to_ssid, from, to, 216 msgtrigger); 217 if (rc) 218 totalrc = -EINVAL; 219 } else 220 totalrc = -EINVAL; 221 } 222 223 return totalrc; 224 } 225 226 static int __init 227 blacklist_setup (char *str) 228 { 229 CIO_MSG_EVENT(6, "Reading blacklist parameters\n"); 230 if (blacklist_parse_parameters(str, add, 1)) 231 return 0; 232 return 1; 233 } 234 235 __setup ("cio_ignore=", blacklist_setup); 236 237 /* Checking if devices are blacklisted */ 238 239 /* 240 * Function: is_blacklisted 241 * Returns 1 if the given devicenumber can be found in the blacklist, 242 * otherwise 0. 243 * Used by validate_subchannel() 244 */ 245 int 246 is_blacklisted (int ssid, int devno) 247 { 248 return test_bit (devno, bl_dev[ssid]); 249 } 250 251 #ifdef CONFIG_PROC_FS 252 /* 253 * Function: blacklist_parse_proc_parameters 254 * parse the stuff which is piped to /proc/cio_ignore 255 */ 256 static int blacklist_parse_proc_parameters(char *buf) 257 { 258 int rc; 259 char *parm; 260 261 parm = strsep(&buf, " "); 262 263 if (strcmp("free", parm) == 0) { 264 rc = blacklist_parse_parameters(buf, free, 0); 265 /* There could be subchannels without proper devices connected. 266 * evaluate all the entries 267 */ 268 css_schedule_eval_all(); 269 } else if (strcmp("add", parm) == 0) 270 rc = blacklist_parse_parameters(buf, add, 0); 271 else if (strcmp("purge", parm) == 0) 272 return ccw_purge_blacklisted(); 273 else 274 return -EINVAL; 275 276 277 return rc; 278 } 279 280 /* Iterator struct for all devices. */ 281 struct ccwdev_iter { 282 int devno; 283 int ssid; 284 int in_range; 285 }; 286 287 static void * 288 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) 289 { 290 struct ccwdev_iter *iter = s->private; 291 292 if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 293 return NULL; 294 memset(iter, 0, sizeof(*iter)); 295 iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); 296 iter->devno = *offset % (__MAX_SUBCHANNEL + 1); 297 return iter; 298 } 299 300 static void 301 cio_ignore_proc_seq_stop(struct seq_file *s, void *it) 302 { 303 } 304 305 static void * 306 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) 307 { 308 struct ccwdev_iter *iter; 309 loff_t p = *offset; 310 311 (*offset)++; 312 if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) 313 return NULL; 314 iter = it; 315 if (iter->devno == __MAX_SUBCHANNEL) { 316 iter->devno = 0; 317 iter->ssid++; 318 if (iter->ssid > __MAX_SSID) 319 return NULL; 320 } else 321 iter->devno++; 322 return iter; 323 } 324 325 static int 326 cio_ignore_proc_seq_show(struct seq_file *s, void *it) 327 { 328 struct ccwdev_iter *iter; 329 330 iter = it; 331 if (!is_blacklisted(iter->ssid, iter->devno)) 332 /* Not blacklisted, nothing to output. */ 333 return 0; 334 if (!iter->in_range) { 335 /* First device in range. */ 336 if ((iter->devno == __MAX_SUBCHANNEL) || 337 !is_blacklisted(iter->ssid, iter->devno + 1)) { 338 /* Singular device. */ 339 seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 340 return 0; 341 } 342 iter->in_range = 1; 343 seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); 344 return 0; 345 } 346 if ((iter->devno == __MAX_SUBCHANNEL) || 347 !is_blacklisted(iter->ssid, iter->devno + 1)) { 348 /* Last device in range. */ 349 iter->in_range = 0; 350 seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); 351 } 352 return 0; 353 } 354 355 static ssize_t 356 cio_ignore_write(struct file *file, const char __user *user_buf, 357 size_t user_len, loff_t *offset) 358 { 359 char *buf; 360 ssize_t rc, ret, i; 361 362 if (*offset) 363 return -EINVAL; 364 if (user_len > 65536) 365 user_len = 65536; 366 buf = vzalloc(user_len + 1); /* maybe better use the stack? */ 367 if (buf == NULL) 368 return -ENOMEM; 369 370 if (strncpy_from_user (buf, user_buf, user_len) < 0) { 371 rc = -EFAULT; 372 goto out_free; 373 } 374 375 i = user_len - 1; 376 while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) { 377 buf[i] = '\0'; 378 i--; 379 } 380 ret = blacklist_parse_proc_parameters(buf); 381 if (ret) 382 rc = ret; 383 else 384 rc = user_len; 385 386 out_free: 387 vfree (buf); 388 return rc; 389 } 390 391 static const struct seq_operations cio_ignore_proc_seq_ops = { 392 .start = cio_ignore_proc_seq_start, 393 .stop = cio_ignore_proc_seq_stop, 394 .next = cio_ignore_proc_seq_next, 395 .show = cio_ignore_proc_seq_show, 396 }; 397 398 static int 399 cio_ignore_proc_open(struct inode *inode, struct file *file) 400 { 401 return seq_open_private(file, &cio_ignore_proc_seq_ops, 402 sizeof(struct ccwdev_iter)); 403 } 404 405 static const struct proc_ops cio_ignore_proc_ops = { 406 .proc_open = cio_ignore_proc_open, 407 .proc_read = seq_read, 408 .proc_lseek = seq_lseek, 409 .proc_release = seq_release_private, 410 .proc_write = cio_ignore_write, 411 }; 412 413 static int 414 cio_ignore_proc_init (void) 415 { 416 struct proc_dir_entry *entry; 417 418 entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, 419 &cio_ignore_proc_ops); 420 if (!entry) 421 return -ENOENT; 422 return 0; 423 } 424 425 __initcall (cio_ignore_proc_init); 426 427 #endif /* CONFIG_PROC_FS */ 428