2  *  drivers/s390/cio/blacklist.c
 
   3  *   S/390 common I/O routines -- blacklisting of specific devices
 
   5  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
 
   7  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
 
   8  *               Cornelia Huck (cornelia.huck@de.ibm.com)
 
   9  *               Arnd Bergmann (arndb@de.ibm.com)
 
  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>
 
  21 #include <asm/uaccess.h>
 
  23 #include "blacklist.h"
 
  25 #include "cio_debug.h"
 
  29  * "Blacklisting" of certain devices:
 
  30  * Device numbers given in the commandline as cio_ignore=... won't be known
 
  33  * These can be single devices or ranges of devices
 
  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)) / \
 
  39 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
 
  40 typedef enum {add, free} range_action;
 
  43  * Function: blacklist_range
 
  44  * (Un-)blacklist the devices from-to
 
  46 static int blacklist_range(range_action action, unsigned int from_ssid,
 
  47                            unsigned int to_ssid, unsigned int from,
 
  48                            unsigned int to, int msgtrigger)
 
  50         if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
 
  52                         printk(KERN_WARNING "cio: Invalid cio_ignore range "
 
  53                                "0.%x.%04x-0.%x.%04x\n", from_ssid, from,
 
  58         while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
 
  61                         set_bit(from, bl_dev[from_ssid]);
 
  63                         clear_bit(from, bl_dev[from_ssid]);
 
  65                 if (from > __MAX_SUBCHANNEL) {
 
  74 static int pure_hex(char **cp, unsigned int *val, int min_digit,
 
  75                     int max_digit, int max_val)
 
  83         while (isxdigit(**cp) && (diff <= max_digit)) {
 
  88                         value = tolower(**cp) - 'a' + 10;
 
  89                 *val = *val * 16 + value;
 
  94         if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
 
 100 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
 
 101                        unsigned int *devno, int msgtrigger)
 
 113         val = simple_strtoul(str, &str_work, 16);
 
 115         if (*str_work == '\0') {
 
 116                 if (val <= __MAX_SUBCHANNEL) {
 
 127         ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
 
 128         if (ret || (str_work[0] != '.'))
 
 131         ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
 
 132         if (ret || (str_work[0] != '.'))
 
 135         ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
 
 136         if (ret || (str_work[0] != '\0'))
 
 141         if (rc && msgtrigger)
 
 142                 printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
 
 148 static int blacklist_parse_parameters(char *str, range_action action,
 
 151         unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
 
 158         while ((parm = strsep(&str, ","))) {
 
 168                 if (strcmp(parm, "all") == 0) {
 
 172                         to_cssid = __MAX_CSSID;
 
 173                         to_ssid = __MAX_SSID;
 
 174                         to = __MAX_SUBCHANNEL;
 
 176                         rc = parse_busid(strsep(&parm, "-"), &from_cssid,
 
 177                                          &from_ssid, &from, msgtrigger);
 
 180                                         rc = parse_busid(parm, &to_cssid,
 
 184                                         to_cssid = from_cssid;
 
 191                         rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
 
 203 blacklist_setup (char *str)
 
 205         CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
 
 206         if (blacklist_parse_parameters(str, add, 1))
 
 211 __setup ("cio_ignore=", blacklist_setup);
 
 213 /* Checking if devices are blacklisted */
 
 216  * Function: is_blacklisted
 
 217  * Returns 1 if the given devicenumber can be found in the blacklist,
 
 219  * Used by validate_subchannel()
 
 222 is_blacklisted (int ssid, int devno)
 
 224         return test_bit (devno, bl_dev[ssid]);
 
 227 #ifdef CONFIG_PROC_FS
 
 229  * Function: blacklist_parse_proc_parameters
 
 230  * parse the stuff which is piped to /proc/cio_ignore
 
 232 static int blacklist_parse_proc_parameters(char *buf)
 
 237         parm = strsep(&buf, " ");
 
 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);
 
 246         css_schedule_reprobe();
 
 251 /* Iterator struct for all devices. */
 
 259 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
 
 261         struct ccwdev_iter *iter;
 
 263         if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
 
 265         iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
 
 267                 return ERR_PTR(-ENOMEM);
 
 268         iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
 
 269         iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
 
 274 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
 
 281 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
 
 283         struct ccwdev_iter *iter;
 
 285         if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
 
 288         if (iter->devno == __MAX_SUBCHANNEL) {
 
 291                 if (iter->ssid > __MAX_SSID)
 
 300 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
 
 302         struct ccwdev_iter *iter;
 
 305         if (!is_blacklisted(iter->ssid, iter->devno))
 
 306                 /* Not blacklisted, nothing to output. */
 
 308         if (!iter->in_range) {
 
 309                 /* First device in range. */
 
 310                 if ((iter->devno == __MAX_SUBCHANNEL) ||
 
 311                     !is_blacklisted(iter->ssid, iter->devno + 1))
 
 312                         /* Singular device. */
 
 313                         return seq_printf(s, "0.%x.%04x\n",
 
 314                                           iter->ssid, iter->devno);
 
 316                 return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
 
 318         if ((iter->devno == __MAX_SUBCHANNEL) ||
 
 319             !is_blacklisted(iter->ssid, iter->devno + 1)) {
 
 320                 /* Last device in range. */
 
 322                 return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
 
 328 cio_ignore_write(struct file *file, const char __user *user_buf,
 
 329                  size_t user_len, loff_t *offset)
 
 337         if (user_len > 65536)
 
 339         buf = vmalloc (user_len + 1); /* maybe better use the stack? */
 
 342         memset(buf, 0, user_len + 1);
 
 344         if (strncpy_from_user (buf, user_buf, user_len) < 0) {
 
 350         while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
 
 354         ret = blacklist_parse_proc_parameters(buf);
 
 365 static const struct seq_operations cio_ignore_proc_seq_ops = {
 
 366         .start = cio_ignore_proc_seq_start,
 
 367         .stop  = cio_ignore_proc_seq_stop,
 
 368         .next  = cio_ignore_proc_seq_next,
 
 369         .show  = cio_ignore_proc_seq_show,
 
 373 cio_ignore_proc_open(struct inode *inode, struct file *file)
 
 375         return seq_open(file, &cio_ignore_proc_seq_ops);
 
 378 static const struct file_operations cio_ignore_proc_fops = {
 
 379         .open    = cio_ignore_proc_open,
 
 382         .release = seq_release,
 
 383         .write   = cio_ignore_write,
 
 387 cio_ignore_proc_init (void)
 
 389         struct proc_dir_entry *entry;
 
 391         entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
 
 392                             &cio_ignore_proc_fops);
 
 398 __initcall (cio_ignore_proc_init);
 
 400 #endif /* CONFIG_PROC_FS */