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/chsc.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/chsc.c')
-rw-r--r-- | drivers/s390/cio/chsc.c | 68 |
1 files changed, 60 insertions, 8 deletions
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; |