mirror of
https://github.com/adulau/aha.git
synced 2025-01-04 23:23:18 +00:00
[S390] cio: Fix parsing mechanism for blacklisted devices.
New format cssid.ssid.devno is now parsed correctly. Signed-off-by: Michael Ernst <mernst@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
139b83dd57
commit
5b8909871b
1 changed files with 177 additions and 161 deletions
|
@ -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;
|
||||||
* 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function: blacklist_busid
|
|
||||||
* 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;
|
|
||||||
char *sav;
|
|
||||||
|
|
||||||
sav = *str;
|
|
||||||
|
|
||||||
/* check for leading '0x' */
|
|
||||||
old_style = 0;
|
|
||||||
if ((*str)[0] == '0' && (*str)[1] == 'x') {
|
|
||||||
*str += 2;
|
|
||||||
old_style = 1;
|
|
||||||
}
|
|
||||||
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
|
|
||||||
goto confused;
|
|
||||||
val = simple_strtoul(*str, str, 16);
|
|
||||||
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)
|
|
||||||
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;
|
return 0;
|
||||||
confused:
|
|
||||||
strsep(str, ",\n");
|
|
||||||
printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int pure_hex(char **cp, unsigned int *val, int min_digit,
|
||||||
blacklist_parse_parameters (char *str, range_action action)
|
int max_digit, int max_val)
|
||||||
{
|
{
|
||||||
int from, to, from_id0, to_id0, from_ssid, to_ssid;
|
int diff;
|
||||||
|
unsigned int value;
|
||||||
|
|
||||||
while (*str != 0 && *str != '\n') {
|
diff = 0;
|
||||||
range_action ra = action;
|
*val = 0;
|
||||||
while(*str == ',')
|
|
||||||
str++;
|
|
||||||
if (*str == '!') {
|
|
||||||
ra = !action;
|
|
||||||
++str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
while (isxdigit(**cp) && (diff <= max_digit)) {
|
||||||
* Since we have to parse the proc commands and the
|
|
||||||
* kernel arguments we have to check four cases
|
|
||||||
*/
|
|
||||||
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
|
|
||||||
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
str += 3;
|
if (isdigit(**cp))
|
||||||
for (j=0; j <= __MAX_SSID; j++)
|
value = **cp - '0';
|
||||||
blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
|
else
|
||||||
} else {
|
value = tolower(**cp) - 'a' + 10;
|
||||||
int rc;
|
*val = *val * 16 + value;
|
||||||
|
(*cp)++;
|
||||||
rc = blacklist_busid(&str, &from_id0,
|
diff++;
|
||||||
&from_ssid, &from);
|
|
||||||
if (rc)
|
|
||||||
continue;
|
|
||||||
to = from;
|
|
||||||
to_id0 = from_id0;
|
|
||||||
to_ssid = from_ssid;
|
|
||||||
if (*str == '-') {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
|
if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
|
||||||
|
int msgtrigger)
|
||||||
|
{
|
||||||
|
char *str_work;
|
||||||
|
int val, rc, ret;
|
||||||
|
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
|
if (*str == '\0')
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
str_work = str;
|
||||||
|
ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
|
||||||
|
if (ret || (str_work[0] != '.'))
|
||||||
|
goto out;
|
||||||
|
str_work++;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int blacklist_parse_parameters(char *str, range_action action,
|
||||||
|
int msgtrigger)
|
||||||
|
{
|
||||||
|
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 {
|
||||||
|
rc = parse_busid(strsep(&parm, "-"), &from_cssid,
|
||||||
|
&from_ssid, &from, msgtrigger);
|
||||||
|
if (!rc) {
|
||||||
|
if (parm != NULL)
|
||||||
|
rc = parse_busid(parm, &to_cssid,
|
||||||
|
&to_ssid, &to,
|
||||||
|
msgtrigger);
|
||||||
|
else {
|
||||||
|
to_cssid = from_cssid;
|
||||||
|
to_ssid = from_ssid;
|
||||||
|
to = from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rc) {
|
||||||
|
rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
|
||||||
|
msgtrigger);
|
||||||
|
if (rc)
|
||||||
|
totalrc = 1;
|
||||||
|
} else
|
||||||
|
totalrc = 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)
|
||||||
* 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,
|
||||||
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,
|
||||||
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 = {
|
||||||
|
|
Loading…
Reference in a new issue