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 | |
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>
-rw-r--r-- | drivers/s390/cio/blacklist.c | 86 | ||||
-rw-r--r-- | drivers/s390/cio/blacklist.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 68 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 4 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 35 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 44 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 22 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 15 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 22 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 40 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 10 | ||||
-rw-r--r-- | drivers/s390/cio/ioasm.h | 29 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.c | 81 | ||||
-rw-r--r-- | drivers/s390/cio/schid.h | 3 | ||||
-rw-r--r-- | drivers/s390/s390mach.c | 56 |
16 files changed, 354 insertions, 165 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 | } |
diff --git a/drivers/s390/cio/blacklist.h b/drivers/s390/cio/blacklist.h index fb42cafbe57c..95e25c1df922 100644 --- a/drivers/s390/cio/blacklist.h +++ b/drivers/s390/cio/blacklist.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #ifndef S390_BLACKLIST_H | 1 | #ifndef S390_BLACKLIST_H |
2 | #define S390_BLACKLIST_H | 2 | #define S390_BLACKLIST_H |
3 | 3 | ||
4 | extern int is_blacklisted (int devno); | 4 | extern int is_blacklisted (int ssid, int devno); |
5 | 5 | ||
6 | #endif | 6 | #endif |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index ebd924962df0..7270808c02d1 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/chsc.c | 2 | * drivers/s390/cio/chsc.c |
3 | * S/390 common I/O routines -- channel subsystem call | 3 | * S/390 common I/O routines -- channel subsystem call |
4 | * $Revision: 1.120 $ | 4 | * $Revision: 1.126 $ |
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 |
@@ -75,7 +75,9 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) | |||
75 | 75 | ||
76 | struct { | 76 | struct { |
77 | struct chsc_header request; | 77 | struct chsc_header request; |
78 | u16 reserved1; | 78 | u16 reserved1a:10; |
79 | u16 ssid:2; | ||
80 | u16 reserved1b:4; | ||
79 | u16 f_sch; /* first subchannel */ | 81 | u16 f_sch; /* first subchannel */ |
80 | u16 reserved2; | 82 | u16 reserved2; |
81 | u16 l_sch; /* last subchannel */ | 83 | u16 l_sch; /* last subchannel */ |
@@ -102,6 +104,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) | |||
102 | .code = 0x0004, | 104 | .code = 0x0004, |
103 | }; | 105 | }; |
104 | 106 | ||
107 | ssd_area->ssid = sch->schid.ssid; | ||
105 | ssd_area->f_sch = sch->schid.sch_no; | 108 | ssd_area->f_sch = sch->schid.sch_no; |
106 | ssd_area->l_sch = sch->schid.sch_no; | 109 | ssd_area->l_sch = sch->schid.sch_no; |
107 | 110 | ||
@@ -145,8 +148,8 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) | |||
145 | */ | 148 | */ |
146 | if (ssd_area->st > 3) { /* uhm, that looks strange... */ | 149 | if (ssd_area->st > 3) { /* uhm, that looks strange... */ |
147 | CIO_CRW_EVENT(0, "Strange subchannel type %d" | 150 | CIO_CRW_EVENT(0, "Strange subchannel type %d" |
148 | " for sch %04x\n", ssd_area->st, | 151 | " for sch 0.%x.%04x\n", ssd_area->st, |
149 | sch->schid.sch_no); | 152 | sch->schid.ssid, sch->schid.sch_no); |
150 | /* | 153 | /* |
151 | * There may have been a new subchannel type defined in the | 154 | * There may have been a new subchannel type defined in the |
152 | * time since this code was written; since we don't know which | 155 | * time since this code was written; since we don't know which |
@@ -155,8 +158,9 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) | |||
155 | return 0; | 158 | return 0; |
156 | } else { | 159 | } else { |
157 | const char *type[4] = {"I/O", "chsc", "message", "ADM"}; | 160 | const char *type[4] = {"I/O", "chsc", "message", "ADM"}; |
158 | CIO_CRW_EVENT(6, "ssd: sch %04x is %s subchannel\n", | 161 | CIO_CRW_EVENT(6, "ssd: sch 0.%x.%04x is %s subchannel\n", |
159 | sch->schid.sch_no, type[ssd_area->st]); | 162 | sch->schid.ssid, sch->schid.sch_no, |
163 | type[ssd_area->st]); | ||
160 | 164 | ||
161 | sch->ssd_info.valid = 1; | 165 | sch->ssd_info.valid = 1; |
162 | sch->ssd_info.type = ssd_area->st; | 166 | sch->ssd_info.type = ssd_area->st; |
@@ -364,7 +368,7 @@ s390_process_res_acc_new_sch(struct subchannel_id schid) | |||
364 | * that beast may be on we'll have to do a stsch | 368 | * that beast may be on we'll have to do a stsch |
365 | * on all devices, grr... | 369 | * on all devices, grr... |
366 | */ | 370 | */ |
367 | if (stsch(schid, &schib)) | 371 | if (stsch_err(schid, &schib)) |
368 | /* We're through */ | 372 | /* We're through */ |
369 | return need_rescan ? -EAGAIN : -ENXIO; | 373 | return need_rescan ? -EAGAIN : -ENXIO; |
370 | 374 | ||
@@ -818,7 +822,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) | |||
818 | put_device(&sch->dev); | 822 | put_device(&sch->dev); |
819 | return 0; | 823 | return 0; |
820 | } | 824 | } |
821 | if (stsch(schid, &schib)) | 825 | if (stsch_err(schid, &schib)) |
822 | /* We're through */ | 826 | /* We're through */ |
823 | return -ENXIO; | 827 | return -ENXIO; |
824 | /* Put it on the slow path. */ | 828 | /* Put it on the slow path. */ |
@@ -1078,6 +1082,54 @@ chsc_alloc_sei_area(void) | |||
1078 | return (sei_page ? 0 : -ENOMEM); | 1082 | return (sei_page ? 0 : -ENOMEM); |
1079 | } | 1083 | } |
1080 | 1084 | ||
1085 | int __init | ||
1086 | chsc_enable_facility(int operation_code) | ||
1087 | { | ||
1088 | int ret; | ||
1089 | struct { | ||
1090 | struct chsc_header request; | ||
1091 | u8 reserved1:4; | ||
1092 | u8 format:4; | ||
1093 | u8 reserved2; | ||
1094 | u16 operation_code; | ||
1095 | u32 reserved3; | ||
1096 | u32 reserved4; | ||
1097 | u32 operation_data_area[252]; | ||
1098 | struct chsc_header response; | ||
1099 | u32 reserved5:4; | ||
1100 | u32 format2:4; | ||
1101 | u32 reserved6:24; | ||
1102 | } *sda_area; | ||
1103 | |||
1104 | sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); | ||
1105 | if (!sda_area) | ||
1106 | return -ENOMEM; | ||
1107 | sda_area->request = (struct chsc_header) { | ||
1108 | .length = 0x0400, | ||
1109 | .code = 0x0031, | ||
1110 | }; | ||
1111 | sda_area->operation_code = operation_code; | ||
1112 | |||
1113 | ret = chsc(sda_area); | ||
1114 | if (ret > 0) { | ||
1115 | ret = (ret == 3) ? -ENODEV : -EBUSY; | ||
1116 | goto out; | ||
1117 | } | ||
1118 | switch (sda_area->response.code) { | ||
1119 | case 0x0003: /* invalid request block */ | ||
1120 | case 0x0007: | ||
1121 | ret = -EINVAL; | ||
1122 | break; | ||
1123 | case 0x0004: /* command not provided */ | ||
1124 | case 0x0101: /* facility not provided */ | ||
1125 | ret = -EOPNOTSUPP; | ||
1126 | break; | ||
1127 | } | ||
1128 | out: | ||
1129 | free_page((unsigned long)sda_area); | ||
1130 | return ret; | ||
1131 | } | ||
1132 | |||
1081 | subsys_initcall(chsc_alloc_sei_area); | 1133 | subsys_initcall(chsc_alloc_sei_area); |
1082 | 1134 | ||
1083 | struct css_general_char css_general_characteristics; | 1135 | struct css_general_char css_general_characteristics; |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 170083ca4349..44e4b4bb1c5a 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #define CHSC_SEI_ACC_LINKADDR 2 | 5 | #define CHSC_SEI_ACC_LINKADDR 2 |
6 | #define CHSC_SEI_ACC_FULLLINKADDR 3 | 6 | #define CHSC_SEI_ACC_FULLLINKADDR 3 |
7 | 7 | ||
8 | #define CHSC_SDA_OC_MSS 0x2 | ||
9 | |||
8 | struct chsc_header { | 10 | struct chsc_header { |
9 | u16 length; | 11 | u16 length; |
10 | u16 code; | 12 | u16 code; |
@@ -64,6 +66,8 @@ extern int css_characteristics_avail; | |||
64 | 66 | ||
65 | extern void *chsc_get_chp_desc(struct subchannel*, int); | 67 | extern void *chsc_get_chp_desc(struct subchannel*, int); |
66 | 68 | ||
69 | extern int chsc_enable_facility(int); | ||
70 | |||
67 | #define to_channelpath(dev) container_of(dev, struct channel_path, dev) | 71 | #define to_channelpath(dev) container_of(dev, struct channel_path, dev) |
68 | 72 | ||
69 | #endif | 73 | #endif |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 3eb6cb608fc9..6f274f4f92eb 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/cio.c | 2 | * drivers/s390/cio/cio.c |
3 | * S/390 common I/O routines -- low level i/o calls | 3 | * S/390 common I/O routines -- low level i/o calls |
4 | * $Revision: 1.135 $ | 4 | * $Revision: 1.138 $ |
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 |
@@ -166,7 +166,8 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) | |||
166 | stsch (sch->schid, &sch->schib); | 166 | stsch (sch->schid, &sch->schib); |
167 | 167 | ||
168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " | 168 | CIO_MSG_EVENT(0, "cio_start: 'not oper' status for " |
169 | "subchannel %04x!\n", sch->schid.sch_no); | 169 | "subchannel 0.%x.%04x!\n", sch->schid.ssid, |
170 | sch->schid.sch_no); | ||
170 | sprintf(dbf_text, "no%s", sch->dev.bus_id); | 171 | sprintf(dbf_text, "no%s", sch->dev.bus_id); |
171 | CIO_TRACE_EVENT(0, dbf_text); | 172 | CIO_TRACE_EVENT(0, dbf_text); |
172 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); | 173 | CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); |
@@ -522,15 +523,18 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
522 | spin_lock_init(&sch->lock); | 523 | spin_lock_init(&sch->lock); |
523 | 524 | ||
524 | /* Set a name for the subchannel */ | 525 | /* Set a name for the subchannel */ |
525 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", schid.sch_no); | 526 | snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid, |
527 | schid.sch_no); | ||
526 | 528 | ||
527 | /* | 529 | /* |
528 | * The first subchannel that is not-operational (ccode==3) | 530 | * The first subchannel that is not-operational (ccode==3) |
529 | * indicates that there aren't any more devices available. | 531 | * indicates that there aren't any more devices available. |
532 | * If stsch gets an exception, it means the current subchannel set | ||
533 | * is not valid. | ||
530 | */ | 534 | */ |
531 | ccode = stsch (schid, &sch->schib); | 535 | ccode = stsch_err (schid, &sch->schib); |
532 | if (ccode) | 536 | if (ccode) |
533 | return -ENXIO; | 537 | return (ccode == 3) ? -ENXIO : ccode; |
534 | 538 | ||
535 | sch->schid = schid; | 539 | sch->schid = schid; |
536 | /* Copy subchannel type from path management control word. */ | 540 | /* Copy subchannel type from path management control word. */ |
@@ -541,9 +545,9 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
541 | */ | 545 | */ |
542 | if (sch->st != 0) { | 546 | if (sch->st != 0) { |
543 | CIO_DEBUG(KERN_INFO, 0, | 547 | CIO_DEBUG(KERN_INFO, 0, |
544 | "Subchannel %04X reports " | 548 | "Subchannel 0.%x.%04x reports " |
545 | "non-I/O subchannel type %04X\n", | 549 | "non-I/O subchannel type %04X\n", |
546 | sch->schid.sch_no, sch->st); | 550 | sch->schid.ssid, sch->schid.sch_no, sch->st); |
547 | /* We stop here for non-io subchannels. */ | 551 | /* We stop here for non-io subchannels. */ |
548 | return sch->st; | 552 | return sch->st; |
549 | } | 553 | } |
@@ -554,26 +558,29 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
554 | return -ENODEV; | 558 | return -ENODEV; |
555 | 559 | ||
556 | /* Devno is valid. */ | 560 | /* Devno is valid. */ |
557 | if (is_blacklisted (sch->schib.pmcw.dev)) { | 561 | if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { |
558 | /* | 562 | /* |
559 | * This device must not be known to Linux. So we simply | 563 | * This device must not be known to Linux. So we simply |
560 | * say that there is no device and return ENODEV. | 564 | * say that there is no device and return ENODEV. |
561 | */ | 565 | */ |
562 | CIO_MSG_EVENT(0, "Blacklisted device detected " | 566 | CIO_MSG_EVENT(0, "Blacklisted device detected " |
563 | "at devno %04X\n", sch->schib.pmcw.dev); | 567 | "at devno %04X, subchannel set %x\n", |
568 | sch->schib.pmcw.dev, sch->schid.ssid); | ||
564 | return -ENODEV; | 569 | return -ENODEV; |
565 | } | 570 | } |
566 | sch->opm = 0xff; | 571 | sch->opm = 0xff; |
567 | chsc_validate_chpids(sch); | 572 | if (!cio_is_console(sch->schid)) |
573 | chsc_validate_chpids(sch); | ||
568 | sch->lpm = sch->schib.pmcw.pim & | 574 | sch->lpm = sch->schib.pmcw.pim & |
569 | sch->schib.pmcw.pam & | 575 | sch->schib.pmcw.pam & |
570 | sch->schib.pmcw.pom & | 576 | sch->schib.pmcw.pom & |
571 | sch->opm; | 577 | sch->opm; |
572 | 578 | ||
573 | CIO_DEBUG(KERN_INFO, 0, | 579 | CIO_DEBUG(KERN_INFO, 0, |
574 | "Detected device %04X on subchannel %04X" | 580 | "Detected device %04x on subchannel 0.%x.%04X" |
575 | " - PIM = %02X, PAM = %02X, POM = %02X\n", | 581 | " - PIM = %02X, PAM = %02X, POM = %02X\n", |
576 | sch->schib.pmcw.dev, sch->schid.sch_no, sch->schib.pmcw.pim, | 582 | sch->schib.pmcw.dev, sch->schid.ssid, |
583 | sch->schid.sch_no, sch->schib.pmcw.pim, | ||
577 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); | 584 | sch->schib.pmcw.pam, sch->schib.pmcw.pom); |
578 | 585 | ||
579 | /* | 586 | /* |
@@ -693,7 +700,7 @@ wait_cons_dev (void) | |||
693 | static int | 700 | static int |
694 | cio_test_for_console(struct subchannel_id schid, void *data) | 701 | cio_test_for_console(struct subchannel_id schid, void *data) |
695 | { | 702 | { |
696 | if (stsch(schid, &console_subchannel.schib) != 0) | 703 | if (stsch_err(schid, &console_subchannel.schib) != 0) |
697 | return -ENXIO; | 704 | return -ENXIO; |
698 | if (console_subchannel.schib.pmcw.dnv && | 705 | if (console_subchannel.schib.pmcw.dnv && |
699 | console_subchannel.schib.pmcw.dev == | 706 | console_subchannel.schib.pmcw.dev == |
@@ -841,7 +848,7 @@ __shutdown_subchannel_easy(struct subchannel_id schid, void *data) | |||
841 | { | 848 | { |
842 | struct schib schib; | 849 | struct schib schib; |
843 | 850 | ||
844 | if (stsch(schid, &schib)) | 851 | if (stsch_err(schid, &schib)) |
845 | return -ENXIO; | 852 | return -ENXIO; |
846 | if (!schib.pmcw.ena) | 853 | if (!schib.pmcw.ena) |
847 | return 0; | 854 | return 0; |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index b6225cbbbee7..9e9d4a157a4c 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/css.c | 2 | * drivers/s390/cio/css.c |
3 | * driver for channel subsystem | 3 | * driver for channel subsystem |
4 | * $Revision: 1.85 $ | 4 | * $Revision: 1.93 $ |
5 | * | 5 | * |
6 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, | 6 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, |
7 | * IBM Corporation | 7 | * IBM Corporation |
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | int need_rescan = 0; | 24 | int need_rescan = 0; |
25 | int css_init_done = 0; | 25 | int css_init_done = 0; |
26 | static int max_ssid = 0; | ||
26 | 27 | ||
27 | struct channel_subsystem *css[__MAX_CSSID + 1]; | 28 | struct channel_subsystem *css[__MAX_CSSID + 1]; |
28 | 29 | ||
@@ -37,10 +38,13 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) | |||
37 | init_subchannel_id(&schid); | 38 | init_subchannel_id(&schid); |
38 | ret = -ENODEV; | 39 | ret = -ENODEV; |
39 | do { | 40 | do { |
40 | ret = fn(schid, data); | 41 | do { |
41 | if (ret) | 42 | ret = fn(schid, data); |
42 | break; | 43 | if (ret) |
43 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | 44 | break; |
45 | } while (schid.sch_no++ < __MAX_SUBCHANNEL); | ||
46 | schid.sch_no = 0; | ||
47 | } while (schid.ssid++ < max_ssid); | ||
44 | return ret; | 48 | return ret; |
45 | } | 49 | } |
46 | 50 | ||
@@ -205,8 +209,8 @@ css_evaluate_subchannel(struct subchannel_id schid, int slow) | |||
205 | return -EAGAIN; /* Will be done on the slow path. */ | 209 | return -EAGAIN; /* Will be done on the slow path. */ |
206 | } | 210 | } |
207 | event = css_get_subchannel_status(sch, schid); | 211 | event = css_get_subchannel_status(sch, schid); |
208 | CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", | 212 | CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", |
209 | schid.sch_no, event, | 213 | schid.ssid, schid.sch_no, event, |
210 | sch?(disc?"disconnected":"normal"):"unknown", | 214 | sch?(disc?"disconnected":"normal"):"unknown", |
211 | slow?"slow":"fast"); | 215 | slow?"slow":"fast"); |
212 | switch (event) { | 216 | switch (event) { |
@@ -352,19 +356,23 @@ css_reiterate_subchannels(void) | |||
352 | * Called from the machine check handler for subchannel report words. | 356 | * Called from the machine check handler for subchannel report words. |
353 | */ | 357 | */ |
354 | int | 358 | int |
355 | css_process_crw(int irq) | 359 | css_process_crw(int rsid1, int rsid2) |
356 | { | 360 | { |
357 | int ret; | 361 | int ret; |
358 | struct subchannel_id mchk_schid; | 362 | struct subchannel_id mchk_schid; |
359 | 363 | ||
360 | CIO_CRW_EVENT(2, "source is subchannel %04X\n", irq); | 364 | CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", |
365 | rsid1, rsid2); | ||
361 | 366 | ||
362 | if (need_rescan) | 367 | if (need_rescan) |
363 | /* We need to iterate all subchannels anyway. */ | 368 | /* We need to iterate all subchannels anyway. */ |
364 | return -EAGAIN; | 369 | return -EAGAIN; |
365 | 370 | ||
366 | init_subchannel_id(&mchk_schid); | 371 | init_subchannel_id(&mchk_schid); |
367 | mchk_schid.sch_no = irq; | 372 | mchk_schid.sch_no = rsid1; |
373 | if (rsid2 != 0) | ||
374 | mchk_schid.ssid = (rsid2 >> 8) & 3; | ||
375 | |||
368 | /* | 376 | /* |
369 | * Since we are always presented with IPI in the CRW, we have to | 377 | * Since we are always presented with IPI in the CRW, we have to |
370 | * use stsch() to find out if the subchannel in question has come | 378 | * use stsch() to find out if the subchannel in question has come |
@@ -465,12 +473,23 @@ init_channel_subsystem (void) | |||
465 | if ((ret = bus_register(&css_bus_type))) | 473 | if ((ret = bus_register(&css_bus_type))) |
466 | goto out; | 474 | goto out; |
467 | 475 | ||
476 | /* Try to enable MSS. */ | ||
477 | ret = chsc_enable_facility(CHSC_SDA_OC_MSS); | ||
478 | switch (ret) { | ||
479 | case 0: /* Success. */ | ||
480 | max_ssid = __MAX_SSID; | ||
481 | break; | ||
482 | case -ENOMEM: | ||
483 | goto out_bus; | ||
484 | default: | ||
485 | max_ssid = 0; | ||
486 | } | ||
468 | /* Setup css structure. */ | 487 | /* Setup css structure. */ |
469 | for (i = 0; i <= __MAX_CSSID; i++) { | 488 | for (i = 0; i <= __MAX_CSSID; i++) { |
470 | css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); | 489 | css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL); |
471 | if (!css[i]) { | 490 | if (!css[i]) { |
472 | ret = -ENOMEM; | 491 | ret = -ENOMEM; |
473 | goto out_bus; | 492 | goto out_unregister; |
474 | } | 493 | } |
475 | setup_css(i); | 494 | setup_css(i); |
476 | ret = device_register(&css[i]->device); | 495 | ret = device_register(&css[i]->device); |
@@ -485,11 +504,12 @@ init_channel_subsystem (void) | |||
485 | return 0; | 504 | return 0; |
486 | out_free: | 505 | out_free: |
487 | kfree(css[i]); | 506 | kfree(css[i]); |
488 | out_bus: | 507 | out_unregister: |
489 | while (i > 0) { | 508 | while (i > 0) { |
490 | i--; | 509 | i--; |
491 | device_unregister(&css[i]->device); | 510 | device_unregister(&css[i]->device); |
492 | } | 511 | } |
512 | out_bus: | ||
493 | bus_unregister(&css_bus_type); | 513 | bus_unregister(&css_bus_type); |
494 | out: | 514 | out: |
495 | return ret; | 515 | return ret; |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index b74659cab0af..251ebd7a7d3a 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -77,6 +77,7 @@ struct ccw_device_private { | |||
77 | unsigned long registered; | 77 | unsigned long registered; |
78 | __u16 devno; /* device number */ | 78 | __u16 devno; /* device number */ |
79 | __u16 sch_no; /* subchannel number */ | 79 | __u16 sch_no; /* subchannel number */ |
80 | __u8 ssid; /* subchannel set id */ | ||
80 | __u8 imask; /* lpm mask for SNID/SID/SPGID */ | 81 | __u8 imask; /* lpm mask for SNID/SID/SPGID */ |
81 | int iretry; /* retry counter SNID/SID/SPGID */ | 82 | int iretry; /* retry counter SNID/SID/SPGID */ |
82 | struct { | 83 | struct { |
@@ -135,6 +136,7 @@ extern int css_init_done; | |||
135 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); | 136 | extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); |
136 | 137 | ||
137 | #define __MAX_SUBCHANNEL 65535 | 138 | #define __MAX_SUBCHANNEL 65535 |
139 | #define __MAX_SSID 3 | ||
138 | #define __MAX_CHPID 255 | 140 | #define __MAX_CHPID 255 |
139 | #define __MAX_CSSID 0 | 141 | #define __MAX_CSSID 0 |
140 | 142 | ||
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index ba9f7c11f63f..fa3e4c0a2536 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -535,7 +535,8 @@ ccw_device_register(struct ccw_device *cdev) | |||
535 | } | 535 | } |
536 | 536 | ||
537 | struct match_data { | 537 | struct match_data { |
538 | unsigned int devno; | 538 | unsigned int devno; |
539 | unsigned int ssid; | ||
539 | struct ccw_device * sibling; | 540 | struct ccw_device * sibling; |
540 | }; | 541 | }; |
541 | 542 | ||
@@ -548,6 +549,7 @@ match_devno(struct device * dev, void * data) | |||
548 | cdev = to_ccwdev(dev); | 549 | cdev = to_ccwdev(dev); |
549 | if ((cdev->private->state == DEV_STATE_DISCONNECTED) && | 550 | if ((cdev->private->state == DEV_STATE_DISCONNECTED) && |
550 | (cdev->private->devno == d->devno) && | 551 | (cdev->private->devno == d->devno) && |
552 | (cdev->private->ssid == d->ssid) && | ||
551 | (cdev != d->sibling)) { | 553 | (cdev != d->sibling)) { |
552 | cdev->private->state = DEV_STATE_NOT_OPER; | 554 | cdev->private->state = DEV_STATE_NOT_OPER; |
553 | return 1; | 555 | return 1; |
@@ -556,11 +558,13 @@ match_devno(struct device * dev, void * data) | |||
556 | } | 558 | } |
557 | 559 | ||
558 | static struct ccw_device * | 560 | static struct ccw_device * |
559 | get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling) | 561 | get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid, |
562 | struct ccw_device *sibling) | ||
560 | { | 563 | { |
561 | struct device *dev; | 564 | struct device *dev; |
562 | struct match_data data = { | 565 | struct match_data data = { |
563 | .devno = devno, | 566 | .devno = devno, |
567 | .ssid = ssid, | ||
564 | .sibling = sibling, | 568 | .sibling = sibling, |
565 | }; | 569 | }; |
566 | 570 | ||
@@ -616,7 +620,7 @@ ccw_device_do_unreg_rereg(void *data) | |||
616 | 620 | ||
617 | need_rename = 1; | 621 | need_rename = 1; |
618 | other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev, | 622 | other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev, |
619 | cdev); | 623 | sch->schid.ssid, cdev); |
620 | if (other_cdev) { | 624 | if (other_cdev) { |
621 | struct subchannel *other_sch; | 625 | struct subchannel *other_sch; |
622 | 626 | ||
@@ -639,8 +643,8 @@ ccw_device_do_unreg_rereg(void *data) | |||
639 | if (test_and_clear_bit(1, &cdev->private->registered)) | 643 | if (test_and_clear_bit(1, &cdev->private->registered)) |
640 | device_del(&cdev->dev); | 644 | device_del(&cdev->dev); |
641 | if (need_rename) | 645 | if (need_rename) |
642 | snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", | 646 | snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", |
643 | sch->schib.pmcw.dev); | 647 | sch->schid.ssid, sch->schib.pmcw.dev); |
644 | PREPARE_WORK(&cdev->private->kick_work, | 648 | PREPARE_WORK(&cdev->private->kick_work, |
645 | ccw_device_add_changed, (void *)cdev); | 649 | ccw_device_add_changed, (void *)cdev); |
646 | queue_work(ccw_device_work, &cdev->private->kick_work); | 650 | queue_work(ccw_device_work, &cdev->private->kick_work); |
@@ -769,9 +773,11 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
769 | sch->dev.driver_data = cdev; | 773 | sch->dev.driver_data = cdev; |
770 | sch->driver = &io_subchannel_driver; | 774 | sch->driver = &io_subchannel_driver; |
771 | cdev->ccwlock = &sch->lock; | 775 | cdev->ccwlock = &sch->lock; |
776 | |||
772 | /* Init private data. */ | 777 | /* Init private data. */ |
773 | priv = cdev->private; | 778 | priv = cdev->private; |
774 | priv->devno = sch->schib.pmcw.dev; | 779 | priv->devno = sch->schib.pmcw.dev; |
780 | priv->ssid = sch->schid.ssid; | ||
775 | priv->sch_no = sch->schid.sch_no; | 781 | priv->sch_no = sch->schid.sch_no; |
776 | priv->state = DEV_STATE_NOT_OPER; | 782 | priv->state = DEV_STATE_NOT_OPER; |
777 | INIT_LIST_HEAD(&priv->cmb_list); | 783 | INIT_LIST_HEAD(&priv->cmb_list); |
@@ -779,8 +785,8 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) | |||
779 | init_timer(&priv->timer); | 785 | init_timer(&priv->timer); |
780 | 786 | ||
781 | /* Set an initial name for the device. */ | 787 | /* Set an initial name for the device. */ |
782 | snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.0.%04x", | 788 | snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", |
783 | sch->schib.pmcw.dev); | 789 | sch->schid.ssid, sch->schib.pmcw.dev); |
784 | 790 | ||
785 | /* Increase counter of devices currently in recognition. */ | 791 | /* Increase counter of devices currently in recognition. */ |
786 | atomic_inc(&ccw_device_init_count); | 792 | atomic_inc(&ccw_device_init_count); |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 9efeae75ad28..23d12b65e5fa 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -257,8 +257,9 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
257 | switch (state) { | 257 | switch (state) { |
258 | case DEV_STATE_NOT_OPER: | 258 | case DEV_STATE_NOT_OPER: |
259 | CIO_DEBUG(KERN_WARNING, 2, | 259 | CIO_DEBUG(KERN_WARNING, 2, |
260 | "SenseID : unknown device %04x on subchannel %04x\n", | 260 | "SenseID : unknown device %04x on subchannel " |
261 | cdev->private->devno, sch->schid.sch_no); | 261 | "0.%x.%04x\n", cdev->private->devno, |
262 | sch->schid.ssid, sch->schid.sch_no); | ||
262 | break; | 263 | break; |
263 | case DEV_STATE_OFFLINE: | 264 | case DEV_STATE_OFFLINE: |
264 | if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { | 265 | if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { |
@@ -282,16 +283,18 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
282 | return; | 283 | return; |
283 | } | 284 | } |
284 | /* Issue device info message. */ | 285 | /* Issue device info message. */ |
285 | CIO_DEBUG(KERN_INFO, 2, "SenseID : device %04x reports: " | 286 | CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: " |
286 | "CU Type/Mod = %04X/%02X, Dev Type/Mod = " | 287 | "CU Type/Mod = %04X/%02X, Dev Type/Mod = " |
287 | "%04X/%02X\n", cdev->private->devno, | 288 | "%04X/%02X\n", |
289 | cdev->private->ssid, cdev->private->devno, | ||
288 | cdev->id.cu_type, cdev->id.cu_model, | 290 | cdev->id.cu_type, cdev->id.cu_model, |
289 | cdev->id.dev_type, cdev->id.dev_model); | 291 | cdev->id.dev_type, cdev->id.dev_model); |
290 | break; | 292 | break; |
291 | case DEV_STATE_BOXED: | 293 | case DEV_STATE_BOXED: |
292 | CIO_DEBUG(KERN_WARNING, 2, | 294 | CIO_DEBUG(KERN_WARNING, 2, |
293 | "SenseID : boxed device %04x on subchannel %04x\n", | 295 | "SenseID : boxed device %04x on subchannel " |
294 | cdev->private->devno, sch->schid.sch_no); | 296 | "0.%x.%04x\n", cdev->private->devno, |
297 | sch->schid.ssid, sch->schid.sch_no); | ||
295 | break; | 298 | break; |
296 | } | 299 | } |
297 | cdev->private->state = state; | 300 | cdev->private->state = state; |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 207881ec7aaf..3c77c3fd461d 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -256,16 +256,17 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
256 | * sense id information. So, for intervention required, | 256 | * sense id information. So, for intervention required, |
257 | * we use the "whack it until it talks" strategy... | 257 | * we use the "whack it until it talks" strategy... |
258 | */ | 258 | */ |
259 | CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel %04x " | 259 | CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel " |
260 | "reports cmd reject\n", | 260 | "0.%x.%04x reports cmd reject\n", |
261 | cdev->private->devno, sch->schid.sch_no); | 261 | cdev->private->devno, sch->schid.ssid, |
262 | sch->schid.sch_no); | ||
262 | return -EOPNOTSUPP; | 263 | return -EOPNOTSUPP; |
263 | } | 264 | } |
264 | if (irb->esw.esw0.erw.cons) { | 265 | if (irb->esw.esw0.erw.cons) { |
265 | CIO_MSG_EVENT(2, "SenseID : UC on dev %04x, " | 266 | CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, " |
266 | "lpum %02X, cnt %02d, sns :" | 267 | "lpum %02X, cnt %02d, sns :" |
267 | " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", | 268 | " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", |
268 | cdev->private->devno, | 269 | cdev->private->ssid, cdev->private->devno, |
269 | irb->esw.esw0.sublog.lpum, | 270 | irb->esw.esw0.sublog.lpum, |
270 | irb->esw.esw0.erw.scnt, | 271 | irb->esw.esw0.erw.scnt, |
271 | irb->ecw[0], irb->ecw[1], | 272 | irb->ecw[0], irb->ecw[1], |
@@ -277,16 +278,17 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
277 | if (irb->scsw.cc == 3) { | 278 | if (irb->scsw.cc == 3) { |
278 | if ((sch->orb.lpm & | 279 | if ((sch->orb.lpm & |
279 | sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) | 280 | sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) |
280 | CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x on" | 281 | CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " |
281 | " subchannel %04x is 'not operational'\n", | 282 | "on subchannel 0.%x.%04x is " |
282 | sch->orb.lpm, cdev->private->devno, | 283 | "'not operational'\n", sch->orb.lpm, |
284 | cdev->private->devno, sch->schid.ssid, | ||
283 | sch->schid.sch_no); | 285 | sch->schid.sch_no); |
284 | return -EACCES; | 286 | return -EACCES; |
285 | } | 287 | } |
286 | /* Hmm, whatever happened, try again. */ | 288 | /* Hmm, whatever happened, try again. */ |
287 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " | 289 | CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on " |
288 | "subchannel %04x returns status %02X%02X\n", | 290 | "subchannel 0.%x.%04x returns status %02X%02X\n", |
289 | cdev->private->devno, sch->schid.sch_no, | 291 | cdev->private->devno, sch->schid.ssid, sch->schid.sch_no, |
290 | irb->scsw.dstat, irb->scsw.cstat); | 292 | irb->scsw.dstat, irb->scsw.cstat); |
291 | return -EAGAIN; | 293 | return -EAGAIN; |
292 | } | 294 | } |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 3c89d70b9c09..052832d03d38 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -57,10 +57,10 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev) | |||
57 | if (ret != -EACCES) | 57 | if (ret != -EACCES) |
58 | return ret; | 58 | return ret; |
59 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " | 59 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " |
60 | "%04x, lpm %02X, became 'not " | 60 | "0.%x.%04x, lpm %02X, became 'not " |
61 | "operational'\n", | 61 | "operational'\n", |
62 | cdev->private->devno, sch->schid.sch_no, | 62 | cdev->private->devno, sch->schid.ssid, |
63 | cdev->private->imask); | 63 | sch->schid.sch_no, cdev->private->imask); |
64 | 64 | ||
65 | } | 65 | } |
66 | cdev->private->imask >>= 1; | 66 | cdev->private->imask >>= 1; |
@@ -106,10 +106,10 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
106 | return -EOPNOTSUPP; | 106 | return -EOPNOTSUPP; |
107 | } | 107 | } |
108 | if (irb->esw.esw0.erw.cons) { | 108 | if (irb->esw.esw0.erw.cons) { |
109 | CIO_MSG_EVENT(2, "SNID - device %04x, unit check, " | 109 | CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, " |
110 | "lpum %02X, cnt %02d, sns : " | 110 | "lpum %02X, cnt %02d, sns : " |
111 | "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", | 111 | "%02X%02X%02X%02X %02X%02X%02X%02X ...\n", |
112 | cdev->private->devno, | 112 | cdev->private->ssid, cdev->private->devno, |
113 | irb->esw.esw0.sublog.lpum, | 113 | irb->esw.esw0.sublog.lpum, |
114 | irb->esw.esw0.erw.scnt, | 114 | irb->esw.esw0.erw.scnt, |
115 | irb->ecw[0], irb->ecw[1], | 115 | irb->ecw[0], irb->ecw[1], |
@@ -119,16 +119,17 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
119 | return -EAGAIN; | 119 | return -EAGAIN; |
120 | } | 120 | } |
121 | if (irb->scsw.cc == 3) { | 121 | if (irb->scsw.cc == 3) { |
122 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel " | 122 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," |
123 | "%04x, lpm %02X, became 'not operational'\n", | 123 | " lpm %02X, became 'not operational'\n", |
124 | cdev->private->devno, sch->schid.sch_no, | 124 | cdev->private->devno, sch->schid.ssid, |
125 | sch->orb.lpm); | 125 | sch->schid.sch_no, sch->orb.lpm); |
126 | return -EACCES; | 126 | return -EACCES; |
127 | } | 127 | } |
128 | if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { | 128 | if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) { |
129 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel %04x " | 129 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x " |
130 | "is reserved by someone else\n", | 130 | "is reserved by someone else\n", |
131 | cdev->private->devno, sch->schid.sch_no); | 131 | cdev->private->devno, sch->schid.ssid, |
132 | sch->schid.sch_no); | ||
132 | return -EUSERS; | 133 | return -EUSERS; |
133 | } | 134 | } |
134 | return 0; | 135 | return 0; |
@@ -237,8 +238,9 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func) | |||
237 | sch->lpm &= ~cdev->private->imask; | 238 | sch->lpm &= ~cdev->private->imask; |
238 | sch->vpm &= ~cdev->private->imask; | 239 | sch->vpm &= ~cdev->private->imask; |
239 | CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " | 240 | CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " |
240 | "%04x, lpm %02X, became 'not operational'\n", | 241 | "0.%x.%04x, lpm %02X, became 'not operational'\n", |
241 | cdev->private->devno, sch->schid.sch_no, cdev->private->imask); | 242 | cdev->private->devno, sch->schid.ssid, |
243 | sch->schid.sch_no, cdev->private->imask); | ||
242 | return ret; | 244 | return ret; |
243 | } | 245 | } |
244 | 246 | ||
@@ -260,8 +262,10 @@ __ccw_device_check_pgid(struct ccw_device *cdev) | |||
260 | if (irb->ecw[0] & SNS0_CMD_REJECT) | 262 | if (irb->ecw[0] & SNS0_CMD_REJECT) |
261 | return -EOPNOTSUPP; | 263 | return -EOPNOTSUPP; |
262 | /* Hmm, whatever happened, try again. */ | 264 | /* Hmm, whatever happened, try again. */ |
263 | CIO_MSG_EVENT(2, "SPID - device %04x, unit check, cnt %02d, " | 265 | CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, " |
266 | "cnt %02d, " | ||
264 | "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n", | 267 | "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n", |
268 | cdev->private->ssid, | ||
265 | cdev->private->devno, irb->esw.esw0.erw.scnt, | 269 | cdev->private->devno, irb->esw.esw0.erw.scnt, |
266 | irb->ecw[0], irb->ecw[1], | 270 | irb->ecw[0], irb->ecw[1], |
267 | irb->ecw[2], irb->ecw[3], | 271 | irb->ecw[2], irb->ecw[3], |
@@ -270,10 +274,10 @@ __ccw_device_check_pgid(struct ccw_device *cdev) | |||
270 | return -EAGAIN; | 274 | return -EAGAIN; |
271 | } | 275 | } |
272 | if (irb->scsw.cc == 3) { | 276 | if (irb->scsw.cc == 3) { |
273 | CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel " | 277 | CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x," |
274 | "%04x, lpm %02X, became 'not operational'\n", | 278 | " lpm %02X, became 'not operational'\n", |
275 | cdev->private->devno, sch->schid.sch_no, | 279 | cdev->private->devno, sch->schid.ssid, |
276 | cdev->private->imask); | 280 | sch->schid.sch_no, cdev->private->imask); |
277 | return -EACCES; | 281 | return -EACCES; |
278 | } | 282 | } |
279 | return 0; | 283 | return 0; |
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 929f8fb505f2..db09c209098b 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c | |||
@@ -36,9 +36,10 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) | |||
36 | 36 | ||
37 | CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " | 37 | CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " |
38 | "received" | 38 | "received" |
39 | " ... device %04X on subchannel %04X, dev_stat " | 39 | " ... device %04x on subchannel 0.%x.%04x, dev_stat " |
40 | ": %02X sch_stat : %02X\n", | 40 | ": %02X sch_stat : %02X\n", |
41 | cdev->private->devno, cdev->private->sch_no, | 41 | cdev->private->devno, cdev->private->ssid, |
42 | cdev->private->sch_no, | ||
42 | irb->scsw.dstat, irb->scsw.cstat); | 43 | irb->scsw.dstat, irb->scsw.cstat); |
43 | 44 | ||
44 | if (irb->scsw.cc != 3) { | 45 | if (irb->scsw.cc != 3) { |
@@ -61,8 +62,9 @@ ccw_device_path_notoper(struct ccw_device *cdev) | |||
61 | sch = to_subchannel(cdev->dev.parent); | 62 | sch = to_subchannel(cdev->dev.parent); |
62 | stsch (sch->schid, &sch->schib); | 63 | stsch (sch->schid, &sch->schib); |
63 | 64 | ||
64 | CIO_MSG_EVENT(0, "%s(%04x) - path(s) %02x are " | 65 | CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are " |
65 | "not operational \n", __FUNCTION__, sch->schid.sch_no, | 66 | "not operational \n", __FUNCTION__, |
67 | sch->schid.ssid, sch->schid.sch_no, | ||
66 | sch->schib.pmcw.pnom); | 68 | sch->schib.pmcw.pnom); |
67 | 69 | ||
68 | sch->lpm &= ~sch->schib.pmcw.pnom; | 70 | sch->lpm &= ~sch->schib.pmcw.pnom; |
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h index 66c882e52f32..62b0e2ad507f 100644 --- a/drivers/s390/cio/ioasm.h +++ b/drivers/s390/cio/ioasm.h | |||
@@ -38,6 +38,35 @@ static inline int stsch(struct subchannel_id schid, | |||
38 | return ccode; | 38 | return ccode; |
39 | } | 39 | } |
40 | 40 | ||
41 | static inline int stsch_err(struct subchannel_id schid, | ||
42 | volatile struct schib *addr) | ||
43 | { | ||
44 | int ccode; | ||
45 | |||
46 | __asm__ __volatile__( | ||
47 | " lhi %0,%3\n" | ||
48 | " lr 1,%1\n" | ||
49 | " stsch 0(%2)\n" | ||
50 | "0: ipm %0\n" | ||
51 | " srl %0,28\n" | ||
52 | "1:\n" | ||
53 | #ifdef CONFIG_ARCH_S390X | ||
54 | ".section __ex_table,\"a\"\n" | ||
55 | " .align 8\n" | ||
56 | " .quad 0b,1b\n" | ||
57 | ".previous" | ||
58 | #else | ||
59 | ".section __ex_table,\"a\"\n" | ||
60 | " .align 4\n" | ||
61 | " .long 0b,1b\n" | ||
62 | ".previous" | ||
63 | #endif | ||
64 | : "=&d" (ccode) | ||
65 | : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr) | ||
66 | : "cc", "1" ); | ||
67 | return ccode; | ||
68 | } | ||
69 | |||
41 | static inline int msch(struct subchannel_id schid, | 70 | static inline int msch(struct subchannel_id schid, |
42 | volatile struct schib *addr) | 71 | volatile struct schib *addr) |
43 | { | 72 | { |
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 5c7001b5c7a1..035c77af9cd3 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -56,7 +56,7 @@ | |||
56 | #include "ioasm.h" | 56 | #include "ioasm.h" |
57 | #include "chsc.h" | 57 | #include "chsc.h" |
58 | 58 | ||
59 | #define VERSION_QDIO_C "$Revision: 1.113 $" | 59 | #define VERSION_QDIO_C "$Revision: 1.114 $" |
60 | 60 | ||
61 | /****************** MODULE PARAMETER VARIABLES ********************/ | 61 | /****************** MODULE PARAMETER VARIABLES ********************/ |
62 | MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); | 62 | MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); |
@@ -2066,21 +2066,22 @@ qdio_timeout_handler(struct ccw_device *cdev) | |||
2066 | 2066 | ||
2067 | switch (irq_ptr->state) { | 2067 | switch (irq_ptr->state) { |
2068 | case QDIO_IRQ_STATE_INACTIVE: | 2068 | case QDIO_IRQ_STATE_INACTIVE: |
2069 | QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n", | 2069 | QDIO_PRINT_ERR("establish queues on irq 0.%x.%04x: timed out\n", |
2070 | irq_ptr->schid.sch_no); | 2070 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); |
2071 | QDIO_DBF_TEXT2(1,setup,"eq:timeo"); | 2071 | QDIO_DBF_TEXT2(1,setup,"eq:timeo"); |
2072 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | 2072 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); |
2073 | break; | 2073 | break; |
2074 | case QDIO_IRQ_STATE_CLEANUP: | 2074 | case QDIO_IRQ_STATE_CLEANUP: |
2075 | QDIO_PRINT_INFO("Did not get interrupt on cleanup, irq=0x%x.\n", | 2075 | QDIO_PRINT_INFO("Did not get interrupt on cleanup, " |
2076 | irq_ptr->schid.sch_no); | 2076 | "irq=0.%x.%x.\n", |
2077 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2077 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | 2078 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); |
2078 | break; | 2079 | break; |
2079 | case QDIO_IRQ_STATE_ESTABLISHED: | 2080 | case QDIO_IRQ_STATE_ESTABLISHED: |
2080 | case QDIO_IRQ_STATE_ACTIVE: | 2081 | case QDIO_IRQ_STATE_ACTIVE: |
2081 | /* I/O has been terminated by common I/O layer. */ | 2082 | /* I/O has been terminated by common I/O layer. */ |
2082 | QDIO_PRINT_INFO("Queues on irq %04x killed by cio.\n", | 2083 | QDIO_PRINT_INFO("Queues on irq 0.%x.%04x killed by cio.\n", |
2083 | irq_ptr->schid.sch_no); | 2084 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); |
2084 | QDIO_DBF_TEXT2(1, trace, "cio:term"); | 2085 | QDIO_DBF_TEXT2(1, trace, "cio:term"); |
2085 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); | 2086 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); |
2086 | if (get_device(&cdev->dev)) { | 2087 | if (get_device(&cdev->dev)) { |
@@ -2273,7 +2274,9 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2273 | unsigned char qdioac; | 2274 | unsigned char qdioac; |
2274 | struct { | 2275 | struct { |
2275 | struct chsc_header request; | 2276 | struct chsc_header request; |
2276 | u16 reserved1; | 2277 | u16 reserved1:10; |
2278 | u16 ssid:2; | ||
2279 | u16 fmt:4; | ||
2277 | u16 first_sch; | 2280 | u16 first_sch; |
2278 | u16 reserved2; | 2281 | u16 reserved2; |
2279 | u16 last_sch; | 2282 | u16 last_sch; |
@@ -2318,12 +2321,13 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2318 | }; | 2321 | }; |
2319 | ssqd_area->first_sch = irq_ptr->schid.sch_no; | 2322 | ssqd_area->first_sch = irq_ptr->schid.sch_no; |
2320 | ssqd_area->last_sch = irq_ptr->schid.sch_no; | 2323 | ssqd_area->last_sch = irq_ptr->schid.sch_no; |
2324 | ssqd_area->ssid = irq_ptr->schid.ssid; | ||
2321 | result = chsc(ssqd_area); | 2325 | result = chsc(ssqd_area); |
2322 | 2326 | ||
2323 | if (result) { | 2327 | if (result) { |
2324 | QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ | 2328 | QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \ |
2325 | "SIGAs for sch x%x.\n", | 2329 | "SIGAs for sch 0.%x.%x.\n", result, |
2326 | result, irq_ptr->schid.sch_no); | 2330 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); |
2327 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY || | 2331 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY || |
2328 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY || | 2332 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY || |
2329 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ | 2333 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ |
@@ -2333,8 +2337,9 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2333 | 2337 | ||
2334 | if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { | 2338 | if (ssqd_area->response.code != QDIO_CHSC_RESPONSE_CODE_OK) { |
2335 | QDIO_PRINT_WARN("response upon checking SIGA needs " \ | 2339 | QDIO_PRINT_WARN("response upon checking SIGA needs " \ |
2336 | "is 0x%x. Using all SIGAs for sch x%x.\n", | 2340 | "is 0x%x. Using all SIGAs for sch 0.%x.%x.\n", |
2337 | ssqd_area->response.code, irq_ptr->schid.sch_no); | 2341 | ssqd_area->response.code, |
2342 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2338 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY || | 2343 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY || |
2339 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY || | 2344 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY || |
2340 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ | 2345 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */ |
@@ -2344,8 +2349,9 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr) | |||
2344 | if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) || | 2349 | if (!(ssqd_area->flags & CHSC_FLAG_QDIO_CAPABILITY) || |
2345 | !(ssqd_area->flags & CHSC_FLAG_VALIDITY) || | 2350 | !(ssqd_area->flags & CHSC_FLAG_VALIDITY) || |
2346 | (ssqd_area->sch != irq_ptr->schid.sch_no)) { | 2351 | (ssqd_area->sch != irq_ptr->schid.sch_no)) { |
2347 | QDIO_PRINT_WARN("huh? problems checking out sch x%x... " \ | 2352 | QDIO_PRINT_WARN("huh? problems checking out sch 0.%x.%x... " \ |
2348 | "using all SIGAs.\n",irq_ptr->schid.sch_no); | 2353 | "using all SIGAs.\n", |
2354 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2349 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | | 2355 | qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY | |
2350 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | | 2356 | CHSC_FLAG_SIGA_OUTPUT_NECESSARY | |
2351 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ | 2357 | CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */ |
@@ -2453,7 +2459,8 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2453 | scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2459 | scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
2454 | if (!scssc_area) { | 2460 | if (!scssc_area) { |
2455 | QDIO_PRINT_WARN("No memory for setting indicators on " \ | 2461 | QDIO_PRINT_WARN("No memory for setting indicators on " \ |
2456 | "subchannel x%x.\n", irq_ptr->schid.sch_no); | 2462 | "subchannel 0.%x.%x.\n", |
2463 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2457 | return -ENOMEM; | 2464 | return -ENOMEM; |
2458 | } | 2465 | } |
2459 | scssc_area->request = (struct chsc_header) { | 2466 | scssc_area->request = (struct chsc_header) { |
@@ -2479,8 +2486,9 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) | |||
2479 | 2486 | ||
2480 | result = chsc(scssc_area); | 2487 | result = chsc(scssc_area); |
2481 | if (result) { | 2488 | if (result) { |
2482 | QDIO_PRINT_WARN("could not set indicators on irq x%x, " \ | 2489 | QDIO_PRINT_WARN("could not set indicators on irq 0.%x.%x, " \ |
2483 | "cc=%i.\n",irq_ptr->schid.sch_no,result); | 2490 | "cc=%i.\n", |
2491 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no,result); | ||
2484 | result = -EIO; | 2492 | result = -EIO; |
2485 | goto out; | 2493 | goto out; |
2486 | } | 2494 | } |
@@ -2536,7 +2544,8 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2536 | scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); | 2544 | scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); |
2537 | if (!scsscf_area) { | 2545 | if (!scsscf_area) { |
2538 | QDIO_PRINT_WARN("No memory for setting delay target on " \ | 2546 | QDIO_PRINT_WARN("No memory for setting delay target on " \ |
2539 | "subchannel x%x.\n", irq_ptr->schid.sch_no); | 2547 | "subchannel 0.%x.%x.\n", |
2548 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
2540 | return -ENOMEM; | 2549 | return -ENOMEM; |
2541 | } | 2550 | } |
2542 | scsscf_area->request = (struct chsc_header) { | 2551 | scsscf_area->request = (struct chsc_header) { |
@@ -2548,8 +2557,9 @@ tiqdio_set_delay_target(struct qdio_irq *irq_ptr, unsigned long delay_target) | |||
2548 | 2557 | ||
2549 | result=chsc(scsscf_area); | 2558 | result=chsc(scsscf_area); |
2550 | if (result) { | 2559 | if (result) { |
2551 | QDIO_PRINT_WARN("could not set delay target on irq x%x, " \ | 2560 | QDIO_PRINT_WARN("could not set delay target on irq 0.%x.%x, " \ |
2552 | "cc=%i. Continuing.\n",irq_ptr->schid.sch_no, | 2561 | "cc=%i. Continuing.\n", |
2562 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, | ||
2553 | result); | 2563 | result); |
2554 | result = -EIO; | 2564 | result = -EIO; |
2555 | goto out; | 2565 | goto out; |
@@ -2870,8 +2880,9 @@ qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, | |||
2870 | QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int)); | 2880 | QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int)); |
2871 | QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int)); | 2881 | QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int)); |
2872 | QDIO_PRINT_ERR("received check condition on establish " \ | 2882 | QDIO_PRINT_ERR("received check condition on establish " \ |
2873 | "queues on irq 0x%x (cs=x%x, ds=x%x).\n", | 2883 | "queues on irq 0.%x.%x (cs=x%x, ds=x%x).\n", |
2874 | irq_ptr->schid.sch_no,cstat,dstat); | 2884 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, |
2885 | cstat,dstat); | ||
2875 | qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ERR); | 2886 | qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ERR); |
2876 | } | 2887 | } |
2877 | 2888 | ||
@@ -2879,9 +2890,10 @@ qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, | |||
2879 | QDIO_DBF_TEXT2(1,setup,"eq:no de"); | 2890 | QDIO_DBF_TEXT2(1,setup,"eq:no de"); |
2880 | QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); | 2891 | QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); |
2881 | QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); | 2892 | QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); |
2882 | QDIO_PRINT_ERR("establish queues on irq %04x: didn't get " | 2893 | QDIO_PRINT_ERR("establish queues on irq 0.%x.%04x: didn't get " |
2883 | "device end: dstat=%02x, cstat=%02x\n", | 2894 | "device end: dstat=%02x, cstat=%02x\n", |
2884 | irq_ptr->schid.sch_no, dstat, cstat); | 2895 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, |
2896 | dstat, cstat); | ||
2885 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | 2897 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); |
2886 | return 1; | 2898 | return 1; |
2887 | } | 2899 | } |
@@ -2890,9 +2902,9 @@ qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, | |||
2890 | QDIO_DBF_TEXT2(1,setup,"eq:badio"); | 2902 | QDIO_DBF_TEXT2(1,setup,"eq:badio"); |
2891 | QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); | 2903 | QDIO_DBF_HEX2(0,setup,&dstat, sizeof(dstat)); |
2892 | QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); | 2904 | QDIO_DBF_HEX2(0,setup,&cstat, sizeof(cstat)); |
2893 | QDIO_PRINT_ERR("establish queues on irq %04x: got " | 2905 | QDIO_PRINT_ERR("establish queues on irq 0.%x.%04x: got " |
2894 | "the following devstat: dstat=%02x, " | 2906 | "the following devstat: dstat=%02x, " |
2895 | "cstat=%02x\n", | 2907 | "cstat=%02x\n", irq_ptr->schid.ssid, |
2896 | irq_ptr->schid.sch_no, dstat, cstat); | 2908 | irq_ptr->schid.sch_no, dstat, cstat); |
2897 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); | 2909 | qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); |
2898 | return 1; | 2910 | return 1; |
@@ -3041,7 +3053,8 @@ int qdio_fill_irq(struct qdio_initialize *init_data) | |||
3041 | QDIO_DBF_HEX1(0,setup,&irq_ptr->dev_st_chg_ind,sizeof(void*)); | 3053 | QDIO_DBF_HEX1(0,setup,&irq_ptr->dev_st_chg_ind,sizeof(void*)); |
3042 | if (!irq_ptr->dev_st_chg_ind) { | 3054 | if (!irq_ptr->dev_st_chg_ind) { |
3043 | QDIO_PRINT_WARN("no indicator location available " \ | 3055 | QDIO_PRINT_WARN("no indicator location available " \ |
3044 | "for irq 0x%x\n",irq_ptr->schid.sch_no); | 3056 | "for irq 0.%x.%x\n", |
3057 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no); | ||
3045 | qdio_release_irq_memory(irq_ptr); | 3058 | qdio_release_irq_memory(irq_ptr); |
3046 | return -ENOBUFS; | 3059 | return -ENOBUFS; |
3047 | } | 3060 | } |
@@ -3198,9 +3211,10 @@ qdio_establish(struct qdio_initialize *init_data) | |||
3198 | sprintf(dbf_text,"eq:io%4x",result); | 3211 | sprintf(dbf_text,"eq:io%4x",result); |
3199 | QDIO_DBF_TEXT2(1,setup,dbf_text); | 3212 | QDIO_DBF_TEXT2(1,setup,dbf_text); |
3200 | } | 3213 | } |
3201 | QDIO_PRINT_WARN("establish queues on irq %04x: do_IO " \ | 3214 | QDIO_PRINT_WARN("establish queues on irq 0.%x.%04x: do_IO " \ |
3202 | "returned %i, next try returned %i\n", | 3215 | "returned %i, next try returned %i\n", |
3203 | irq_ptr->schid.sch_no,result,result2); | 3216 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, |
3217 | result, result2); | ||
3204 | result=result2; | 3218 | result=result2; |
3205 | if (result) | 3219 | if (result) |
3206 | ccw_device_set_timeout(cdev, 0); | 3220 | ccw_device_set_timeout(cdev, 0); |
@@ -3298,9 +3312,10 @@ qdio_activate(struct ccw_device *cdev, int flags) | |||
3298 | sprintf(dbf_text,"aq:io%4x",result); | 3312 | sprintf(dbf_text,"aq:io%4x",result); |
3299 | QDIO_DBF_TEXT2(1,setup,dbf_text); | 3313 | QDIO_DBF_TEXT2(1,setup,dbf_text); |
3300 | } | 3314 | } |
3301 | QDIO_PRINT_WARN("activate queues on irq %04x: do_IO " \ | 3315 | QDIO_PRINT_WARN("activate queues on irq 0.%x.%04x: do_IO " \ |
3302 | "returned %i, next try returned %i\n", | 3316 | "returned %i, next try returned %i\n", |
3303 | irq_ptr->schid.sch_no,result,result2); | 3317 | irq_ptr->schid.ssid, irq_ptr->schid.sch_no, |
3318 | result, result2); | ||
3304 | result=result2; | 3319 | result=result2; |
3305 | } | 3320 | } |
3306 | 3321 | ||
diff --git a/drivers/s390/cio/schid.h b/drivers/s390/cio/schid.h index 220d97882341..54328fec5ade 100644 --- a/drivers/s390/cio/schid.h +++ b/drivers/s390/cio/schid.h | |||
@@ -2,7 +2,8 @@ | |||
2 | #define S390_SCHID_H | 2 | #define S390_SCHID_H |
3 | 3 | ||
4 | struct subchannel_id { | 4 | struct subchannel_id { |
5 | __u32 reserved:15; | 5 | __u32 reserved:13; |
6 | __u32 ssid:2; | ||
6 | __u32 one:1; | 7 | __u32 one:1; |
7 | __u32 sch_no:16; | 8 | __u32 sch_no:16; |
8 | } __attribute__ ((packed,aligned(4))); | 9 | } __attribute__ ((packed,aligned(4))); |
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 4191fd9d4d11..7dad597ff86e 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c | |||
@@ -23,7 +23,7 @@ | |||
23 | 23 | ||
24 | static struct semaphore m_sem; | 24 | static struct semaphore m_sem; |
25 | 25 | ||
26 | extern int css_process_crw(int); | 26 | extern int css_process_crw(int, int); |
27 | extern int chsc_process_crw(void); | 27 | extern int chsc_process_crw(void); |
28 | extern int chp_process_crw(int, int); | 28 | extern int chp_process_crw(int, int); |
29 | extern void css_reiterate_subchannels(void); | 29 | extern void css_reiterate_subchannels(void); |
@@ -49,9 +49,10 @@ s390_handle_damage(char *msg) | |||
49 | static int | 49 | static int |
50 | s390_collect_crw_info(void *param) | 50 | s390_collect_crw_info(void *param) |
51 | { | 51 | { |
52 | struct crw crw; | 52 | struct crw crw[2]; |
53 | int ccode, ret, slow; | 53 | int ccode, ret, slow; |
54 | struct semaphore *sem; | 54 | struct semaphore *sem; |
55 | unsigned int chain; | ||
55 | 56 | ||
56 | sem = (struct semaphore *)param; | 57 | sem = (struct semaphore *)param; |
57 | /* Set a nice name. */ | 58 | /* Set a nice name. */ |
@@ -59,25 +60,50 @@ s390_collect_crw_info(void *param) | |||
59 | repeat: | 60 | repeat: |
60 | down_interruptible(sem); | 61 | down_interruptible(sem); |
61 | slow = 0; | 62 | slow = 0; |
63 | chain = 0; | ||
62 | while (1) { | 64 | while (1) { |
63 | ccode = stcrw(&crw); | 65 | if (unlikely(chain > 1)) { |
66 | struct crw tmp_crw; | ||
67 | |||
68 | printk(KERN_WARNING"%s: Code does not support more " | ||
69 | "than two chained crws; please report to " | ||
70 | "linux390@de.ibm.com!\n", __FUNCTION__); | ||
71 | ccode = stcrw(&tmp_crw); | ||
72 | printk(KERN_WARNING"%s: crw reports slct=%d, oflw=%d, " | ||
73 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | ||
74 | __FUNCTION__, tmp_crw.slct, tmp_crw.oflw, | ||
75 | tmp_crw.chn, tmp_crw.rsc, tmp_crw.anc, | ||
76 | tmp_crw.erc, tmp_crw.rsid); | ||
77 | printk(KERN_WARNING"%s: This was crw number %x in the " | ||
78 | "chain\n", __FUNCTION__, chain); | ||
79 | if (ccode != 0) | ||
80 | break; | ||
81 | chain = tmp_crw.chn ? chain + 1 : 0; | ||
82 | continue; | ||
83 | } | ||
84 | ccode = stcrw(&crw[chain]); | ||
64 | if (ccode != 0) | 85 | if (ccode != 0) |
65 | break; | 86 | break; |
66 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " | 87 | DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, " |
67 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", | 88 | "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", |
68 | crw.slct, crw.oflw, crw.chn, crw.rsc, crw.anc, | 89 | crw[chain].slct, crw[chain].oflw, crw[chain].chn, |
69 | crw.erc, crw.rsid); | 90 | crw[chain].rsc, crw[chain].anc, crw[chain].erc, |
91 | crw[chain].rsid); | ||
70 | /* Check for overflows. */ | 92 | /* Check for overflows. */ |
71 | if (crw.oflw) { | 93 | if (crw[chain].oflw) { |
72 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); | 94 | pr_debug("%s: crw overflow detected!\n", __FUNCTION__); |
73 | css_reiterate_subchannels(); | 95 | css_reiterate_subchannels(); |
96 | chain = 0; | ||
74 | slow = 1; | 97 | slow = 1; |
75 | continue; | 98 | continue; |
76 | } | 99 | } |
77 | switch (crw.rsc) { | 100 | switch (crw[chain].rsc) { |
78 | case CRW_RSC_SCH: | 101 | case CRW_RSC_SCH: |
79 | pr_debug("source is subchannel %04X\n", crw.rsid); | 102 | if (crw[0].chn && !chain) |
80 | ret = css_process_crw (crw.rsid); | 103 | break; |
104 | pr_debug("source is subchannel %04X\n", crw[0].rsid); | ||
105 | ret = css_process_crw (crw[0].rsid, | ||
106 | chain ? crw[1].rsid : 0); | ||
81 | if (ret == -EAGAIN) | 107 | if (ret == -EAGAIN) |
82 | slow = 1; | 108 | slow = 1; |
83 | break; | 109 | break; |
@@ -85,18 +111,18 @@ repeat: | |||
85 | pr_debug("source is monitoring facility\n"); | 111 | pr_debug("source is monitoring facility\n"); |
86 | break; | 112 | break; |
87 | case CRW_RSC_CPATH: | 113 | case CRW_RSC_CPATH: |
88 | pr_debug("source is channel path %02X\n", crw.rsid); | 114 | pr_debug("source is channel path %02X\n", crw[0].rsid); |
89 | switch (crw.erc) { | 115 | switch (crw[0].erc) { |
90 | case CRW_ERC_IPARM: /* Path has come. */ | 116 | case CRW_ERC_IPARM: /* Path has come. */ |
91 | ret = chp_process_crw(crw.rsid, 1); | 117 | ret = chp_process_crw(crw[0].rsid, 1); |
92 | break; | 118 | break; |
93 | case CRW_ERC_PERRI: /* Path has gone. */ | 119 | case CRW_ERC_PERRI: /* Path has gone. */ |
94 | case CRW_ERC_PERRN: | 120 | case CRW_ERC_PERRN: |
95 | ret = chp_process_crw(crw.rsid, 0); | 121 | ret = chp_process_crw(crw[0].rsid, 0); |
96 | break; | 122 | break; |
97 | default: | 123 | default: |
98 | pr_debug("Don't know how to handle erc=%x\n", | 124 | pr_debug("Don't know how to handle erc=%x\n", |
99 | crw.erc); | 125 | crw[0].erc); |
100 | ret = 0; | 126 | ret = 0; |
101 | } | 127 | } |
102 | if (ret == -EAGAIN) | 128 | if (ret == -EAGAIN) |
@@ -115,6 +141,8 @@ repeat: | |||
115 | pr_debug("unknown source\n"); | 141 | pr_debug("unknown source\n"); |
116 | break; | 142 | break; |
117 | } | 143 | } |
144 | /* chain is always 0 or 1 here. */ | ||
145 | chain = crw[chain].chn ? chain + 1 : 0; | ||
118 | } | 146 | } |
119 | if (slow) | 147 | if (slow) |
120 | queue_work(slow_path_wq, &slow_path_work); | 148 | queue_work(slow_path_wq, &slow_path_work); |