Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *   S/390 common I/O routines -- blacklisting of specific devices
0004  *
0005  *    Copyright IBM Corp. 1999, 2013
0006  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
0007  *       Cornelia Huck (cornelia.huck@de.ibm.com)
0008  *       Arnd Bergmann (arndb@de.ibm.com)
0009  */
0010 
0011 #define KMSG_COMPONENT "cio"
0012 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0013 
0014 #include <linux/init.h>
0015 #include <linux/vmalloc.h>
0016 #include <linux/proc_fs.h>
0017 #include <linux/seq_file.h>
0018 #include <linux/ctype.h>
0019 #include <linux/device.h>
0020 
0021 #include <linux/uaccess.h>
0022 #include <asm/cio.h>
0023 #include <asm/ipl.h>
0024 
0025 #include "blacklist.h"
0026 #include "cio.h"
0027 #include "cio_debug.h"
0028 #include "css.h"
0029 #include "device.h"
0030 
0031 /*
0032  * "Blacklisting" of certain devices:
0033  * Device numbers given in the commandline as cio_ignore=... won't be known
0034  * to Linux.
0035  *
0036  * These can be single devices or ranges of devices
0037  */
0038 
0039 /* 65536 bits for each set to indicate if a devno is blacklisted or not */
0040 #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
0041              (8*sizeof(long)))
0042 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
0043 typedef enum {add, free} range_action;
0044 
0045 /*
0046  * Function: blacklist_range
0047  * (Un-)blacklist the devices from-to
0048  */
0049 static int blacklist_range(range_action action, unsigned int from_ssid,
0050                unsigned int to_ssid, unsigned int from,
0051                unsigned int to, int msgtrigger)
0052 {
0053     if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
0054         if (msgtrigger)
0055             pr_warn("0.%x.%04x to 0.%x.%04x is not a valid range for cio_ignore\n",
0056                 from_ssid, from, to_ssid, to);
0057 
0058         return 1;
0059     }
0060 
0061     while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
0062            (from <= to))) {
0063         if (action == add)
0064             set_bit(from, bl_dev[from_ssid]);
0065         else
0066             clear_bit(from, bl_dev[from_ssid]);
0067         from++;
0068         if (from > __MAX_SUBCHANNEL) {
0069             from_ssid++;
0070             from = 0;
0071         }
0072     }
0073 
0074     return 0;
0075 }
0076 
0077 static int pure_hex(char **cp, unsigned int *val, int min_digit,
0078             int max_digit, int max_val)
0079 {
0080     int diff;
0081 
0082     diff = 0;
0083     *val = 0;
0084 
0085     while (diff <= max_digit) {
0086         int value = hex_to_bin(**cp);
0087 
0088         if (value < 0)
0089             break;
0090         *val = *val * 16 + value;
0091         (*cp)++;
0092         diff++;
0093     }
0094 
0095     if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
0096         return 1;
0097 
0098     return 0;
0099 }
0100 
0101 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
0102                unsigned int *devno, int msgtrigger)
0103 {
0104     char *str_work;
0105     int val, rc, ret;
0106 
0107     rc = 1;
0108 
0109     if (*str == '\0')
0110         goto out;
0111 
0112     /* old style */
0113     str_work = str;
0114     val = simple_strtoul(str, &str_work, 16);
0115 
0116     if (*str_work == '\0') {
0117         if (val <= __MAX_SUBCHANNEL) {
0118             *devno = val;
0119             *ssid = 0;
0120             *cssid = 0;
0121             rc = 0;
0122         }
0123         goto out;
0124     }
0125 
0126     /* new style */
0127     str_work = str;
0128     ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
0129     if (ret || (str_work[0] != '.'))
0130         goto out;
0131     str_work++;
0132     ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
0133     if (ret || (str_work[0] != '.'))
0134         goto out;
0135     str_work++;
0136     ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
0137     if (ret || (str_work[0] != '\0'))
0138         goto out;
0139 
0140     rc = 0;
0141 out:
0142     if (rc && msgtrigger)
0143         pr_warn("%s is not a valid device for the cio_ignore kernel parameter\n",
0144             str);
0145 
0146     return rc;
0147 }
0148 
0149 static int blacklist_parse_parameters(char *str, range_action action,
0150                       int msgtrigger)
0151 {
0152     unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
0153     int rc, totalrc;
0154     char *parm;
0155     range_action ra;
0156 
0157     totalrc = 0;
0158 
0159     while ((parm = strsep(&str, ","))) {
0160         rc = 0;
0161         ra = action;
0162         if (*parm == '!') {
0163             if (ra == add)
0164                 ra = free;
0165             else
0166                 ra = add;
0167             parm++;
0168         }
0169         if (strcmp(parm, "all") == 0) {
0170             from_cssid = 0;
0171             from_ssid = 0;
0172             from = 0;
0173             to_cssid = __MAX_CSSID;
0174             to_ssid = __MAX_SSID;
0175             to = __MAX_SUBCHANNEL;
0176         } else if (strcmp(parm, "ipldev") == 0) {
0177             if (ipl_info.type == IPL_TYPE_CCW) {
0178                 from_cssid = 0;
0179                 from_ssid = ipl_info.data.ccw.dev_id.ssid;
0180                 from = ipl_info.data.ccw.dev_id.devno;
0181             } else if (ipl_info.type == IPL_TYPE_FCP ||
0182                    ipl_info.type == IPL_TYPE_FCP_DUMP) {
0183                 from_cssid = 0;
0184                 from_ssid = ipl_info.data.fcp.dev_id.ssid;
0185                 from = ipl_info.data.fcp.dev_id.devno;
0186             } else {
0187                 continue;
0188             }
0189             to_cssid = from_cssid;
0190             to_ssid = from_ssid;
0191             to = from;
0192         } else if (strcmp(parm, "condev") == 0) {
0193             if (console_devno == -1)
0194                 continue;
0195 
0196             from_cssid = to_cssid = 0;
0197             from_ssid = to_ssid = 0;
0198             from = to = console_devno;
0199         } else {
0200             rc = parse_busid(strsep(&parm, "-"), &from_cssid,
0201                      &from_ssid, &from, msgtrigger);
0202             if (!rc) {
0203                 if (parm != NULL)
0204                     rc = parse_busid(parm, &to_cssid,
0205                              &to_ssid, &to,
0206                              msgtrigger);
0207                 else {
0208                     to_cssid = from_cssid;
0209                     to_ssid = from_ssid;
0210                     to = from;
0211                 }
0212             }
0213         }
0214         if (!rc) {
0215             rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
0216                          msgtrigger);
0217             if (rc)
0218                 totalrc = -EINVAL;
0219         } else
0220             totalrc = -EINVAL;
0221     }
0222 
0223     return totalrc;
0224 }
0225 
0226 static int __init
0227 blacklist_setup (char *str)
0228 {
0229     CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
0230     if (blacklist_parse_parameters(str, add, 1))
0231         return 0;
0232     return 1;
0233 }
0234 
0235 __setup ("cio_ignore=", blacklist_setup);
0236 
0237 /* Checking if devices are blacklisted */
0238 
0239 /*
0240  * Function: is_blacklisted
0241  * Returns 1 if the given devicenumber can be found in the blacklist,
0242  * otherwise 0.
0243  * Used by validate_subchannel()
0244  */
0245 int
0246 is_blacklisted (int ssid, int devno)
0247 {
0248     return test_bit (devno, bl_dev[ssid]);
0249 }
0250 
0251 #ifdef CONFIG_PROC_FS
0252 /*
0253  * Function: blacklist_parse_proc_parameters
0254  * parse the stuff which is piped to /proc/cio_ignore
0255  */
0256 static int blacklist_parse_proc_parameters(char *buf)
0257 {
0258     int rc;
0259     char *parm;
0260 
0261     parm = strsep(&buf, " ");
0262 
0263     if (strcmp("free", parm) == 0) {
0264         rc = blacklist_parse_parameters(buf, free, 0);
0265         /*
0266          * Evaluate the subchannels without an online device. This way,
0267          * no path-verification will be triggered on those subchannels
0268          * and it avoids unnecessary delays.
0269          */
0270         css_schedule_eval_cond(CSS_EVAL_NOT_ONLINE, 0);
0271     } else if (strcmp("add", parm) == 0)
0272         rc = blacklist_parse_parameters(buf, add, 0);
0273     else if (strcmp("purge", parm) == 0)
0274         return ccw_purge_blacklisted();
0275     else
0276         return -EINVAL;
0277 
0278 
0279     return rc;
0280 }
0281 
0282 /* Iterator struct for all devices. */
0283 struct ccwdev_iter {
0284     int devno;
0285     int ssid;
0286     int in_range;
0287 };
0288 
0289 static void *
0290 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
0291 {
0292     struct ccwdev_iter *iter = s->private;
0293 
0294     if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
0295         return NULL;
0296     memset(iter, 0, sizeof(*iter));
0297     iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
0298     iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
0299     return iter;
0300 }
0301 
0302 static void
0303 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
0304 {
0305 }
0306 
0307 static void *
0308 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
0309 {
0310     struct ccwdev_iter *iter;
0311     loff_t p = *offset;
0312 
0313     (*offset)++;
0314     if (p >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
0315         return NULL;
0316     iter = it;
0317     if (iter->devno == __MAX_SUBCHANNEL) {
0318         iter->devno = 0;
0319         iter->ssid++;
0320         if (iter->ssid > __MAX_SSID)
0321             return NULL;
0322     } else
0323         iter->devno++;
0324     return iter;
0325 }
0326 
0327 static int
0328 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
0329 {
0330     struct ccwdev_iter *iter;
0331 
0332     iter = it;
0333     if (!is_blacklisted(iter->ssid, iter->devno))
0334         /* Not blacklisted, nothing to output. */
0335         return 0;
0336     if (!iter->in_range) {
0337         /* First device in range. */
0338         if ((iter->devno == __MAX_SUBCHANNEL) ||
0339             !is_blacklisted(iter->ssid, iter->devno + 1)) {
0340             /* Singular device. */
0341             seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
0342             return 0;
0343         }
0344         iter->in_range = 1;
0345         seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
0346         return 0;
0347     }
0348     if ((iter->devno == __MAX_SUBCHANNEL) ||
0349         !is_blacklisted(iter->ssid, iter->devno + 1)) {
0350         /* Last device in range. */
0351         iter->in_range = 0;
0352         seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
0353     }
0354     return 0;
0355 }
0356 
0357 static ssize_t
0358 cio_ignore_write(struct file *file, const char __user *user_buf,
0359          size_t user_len, loff_t *offset)
0360 {
0361     char *buf;
0362     ssize_t rc, ret, i;
0363 
0364     if (*offset)
0365         return -EINVAL;
0366     if (user_len > 65536)
0367         user_len = 65536;
0368     buf = vzalloc(user_len + 1); /* maybe better use the stack? */
0369     if (buf == NULL)
0370         return -ENOMEM;
0371 
0372     if (strncpy_from_user (buf, user_buf, user_len) < 0) {
0373         rc = -EFAULT;
0374         goto out_free;
0375     }
0376 
0377     i = user_len - 1;
0378     while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
0379         buf[i] = '\0';
0380         i--;
0381     }
0382     ret = blacklist_parse_proc_parameters(buf);
0383     if (ret)
0384         rc = ret;
0385     else
0386         rc = user_len;
0387 
0388 out_free:
0389     vfree (buf);
0390     return rc;
0391 }
0392 
0393 static const struct seq_operations cio_ignore_proc_seq_ops = {
0394     .start = cio_ignore_proc_seq_start,
0395     .stop  = cio_ignore_proc_seq_stop,
0396     .next  = cio_ignore_proc_seq_next,
0397     .show  = cio_ignore_proc_seq_show,
0398 };
0399 
0400 static int
0401 cio_ignore_proc_open(struct inode *inode, struct file *file)
0402 {
0403     return seq_open_private(file, &cio_ignore_proc_seq_ops,
0404                 sizeof(struct ccwdev_iter));
0405 }
0406 
0407 static const struct proc_ops cio_ignore_proc_ops = {
0408     .proc_open  = cio_ignore_proc_open,
0409     .proc_read  = seq_read,
0410     .proc_lseek = seq_lseek,
0411     .proc_release   = seq_release_private,
0412     .proc_write = cio_ignore_write,
0413 };
0414 
0415 static int
0416 cio_ignore_proc_init (void)
0417 {
0418     struct proc_dir_entry *entry;
0419 
0420     entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
0421                 &cio_ignore_proc_ops);
0422     if (!entry)
0423         return -ENOENT;
0424     return 0;
0425 }
0426 
0427 __initcall (cio_ignore_proc_init);
0428 
0429 #endif /* CONFIG_PROC_FS */