[PATCH] s390: multiple subchannel sets support
Add support for multiple subchannel sets. Works with arbitrary devices in subchannel set 1 and is transparent to device drivers. Although currently only two subchannel sets are available, this will work with the architectured maximum number of subchannel sets as well. Signed-off-by: Cornelia Huck <cohuck@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:

committed by
Linus Torvalds

parent
678a395b35
commit
fb6958a594
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* drivers/s390/cio/blacklist.c
|
||||
* S/390 common I/O routines -- blacklisting of specific devices
|
||||
* $Revision: 1.35 $
|
||||
* $Revision: 1.39 $
|
||||
*
|
||||
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
|
||||
* IBM Corporation
|
||||
@@ -35,10 +35,10 @@
|
||||
* These can be single devices or ranges of devices
|
||||
*/
|
||||
|
||||
/* 65536 bits to indicate if a devno is blacklisted or not */
|
||||
/* 65536 bits for each set to indicate if a devno is blacklisted or not */
|
||||
#define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
|
||||
(8*sizeof(long)))
|
||||
static unsigned long bl_dev[__BL_DEV_WORDS];
|
||||
static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
|
||||
typedef enum {add, free} range_action;
|
||||
|
||||
/*
|
||||
@@ -46,21 +46,23 @@ typedef enum {add, free} range_action;
|
||||
* (Un-)blacklist the devices from-to
|
||||
*/
|
||||
static inline void
|
||||
blacklist_range (range_action action, unsigned int from, unsigned int to)
|
||||
blacklist_range (range_action action, unsigned int from, unsigned int to,
|
||||
unsigned int ssid)
|
||||
{
|
||||
if (!to)
|
||||
to = from;
|
||||
|
||||
if (from > to || to > __MAX_SUBCHANNEL) {
|
||||
if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
|
||||
printk (KERN_WARNING "Invalid blacklist range "
|
||||
"0x%04x to 0x%04x, skipping\n", from, to);
|
||||
"0.%x.%04x to 0.%x.%04x, skipping\n",
|
||||
ssid, from, ssid, to);
|
||||
return;
|
||||
}
|
||||
for (; from <= to; from++) {
|
||||
if (action == add)
|
||||
set_bit (from, bl_dev);
|
||||
set_bit (from, bl_dev[ssid]);
|
||||
else
|
||||
clear_bit (from, bl_dev);
|
||||
clear_bit (from, bl_dev[ssid]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +72,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to)
|
||||
* Shamelessly grabbed from dasd_devmap.c.
|
||||
*/
|
||||
static inline int
|
||||
blacklist_busid(char **str, int *id0, int *id1, int *devno)
|
||||
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
|
||||
{
|
||||
int val, old_style;
|
||||
char *sav;
|
||||
@@ -87,7 +89,7 @@ blacklist_busid(char **str, int *id0, int *id1, int *devno)
|
||||
goto confused;
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
if (old_style || (*str)[0] != '.') {
|
||||
*id0 = *id1 = 0;
|
||||
*id0 = *ssid = 0;
|
||||
if (val < 0 || val > 0xffff)
|
||||
goto confused;
|
||||
*devno = val;
|
||||
@@ -106,7 +108,7 @@ blacklist_busid(char **str, int *id0, int *id1, int *devno)
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
if (val < 0 || val > 0xff || (*str)++[0] != '.')
|
||||
goto confused;
|
||||
*id1 = val;
|
||||
*ssid = val;
|
||||
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
|
||||
goto confused;
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
@@ -126,7 +128,7 @@ confused:
|
||||
static inline int
|
||||
blacklist_parse_parameters (char *str, range_action action)
|
||||
{
|
||||
unsigned int from, to, from_id0, to_id0, from_id1, to_id1;
|
||||
unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
|
||||
|
||||
while (*str != 0 && *str != '\n') {
|
||||
range_action ra = action;
|
||||
@@ -143,23 +145,25 @@ blacklist_parse_parameters (char *str, range_action action)
|
||||
*/
|
||||
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
|
||||
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
|
||||
from = 0;
|
||||
to = __MAX_SUBCHANNEL;
|
||||
int j;
|
||||
|
||||
str += 3;
|
||||
for (j=0; j <= __MAX_SSID; j++)
|
||||
blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
|
||||
} else {
|
||||
int rc;
|
||||
|
||||
rc = blacklist_busid(&str, &from_id0,
|
||||
&from_id1, &from);
|
||||
&from_ssid, &from);
|
||||
if (rc)
|
||||
continue;
|
||||
to = from;
|
||||
to_id0 = from_id0;
|
||||
to_id1 = from_id1;
|
||||
to_ssid = from_ssid;
|
||||
if (*str == '-') {
|
||||
str++;
|
||||
rc = blacklist_busid(&str, &to_id0,
|
||||
&to_id1, &to);
|
||||
&to_ssid, &to);
|
||||
if (rc)
|
||||
continue;
|
||||
}
|
||||
@@ -169,18 +173,19 @@ blacklist_parse_parameters (char *str, range_action action)
|
||||
strsep(&str, ",\n"));
|
||||
continue;
|
||||
}
|
||||
if ((from_id0 != to_id0) || (from_id1 != to_id1)) {
|
||||
if ((from_id0 != to_id0) ||
|
||||
(from_ssid != to_ssid)) {
|
||||
printk(KERN_WARNING "invalid cio_ignore range "
|
||||
"%x.%x.%04x-%x.%x.%04x\n",
|
||||
from_id0, from_id1, from,
|
||||
to_id0, to_id1, to);
|
||||
from_id0, from_ssid, from,
|
||||
to_id0, to_ssid, to);
|
||||
continue;
|
||||
}
|
||||
pr_debug("blacklist_setup: adding range "
|
||||
"from %x.%x.%04x to %x.%x.%04x\n",
|
||||
from_id0, from_ssid, from, to_id0, to_ssid, to);
|
||||
blacklist_range (ra, from, to, to_ssid);
|
||||
}
|
||||
/* FIXME: ignoring id0 and id1 here. */
|
||||
pr_debug("blacklist_setup: adding range "
|
||||
"from 0.0.%04x to 0.0.%04x\n", from, to);
|
||||
blacklist_range (ra, from, to);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -214,9 +219,9 @@ __setup ("cio_ignore=", blacklist_setup);
|
||||
* Used by validate_subchannel()
|
||||
*/
|
||||
int
|
||||
is_blacklisted (int devno)
|
||||
is_blacklisted (int ssid, int devno)
|
||||
{
|
||||
return test_bit (devno, bl_dev);
|
||||
return test_bit (devno, bl_dev[ssid]);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
@@ -283,6 +288,7 @@ blacklist_parse_proc_parameters (char *buf)
|
||||
/* Iterator struct for all devices. */
|
||||
struct ccwdev_iter {
|
||||
int devno;
|
||||
int ssid;
|
||||
int in_range;
|
||||
};
|
||||
|
||||
@@ -291,13 +297,14 @@ cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
|
||||
{
|
||||
struct ccwdev_iter *iter;
|
||||
|
||||
if (*offset > __MAX_SUBCHANNEL)
|
||||
if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
|
||||
return NULL;
|
||||
iter = kmalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
|
||||
if (!iter)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
memset(iter, 0, sizeof(struct ccwdev_iter));
|
||||
iter->devno = *offset;
|
||||
iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
|
||||
iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
|
||||
return iter;
|
||||
}
|
||||
|
||||
@@ -313,10 +320,16 @@ cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
|
||||
{
|
||||
struct ccwdev_iter *iter;
|
||||
|
||||
if (*offset > __MAX_SUBCHANNEL)
|
||||
if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
|
||||
return NULL;
|
||||
iter = (struct ccwdev_iter *)it;
|
||||
iter->devno++;
|
||||
if (iter->devno == __MAX_SUBCHANNEL) {
|
||||
iter->devno = 0;
|
||||
iter->ssid++;
|
||||
if (iter->ssid > __MAX_SSID)
|
||||
return NULL;
|
||||
} else
|
||||
iter->devno++;
|
||||
(*offset)++;
|
||||
return iter;
|
||||
}
|
||||
@@ -327,23 +340,24 @@ cio_ignore_proc_seq_show(struct seq_file *s, void *it)
|
||||
struct ccwdev_iter *iter;
|
||||
|
||||
iter = (struct ccwdev_iter *)it;
|
||||
if (!is_blacklisted(iter->devno))
|
||||
if (!is_blacklisted(iter->ssid, iter->devno))
|
||||
/* Not blacklisted, nothing to output. */
|
||||
return 0;
|
||||
if (!iter->in_range) {
|
||||
/* First device in range. */
|
||||
if ((iter->devno == __MAX_SUBCHANNEL) ||
|
||||
!is_blacklisted(iter->devno + 1))
|
||||
!is_blacklisted(iter->ssid, iter->devno + 1))
|
||||
/* Singular device. */
|
||||
return seq_printf(s, "0.0.%04x\n", iter->devno);
|
||||
return seq_printf(s, "0.%x.%04x\n",
|
||||
iter->ssid, iter->devno);
|
||||
iter->in_range = 1;
|
||||
return seq_printf(s, "0.0.%04x-", iter->devno);
|
||||
return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
|
||||
}
|
||||
if ((iter->devno == __MAX_SUBCHANNEL) ||
|
||||
!is_blacklisted(iter->devno + 1)) {
|
||||
!is_blacklisted(iter->ssid, iter->devno + 1)) {
|
||||
/* Last device in range. */
|
||||
iter->in_range = 0;
|
||||
return seq_printf(s, "0.0.%04x\n", iter->devno);
|
||||
return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user