[S390] sclp: convert channel path configure code to use sync interface.
[deliverable/linux.git] / drivers / s390 / char / sclp_cmd.c
CommitLineData
08d07968
HC
1/*
2 * drivers/s390/char/sclp_cmd.c
3 *
4 * Copyright IBM Corp. 2007
4b28a8fe
HC
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
6 * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
08d07968
HC
7 */
8
9#include <linux/completion.h>
10#include <linux/init.h>
11#include <linux/errno.h>
12#include <linux/slab.h>
13#include <linux/string.h>
4b28a8fe 14#include <asm/chpid.h>
08d07968
HC
15#include <asm/sclp.h>
16#include "sclp.h"
17
18#define TAG "sclp_cmd: "
19
20#define SCLP_CMDW_READ_SCP_INFO 0x00020001
21#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
22
23struct read_info_sccb {
24 struct sccb_header header; /* 0-7 */
25 u16 rnmax; /* 8-9 */
26 u8 rnsize; /* 10 */
27 u8 _reserved0[24 - 11]; /* 11-15 */
28 u8 loadparm[8]; /* 24-31 */
29 u8 _reserved1[48 - 32]; /* 32-47 */
30 u64 facilities; /* 48-55 */
31 u8 _reserved2[84 - 56]; /* 56-83 */
32 u8 fac84; /* 84 */
33 u8 _reserved3[91 - 85]; /* 85-90 */
34 u8 flags; /* 91 */
35 u8 _reserved4[100 - 92]; /* 92-99 */
36 u32 rnsize2; /* 100-103 */
37 u64 rnmax2; /* 104-111 */
38 u8 _reserved5[4096 - 112]; /* 112-4095 */
39} __attribute__((packed, aligned(PAGE_SIZE)));
40
41static struct read_info_sccb __initdata early_read_info_sccb;
42static int __initdata early_read_info_sccb_valid;
43
44u64 sclp_facilities;
45static u8 sclp_fac84;
46
47static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
48{
49 int rc;
50
51 __ctl_set_bit(0, 9);
52 rc = sclp_service_call(cmd, sccb);
53 if (rc)
54 goto out;
55 __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
56 PSW_MASK_WAIT | PSW_DEFAULT_KEY);
57 local_irq_disable();
58out:
59 /* Contents of the sccb might have changed. */
60 barrier();
61 __ctl_clear_bit(0, 9);
62 return rc;
63}
64
65void __init sclp_read_info_early(void)
66{
67 int rc;
68 int i;
69 struct read_info_sccb *sccb;
70 sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
71 SCLP_CMDW_READ_SCP_INFO};
72
73 sccb = &early_read_info_sccb;
74 for (i = 0; i < ARRAY_SIZE(commands); i++) {
75 do {
76 memset(sccb, 0, sizeof(*sccb));
77 sccb->header.length = sizeof(*sccb);
78 sccb->header.control_mask[2] = 0x80;
79 rc = sclp_cmd_sync_early(commands[i], sccb);
80 } while (rc == -EBUSY);
81
82 if (rc)
83 break;
84 if (sccb->header.response_code == 0x10) {
85 early_read_info_sccb_valid = 1;
86 break;
87 }
88 if (sccb->header.response_code != 0x1f0)
89 break;
90 }
91}
92
93void __init sclp_facilities_detect(void)
94{
95 if (!early_read_info_sccb_valid)
96 return;
97 sclp_facilities = early_read_info_sccb.facilities;
98 sclp_fac84 = early_read_info_sccb.fac84;
99}
100
101unsigned long long __init sclp_memory_detect(void)
102{
103 unsigned long long memsize;
104 struct read_info_sccb *sccb;
105
106 if (!early_read_info_sccb_valid)
107 return 0;
108 sccb = &early_read_info_sccb;
109 if (sccb->rnsize)
110 memsize = sccb->rnsize << 20;
111 else
112 memsize = sccb->rnsize2 << 20;
113 if (sccb->rnmax)
114 memsize *= sccb->rnmax;
115 else
116 memsize *= sccb->rnmax2;
117 return memsize;
118}
119
120/*
121 * This function will be called after sclp_memory_detect(), which gets called
122 * early from early.c code. Therefore the sccb should have valid contents.
123 */
124void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
125{
126 struct read_info_sccb *sccb;
127
128 if (!early_read_info_sccb_valid)
129 return;
130 sccb = &early_read_info_sccb;
131 info->is_valid = 1;
132 if (sccb->flags & 0x2)
133 info->has_dump = 1;
134 memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
135}
136
137static void sclp_sync_callback(struct sclp_req *req, void *data)
138{
139 struct completion *completion = data;
140
141 complete(completion);
142}
143
144static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
145{
146 struct completion completion;
147 struct sclp_req *request;
148 int rc;
149
150 request = kzalloc(sizeof(*request), GFP_KERNEL);
151 if (!request)
152 return -ENOMEM;
153 request->command = cmd;
154 request->sccb = sccb;
155 request->status = SCLP_REQ_FILLED;
156 request->callback = sclp_sync_callback;
157 request->callback_data = &completion;
158 init_completion(&completion);
159
160 /* Perform sclp request. */
161 rc = sclp_add_request(request);
162 if (rc)
163 goto out;
164 wait_for_completion(&completion);
165
166 /* Check response. */
167 if (request->status != SCLP_REQ_DONE) {
168 printk(KERN_WARNING TAG "sync request failed "
169 "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
170 rc = -EIO;
171 }
172out:
173 kfree(request);
174 return rc;
175}
176
177/*
178 * CPU configuration related functions.
179 */
180
181#define SCLP_CMDW_READ_CPU_INFO 0x00010001
182#define SCLP_CMDW_CONFIGURE_CPU 0x00110001
183#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001
184
185struct read_cpu_info_sccb {
186 struct sccb_header header;
187 u16 nr_configured;
188 u16 offset_configured;
189 u16 nr_standby;
190 u16 offset_standby;
191 u8 reserved[4096 - 16];
192} __attribute__((packed, aligned(PAGE_SIZE)));
193
194static struct read_cpu_info_sccb __initdata early_read_cpu_info_sccb;
195static struct sclp_cpu_info __initdata sclp_cpu_info;
196
197static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
198 struct read_cpu_info_sccb *sccb)
199{
200 char *page = (char *) sccb;
201
202 memset(info, 0, sizeof(*info));
203 info->configured = sccb->nr_configured;
204 info->standby = sccb->nr_standby;
205 info->combined = sccb->nr_configured + sccb->nr_standby;
206 info->has_cpu_type = sclp_fac84 & 0x1;
207 memcpy(&info->cpu, page + sccb->offset_configured,
208 info->combined * sizeof(struct sclp_cpu_entry));
209}
210
211void __init sclp_read_cpu_info_early(void)
212{
213 int rc;
214 struct read_cpu_info_sccb *sccb;
215
216 if (!SCLP_HAS_CPU_INFO)
217 return;
218
219 sccb = &early_read_cpu_info_sccb;
220 do {
221 memset(sccb, 0, sizeof(*sccb));
222 sccb->header.length = sizeof(*sccb);
223 rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb);
224 } while (rc == -EBUSY);
225
226 if (rc)
227 return;
228 if (sccb->header.response_code != 0x10)
229 return;
230 sclp_fill_cpu_info(&sclp_cpu_info, sccb);
231}
232
233static int __init sclp_get_cpu_info_early(struct sclp_cpu_info *info)
234{
235 if (!SCLP_HAS_CPU_INFO)
236 return -EOPNOTSUPP;
237 *info = sclp_cpu_info;
238 return 0;
239}
240
241static int sclp_get_cpu_info_late(struct sclp_cpu_info *info)
242{
243 int rc;
244 struct read_cpu_info_sccb *sccb;
245
246 if (!SCLP_HAS_CPU_INFO)
247 return -EOPNOTSUPP;
248 sccb = (struct read_cpu_info_sccb *) __get_free_page(GFP_KERNEL
249 | GFP_DMA);
250 if (!sccb)
251 return -ENOMEM;
252 memset(sccb, 0, sizeof(*sccb));
253 sccb->header.length = sizeof(*sccb);
254 rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
255 if (rc)
256 goto out;
257 if (sccb->header.response_code != 0x0010) {
258 printk(KERN_WARNING TAG "readcpuinfo failed "
259 "(response=0x%04x)\n", sccb->header.response_code);
260 rc = -EIO;
261 goto out;
262 }
263 sclp_fill_cpu_info(info, sccb);
264out:
265 free_page((unsigned long) sccb);
266 return rc;
267}
268
269int __init_refok sclp_get_cpu_info(struct sclp_cpu_info *info)
270{
271 if (slab_is_available())
272 return sclp_get_cpu_info_late(info);
273 return sclp_get_cpu_info_early(info);
274}
275
276struct cpu_configure_sccb {
277 struct sccb_header header;
278} __attribute__((packed, aligned(8)));
279
280static int do_cpu_configure(sclp_cmdw_t cmd)
281{
282 struct cpu_configure_sccb *sccb;
283 int rc;
284
285 if (!SCLP_HAS_CPU_RECONFIG)
286 return -EOPNOTSUPP;
287 /*
288 * This is not going to cross a page boundary since we force
289 * kmalloc to have a minimum alignment of 8 bytes on s390.
290 */
291 sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
292 if (!sccb)
293 return -ENOMEM;
294 sccb->header.length = sizeof(*sccb);
295 rc = do_sync_request(cmd, sccb);
296 if (rc)
297 goto out;
298 switch (sccb->header.response_code) {
299 case 0x0020:
300 case 0x0120:
301 break;
302 default:
303 printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
304 "response=0x%04x)\n", cmd, sccb->header.response_code);
305 rc = -EIO;
306 break;
307 }
308out:
309 kfree(sccb);
310 return rc;
311}
312
313int sclp_cpu_configure(u8 cpu)
314{
315 return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
316}
317
318int sclp_cpu_deconfigure(u8 cpu)
319{
320 return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
321}
4b28a8fe
HC
322
323/*
324 * Channel path configuration related functions.
325 */
326
327#define SCLP_CMDW_CONFIGURE_CHPATH 0x000f0001
328#define SCLP_CMDW_DECONFIGURE_CHPATH 0x000e0001
329#define SCLP_CMDW_READ_CHPATH_INFORMATION 0x00030001
330
331struct chp_cfg_sccb {
332 struct sccb_header header;
333 u8 ccm;
334 u8 reserved[6];
335 u8 cssid;
336} __attribute__((packed));
337
338static int do_chp_configure(sclp_cmdw_t cmd)
339{
340 struct chp_cfg_sccb *sccb;
341 int rc;
342
343 if (!SCLP_HAS_CHP_RECONFIG)
344 return -EOPNOTSUPP;
345 /* Prepare sccb. */
346 sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
347 if (!sccb)
348 return -ENOMEM;
349 sccb->header.length = sizeof(*sccb);
350 rc = do_sync_request(cmd, sccb);
351 if (rc)
352 goto out;
353 switch (sccb->header.response_code) {
354 case 0x0020:
355 case 0x0120:
356 case 0x0440:
357 case 0x0450:
358 break;
359 default:
360 printk(KERN_WARNING TAG "configure channel-path failed "
361 "(cmd=0x%08x, response=0x%04x)\n", cmd,
362 sccb->header.response_code);
363 rc = -EIO;
364 break;
365 }
366out:
367 free_page((unsigned long) sccb);
368 return rc;
369}
370
371/**
372 * sclp_chp_configure - perform configure channel-path sclp command
373 * @chpid: channel-path ID
374 *
375 * Perform configure channel-path command sclp command for specified chpid.
376 * Return 0 after command successfully finished, non-zero otherwise.
377 */
378int sclp_chp_configure(struct chp_id chpid)
379{
380 return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8);
381}
382
383/**
384 * sclp_chp_deconfigure - perform deconfigure channel-path sclp command
385 * @chpid: channel-path ID
386 *
387 * Perform deconfigure channel-path command sclp command for specified chpid
388 * and wait for completion. On success return 0. Return non-zero otherwise.
389 */
390int sclp_chp_deconfigure(struct chp_id chpid)
391{
392 return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8);
393}
394
395struct chp_info_sccb {
396 struct sccb_header header;
397 u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
398 u8 standby[SCLP_CHP_INFO_MASK_SIZE];
399 u8 configured[SCLP_CHP_INFO_MASK_SIZE];
400 u8 ccm;
401 u8 reserved[6];
402 u8 cssid;
403} __attribute__((packed));
404
405/**
406 * sclp_chp_read_info - perform read channel-path information sclp command
407 * @info: resulting channel-path information data
408 *
409 * Perform read channel-path information sclp command and wait for completion.
410 * On success, store channel-path information in @info and return 0. Return
411 * non-zero otherwise.
412 */
413int sclp_chp_read_info(struct sclp_chp_info *info)
414{
415 struct chp_info_sccb *sccb;
416 int rc;
417
418 if (!SCLP_HAS_CHP_INFO)
419 return -EOPNOTSUPP;
420 /* Prepare sccb. */
421 sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
422 if (!sccb)
423 return -ENOMEM;
424 sccb->header.length = sizeof(*sccb);
425 rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb);
426 if (rc)
427 goto out;
428 if (sccb->header.response_code != 0x0010) {
429 printk(KERN_WARNING TAG "read channel-path info failed "
430 "(response=0x%04x)\n", sccb->header.response_code);
431 rc = -EIO;
432 goto out;
433 }
434 memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE);
435 memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE);
436 memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE);
437out:
438 free_page((unsigned long) sccb);
439 return rc;
440}
This page took 0.058379 seconds and 5 git commands to generate.