aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/chsc.c
diff options
context:
space:
mode:
authorCornelia Huck <cohuck@de.ibm.com>2006-01-06 03:19:25 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:52 -0500
commitfb6958a594da49ece869793e6ec163b89fc5f79f (patch)
tree0746cc23ab13a059f9a34d7fc134aaf6410d07b8 /drivers/s390/cio/chsc.c
parent678a395b356a98368a93c3640252502b70c3676f (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.c68
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
1085int __init
1086chsc_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
1081subsys_initcall(chsc_alloc_sei_area); 1133subsys_initcall(chsc_alloc_sei_area);
1082 1134
1083struct css_general_char css_general_characteristics; 1135struct css_general_char css_general_characteristics;