diff options
author | Cornelia Huck <cohuck@de.ibm.com> | 2006-01-06 00:19:25 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 08:33:52 -0800 |
commit | fb6958a594da49ece869793e6ec163b89fc5f79f (patch) | |
tree | 0746cc23ab13a059f9a34d7fc134aaf6410d07b8 /drivers/s390/cio/blacklist.c | |
parent | 678a395b356a98368a93c3640252502b70c3676f (diff) | |
download | op-kernel-dev-fb6958a594da49ece869793e6ec163b89fc5f79f.zip op-kernel-dev-fb6958a594da49ece869793e6ec163b89fc5f79f.tar.gz |
[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>
Diffstat (limited to 'drivers/s390/cio/blacklist.c')
-rw-r--r-- | drivers/s390/cio/blacklist.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index daea41c..2d444cb 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -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; } |