]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/s390/cio/chsc.c
[S390] cio: Use isc_{register,unregister}.
[net-next-2.6.git] / drivers / s390 / cio / chsc.c
CommitLineData
1da177e4
LT
1/*
2 * drivers/s390/cio/chsc.c
3 * S/390 common I/O routines -- channel subsystem call
1da177e4 4 *
c820de39 5 * Copyright IBM Corp. 1999,2008
1da177e4 6 * Author(s): Ingo Adlung (adlung@de.ibm.com)
4ce3b30c 7 * Cornelia Huck (cornelia.huck@de.ibm.com)
1da177e4
LT
8 * Arnd Bergmann (arndb@de.ibm.com)
9 */
10
11#include <linux/module.h>
1da177e4
LT
12#include <linux/slab.h>
13#include <linux/init.h>
14#include <linux/device.h>
15
16#include <asm/cio.h>
e5854a58 17#include <asm/chpid.h>
1da177e4 18
c1156189 19#include "../s390mach.h"
1da177e4
LT
20#include "css.h"
21#include "cio.h"
22#include "cio_debug.h"
23#include "ioasm.h"
e6b6e10a 24#include "chp.h"
1da177e4
LT
25#include "chsc.h"
26
1da177e4
LT
27static void *sei_page;
28
b9c9a21a
CH
29static int chsc_error_from_response(int response)
30{
31 switch (response) {
32 case 0x0001:
33 return 0;
34 case 0x0002:
35 case 0x0003:
36 case 0x0006:
37 case 0x0007:
38 case 0x0008:
39 case 0x000a:
40 return -EINVAL;
41 case 0x0004:
42 return -EOPNOTSUPP;
43 default:
44 return -EIO;
45 }
46}
47
7ad6a249
PO
48struct chsc_ssd_area {
49 struct chsc_header request;
50 u16 :10;
51 u16 ssid:2;
52 u16 :4;
53 u16 f_sch; /* first subchannel */
54 u16 :16;
55 u16 l_sch; /* last subchannel */
56 u32 :32;
57 struct chsc_header response;
58 u32 :32;
59 u8 sch_valid : 1;
60 u8 dev_valid : 1;
61 u8 st : 3; /* subchannel type */
62 u8 zeroes : 3;
63 u8 unit_addr; /* unit address */
64 u16 devno; /* device number */
65 u8 path_mask;
66 u8 fla_valid_mask;
67 u16 sch; /* subchannel */
68 u8 chpid[8]; /* chpids 0-7 */
69 u16 fla[8]; /* full link addresses 0-7 */
70} __attribute__ ((packed));
71
72int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd)
1da177e4 73{
7ad6a249
PO
74 unsigned long page;
75 struct chsc_ssd_area *ssd_area;
76 int ccode;
77 int ret;
78 int i;
79 int mask;
1da177e4 80
7ad6a249
PO
81 page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
82 if (!page)
83 return -ENOMEM;
84 ssd_area = (struct chsc_ssd_area *) page;
495a5b45
CH
85 ssd_area->request.length = 0x0010;
86 ssd_area->request.code = 0x0004;
7ad6a249
PO
87 ssd_area->ssid = schid.ssid;
88 ssd_area->f_sch = schid.sch_no;
89 ssd_area->l_sch = schid.sch_no;
1da177e4
LT
90
91 ccode = chsc(ssd_area);
7ad6a249 92 /* Check response. */
1da177e4 93 if (ccode > 0) {
7ad6a249
PO
94 ret = (ccode == 3) ? -ENODEV : -EBUSY;
95 goto out_free;
1da177e4 96 }
b9c9a21a
CH
97 ret = chsc_error_from_response(ssd_area->response.code);
98 if (ret != 0) {
7ad6a249
PO
99 CIO_MSG_EVENT(2, "chsc: ssd failed for 0.%x.%04x (rc=%04x)\n",
100 schid.ssid, schid.sch_no,
1da177e4 101 ssd_area->response.code);
7ad6a249 102 goto out_free;
1da177e4 103 }
7ad6a249
PO
104 if (!ssd_area->sch_valid) {
105 ret = -ENODEV;
106 goto out_free;
1da177e4 107 }
7ad6a249
PO
108 /* Copy data */
109 ret = 0;
110 memset(ssd, 0, sizeof(struct chsc_ssd_info));
b279a4f5
CH
111 if ((ssd_area->st != SUBCHANNEL_TYPE_IO) &&
112 (ssd_area->st != SUBCHANNEL_TYPE_MSG))
7ad6a249
PO
113 goto out_free;
114 ssd->path_mask = ssd_area->path_mask;
115 ssd->fla_valid_mask = ssd_area->fla_valid_mask;
116 for (i = 0; i < 8; i++) {
117 mask = 0x80 >> i;
118 if (ssd_area->path_mask & mask) {
119 chp_id_init(&ssd->chpid[i]);
120 ssd->chpid[i].id = ssd_area->chpid[i];
1da177e4 121 }
7ad6a249
PO
122 if (ssd_area->fla_valid_mask & mask)
123 ssd->fla[i] = ssd_area->fla[i];
1da177e4 124 }
7ad6a249
PO
125out_free:
126 free_page(page);
1da177e4
LT
127 return ret;
128}
129
e82a1567 130static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data)
1da177e4 131{
2ec22984 132 spin_lock_irq(sch->lock);
c820de39
CH
133 if (sch->driver && sch->driver->chp_event)
134 if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0)
1da177e4 135 goto out_unreg;
2ec22984 136 spin_unlock_irq(sch->lock);
1da177e4 137 return 0;
387b734f 138
1da177e4 139out_unreg:
1da177e4 140 sch->lpm = 0;
387b734f 141 spin_unlock_irq(sch->lock);
83b3370c 142 css_schedule_eval(sch->schid);
1da177e4
LT
143 return 0;
144}
145
e6b6e10a 146void chsc_chp_offline(struct chp_id chpid)
1da177e4
LT
147{
148 char dbf_txt[15];
149
f86635fa 150 sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
1da177e4
LT
151 CIO_TRACE_EVENT(2, dbf_txt);
152
e6b6e10a 153 if (chp_get_status(chpid) <= 0)
1da177e4 154 return;
22806dc1
CH
155 /* Wait until previous actions have settled. */
156 css_wait_for_slow_path();
e82a1567 157 for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid);
1da177e4
LT
158}
159
e82a1567 160static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
f97a56fb
CH
161{
162 struct schib schib;
f97a56fb
CH
163 /*
164 * We don't know the device yet, but since a path
165 * may be available now to the device we'll have
166 * to do recognition again.
167 * Since we don't have any idea about which chpid
168 * that beast may be on we'll have to do a stsch
169 * on all devices, grr...
170 */
fb6958a5 171 if (stsch_err(schid, &schib))
f97a56fb 172 /* We're through */
83b3370c 173 return -ENXIO;
f97a56fb
CH
174
175 /* Put it on the slow path. */
83b3370c 176 css_schedule_eval(schid);
f97a56fb
CH
177 return 0;
178}
179
e82a1567 180static int __s390_process_res_acc(struct subchannel *sch, void *data)
1da177e4 181{
2ec22984 182 spin_lock_irq(sch->lock);
c820de39
CH
183 if (sch->driver && sch->driver->chp_event)
184 sch->driver->chp_event(sch, data, CHP_ONLINE);
2ec22984 185 spin_unlock_irq(sch->lock);
e82a1567 186
dd9963f9 187 return 0;
f97a56fb
CH
188}
189
83b3370c 190static void s390_process_res_acc (struct res_acc_data *res_data)
f97a56fb 191{
1da177e4
LT
192 char dbf_txt[15];
193
e6b6e10a
PO
194 sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid,
195 res_data->chpid.id);
1da177e4 196 CIO_TRACE_EVENT( 2, dbf_txt);
f97a56fb
CH
197 if (res_data->fla != 0) {
198 sprintf(dbf_txt, "fla%x", res_data->fla);
1da177e4
LT
199 CIO_TRACE_EVENT( 2, dbf_txt);
200 }
22806dc1
CH
201 /* Wait until previous actions have settled. */
202 css_wait_for_slow_path();
1da177e4
LT
203 /*
204 * I/O resources may have become accessible.
205 * Scan through all subchannels that may be concerned and
206 * do a validation on those.
207 * The more information we have (info), the less scanning
208 * will we have to do.
209 */
e82a1567
PO
210 for_each_subchannel_staged(__s390_process_res_acc,
211 s390_process_res_acc_new_sch, res_data);
1da177e4
LT
212}
213
214static int
215__get_chpid_from_lir(void *data)
216{
217 struct lir {
218 u8 iq;
219 u8 ic;
220 u16 sci;
221 /* incident-node descriptor */
222 u32 indesc[28];
223 /* attached-node descriptor */
224 u32 andesc[28];
225 /* incident-specific information */
226 u32 isinfo[28];
0f008aa3 227 } __attribute__ ((packed)) *lir;
1da177e4 228
12975aef 229 lir = data;
1da177e4
LT
230 if (!(lir->iq&0x80))
231 /* NULL link incident record */
232 return -EINVAL;
233 if (!(lir->indesc[0]&0xc0000000))
234 /* node descriptor not valid */
235 return -EINVAL;
236 if (!(lir->indesc[0]&0x10000000))
237 /* don't handle device-type nodes - FIXME */
238 return -EINVAL;
239 /* Byte 3 contains the chpid. Could also be CTCA, but we don't care */
240
241 return (u16) (lir->indesc[0]&0x000000ff);
242}
243
184357a5
PO
244struct chsc_sei_area {
245 struct chsc_header request;
246 u32 reserved1;
247 u32 reserved2;
248 u32 reserved3;
249 struct chsc_header response;
250 u32 reserved4;
251 u8 flags;
252 u8 vf; /* validity flags */
253 u8 rs; /* reporting source */
254 u8 cc; /* content code */
255 u16 fla; /* full link address */
256 u16 rsid; /* reporting source id */
257 u32 reserved5;
258 u32 reserved6;
259 u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
260 /* ccdf has to be big enough for a link-incident record */
261} __attribute__ ((packed));
262
83b3370c 263static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
184357a5 264{
f86635fa
PO
265 struct chp_id chpid;
266 int id;
184357a5
PO
267
268 CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
269 sei_area->rs, sei_area->rsid);
270 if (sei_area->rs != 4)
83b3370c 271 return;
f86635fa
PO
272 id = __get_chpid_from_lir(sei_area->ccdf);
273 if (id < 0)
184357a5 274 CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
f86635fa
PO
275 else {
276 chp_id_init(&chpid);
277 chpid.id = id;
e6b6e10a 278 chsc_chp_offline(chpid);
f86635fa 279 }
184357a5
PO
280}
281
83b3370c 282static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
1da177e4 283{
f97a56fb 284 struct res_acc_data res_data;
f86635fa 285 struct chp_id chpid;
184357a5 286 int status;
184357a5
PO
287
288 CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
289 "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
290 if (sei_area->rs != 4)
83b3370c 291 return;
f86635fa
PO
292 chp_id_init(&chpid);
293 chpid.id = sei_area->rsid;
184357a5 294 /* allocate a new channel path structure, if needed */
e6b6e10a 295 status = chp_get_status(chpid);
184357a5 296 if (status < 0)
e6b6e10a 297 chp_new(chpid);
184357a5 298 else if (!status)
83b3370c 299 return;
184357a5 300 memset(&res_data, 0, sizeof(struct res_acc_data));
e6b6e10a 301 res_data.chpid = chpid;
184357a5
PO
302 if ((sei_area->vf & 0xc0) != 0) {
303 res_data.fla = sei_area->fla;
304 if ((sei_area->vf & 0xc0) == 0xc0)
305 /* full link address */
306 res_data.fla_mask = 0xffff;
307 else
308 /* link address */
309 res_data.fla_mask = 0xff00;
310 }
83b3370c 311 s390_process_res_acc(&res_data);
184357a5
PO
312}
313
e5854a58
PO
314struct chp_config_data {
315 u8 map[32];
316 u8 op;
317 u8 pc;
318};
319
83b3370c 320static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area)
e5854a58
PO
321{
322 struct chp_config_data *data;
323 struct chp_id chpid;
324 int num;
325
326 CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n");
327 if (sei_area->rs != 0)
83b3370c 328 return;
e5854a58
PO
329 data = (struct chp_config_data *) &(sei_area->ccdf);
330 chp_id_init(&chpid);
331 for (num = 0; num <= __MAX_CHPID; num++) {
332 if (!chp_test_bit(data->map, num))
333 continue;
334 chpid.id = num;
335 printk(KERN_WARNING "cio: processing configure event %d for "
336 "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id);
337 switch (data->op) {
338 case 0:
339 chp_cfg_schedule(chpid, 1);
340 break;
341 case 1:
342 chp_cfg_schedule(chpid, 0);
343 break;
344 case 2:
345 chp_cfg_cancel_deconfigure(chpid);
346 break;
347 }
348 }
e5854a58
PO
349}
350
83b3370c 351static void chsc_process_sei(struct chsc_sei_area *sei_area)
184357a5 352{
184357a5 353 /* Check if we might have lost some information. */
83b3370c 354 if (sei_area->flags & 0x40) {
184357a5 355 CIO_CRW_EVENT(2, "chsc: event overflow\n");
83b3370c
PO
356 css_schedule_eval_all();
357 }
184357a5 358 /* which kind of information was stored? */
184357a5
PO
359 switch (sei_area->cc) {
360 case 1: /* link incident*/
83b3370c 361 chsc_process_sei_link_incident(sei_area);
184357a5
PO
362 break;
363 case 2: /* i/o resource accessibiliy */
83b3370c 364 chsc_process_sei_res_acc(sei_area);
184357a5 365 break;
e5854a58 366 case 8: /* channel-path-configuration notification */
83b3370c 367 chsc_process_sei_chp_config(sei_area);
e5854a58 368 break;
184357a5
PO
369 default: /* other stuff */
370 CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
371 sei_area->cc);
372 break;
373 }
184357a5
PO
374}
375
c1156189 376static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
184357a5
PO
377{
378 struct chsc_sei_area *sei_area;
1da177e4 379
c1156189
CH
380 if (overflow) {
381 css_schedule_eval_all();
382 return;
383 }
384 CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, "
385 "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
386 crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
387 crw0->erc, crw0->rsid);
1da177e4 388 if (!sei_page)
83b3370c 389 return;
184357a5
PO
390 /* Access to sei_page is serialized through machine check handler
391 * thread, so no need for locking. */
1da177e4
LT
392 sei_area = sei_page;
393
c1156189 394 CIO_TRACE_EVENT(2, "prcss");
1da177e4 395 do {
1da177e4 396 memset(sei_area, 0, sizeof(*sei_area));
495a5b45
CH
397 sei_area->request.length = 0x0010;
398 sei_area->request.code = 0x000e;
184357a5
PO
399 if (chsc(sei_area))
400 break;
1da177e4 401
184357a5
PO
402 if (sei_area->response.code == 0x0001) {
403 CIO_CRW_EVENT(4, "chsc: sei successful\n");
83b3370c 404 chsc_process_sei(sei_area);
184357a5
PO
405 } else {
406 CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
1da177e4 407 sei_area->response.code);
1da177e4
LT
408 break;
409 }
410 } while (sei_area->flags & 0x80);
1da177e4
LT
411}
412
83b3370c 413void chsc_chp_online(struct chp_id chpid)
f97a56fb 414{
1da177e4 415 char dbf_txt[15];
c820de39 416 struct res_acc_data res_data;
1da177e4 417
f86635fa 418 sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
1da177e4
LT
419 CIO_TRACE_EVENT(2, dbf_txt);
420
22806dc1 421 if (chp_get_status(chpid) != 0) {
c820de39
CH
422 memset(&res_data, 0, sizeof(struct res_acc_data));
423 res_data.chpid = chpid;
22806dc1
CH
424 /* Wait until previous actions have settled. */
425 css_wait_for_slow_path();
c820de39
CH
426 for_each_subchannel_staged(__s390_process_res_acc, NULL,
427 &res_data);
22806dc1 428 }
1da177e4
LT
429}
430
f86635fa
PO
431static void __s390_subchannel_vary_chpid(struct subchannel *sch,
432 struct chp_id chpid, int on)
1da177e4 433{
1da177e4 434 unsigned long flags;
c820de39 435 struct res_acc_data res_data;
1da177e4 436
c820de39
CH
437 memset(&res_data, 0, sizeof(struct res_acc_data));
438 res_data.chpid = chpid;
2ec22984 439 spin_lock_irqsave(sch->lock, flags);
c820de39
CH
440 if (sch->driver && sch->driver->chp_event)
441 sch->driver->chp_event(sch, &res_data,
442 on ? CHP_VARY_ON : CHP_VARY_OFF);
2ec22984 443 spin_unlock_irqrestore(sch->lock, flags);
1da177e4
LT
444}
445
e82a1567 446static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data)
1da177e4 447{
e82a1567 448 struct chp_id *chpid = data;
1da177e4
LT
449
450 __s390_subchannel_vary_chpid(sch, *chpid, 0);
451 return 0;
452}
453
e82a1567 454static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data)
1da177e4 455{
e82a1567 456 struct chp_id *chpid = data;
1da177e4
LT
457
458 __s390_subchannel_vary_chpid(sch, *chpid, 1);
459 return 0;
460}
461
f97a56fb
CH
462static int
463__s390_vary_chpid_on(struct subchannel_id schid, void *data)
464{
465 struct schib schib;
f97a56fb 466
fb6958a5 467 if (stsch_err(schid, &schib))
f97a56fb
CH
468 /* We're through */
469 return -ENXIO;
470 /* Put it on the slow path. */
83b3370c 471 css_schedule_eval(schid);
f97a56fb
CH
472 return 0;
473}
474
e6b6e10a
PO
475/**
476 * chsc_chp_vary - propagate channel-path vary operation to subchannels
477 * @chpid: channl-path ID
478 * @on: non-zero for vary online, zero for vary offline
1da177e4 479 */
e6b6e10a 480int chsc_chp_vary(struct chp_id chpid, int on)
1da177e4 481{
22806dc1
CH
482 /* Wait until previous actions have settled. */
483 css_wait_for_slow_path();
1da177e4
LT
484 /*
485 * Redo PathVerification on the devices the chpid connects to
486 */
487
f97a56fb 488 if (on)
e82a1567
PO
489 for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
490 __s390_vary_chpid_on, &chpid);
491 else
492 for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
493 NULL, &chpid);
494
1da177e4
LT
495 return 0;
496}
497
495a5b45
CH
498static void
499chsc_remove_cmg_attr(struct channel_subsystem *css)
500{
501 int i;
502
503 for (i = 0; i <= __MAX_CHPID; i++) {
504 if (!css->chps[i])
505 continue;
e6b6e10a 506 chp_remove_cmg_attr(css->chps[i]);
495a5b45
CH
507 }
508}
509
510static int
511chsc_add_cmg_attr(struct channel_subsystem *css)
512{
513 int i, ret;
514
515 ret = 0;
516 for (i = 0; i <= __MAX_CHPID; i++) {
517 if (!css->chps[i])
518 continue;
e6b6e10a 519 ret = chp_add_cmg_attr(css->chps[i]);
495a5b45
CH
520 if (ret)
521 goto cleanup;
522 }
523 return ret;
524cleanup:
525 for (--i; i >= 0; i--) {
526 if (!css->chps[i])
527 continue;
e6b6e10a 528 chp_remove_cmg_attr(css->chps[i]);
495a5b45
CH
529 }
530 return ret;
531}
532
495a5b45
CH
533static int
534__chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
535{
536 struct {
537 struct chsc_header request;
538 u32 operation_code : 2;
539 u32 : 30;
540 u32 key : 4;
541 u32 : 28;
542 u32 zeroes1;
543 u32 cub_addr1;
544 u32 zeroes2;
545 u32 cub_addr2;
546 u32 reserved[13];
547 struct chsc_header response;
548 u32 status : 8;
549 u32 : 4;
550 u32 fmt : 4;
551 u32 : 16;
0f008aa3 552 } __attribute__ ((packed)) *secm_area;
495a5b45
CH
553 int ret, ccode;
554
555 secm_area = page;
556 secm_area->request.length = 0x0050;
557 secm_area->request.code = 0x0016;
558
559 secm_area->key = PAGE_DEFAULT_KEY;
560 secm_area->cub_addr1 = (u64)(unsigned long)css->cub_addr1;
561 secm_area->cub_addr2 = (u64)(unsigned long)css->cub_addr2;
562
563 secm_area->operation_code = enable ? 0 : 1;
564
565 ccode = chsc(secm_area);
566 if (ccode > 0)
567 return (ccode == 3) ? -ENODEV : -EBUSY;
568
569 switch (secm_area->response.code) {
b9c9a21a
CH
570 case 0x0102:
571 case 0x0103:
495a5b45 572 ret = -EINVAL;
495a5b45 573 default:
b9c9a21a 574 ret = chsc_error_from_response(secm_area->response.code);
495a5b45 575 }
b9c9a21a
CH
576 if (ret != 0)
577 CIO_CRW_EVENT(2, "chsc: secm failed (rc=%04x)\n",
578 secm_area->response.code);
495a5b45
CH
579 return ret;
580}
581
582int
583chsc_secm(struct channel_subsystem *css, int enable)
584{
585 void *secm_area;
586 int ret;
587
588 secm_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
589 if (!secm_area)
590 return -ENOMEM;
591
495a5b45
CH
592 if (enable && !css->cm_enabled) {
593 css->cub_addr1 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
594 css->cub_addr2 = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
595 if (!css->cub_addr1 || !css->cub_addr2) {
596 free_page((unsigned long)css->cub_addr1);
597 free_page((unsigned long)css->cub_addr2);
598 free_page((unsigned long)secm_area);
495a5b45
CH
599 return -ENOMEM;
600 }
601 }
602 ret = __chsc_do_secm(css, enable, secm_area);
603 if (!ret) {
604 css->cm_enabled = enable;
605 if (css->cm_enabled) {
606 ret = chsc_add_cmg_attr(css);
607 if (ret) {
608 memset(secm_area, 0, PAGE_SIZE);
609 __chsc_do_secm(css, 0, secm_area);
610 css->cm_enabled = 0;
611 }
612 } else
613 chsc_remove_cmg_attr(css);
614 }
8c4941c5 615 if (!css->cm_enabled) {
495a5b45
CH
616 free_page((unsigned long)css->cub_addr1);
617 free_page((unsigned long)css->cub_addr2);
618 }
495a5b45
CH
619 free_page((unsigned long)secm_area);
620 return ret;
621}
622
e6b6e10a
PO
623int chsc_determine_channel_path_description(struct chp_id chpid,
624 struct channel_path_desc *desc)
1da177e4
LT
625{
626 int ccode, ret;
627
628 struct {
629 struct chsc_header request;
630 u32 : 24;
631 u32 first_chpid : 8;
632 u32 : 24;
633 u32 last_chpid : 8;
634 u32 zeroes1;
635 struct chsc_header response;
636 u32 zeroes2;
637 struct channel_path_desc desc;
0f008aa3 638 } __attribute__ ((packed)) *scpd_area;
1da177e4
LT
639
640 scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
641 if (!scpd_area)
642 return -ENOMEM;
643
495a5b45
CH
644 scpd_area->request.length = 0x0010;
645 scpd_area->request.code = 0x0002;
1da177e4 646
f86635fa
PO
647 scpd_area->first_chpid = chpid.id;
648 scpd_area->last_chpid = chpid.id;
1da177e4
LT
649
650 ccode = chsc(scpd_area);
651 if (ccode > 0) {
652 ret = (ccode == 3) ? -ENODEV : -EBUSY;
653 goto out;
654 }
655
b9c9a21a
CH
656 ret = chsc_error_from_response(scpd_area->response.code);
657 if (ret == 0)
658 /* Success. */
1da177e4
LT
659 memcpy(desc, &scpd_area->desc,
660 sizeof(struct channel_path_desc));
b9c9a21a
CH
661 else
662 CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
1da177e4 663 scpd_area->response.code);
1da177e4
LT
664out:
665 free_page((unsigned long)scpd_area);
666 return ret;
667}
668
495a5b45
CH
669static void
670chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
671 struct cmg_chars *chars)
672{
673 switch (chp->cmg) {
674 case 2:
675 case 3:
676 chp->cmg_chars = kmalloc(sizeof(struct cmg_chars),
677 GFP_KERNEL);
678 if (chp->cmg_chars) {
679 int i, mask;
680 struct cmg_chars *cmg_chars;
681
682 cmg_chars = chp->cmg_chars;
683 for (i = 0; i < NR_MEASUREMENT_CHARS; i++) {
684 mask = 0x80 >> (i + 3);
685 if (cmcv & mask)
686 cmg_chars->values[i] = chars->values[i];
687 else
688 cmg_chars->values[i] = 0;
689 }
690 }
691 break;
692 default:
693 /* No cmg-dependent data. */
694 break;
695 }
696}
697
e6b6e10a 698int chsc_get_channel_measurement_chars(struct channel_path *chp)
495a5b45
CH
699{
700 int ccode, ret;
701
702 struct {
703 struct chsc_header request;
704 u32 : 24;
705 u32 first_chpid : 8;
706 u32 : 24;
707 u32 last_chpid : 8;
708 u32 zeroes1;
709 struct chsc_header response;
710 u32 zeroes2;
711 u32 not_valid : 1;
712 u32 shared : 1;
713 u32 : 22;
714 u32 chpid : 8;
715 u32 cmcv : 5;
716 u32 : 11;
717 u32 cmgq : 8;
718 u32 cmg : 8;
719 u32 zeroes3;
720 u32 data[NR_MEASUREMENT_CHARS];
0f008aa3 721 } __attribute__ ((packed)) *scmc_area;
495a5b45
CH
722
723 scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
724 if (!scmc_area)
725 return -ENOMEM;
726
727 scmc_area->request.length = 0x0010;
728 scmc_area->request.code = 0x0022;
729
f86635fa
PO
730 scmc_area->first_chpid = chp->chpid.id;
731 scmc_area->last_chpid = chp->chpid.id;
495a5b45
CH
732
733 ccode = chsc(scmc_area);
734 if (ccode > 0) {
735 ret = (ccode == 3) ? -ENODEV : -EBUSY;
736 goto out;
737 }
738
b9c9a21a
CH
739 ret = chsc_error_from_response(scmc_area->response.code);
740 if (ret == 0) {
741 /* Success. */
495a5b45
CH
742 if (!scmc_area->not_valid) {
743 chp->cmg = scmc_area->cmg;
744 chp->shared = scmc_area->shared;
745 chsc_initialize_cmg_chars(chp, scmc_area->cmcv,
746 (struct cmg_chars *)
747 &scmc_area->data);
748 } else {
749 chp->cmg = -1;
750 chp->shared = -1;
751 }
b9c9a21a
CH
752 } else {
753 CIO_CRW_EVENT(2, "chsc: scmc failed (rc=%04x)\n",
495a5b45 754 scmc_area->response.code);
495a5b45
CH
755 }
756out:
757 free_page((unsigned long)scmc_area);
758 return ret;
759}
760
4434a38c 761int __init chsc_alloc_sei_area(void)
1da177e4 762{
c1156189
CH
763 int ret;
764
1da177e4 765 sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
c1156189 766 if (!sei_page) {
e556bbbd
CH
767 CIO_MSG_EVENT(0, "Can't allocate page for processing of "
768 "chsc machine checks!\n");
c1156189
CH
769 return -ENOMEM;
770 }
771 ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw);
772 if (ret)
773 kfree(sei_page);
774 return ret;
1da177e4
LT
775}
776
4434a38c
CH
777void __init chsc_free_sei_area(void)
778{
c1156189 779 s390_unregister_crw_handler(CRW_RSC_CSS);
4434a38c
CH
780 kfree(sei_page);
781}
782
fb6958a5
CH
783int __init
784chsc_enable_facility(int operation_code)
785{
786 int ret;
787 struct {
788 struct chsc_header request;
789 u8 reserved1:4;
790 u8 format:4;
791 u8 reserved2;
792 u16 operation_code;
793 u32 reserved3;
794 u32 reserved4;
795 u32 operation_data_area[252];
796 struct chsc_header response;
797 u32 reserved5:4;
798 u32 format2:4;
799 u32 reserved6:24;
0f008aa3 800 } __attribute__ ((packed)) *sda_area;
fb6958a5
CH
801
802 sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
803 if (!sda_area)
804 return -ENOMEM;
495a5b45
CH
805 sda_area->request.length = 0x0400;
806 sda_area->request.code = 0x0031;
fb6958a5
CH
807 sda_area->operation_code = operation_code;
808
809 ret = chsc(sda_area);
810 if (ret > 0) {
811 ret = (ret == 3) ? -ENODEV : -EBUSY;
812 goto out;
813 }
b9c9a21a 814
fb6958a5 815 switch (sda_area->response.code) {
b9c9a21a 816 case 0x0101:
fb6958a5
CH
817 ret = -EOPNOTSUPP;
818 break;
b9c9a21a
CH
819 default:
820 ret = chsc_error_from_response(sda_area->response.code);
fb6958a5 821 }
b9c9a21a
CH
822 if (ret != 0)
823 CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
824 operation_code, sda_area->response.code);
fb6958a5
CH
825 out:
826 free_page((unsigned long)sda_area);
827 return ret;
828}
829
1da177e4
LT
830struct css_general_char css_general_characteristics;
831struct css_chsc_char css_chsc_characteristics;
832
833int __init
834chsc_determine_css_characteristics(void)
835{
836 int result;
837 struct {
838 struct chsc_header request;
839 u32 reserved1;
840 u32 reserved2;
841 u32 reserved3;
842 struct chsc_header response;
843 u32 reserved4;
844 u32 general_char[510];
845 u32 chsc_char[518];
0f008aa3 846 } __attribute__ ((packed)) *scsc_area;
1da177e4
LT
847
848 scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
b9c9a21a 849 if (!scsc_area)
1da177e4 850 return -ENOMEM;
1da177e4 851
495a5b45
CH
852 scsc_area->request.length = 0x0010;
853 scsc_area->request.code = 0x0010;
1da177e4
LT
854
855 result = chsc(scsc_area);
856 if (result) {
b9c9a21a 857 result = (result == 3) ? -ENODEV : -EBUSY;
1da177e4
LT
858 goto exit;
859 }
860
b9c9a21a
CH
861 result = chsc_error_from_response(scsc_area->response.code);
862 if (result == 0) {
863 memcpy(&css_general_characteristics, scsc_area->general_char,
864 sizeof(css_general_characteristics));
865 memcpy(&css_chsc_characteristics, scsc_area->chsc_char,
866 sizeof(css_chsc_characteristics));
867 } else
868 CIO_CRW_EVENT(2, "chsc: scsc failed (rc=%04x)\n",
869 scsc_area->response.code);
1da177e4
LT
870exit:
871 free_page ((unsigned long) scsc_area);
872 return result;
873}
874
875EXPORT_SYMBOL_GPL(css_general_characteristics);
876EXPORT_SYMBOL_GPL(css_chsc_characteristics);
d2fec595
MS
877
878int chsc_sstpc(void *page, unsigned int op, u16 ctrl)
879{
880 struct {
881 struct chsc_header request;
882 unsigned int rsvd0;
883 unsigned int op : 8;
884 unsigned int rsvd1 : 8;
885 unsigned int ctrl : 16;
886 unsigned int rsvd2[5];
887 struct chsc_header response;
888 unsigned int rsvd3[7];
889 } __attribute__ ((packed)) *rr;
890 int rc;
891
892 memset(page, 0, PAGE_SIZE);
893 rr = page;
894 rr->request.length = 0x0020;
895 rr->request.code = 0x0033;
896 rr->op = op;
897 rr->ctrl = ctrl;
898 rc = chsc(rr);
899 if (rc)
900 return -EIO;
901 rc = (rr->response.code == 0x0001) ? 0 : -EIO;
902 return rc;
903}
904
905int chsc_sstpi(void *page, void *result, size_t size)
906{
907 struct {
908 struct chsc_header request;
909 unsigned int rsvd0[3];
910 struct chsc_header response;
911 char data[size];
912 } __attribute__ ((packed)) *rr;
913 int rc;
914
915 memset(page, 0, PAGE_SIZE);
916 rr = page;
917 rr->request.length = 0x0010;
918 rr->request.code = 0x0038;
919 rc = chsc(rr);
920 if (rc)
921 return -EIO;
922 memcpy(result, &rr->data, size);
923 return (rr->response.code == 0x0001) ? 0 : -EIO;
924}
925