diff options
author | Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | 2007-04-27 10:01:31 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:39 -0400 |
commit | e5854a5839fa426a7873f038080f63587de5f1f1 (patch) | |
tree | c0a3705df925e652ff0694a47e7acb98e5f7d7bd /drivers/s390/char | |
parent | f5ba6c863617c15d22cce5f8666ff4c832773025 (diff) |
[S390] cio: Channel-path configure function.
Add a new attribute to the channel-path sysfs directory through which
channel-path configure operations can be triggered. Also listen for
hardware events requesting channel-path configure operations and
process them accordingly.
Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'drivers/s390/char')
-rw-r--r-- | drivers/s390/char/Makefile | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_chp.c | 196 |
2 files changed, 197 insertions, 1 deletions
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 293e667b50f2..5fd581c22db3 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 5 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
6 | sclp_info.o | 6 | sclp_info.o sclp_chp.o |
7 | 7 | ||
8 | obj-$(CONFIG_TN3270) += raw3270.o | 8 | obj-$(CONFIG_TN3270) += raw3270.o |
9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 9 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c new file mode 100644 index 000000000000..a66b914519b5 --- /dev/null +++ b/drivers/s390/char/sclp_chp.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * drivers/s390/char/sclp_chp.c | ||
3 | * | ||
4 | * Copyright IBM Corp. 2007 | ||
5 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/types.h> | ||
9 | #include <linux/gfp.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/completion.h> | ||
12 | #include <asm/sclp.h> | ||
13 | #include <asm/chpid.h> | ||
14 | |||
15 | #include "sclp.h" | ||
16 | |||
17 | #define TAG "sclp_chp: " | ||
18 | |||
19 | #define SCLP_CMDW_CONFIGURE_CHANNEL_PATH 0x000f0001 | ||
20 | #define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH 0x000e0001 | ||
21 | #define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION 0x00030001 | ||
22 | |||
23 | static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid) | ||
24 | { | ||
25 | return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8; | ||
26 | } | ||
27 | |||
28 | static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid) | ||
29 | { | ||
30 | return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8; | ||
31 | } | ||
32 | |||
33 | static void chp_callback(struct sclp_req *req, void *data) | ||
34 | { | ||
35 | struct completion *completion = data; | ||
36 | |||
37 | complete(completion); | ||
38 | } | ||
39 | |||
40 | struct chp_cfg_sccb { | ||
41 | struct sccb_header header; | ||
42 | u8 ccm; | ||
43 | u8 reserved[6]; | ||
44 | u8 cssid; | ||
45 | } __attribute__((packed)); | ||
46 | |||
47 | struct chp_cfg_data { | ||
48 | struct chp_cfg_sccb sccb; | ||
49 | struct sclp_req req; | ||
50 | struct completion completion; | ||
51 | } __attribute__((packed)); | ||
52 | |||
53 | static int do_configure(sclp_cmdw_t cmd) | ||
54 | { | ||
55 | struct chp_cfg_data *data; | ||
56 | int rc; | ||
57 | |||
58 | /* Prepare sccb. */ | ||
59 | data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
60 | if (!data) | ||
61 | return -ENOMEM; | ||
62 | data->sccb.header.length = sizeof(struct chp_cfg_sccb); | ||
63 | data->req.command = cmd; | ||
64 | data->req.sccb = &(data->sccb); | ||
65 | data->req.status = SCLP_REQ_FILLED; | ||
66 | data->req.callback = chp_callback; | ||
67 | data->req.callback_data = &(data->completion); | ||
68 | init_completion(&data->completion); | ||
69 | |||
70 | /* Perform sclp request. */ | ||
71 | rc = sclp_add_request(&(data->req)); | ||
72 | if (rc) | ||
73 | goto out; | ||
74 | wait_for_completion(&data->completion); | ||
75 | |||
76 | /* Check response .*/ | ||
77 | if (data->req.status != SCLP_REQ_DONE) { | ||
78 | printk(KERN_WARNING TAG "configure channel-path request failed " | ||
79 | "(status=0x%02x)\n", data->req.status); | ||
80 | rc = -EIO; | ||
81 | goto out; | ||
82 | } | ||
83 | switch (data->sccb.header.response_code) { | ||
84 | case 0x0020: | ||
85 | case 0x0120: | ||
86 | case 0x0440: | ||
87 | case 0x0450: | ||
88 | break; | ||
89 | default: | ||
90 | printk(KERN_WARNING TAG "configure channel-path failed " | ||
91 | "(cmd=0x%08x, response=0x%04x)\n", cmd, | ||
92 | data->sccb.header.response_code); | ||
93 | rc = -EIO; | ||
94 | break; | ||
95 | } | ||
96 | out: | ||
97 | free_page((unsigned long) data); | ||
98 | |||
99 | return rc; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * sclp_chp_configure - perform configure channel-path sclp command | ||
104 | * @chpid: channel-path ID | ||
105 | * | ||
106 | * Perform configure channel-path command sclp command for specified chpid. | ||
107 | * Return 0 after command successfully finished, non-zero otherwise. | ||
108 | */ | ||
109 | int sclp_chp_configure(struct chp_id chpid) | ||
110 | { | ||
111 | return do_configure(get_configure_cmdw(chpid)); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * sclp_chp_deconfigure - perform deconfigure channel-path sclp command | ||
116 | * @chpid: channel-path ID | ||
117 | * | ||
118 | * Perform deconfigure channel-path command sclp command for specified chpid | ||
119 | * and wait for completion. On success return 0. Return non-zero otherwise. | ||
120 | */ | ||
121 | int sclp_chp_deconfigure(struct chp_id chpid) | ||
122 | { | ||
123 | return do_configure(get_deconfigure_cmdw(chpid)); | ||
124 | } | ||
125 | |||
126 | struct chp_info_sccb { | ||
127 | struct sccb_header header; | ||
128 | u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; | ||
129 | u8 standby[SCLP_CHP_INFO_MASK_SIZE]; | ||
130 | u8 configured[SCLP_CHP_INFO_MASK_SIZE]; | ||
131 | u8 ccm; | ||
132 | u8 reserved[6]; | ||
133 | u8 cssid; | ||
134 | } __attribute__((packed)); | ||
135 | |||
136 | struct chp_info_data { | ||
137 | struct chp_info_sccb sccb; | ||
138 | struct sclp_req req; | ||
139 | struct completion completion; | ||
140 | } __attribute__((packed)); | ||
141 | |||
142 | /** | ||
143 | * sclp_chp_read_info - perform read channel-path information sclp command | ||
144 | * @info: resulting channel-path information data | ||
145 | * | ||
146 | * Perform read channel-path information sclp command and wait for completion. | ||
147 | * On success, store channel-path information in @info and return 0. Return | ||
148 | * non-zero otherwise. | ||
149 | */ | ||
150 | int sclp_chp_read_info(struct sclp_chp_info *info) | ||
151 | { | ||
152 | struct chp_info_data *data; | ||
153 | int rc; | ||
154 | |||
155 | /* Prepare sccb. */ | ||
156 | data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); | ||
157 | if (!data) | ||
158 | return -ENOMEM; | ||
159 | data->sccb.header.length = sizeof(struct chp_info_sccb); | ||
160 | data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION; | ||
161 | data->req.sccb = &(data->sccb); | ||
162 | data->req.status = SCLP_REQ_FILLED; | ||
163 | data->req.callback = chp_callback; | ||
164 | data->req.callback_data = &(data->completion); | ||
165 | init_completion(&data->completion); | ||
166 | |||
167 | /* Perform sclp request. */ | ||
168 | rc = sclp_add_request(&(data->req)); | ||
169 | if (rc) | ||
170 | goto out; | ||
171 | wait_for_completion(&data->completion); | ||
172 | |||
173 | /* Check response .*/ | ||
174 | if (data->req.status != SCLP_REQ_DONE) { | ||
175 | printk(KERN_WARNING TAG "read channel-path info request failed " | ||
176 | "(status=0x%02x)\n", data->req.status); | ||
177 | rc = -EIO; | ||
178 | goto out; | ||
179 | } | ||
180 | if (data->sccb.header.response_code != 0x0010) { | ||
181 | printk(KERN_WARNING TAG "read channel-path info failed " | ||
182 | "(response=0x%04x)\n", data->sccb.header.response_code); | ||
183 | rc = -EIO; | ||
184 | goto out; | ||
185 | } | ||
186 | memcpy(info->recognized, data->sccb.recognized, | ||
187 | SCLP_CHP_INFO_MASK_SIZE); | ||
188 | memcpy(info->standby, data->sccb.standby, | ||
189 | SCLP_CHP_INFO_MASK_SIZE); | ||
190 | memcpy(info->configured, data->sccb.configured, | ||
191 | SCLP_CHP_INFO_MASK_SIZE); | ||
192 | out: | ||
193 | free_page((unsigned long) data); | ||
194 | |||
195 | return rc; | ||
196 | } | ||