root/drivers/s390/cio/blacklist.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. blacklist_range
  2. pure_hex
  3. parse_busid
  4. blacklist_parse_parameters
  5. blacklist_setup
  6. is_blacklisted
  7. blacklist_parse_proc_parameters
  8. cio_ignore_proc_seq_start
  9. cio_ignore_proc_seq_stop
  10. cio_ignore_proc_seq_next
  11. cio_ignore_proc_seq_show
  12. cio_ignore_write
  13. cio_ignore_proc_open
  14. cio_ignore_proc_init

   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                 css_schedule_eval_all_unreg(0);
 266         } else if (strcmp("add", parm) == 0)
 267                 rc = blacklist_parse_parameters(buf, add, 0);
 268         else if (strcmp("purge", parm) == 0)
 269                 return ccw_purge_blacklisted();
 270         else
 271                 return -EINVAL;
 272 
 273 
 274         return rc;
 275 }
 276 
 277 /* Iterator struct for all devices. */
 278 struct ccwdev_iter {
 279         int devno;
 280         int ssid;
 281         int in_range;
 282 };
 283 
 284 static void *
 285 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
 286 {
 287         struct ccwdev_iter *iter = s->private;
 288 
 289         if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
 290                 return NULL;
 291         memset(iter, 0, sizeof(*iter));
 292         iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
 293         iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
 294         return iter;
 295 }
 296 
 297 static void
 298 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
 299 {
 300 }
 301 
 302 static void *
 303 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
 304 {
 305         struct ccwdev_iter *iter;
 306         loff_t p = *offset;
 307 
 308         (*offset)++;
 309         if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
 310                 return NULL;
 311         iter = it;
 312         if (iter->devno == __MAX_SUBCHANNEL) {
 313                 iter->devno = 0;
 314                 iter->ssid++;
 315                 if (iter->ssid > __MAX_SSID)
 316                         return NULL;
 317         } else
 318                 iter->devno++;
 319         return iter;
 320 }
 321 
 322 static int
 323 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
 324 {
 325         struct ccwdev_iter *iter;
 326 
 327         iter = it;
 328         if (!is_blacklisted(iter->ssid, iter->devno))
 329                 /* Not blacklisted, nothing to output. */
 330                 return 0;
 331         if (!iter->in_range) {
 332                 /* First device in range. */
 333                 if ((iter->devno == __MAX_SUBCHANNEL) ||
 334                     !is_blacklisted(iter->ssid, iter->devno + 1)) {
 335                         /* Singular device. */
 336                         seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
 337                         return 0;
 338                 }
 339                 iter->in_range = 1;
 340                 seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
 341                 return 0;
 342         }
 343         if ((iter->devno == __MAX_SUBCHANNEL) ||
 344             !is_blacklisted(iter->ssid, iter->devno + 1)) {
 345                 /* Last device in range. */
 346                 iter->in_range = 0;
 347                 seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
 348         }
 349         return 0;
 350 }
 351 
 352 static ssize_t
 353 cio_ignore_write(struct file *file, const char __user *user_buf,
 354                  size_t user_len, loff_t *offset)
 355 {
 356         char *buf;
 357         ssize_t rc, ret, i;
 358 
 359         if (*offset)
 360                 return -EINVAL;
 361         if (user_len > 65536)
 362                 user_len = 65536;
 363         buf = vzalloc(user_len + 1); /* maybe better use the stack? */
 364         if (buf == NULL)
 365                 return -ENOMEM;
 366 
 367         if (strncpy_from_user (buf, user_buf, user_len) < 0) {
 368                 rc = -EFAULT;
 369                 goto out_free;
 370         }
 371 
 372         i = user_len - 1;
 373         while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
 374                 buf[i] = '\0';
 375                 i--;
 376         }
 377         ret = blacklist_parse_proc_parameters(buf);
 378         if (ret)
 379                 rc = ret;
 380         else
 381                 rc = user_len;
 382 
 383 out_free:
 384         vfree (buf);
 385         return rc;
 386 }
 387 
 388 static const struct seq_operations cio_ignore_proc_seq_ops = {
 389         .start = cio_ignore_proc_seq_start,
 390         .stop  = cio_ignore_proc_seq_stop,
 391         .next  = cio_ignore_proc_seq_next,
 392         .show  = cio_ignore_proc_seq_show,
 393 };
 394 
 395 static int
 396 cio_ignore_proc_open(struct inode *inode, struct file *file)
 397 {
 398         return seq_open_private(file, &cio_ignore_proc_seq_ops,
 399                                 sizeof(struct ccwdev_iter));
 400 }
 401 
 402 static const 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_private,
 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 = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
 416                             &cio_ignore_proc_fops);
 417         if (!entry)
 418                 return -ENOENT;
 419         return 0;
 420 }
 421 
 422 __initcall (cio_ignore_proc_init);
 423 
 424 #endif /* CONFIG_PROC_FS */

/* [<][>][^][v][top][bottom][index][help] */