Commit 5b890987 authored by Michael Ernst's avatar Michael Ernst Committed by Martin Schwidefsky

[S390] cio: Fix parsing mechanism for blacklisted devices.

New format cssid.ssid.devno is now parsed correctly.
Signed-off-by: default avatarMichael Ernst <mernst@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 139b83dd
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/cio.h> #include <asm/cio.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/cio.h>
#include "blacklist.h" #include "blacklist.h"
#include "cio.h" #include "cio.h"
...@@ -43,163 +44,169 @@ typedef enum {add, free} range_action; ...@@ -43,163 +44,169 @@ typedef enum {add, free} range_action;
* Function: blacklist_range * Function: blacklist_range
* (Un-)blacklist the devices from-to * (Un-)blacklist the devices from-to
*/ */
static void static int blacklist_range(range_action action, unsigned int from_ssid,
blacklist_range (range_action action, unsigned int from, unsigned int to, unsigned int to_ssid, unsigned int from,
unsigned int ssid) unsigned int to, int msgtrigger)
{ {
if (!to) if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
to = from; if (msgtrigger)
printk(KERN_WARNING "cio: Invalid cio_ignore range "
if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) { "0.%x.%04x-0.%x.%04x\n", from_ssid, from,
printk (KERN_WARNING "cio: Invalid blacklist range " to_ssid, to);
"0.%x.%04x to 0.%x.%04x, skipping\n", return 1;
ssid, from, ssid, to);
return;
} }
for (; from <= to; from++) {
while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
(from <= to))) {
if (action == add) if (action == add)
set_bit (from, bl_dev[ssid]); set_bit(from, bl_dev[from_ssid]);
else else
clear_bit (from, bl_dev[ssid]); clear_bit(from, bl_dev[from_ssid]);
from++;
if (from > __MAX_SUBCHANNEL) {
from_ssid++;
from = 0;
} }
}
return 0;
} }
/* static int pure_hex(char **cp, unsigned int *val, int min_digit,
* Function: blacklist_busid int max_digit, int max_val)
* Get devno/busid from given string.
* Shamelessly grabbed from dasd_devmap.c.
*/
static int
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
{ {
int val, old_style; int diff;
char *sav; unsigned int value;
sav = *str; diff = 0;
*val = 0;
/* check for leading '0x' */ while (isxdigit(**cp) && (diff <= max_digit)) {
old_style = 0;
if ((*str)[0] == '0' && (*str)[1] == 'x') { if (isdigit(**cp))
*str += 2; value = **cp - '0';
old_style = 1; else
} value = tolower(**cp) - 'a' + 10;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */ *val = *val * 16 + value;
goto confused; (*cp)++;
val = simple_strtoul(*str, str, 16); diff++;
if (old_style || (*str)[0] != '.') {
*id0 = *ssid = 0;
if (val < 0 || val > 0xffff)
goto confused;
*devno = val;
if ((*str)[0] != ',' && (*str)[0] != '-' &&
(*str)[0] != '\n' && (*str)[0] != '\0')
goto confused;
return 0;
} }
/* New style x.y.z busid */
if (val < 0 || val > 0xff) if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
goto confused;
*id0 = val;
(*str)++;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
goto confused;
val = simple_strtoul(*str, str, 16);
if (val < 0 || val > 0xff || (*str)++[0] != '.')
goto confused;
*ssid = val;
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
goto confused;
val = simple_strtoul(*str, str, 16);
if (val < 0 || val > 0xffff)
goto confused;
*devno = val;
if ((*str)[0] != ',' && (*str)[0] != '-' &&
(*str)[0] != '\n' && (*str)[0] != '\0')
goto confused;
return 0;
confused:
strsep(str, ",\n");
printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
return 1; return 1;
return 0;
} }
static int static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
blacklist_parse_parameters (char *str, range_action action) int msgtrigger)
{ {
int from, to, from_id0, to_id0, from_ssid, to_ssid; char *str_work;
int val, rc, ret;
while (*str != 0 && *str != '\n') {
range_action ra = action; rc = 1;
while(*str == ',')
str++; if (*str == '\0')
if (*str == '!') { goto out;
ra = !action;
++str; /* old style */
str_work = str;
val = simple_strtoul(str, &str_work, 16);
if (*str_work == '\0') {
if (val <= __MAX_SUBCHANNEL) {
*devno = val;
*ssid = 0;
*cssid = 0;
rc = 0;
}
goto out;
} }
/* /* new style */
* Since we have to parse the proc commands and the str_work = str;
* kernel arguments we have to check four cases ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
*/ if (ret || (str_work[0] != '.'))
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 || goto out;
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) { str_work++;
int j; ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
if (ret || (str_work[0] != '.'))
goto out;
str_work++;
ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
if (ret || (str_work[0] != '\0'))
goto out;
rc = 0;
out:
if (rc && msgtrigger)
printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
str);
return rc;
}
str += 3; static int blacklist_parse_parameters(char *str, range_action action,
for (j=0; j <= __MAX_SSID; j++) int msgtrigger)
blacklist_range(ra, 0, __MAX_SUBCHANNEL, j); {
int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
int rc, totalrc;
char *parm;
range_action ra;
totalrc = 0;
while ((parm = strsep(&str, ","))) {
rc = 0;
ra = action;
if (*parm == '!') {
if (ra == add)
ra = free;
else
ra = add;
parm++;
}
if (strcmp(parm, "all") == 0) {
from_cssid = 0;
from_ssid = 0;
from = 0;
to_cssid = __MAX_CSSID;
to_ssid = __MAX_SSID;
to = __MAX_SUBCHANNEL;
} else { } else {
int rc; rc = parse_busid(strsep(&parm, "-"), &from_cssid,
&from_ssid, &from, msgtrigger);
rc = blacklist_busid(&str, &from_id0, if (!rc) {
&from_ssid, &from); if (parm != NULL)
if (rc) rc = parse_busid(parm, &to_cssid,
continue; &to_ssid, &to,
to = from; msgtrigger);
to_id0 = from_id0; else {
to_cssid = from_cssid;
to_ssid = from_ssid; to_ssid = from_ssid;
if (*str == '-') { to = from;
str++;
rc = blacklist_busid(&str, &to_id0,
&to_ssid, &to);
if (rc)
continue;
}
if (*str == '-') {
printk(KERN_WARNING "cio: invalid cio_ignore "
"parameter '%s'\n",
strsep(&str, ",\n"));
continue;
} }
if ((from_id0 != to_id0) ||
(from_ssid != to_ssid)) {
printk(KERN_WARNING "cio: invalid cio_ignore "
"range %x.%x.%04x-%x.%x.%04x\n",
from_id0, from_ssid, from,
to_id0, to_ssid, to);
continue;
} }
blacklist_range (ra, from, to, to_ssid);
} }
if (!rc) {
rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
msgtrigger);
if (rc)
totalrc = 1;
} else
totalrc = 1;
} }
return 1;
return totalrc;
} }
/* Parsing the commandline for blacklist parameters, e.g. to blacklist
* bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
* - cio_ignore=1234-1236
* - cio_ignore=0x1234-0x1235,1236
* - cio_ignore=0x1234,1235-1236
* - cio_ignore=1236 cio_ignore=1234-0x1236
* - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
* - cio_ignore=0.0.1234-0.0.1236
* - cio_ignore=0.0.1234,0x1235,1236
* - ...
*/
static int __init static int __init
blacklist_setup (char *str) blacklist_setup (char *str)
{ {
return blacklist_parse_parameters (str, add); CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
if (blacklist_parse_parameters(str, add, 1))
return 0;
return 1;
} }
__setup ("cio_ignore=", blacklist_setup); __setup ("cio_ignore=", blacklist_setup);
...@@ -223,27 +230,23 @@ is_blacklisted (int ssid, int devno) ...@@ -223,27 +230,23 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters * Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore * parse the stuff which is piped to /proc/cio_ignore
*/ */
static void static int blacklist_parse_proc_parameters(char *buf)
blacklist_parse_proc_parameters (char *buf)
{ {
if (strncmp (buf, "free ", 5) == 0) { int rc;
blacklist_parse_parameters (buf + 5, free); char *parm;
} else if (strncmp (buf, "add ", 4) == 0) {
/* parm = strsep(&buf, " ");
* We don't need to check for known devices since
* css_probe_device will handle this correctly. if (strcmp("free", parm) == 0)
*/ rc = blacklist_parse_parameters(buf, free, 0);
blacklist_parse_parameters (buf + 4, add); else if (strcmp("add", parm) == 0)
} else { rc = blacklist_parse_parameters(buf, add, 0);
printk (KERN_WARNING "cio: cio_ignore: Parse error; \n" else
KERN_WARNING "try using 'free all|<devno-range>," return 1;
"<devno-range>,...'\n"
KERN_WARNING "or 'add <devno-range>,"
"<devno-range>,...'\n");
return;
}
css_schedule_reprobe(); css_schedule_reprobe();
return rc;
} }
/* Iterator struct for all devices. */ /* Iterator struct for all devices. */
...@@ -327,6 +330,8 @@ cio_ignore_write(struct file *file, const char __user *user_buf, ...@@ -327,6 +330,8 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
size_t user_len, loff_t *offset) size_t user_len, loff_t *offset)
{ {
char *buf; char *buf;
size_t i;
ssize_t rc, ret;
if (*offset) if (*offset)
return -EINVAL; return -EINVAL;
...@@ -335,16 +340,27 @@ cio_ignore_write(struct file *file, const char __user *user_buf, ...@@ -335,16 +340,27 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
buf = vmalloc (user_len + 1); /* maybe better use the stack? */ buf = vmalloc (user_len + 1); /* maybe better use the stack? */
if (buf == NULL) if (buf == NULL)
return -ENOMEM; return -ENOMEM;
memset(buf, 0, user_len + 1);
if (strncpy_from_user (buf, user_buf, user_len) < 0) { if (strncpy_from_user (buf, user_buf, user_len) < 0) {
vfree (buf); rc = -EFAULT;
return -EFAULT; goto out_free;
} }
buf[user_len] = '\0';
blacklist_parse_proc_parameters (buf); i = user_len - 1;
while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
buf[i] = '\0';
i--;
}
ret = blacklist_parse_proc_parameters(buf);
if (ret)
rc = -EINVAL;
else
rc = user_len;
out_free:
vfree (buf); vfree (buf);
return user_len; return rc;
} }
static const struct seq_operations cio_ignore_proc_seq_ops = { static const struct seq_operations cio_ignore_proc_seq_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment