0001
0002
0003
0004
0005
0006
0007
0008
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
0033
0034
0035
0036
0037
0038
0039
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
0047
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
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
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
0238
0239
0240
0241
0242
0243
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
0254
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
0267
0268
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
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
0335 return 0;
0336 if (!iter->in_range) {
0337
0338 if ((iter->devno == __MAX_SUBCHANNEL) ||
0339 !is_blacklisted(iter->ssid, iter->devno + 1)) {
0340
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
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);
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