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/css.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/css.c')
-rw-r--r-- | drivers/s390/cio/css.c | 44 |
1 files changed, 32 insertions, 12 deletions
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; |