diff options
author | Cornelia Huck <cohuck@de.ibm.com> | 2006-01-06 03:19:25 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:52 -0500 |
commit | fb6958a594da49ece869793e6ec163b89fc5f79f (patch) | |
tree | 0746cc23ab13a059f9a34d7fc134aaf6410d07b8 /drivers/s390/cio/blacklist.c | |
parent | 678a395b356a98368a93c3640252502b70c3676f (diff) |
[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 daea41c63329..2d444cb2fdf7 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/blacklist.c | 2 | * drivers/s390/cio/blacklist.c |
3 | * S/390 common I/O routines -- blacklisting of specific devices | 3 | * S/390 common I/O routines -- blacklisting of specific devices |
4 | * $Revision: 1.35 $ | 4 | * $Revision: 1.39 $ |
5 | * | 5 | * |
6 | * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, | 6 | * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, |
7 | * IBM Corporation | 7 | * IBM Corporation |
@@ -35,10 +35,10 @@ | |||
35 | * These can be single devices or ranges of devices | 35 | * These can be single devices or ranges of devices |
36 | */ | 36 | */ |
37 | 37 | ||
38 | /* 65536 bits to indicate if a devno is blacklisted or not */ | 38 | /* 65536 bits for each set to indicate if a devno is blacklisted or not */ |
39 | #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ | 39 | #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \ |
40 | (8*sizeof(long))) | 40 | (8*sizeof(long))) |
41 | static unsigned long bl_dev[__BL_DEV_WORDS]; | 41 | static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS]; |
42 | typedef enum {add, free} range_action; | 42 | typedef enum {add, free} range_action; |
43 | 43 | ||
44 | /* | 44 | /* |
@@ -46,21 +46,23 @@ typedef enum {add, free} range_action; | |||
46 | * (Un-)blacklist the devices from-to | 46 | * (Un-)blacklist the devices from-to |
47 | */ | 47 | */ |
48 | static inline void | 48 | static inline void |
49 | blacklist_range (range_action action, unsigned int from, unsigned int to) | 49 | blacklist_range (range_action action, unsigned int from, unsigned int to, |
50 | unsigned int ssid) | ||
50 | { | 51 | { |
51 | if (!to) | 52 | if (!to) |
52 | to = from; | 53 | to = from; |
53 | 54 | ||
54 | if (from > to || to > __MAX_SUBCHANNEL) { | 55 | if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) { |
55 | printk (KERN_WARNING "Invalid blacklist range " | 56 | printk (KERN_WARNING "Invalid blacklist range " |
56 | "0x%04x to 0x%04x, skipping\n", from, to); | 57 | "0.%x.%04x to 0.%x.%04x, skipping\n", |
58 | ssid, from, ssid, to); | ||
57 | return; | 59 | return; |
58 | } | 60 | } |
59 | for (; from <= to; from++) { | 61 | for (; from <= to; from++) { |
60 | if (action == add) | 62 | if (action == add) |
61 | set_bit (from, bl_dev); | 63 | set_bit (from, bl_dev[ssid]); |
62 | else | 64 | else |
63 | clear_bit (from, bl_dev); | 65 | clear_bit (from, bl_dev[ssid]); |
64 | } | 66 | } |
65 | } | 67 | } |
66 | 68 | ||
@@ -70,7 +72,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to) | |||
70 | * Shamelessly grabbed from dasd_devmap.c. | 72 | * Shamelessly grabbed from dasd_devmap.c. |
71 | */ | 73 | */ |
72 | static inline int | 74 | static inline int |
73 | blacklist_busid(char **str, int *id0, int *id1, int *devno) | 75 | blacklist_busid(char **str, int *id0, int *ssid, int *devno) |
74 | { | 76 | { |
75 | int val, old_style; | 77 | int val, old_style; |
76 | char *sav; | 78 | char *sav; |
@@ -87,7 +89,7 @@ blacklist_busid(char **str, int *id0, int *id1, int *devno) | |||
87 | goto confused; | 89 | goto confused; |
88 | val = simple_strtoul(*str, str, 16); | 90 | val = simple_strtoul(*str, str, 16); |
89 | if (old_style || (*str)[0] != '.') { | 91 | if (old_style || (*str)[0] != '.') { |
90 | *id0 = *id1 = 0; | 92 | *id0 = *ssid = 0; |
91 | if (val < 0 || val > 0xffff) | 93 | if (val < 0 || val > 0xffff) |
92 | goto confused; | 94 | goto confused; |
93 | *devno = val; | 95 | *devno = val; |
@@ -106,7 +108,7 @@ blacklist_busid(char **str, int *id0, int *id1, int *devno) | |||
106 | val = simple_strtoul(*str, str, 16); | 108 | val = simple_strtoul(*str, str, 16); |
107 | if (val < 0 || val > 0xff || (*str)++[0] != '.') | 109 | if (val < 0 || val > 0xff || (*str)++[0] != '.') |
108 | goto confused; | 110 | goto confused; |
109 | *id1 = val; | 111 | *ssid = val; |
110 | if (!isxdigit((*str)[0])) /* We require at least one hex digit */ | 112 | if (!isxdigit((*str)[0])) /* We require at least one hex digit */ |
111 | goto confused; | 113 | goto confused; |
112 | val = simple_strtoul(*str, str, 16); | 114 | val = simple_strtoul(*str, str, 16); |
@@ -126,7 +128,7 @@ confused: | |||
126 | static inline int | 128 | static inline int |
127 | blacklist_parse_parameters (char *str, range_action action) | 129 | blacklist_parse_parameters (char *str, range_action action) |
128 | { | 130 | { |
129 | unsigned int from, to, from_id0, to_id0, from_id1, to_id1; | 131 | unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid; |
130 | 132 | ||
131 | while (*str != 0 && *str != '\n') { | 133 | while (*str != 0 && *str != '\n') { |
132 | range_action ra = action; | 134 | range_action ra = action; |
@@ -143,23 +145,25 @@ blacklist_parse_parameters (char *str, range_action action) | |||
143 | */ | 145 | */ |
144 | if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 || | 146 | if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 || |
145 | strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) { | 147 | strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) { |
146 | from = 0; | 148 | int j; |
147 | to = __MAX_SUBCHANNEL; | 149 | |
148 | str += 3; | 150 | str += 3; |
151 | for (j=0; j <= __MAX_SSID; j++) | ||
152 | blacklist_range(ra, 0, __MAX_SUBCHANNEL, j); | ||
149 | } else { | 153 | } else { |
150 | int rc; | 154 | int rc; |
151 | 155 | ||
152 | rc = blacklist_busid(&str, &from_id0, | 156 | rc = blacklist_busid(&str, &from_id0, |
153 | &from_id1, &from); | 157 | &from_ssid, &from); |
154 | if (rc) | 158 | if (rc) |
155 | continue; | 159 | continue; |
156 | to = from; | 160 | to = from; |
157 | to_id0 = from_id0; | 161 | to_id0 = from_id0; |
158 | to_id1 = from_id1; | 162 | to_ssid = from_ssid; |
159 | if (*str == '-') { | 163 | if (*str == '-') { |
160 | str++; | 164 | str++; |
161 | rc = blacklist_busid(&str, &to_id0, | 165 | rc = blacklist_busid(&str, &to_id0, |
162 | &to_id1, &to); | 166 | &to_ssid, &to); |
163 | if (rc) | 167 | if (rc) |
164 | continue; | 168 | continue; |
165 | } | 169 | } |
@@ -169,18 +173,19 @@ blacklist_parse_parameters (char *str, range_action action) | |||
169 | strsep(&str, ",\n")); | 173 | strsep(&str, ",\n")); |
170 | continue; | 174 | continue; |
171 | } | 175 | } |
172 | if ((from_id0 != to_id0) || (from_id1 != to_id1)) { | 176 | if ((from_id0 != to_id0) || |
177 | (from_ssid != to_ssid)) { | ||
173 | printk(KERN_WARNING "invalid cio_ignore range " | 178 | printk(KERN_WARNING "invalid cio_ignore range " |
174 | "%x.%x.%04x-%x.%x.%04x\n", | 179 | "%x.%x.%04x-%x.%x.%04x\n", |
175 | from_id0, from_id1, from, | 180 | from_id0, from_ssid, from, |
176 | to_id0, to_id1, to); | 181 | to_id0, to_ssid, to); |
177 | continue; | 182 | continue; |
178 | } | 183 | } |
184 | pr_debug("blacklist_setup: adding range " | ||
185 | "from %x.%x.%04x to %x.%x.%04x\n", | ||
186 | from_id0, from_ssid, from, to_id0, to_ssid, to); | ||
187 | blacklist_range (ra, from, to, to_ssid); | ||
179 | } | 188 | } |
180 | /* FIXME: ignoring id0 and id1 here. */ | ||
181 | pr_debug("blacklist_setup: adding range " | ||
182 | "from 0.0.%04x to 0.0.%04x\n", from, to); | ||
183 | blacklist_range (ra, from, to); | ||
184 | } | 189 | } |
185 | return 1; | 190 | return 1; |
186 | } | 191 | } |
@@ -214,9 +219,9 @@ __setup ("cio_ignore=", blacklist_setup); | |||
214 | * Used by validate_subchannel() | 219 | * Used by validate_subchannel() |
215 | */ | 220 | */ |
216 | int | 221 | int |
217 | is_blacklisted (int devno) | 222 | is_blacklisted (int ssid, int devno) |
218 | { | 223 | { |
219 | return test_bit (devno, bl_dev); | 224 | return test_bit (devno, bl_dev[ssid]); |
220 | } | 225 | } |
221 | 226 | ||
222 | #ifdef CONFIG_PROC_FS | 227 | #ifdef CONFIG_PROC_FS |
@@ -283,6 +288,7 @@ blacklist_parse_proc_parameters (char *buf) | |||
283 | /* Iterator struct for all devices. */ | 288 | /* Iterator struct for all devices. */ |
284 | struct ccwdev_iter { | 289 | struct ccwdev_iter { |
285 | int devno; | 290 | int devno; |
291 | int ssid; | ||
286 | int in_range; | 292 | int in_range; |
287 | }; | 293 | }; |
288 | 294 | ||
@@ -291,13 +297,14 @@ cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset) | |||
291 | { | 297 | { |
292 | struct ccwdev_iter *iter; | 298 | struct ccwdev_iter *iter; |
293 | 299 | ||
294 | if (*offset > __MAX_SUBCHANNEL) | 300 | if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) |
295 | return NULL; | 301 | return NULL; |
296 | iter = kmalloc(sizeof(struct ccwdev_iter), GFP_KERNEL); | 302 | iter = kmalloc(sizeof(struct ccwdev_iter), GFP_KERNEL); |
297 | if (!iter) | 303 | if (!iter) |
298 | return ERR_PTR(-ENOMEM); | 304 | return ERR_PTR(-ENOMEM); |
299 | memset(iter, 0, sizeof(struct ccwdev_iter)); | 305 | memset(iter, 0, sizeof(struct ccwdev_iter)); |
300 | iter->devno = *offset; | 306 | iter->ssid = *offset / (__MAX_SUBCHANNEL + 1); |
307 | iter->devno = *offset % (__MAX_SUBCHANNEL + 1); | ||
301 | return iter; | 308 | return iter; |
302 | } | 309 | } |
303 | 310 | ||
@@ -313,10 +320,16 @@ cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset) | |||
313 | { | 320 | { |
314 | struct ccwdev_iter *iter; | 321 | struct ccwdev_iter *iter; |
315 | 322 | ||
316 | if (*offset > __MAX_SUBCHANNEL) | 323 | if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1)) |
317 | return NULL; | 324 | return NULL; |
318 | iter = (struct ccwdev_iter *)it; | 325 | iter = (struct ccwdev_iter *)it; |
319 | iter->devno++; | 326 | if (iter->devno == __MAX_SUBCHANNEL) { |
327 | iter->devno = 0; | ||
328 | iter->ssid++; | ||
329 | if (iter->ssid > __MAX_SSID) | ||
330 | return NULL; | ||
331 | } else | ||
332 | iter->devno++; | ||
320 | (*offset)++; | 333 | (*offset)++; |
321 | return iter; | 334 | return iter; |
322 | } | 335 | } |
@@ -327,23 +340,24 @@ cio_ignore_proc_seq_show(struct seq_file *s, void *it) | |||
327 | struct ccwdev_iter *iter; | 340 | struct ccwdev_iter *iter; |
328 | 341 | ||
329 | iter = (struct ccwdev_iter *)it; | 342 | iter = (struct ccwdev_iter *)it; |
330 | if (!is_blacklisted(iter->devno)) | 343 | if (!is_blacklisted(iter->ssid, iter->devno)) |
331 | /* Not blacklisted, nothing to output. */ | 344 | /* Not blacklisted, nothing to output. */ |
332 | return 0; | 345 | return 0; |
333 | if (!iter->in_range) { | 346 | if (!iter->in_range) { |
334 | /* First device in range. */ | 347 | /* First device in range. */ |
335 | if ((iter->devno == __MAX_SUBCHANNEL) || | 348 | if ((iter->devno == __MAX_SUBCHANNEL) || |
336 | !is_blacklisted(iter->devno + 1)) | 349 | !is_blacklisted(iter->ssid, iter->devno + 1)) |
337 | /* Singular device. */ | 350 | /* Singular device. */ |
338 | return seq_printf(s, "0.0.%04x\n", iter->devno); | 351 | return seq_printf(s, "0.%x.%04x\n", |
352 | iter->ssid, iter->devno); | ||
339 | iter->in_range = 1; | 353 | iter->in_range = 1; |
340 | return seq_printf(s, "0.0.%04x-", iter->devno); | 354 | return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno); |
341 | } | 355 | } |
342 | if ((iter->devno == __MAX_SUBCHANNEL) || | 356 | if ((iter->devno == __MAX_SUBCHANNEL) || |
343 | !is_blacklisted(iter->devno + 1)) { | 357 | !is_blacklisted(iter->ssid, iter->devno + 1)) { |
344 | /* Last device in range. */ | 358 | /* Last device in range. */ |
345 | iter->in_range = 0; | 359 | iter->in_range = 0; |
346 | return seq_printf(s, "0.0.%04x\n", iter->devno); | 360 | return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno); |
347 | } | 361 | } |
348 | return 0; | 362 | return 0; |
349 | } | 363 | } |