Merge tag 'v1.6.0' into tizen_qemu_1.6
[sdk/emulator/qemu.git] / target-s390x / ioinst.c
1 /*
2  * I/O instructions for S/390
3  *
4  * Copyright 2012 IBM Corp.
5  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2 or (at
8  * your option) any later version. See the COPYING file in the top-level
9  * directory.
10  */
11
12 #include <sys/types.h>
13
14 #include "cpu.h"
15 #include "ioinst.h"
16 #include "trace.h"
17
18 int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
19                                  int *schid)
20 {
21     if (!IOINST_SCHID_ONE(value)) {
22         return -EINVAL;
23     }
24     if (!IOINST_SCHID_M(value)) {
25         if (IOINST_SCHID_CSSID(value)) {
26             return -EINVAL;
27         }
28         *cssid = 0;
29         *m = 0;
30     } else {
31         *cssid = IOINST_SCHID_CSSID(value);
32         *m = 1;
33     }
34     *ssid = IOINST_SCHID_SSID(value);
35     *schid = IOINST_SCHID_NR(value);
36     return 0;
37 }
38
39 int ioinst_handle_xsch(CPUS390XState *env, uint64_t reg1)
40 {
41     int cssid, ssid, schid, m;
42     SubchDev *sch;
43     int ret = -ENODEV;
44     int cc;
45
46     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
47         program_interrupt(env, PGM_OPERAND, 2);
48         return -EIO;
49     }
50     trace_ioinst_sch_id("xsch", cssid, ssid, schid);
51     sch = css_find_subch(m, cssid, ssid, schid);
52     if (sch && css_subch_visible(sch)) {
53         ret = css_do_xsch(sch);
54     }
55     switch (ret) {
56     case -ENODEV:
57         cc = 3;
58         break;
59     case -EBUSY:
60         cc = 2;
61         break;
62     case 0:
63         cc = 0;
64         break;
65     default:
66         cc = 1;
67         break;
68     }
69
70     return cc;
71 }
72
73 int ioinst_handle_csch(CPUS390XState *env, uint64_t reg1)
74 {
75     int cssid, ssid, schid, m;
76     SubchDev *sch;
77     int ret = -ENODEV;
78     int cc;
79
80     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
81         program_interrupt(env, PGM_OPERAND, 2);
82         return -EIO;
83     }
84     trace_ioinst_sch_id("csch", cssid, ssid, schid);
85     sch = css_find_subch(m, cssid, ssid, schid);
86     if (sch && css_subch_visible(sch)) {
87         ret = css_do_csch(sch);
88     }
89     if (ret == -ENODEV) {
90         cc = 3;
91     } else {
92         cc = 0;
93     }
94     return cc;
95 }
96
97 int ioinst_handle_hsch(CPUS390XState *env, uint64_t reg1)
98 {
99     int cssid, ssid, schid, m;
100     SubchDev *sch;
101     int ret = -ENODEV;
102     int cc;
103
104     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
105         program_interrupt(env, PGM_OPERAND, 2);
106         return -EIO;
107     }
108     trace_ioinst_sch_id("hsch", cssid, ssid, schid);
109     sch = css_find_subch(m, cssid, ssid, schid);
110     if (sch && css_subch_visible(sch)) {
111         ret = css_do_hsch(sch);
112     }
113     switch (ret) {
114     case -ENODEV:
115         cc = 3;
116         break;
117     case -EBUSY:
118         cc = 2;
119         break;
120     case 0:
121         cc = 0;
122         break;
123     default:
124         cc = 1;
125         break;
126     }
127
128     return cc;
129 }
130
131 static int ioinst_schib_valid(SCHIB *schib)
132 {
133     if ((schib->pmcw.flags & PMCW_FLAGS_MASK_INVALID) ||
134         (schib->pmcw.chars & PMCW_CHARS_MASK_INVALID)) {
135         return 0;
136     }
137     /* Disallow extended measurements for now. */
138     if (schib->pmcw.chars & PMCW_CHARS_MASK_XMWME) {
139         return 0;
140     }
141     return 1;
142 }
143
144 int ioinst_handle_msch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
145 {
146     int cssid, ssid, schid, m;
147     SubchDev *sch;
148     SCHIB *schib;
149     uint64_t addr;
150     int ret = -ENODEV;
151     int cc;
152     hwaddr len = sizeof(*schib);
153
154     addr = decode_basedisp_s(env, ipb);
155     if (addr & 3) {
156         program_interrupt(env, PGM_SPECIFICATION, 2);
157         return -EIO;
158     }
159     schib = s390_cpu_physical_memory_map(env, addr, &len, 0);
160     if (!schib || len != sizeof(*schib)) {
161         program_interrupt(env, PGM_ADDRESSING, 2);
162         cc = -EIO;
163         goto out;
164     }
165     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
166         !ioinst_schib_valid(schib)) {
167         program_interrupt(env, PGM_OPERAND, 2);
168         cc = -EIO;
169         goto out;
170     }
171     trace_ioinst_sch_id("msch", cssid, ssid, schid);
172     sch = css_find_subch(m, cssid, ssid, schid);
173     if (sch && css_subch_visible(sch)) {
174         ret = css_do_msch(sch, schib);
175     }
176     switch (ret) {
177     case -ENODEV:
178         cc = 3;
179         break;
180     case -EBUSY:
181         cc = 2;
182         break;
183     case 0:
184         cc = 0;
185         break;
186     default:
187         cc = 1;
188         break;
189     }
190 out:
191     s390_cpu_physical_memory_unmap(env, schib, len, 0);
192     return cc;
193 }
194
195 static void copy_orb_from_guest(ORB *dest, const ORB *src)
196 {
197     dest->intparm = be32_to_cpu(src->intparm);
198     dest->ctrl0 = be16_to_cpu(src->ctrl0);
199     dest->lpm = src->lpm;
200     dest->ctrl1 = src->ctrl1;
201     dest->cpa = be32_to_cpu(src->cpa);
202 }
203
204 static int ioinst_orb_valid(ORB *orb)
205 {
206     if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) ||
207         (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) {
208         return 0;
209     }
210     if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
211         return 0;
212     }
213     return 1;
214 }
215
216 int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
217 {
218     int cssid, ssid, schid, m;
219     SubchDev *sch;
220     ORB *orig_orb, orb;
221     uint64_t addr;
222     int ret = -ENODEV;
223     int cc;
224     hwaddr len = sizeof(*orig_orb);
225
226     addr = decode_basedisp_s(env, ipb);
227     if (addr & 3) {
228         program_interrupt(env, PGM_SPECIFICATION, 2);
229         return -EIO;
230     }
231     orig_orb = s390_cpu_physical_memory_map(env, addr, &len, 0);
232     if (!orig_orb || len != sizeof(*orig_orb)) {
233         program_interrupt(env, PGM_ADDRESSING, 2);
234         cc = -EIO;
235         goto out;
236     }
237     copy_orb_from_guest(&orb, orig_orb);
238     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
239         !ioinst_orb_valid(&orb)) {
240         program_interrupt(env, PGM_OPERAND, 2);
241         cc = -EIO;
242         goto out;
243     }
244     trace_ioinst_sch_id("ssch", cssid, ssid, schid);
245     sch = css_find_subch(m, cssid, ssid, schid);
246     if (sch && css_subch_visible(sch)) {
247         ret = css_do_ssch(sch, &orb);
248     }
249     switch (ret) {
250     case -ENODEV:
251         cc = 3;
252         break;
253     case -EBUSY:
254         cc = 2;
255         break;
256     case 0:
257         cc = 0;
258         break;
259     default:
260         cc = 1;
261         break;
262     }
263
264 out:
265     s390_cpu_physical_memory_unmap(env, orig_orb, len, 0);
266     return cc;
267 }
268
269 int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb)
270 {
271     CRW *crw;
272     uint64_t addr;
273     int cc;
274     hwaddr len = sizeof(*crw);
275
276     addr = decode_basedisp_s(env, ipb);
277     if (addr & 3) {
278         program_interrupt(env, PGM_SPECIFICATION, 2);
279         return -EIO;
280     }
281     crw = s390_cpu_physical_memory_map(env, addr, &len, 1);
282     if (!crw || len != sizeof(*crw)) {
283         program_interrupt(env, PGM_ADDRESSING, 2);
284         cc = -EIO;
285         goto out;
286     }
287     cc = css_do_stcrw(crw);
288     /* 0 - crw stored, 1 - zeroes stored */
289 out:
290     s390_cpu_physical_memory_unmap(env, crw, len, 1);
291     return cc;
292 }
293
294 int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
295 {
296     int cssid, ssid, schid, m;
297     SubchDev *sch;
298     uint64_t addr;
299     int cc;
300     SCHIB *schib;
301     hwaddr len = sizeof(*schib);
302
303     addr = decode_basedisp_s(env, ipb);
304     if (addr & 3) {
305         program_interrupt(env, PGM_SPECIFICATION, 2);
306         return -EIO;
307     }
308     schib = s390_cpu_physical_memory_map(env, addr, &len, 1);
309     if (!schib || len != sizeof(*schib)) {
310         program_interrupt(env, PGM_ADDRESSING, 2);
311         cc = -EIO;
312         goto out;
313     }
314
315     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
316         program_interrupt(env, PGM_OPERAND, 2);
317         cc = -EIO;
318         goto out;
319     }
320     trace_ioinst_sch_id("stsch", cssid, ssid, schid);
321     sch = css_find_subch(m, cssid, ssid, schid);
322     if (sch) {
323         if (css_subch_visible(sch)) {
324             css_do_stsch(sch, schib);
325             cc = 0;
326         } else {
327             /* Indicate no more subchannels in this css/ss */
328             cc = 3;
329         }
330     } else {
331         if (css_schid_final(m, cssid, ssid, schid)) {
332             cc = 3; /* No more subchannels in this css/ss */
333         } else {
334             /* Store an empty schib. */
335             memset(schib, 0, sizeof(*schib));
336             cc = 0;
337         }
338     }
339 out:
340     s390_cpu_physical_memory_unmap(env, schib, len, 1);
341     return cc;
342 }
343
344 int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
345 {
346     int cssid, ssid, schid, m;
347     SubchDev *sch;
348     IRB *irb;
349     uint64_t addr;
350     int ret = -ENODEV;
351     int cc;
352     hwaddr len = sizeof(*irb);
353
354     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
355         program_interrupt(env, PGM_OPERAND, 2);
356         return -EIO;
357     }
358     trace_ioinst_sch_id("tsch", cssid, ssid, schid);
359     addr = decode_basedisp_s(env, ipb);
360     if (addr & 3) {
361         program_interrupt(env, PGM_SPECIFICATION, 2);
362         return -EIO;
363     }
364     irb = s390_cpu_physical_memory_map(env, addr, &len, 1);
365     if (!irb || len != sizeof(*irb)) {
366         program_interrupt(env, PGM_ADDRESSING, 2);
367         cc = -EIO;
368         goto out;
369     }
370     sch = css_find_subch(m, cssid, ssid, schid);
371     if (sch && css_subch_visible(sch)) {
372         ret = css_do_tsch(sch, irb);
373         /* 0 - status pending, 1 - not status pending */
374         cc = ret;
375     } else {
376         cc = 3;
377     }
378 out:
379     s390_cpu_physical_memory_unmap(env, irb, sizeof(*irb), 1);
380     return cc;
381 }
382
383 typedef struct ChscReq {
384     uint16_t len;
385     uint16_t command;
386     uint32_t param0;
387     uint32_t param1;
388     uint32_t param2;
389 } QEMU_PACKED ChscReq;
390
391 typedef struct ChscResp {
392     uint16_t len;
393     uint16_t code;
394     uint32_t param;
395     char data[0];
396 } QEMU_PACKED ChscResp;
397
398 #define CHSC_MIN_RESP_LEN 0x0008
399
400 #define CHSC_SCPD 0x0002
401 #define CHSC_SCSC 0x0010
402 #define CHSC_SDA  0x0031
403
404 #define CHSC_SCPD_0_M 0x20000000
405 #define CHSC_SCPD_0_C 0x10000000
406 #define CHSC_SCPD_0_FMT 0x0f000000
407 #define CHSC_SCPD_0_CSSID 0x00ff0000
408 #define CHSC_SCPD_0_RFMT 0x00000f00
409 #define CHSC_SCPD_0_RES 0xc000f000
410 #define CHSC_SCPD_1_RES 0xffffff00
411 #define CHSC_SCPD_01_CHPID 0x000000ff
412 static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
413 {
414     uint16_t len = be16_to_cpu(req->len);
415     uint32_t param0 = be32_to_cpu(req->param0);
416     uint32_t param1 = be32_to_cpu(req->param1);
417     uint16_t resp_code;
418     int rfmt;
419     uint16_t cssid;
420     uint8_t f_chpid, l_chpid;
421     int desc_size;
422     int m;
423
424     rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
425     if ((rfmt == 0) ||  (rfmt == 1)) {
426         rfmt = !!(param0 & CHSC_SCPD_0_C);
427     }
428     if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
429         (param1 & CHSC_SCPD_1_RES) || req->param2) {
430         resp_code = 0x0003;
431         goto out_err;
432     }
433     if (param0 & CHSC_SCPD_0_FMT) {
434         resp_code = 0x0007;
435         goto out_err;
436     }
437     cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
438     m = param0 & CHSC_SCPD_0_M;
439     if (cssid != 0) {
440         if (!m || !css_present(cssid)) {
441             resp_code = 0x0008;
442             goto out_err;
443         }
444     }
445     f_chpid = param0 & CHSC_SCPD_01_CHPID;
446     l_chpid = param1 & CHSC_SCPD_01_CHPID;
447     if (l_chpid < f_chpid) {
448         resp_code = 0x0003;
449         goto out_err;
450     }
451     /* css_collect_chp_desc() is endian-aware */
452     desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
453                                      &res->data);
454     res->code = cpu_to_be16(0x0001);
455     res->len = cpu_to_be16(8 + desc_size);
456     res->param = cpu_to_be32(rfmt);
457     return;
458
459   out_err:
460     res->code = cpu_to_be16(resp_code);
461     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
462     res->param = cpu_to_be32(rfmt);
463 }
464
465 #define CHSC_SCSC_0_M 0x20000000
466 #define CHSC_SCSC_0_FMT 0x000f0000
467 #define CHSC_SCSC_0_CSSID 0x0000ff00
468 #define CHSC_SCSC_0_RES 0xdff000ff
469 static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
470 {
471     uint16_t len = be16_to_cpu(req->len);
472     uint32_t param0 = be32_to_cpu(req->param0);
473     uint8_t cssid;
474     uint16_t resp_code;
475     uint32_t general_chars[510];
476     uint32_t chsc_chars[508];
477
478     if (len != 0x0010) {
479         resp_code = 0x0003;
480         goto out_err;
481     }
482
483     if (param0 & CHSC_SCSC_0_FMT) {
484         resp_code = 0x0007;
485         goto out_err;
486     }
487     cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
488     if (cssid != 0) {
489         if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
490             resp_code = 0x0008;
491             goto out_err;
492         }
493     }
494     if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
495         resp_code = 0x0003;
496         goto out_err;
497     }
498     res->code = cpu_to_be16(0x0001);
499     res->len = cpu_to_be16(4080);
500     res->param = 0;
501
502     memset(general_chars, 0, sizeof(general_chars));
503     memset(chsc_chars, 0, sizeof(chsc_chars));
504
505     general_chars[0] = cpu_to_be32(0x03000000);
506     general_chars[1] = cpu_to_be32(0x00059000);
507
508     chsc_chars[0] = cpu_to_be32(0x40000000);
509     chsc_chars[3] = cpu_to_be32(0x00040000);
510
511     memcpy(res->data, general_chars, sizeof(general_chars));
512     memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
513     return;
514
515   out_err:
516     res->code = cpu_to_be16(resp_code);
517     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
518     res->param = 0;
519 }
520
521 #define CHSC_SDA_0_FMT 0x0f000000
522 #define CHSC_SDA_0_OC 0x0000ffff
523 #define CHSC_SDA_0_RES 0xf0ff0000
524 #define CHSC_SDA_OC_MCSSE 0x0
525 #define CHSC_SDA_OC_MSS 0x2
526 static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
527 {
528     uint16_t resp_code = 0x0001;
529     uint16_t len = be16_to_cpu(req->len);
530     uint32_t param0 = be32_to_cpu(req->param0);
531     uint16_t oc;
532     int ret;
533
534     if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
535         resp_code = 0x0003;
536         goto out;
537     }
538
539     if (param0 & CHSC_SDA_0_FMT) {
540         resp_code = 0x0007;
541         goto out;
542     }
543
544     oc = param0 & CHSC_SDA_0_OC;
545     switch (oc) {
546     case CHSC_SDA_OC_MCSSE:
547         ret = css_enable_mcsse();
548         if (ret == -EINVAL) {
549             resp_code = 0x0101;
550             goto out;
551         }
552         break;
553     case CHSC_SDA_OC_MSS:
554         ret = css_enable_mss();
555         if (ret == -EINVAL) {
556             resp_code = 0x0101;
557             goto out;
558         }
559         break;
560     default:
561         resp_code = 0x0003;
562         goto out;
563     }
564
565 out:
566     res->code = cpu_to_be16(resp_code);
567     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
568     res->param = 0;
569 }
570
571 static void ioinst_handle_chsc_unimplemented(ChscResp *res)
572 {
573     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
574     res->code = cpu_to_be16(0x0004);
575     res->param = 0;
576 }
577
578 int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
579 {
580     ChscReq *req;
581     ChscResp *res;
582     uint64_t addr;
583     int reg;
584     uint16_t len;
585     uint16_t command;
586     hwaddr map_size = TARGET_PAGE_SIZE;
587     int ret = 0;
588
589     trace_ioinst("chsc");
590     reg = (ipb >> 20) & 0x00f;
591     addr = env->regs[reg];
592     /* Page boundary? */
593     if (addr & 0xfff) {
594         program_interrupt(env, PGM_SPECIFICATION, 2);
595         return -EIO;
596     }
597     req = s390_cpu_physical_memory_map(env, addr, &map_size, 1);
598     if (!req || map_size != TARGET_PAGE_SIZE) {
599         program_interrupt(env, PGM_ADDRESSING, 2);
600         ret = -EIO;
601         goto out;
602     }
603     len = be16_to_cpu(req->len);
604     /* Length field valid? */
605     if ((len < 16) || (len > 4088) || (len & 7)) {
606         program_interrupt(env, PGM_OPERAND, 2);
607         ret = -EIO;
608         goto out;
609     }
610     memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
611     res = (void *)((char *)req + len);
612     command = be16_to_cpu(req->command);
613     trace_ioinst_chsc_cmd(command, len);
614     switch (command) {
615     case CHSC_SCSC:
616         ioinst_handle_chsc_scsc(req, res);
617         break;
618     case CHSC_SCPD:
619         ioinst_handle_chsc_scpd(req, res);
620         break;
621     case CHSC_SDA:
622         ioinst_handle_chsc_sda(req, res);
623         break;
624     default:
625         ioinst_handle_chsc_unimplemented(res);
626         break;
627     }
628
629 out:
630     s390_cpu_physical_memory_unmap(env, req, map_size, 1);
631     return ret;
632 }
633
634 int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb)
635 {
636     uint64_t addr;
637     int lowcore;
638     IOIntCode *int_code;
639     hwaddr len, orig_len;
640     int ret;
641
642     trace_ioinst("tpi");
643     addr = decode_basedisp_s(env, ipb);
644     if (addr & 3) {
645         program_interrupt(env, PGM_SPECIFICATION, 2);
646         return -EIO;
647     }
648
649     lowcore = addr ? 0 : 1;
650     len = lowcore ? 8 /* two words */ : 12 /* three words */;
651     orig_len = len;
652     int_code = s390_cpu_physical_memory_map(env, addr, &len, 1);
653     if (!int_code || (len != orig_len)) {
654         program_interrupt(env, PGM_ADDRESSING, 2);
655         ret = -EIO;
656         goto out;
657     }
658     ret = css_do_tpi(int_code, lowcore);
659 out:
660     s390_cpu_physical_memory_unmap(env, int_code, len, 1);
661     return ret;
662 }
663
664 #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
665 #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
666 #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
667 #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
668
669 int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
670                        uint32_t ipb)
671 {
672     uint8_t mbk;
673     int update;
674     int dct;
675
676     trace_ioinst("schm");
677
678     if (SCHM_REG1_RES(reg1)) {
679         program_interrupt(env, PGM_OPERAND, 2);
680         return -EIO;
681     }
682
683     mbk = SCHM_REG1_MBK(reg1);
684     update = SCHM_REG1_UPD(reg1);
685     dct = SCHM_REG1_DCT(reg1);
686
687     if (update && (reg2 & 0x000000000000001f)) {
688         program_interrupt(env, PGM_OPERAND, 2);
689         return -EIO;
690     }
691
692     css_do_schm(mbk, update, dct, update ? reg2 : 0);
693
694     return 0;
695 }
696
697 int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
698 {
699     int cssid, ssid, schid, m;
700     SubchDev *sch;
701     int ret = -ENODEV;
702     int cc;
703
704     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
705         program_interrupt(env, PGM_OPERAND, 2);
706         return -EIO;
707     }
708     trace_ioinst_sch_id("rsch", cssid, ssid, schid);
709     sch = css_find_subch(m, cssid, ssid, schid);
710     if (sch && css_subch_visible(sch)) {
711         ret = css_do_rsch(sch);
712     }
713     switch (ret) {
714     case -ENODEV:
715         cc = 3;
716         break;
717     case -EINVAL:
718         cc = 2;
719         break;
720     case 0:
721         cc = 0;
722         break;
723     default:
724         cc = 1;
725         break;
726     }
727
728     return cc;
729
730 }
731
732 #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
733 #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
734 #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
735 int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
736 {
737     int cc;
738     uint8_t cssid;
739     uint8_t chpid;
740     int ret;
741
742     if (RCHP_REG1_RES(reg1)) {
743         program_interrupt(env, PGM_OPERAND, 2);
744         return -EIO;
745     }
746
747     cssid = RCHP_REG1_CSSID(reg1);
748     chpid = RCHP_REG1_CHPID(reg1);
749
750     trace_ioinst_chp_id("rchp", cssid, chpid);
751
752     ret = css_do_rchp(cssid, chpid);
753
754     switch (ret) {
755     case -ENODEV:
756         cc = 3;
757         break;
758     case -EBUSY:
759         cc = 2;
760         break;
761     case 0:
762         cc = 0;
763         break;
764     default:
765         /* Invalid channel subsystem. */
766         program_interrupt(env, PGM_OPERAND, 2);
767         return -EIO;
768     }
769
770     return cc;
771 }
772
773 #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
774 int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1)
775 {
776     /* We do not provide address limit checking, so let's suppress it. */
777     if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
778         program_interrupt(env, PGM_OPERAND, 2);
779         return -EIO;
780     }
781     return 0;
782 }