s390/css: Fix subchannel detection
[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     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
155         program_interrupt(env, PGM_OPERAND, 2);
156         return -EIO;
157     }
158     trace_ioinst_sch_id("msch", cssid, ssid, schid);
159     addr = decode_basedisp_s(env, ipb);
160     schib = s390_cpu_physical_memory_map(env, addr, &len, 0);
161     if (!schib || len != sizeof(*schib)) {
162         program_interrupt(env, PGM_SPECIFICATION, 2);
163         cc = -EIO;
164         goto out;
165     }
166     if (!ioinst_schib_valid(schib)) {
167         program_interrupt(env, PGM_OPERAND, 2);
168         cc = -EIO;
169         goto out;
170     }
171     sch = css_find_subch(m, cssid, ssid, schid);
172     if (sch && css_subch_visible(sch)) {
173         ret = css_do_msch(sch, schib);
174     }
175     switch (ret) {
176     case -ENODEV:
177         cc = 3;
178         break;
179     case -EBUSY:
180         cc = 2;
181         break;
182     case 0:
183         cc = 0;
184         break;
185     default:
186         cc = 1;
187         break;
188     }
189 out:
190     s390_cpu_physical_memory_unmap(env, schib, len, 0);
191     return cc;
192 }
193
194 static void copy_orb_from_guest(ORB *dest, const ORB *src)
195 {
196     dest->intparm = be32_to_cpu(src->intparm);
197     dest->ctrl0 = be16_to_cpu(src->ctrl0);
198     dest->lpm = src->lpm;
199     dest->ctrl1 = src->ctrl1;
200     dest->cpa = be32_to_cpu(src->cpa);
201 }
202
203 static int ioinst_orb_valid(ORB *orb)
204 {
205     if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) ||
206         (orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) {
207         return 0;
208     }
209     if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
210         return 0;
211     }
212     return 1;
213 }
214
215 int ioinst_handle_ssch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
216 {
217     int cssid, ssid, schid, m;
218     SubchDev *sch;
219     ORB *orig_orb, orb;
220     uint64_t addr;
221     int ret = -ENODEV;
222     int cc;
223     hwaddr len = sizeof(*orig_orb);
224
225     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
226         program_interrupt(env, PGM_OPERAND, 2);
227         return -EIO;
228     }
229     trace_ioinst_sch_id("ssch", cssid, ssid, schid);
230     addr = decode_basedisp_s(env, ipb);
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_SPECIFICATION, 2);
234         cc = -EIO;
235         goto out;
236     }
237     copy_orb_from_guest(&orb, orig_orb);
238     if (!ioinst_orb_valid(&orb)) {
239         program_interrupt(env, PGM_OPERAND, 2);
240         cc = -EIO;
241         goto out;
242     }
243     sch = css_find_subch(m, cssid, ssid, schid);
244     if (sch && css_subch_visible(sch)) {
245         ret = css_do_ssch(sch, &orb);
246     }
247     switch (ret) {
248     case -ENODEV:
249         cc = 3;
250         break;
251     case -EBUSY:
252         cc = 2;
253         break;
254     case 0:
255         cc = 0;
256         break;
257     default:
258         cc = 1;
259         break;
260     }
261
262 out:
263     s390_cpu_physical_memory_unmap(env, orig_orb, len, 0);
264     return cc;
265 }
266
267 int ioinst_handle_stcrw(CPUS390XState *env, uint32_t ipb)
268 {
269     CRW *crw;
270     uint64_t addr;
271     int cc;
272     hwaddr len = sizeof(*crw);
273
274     addr = decode_basedisp_s(env, ipb);
275     crw = s390_cpu_physical_memory_map(env, addr, &len, 1);
276     if (!crw || len != sizeof(*crw)) {
277         program_interrupt(env, PGM_SPECIFICATION, 2);
278         cc = -EIO;
279         goto out;
280     }
281     cc = css_do_stcrw(crw);
282     /* 0 - crw stored, 1 - zeroes stored */
283 out:
284     s390_cpu_physical_memory_unmap(env, crw, len, 1);
285     return cc;
286 }
287
288 int ioinst_handle_stsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
289 {
290     int cssid, ssid, schid, m;
291     SubchDev *sch;
292     uint64_t addr;
293     int cc;
294     SCHIB *schib;
295     hwaddr len = sizeof(*schib);
296
297     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
298         program_interrupt(env, PGM_OPERAND, 2);
299         return -EIO;
300     }
301     trace_ioinst_sch_id("stsch", cssid, ssid, schid);
302     addr = decode_basedisp_s(env, ipb);
303     schib = s390_cpu_physical_memory_map(env, addr, &len, 1);
304     if (!schib || len != sizeof(*schib)) {
305         program_interrupt(env, PGM_SPECIFICATION, 2);
306         cc = -EIO;
307         goto out;
308     }
309     sch = css_find_subch(m, cssid, ssid, schid);
310     if (sch) {
311         if (css_subch_visible(sch)) {
312             css_do_stsch(sch, schib);
313             cc = 0;
314         } else {
315             /* Indicate no more subchannels in this css/ss */
316             cc = 3;
317         }
318     } else {
319         if (css_schid_final(m, cssid, ssid, schid)) {
320             cc = 3; /* No more subchannels in this css/ss */
321         } else {
322             /* Store an empty schib. */
323             memset(schib, 0, sizeof(*schib));
324             cc = 0;
325         }
326     }
327 out:
328     s390_cpu_physical_memory_unmap(env, schib, len, 1);
329     return cc;
330 }
331
332 int ioinst_handle_tsch(CPUS390XState *env, uint64_t reg1, uint32_t ipb)
333 {
334     int cssid, ssid, schid, m;
335     SubchDev *sch;
336     IRB *irb;
337     uint64_t addr;
338     int ret = -ENODEV;
339     int cc;
340     hwaddr len = sizeof(*irb);
341
342     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
343         program_interrupt(env, PGM_OPERAND, 2);
344         return -EIO;
345     }
346     trace_ioinst_sch_id("tsch", cssid, ssid, schid);
347     addr = decode_basedisp_s(env, ipb);
348     irb = s390_cpu_physical_memory_map(env, addr, &len, 1);
349     if (!irb || len != sizeof(*irb)) {
350         program_interrupt(env, PGM_SPECIFICATION, 2);
351         cc = -EIO;
352         goto out;
353     }
354     sch = css_find_subch(m, cssid, ssid, schid);
355     if (sch && css_subch_visible(sch)) {
356         ret = css_do_tsch(sch, irb);
357         /* 0 - status pending, 1 - not status pending */
358         cc = ret;
359     } else {
360         cc = 3;
361     }
362 out:
363     s390_cpu_physical_memory_unmap(env, irb, sizeof(*irb), 1);
364     return cc;
365 }
366
367 typedef struct ChscReq {
368     uint16_t len;
369     uint16_t command;
370     uint32_t param0;
371     uint32_t param1;
372     uint32_t param2;
373 } QEMU_PACKED ChscReq;
374
375 typedef struct ChscResp {
376     uint16_t len;
377     uint16_t code;
378     uint32_t param;
379     char data[0];
380 } QEMU_PACKED ChscResp;
381
382 #define CHSC_MIN_RESP_LEN 0x0008
383
384 #define CHSC_SCPD 0x0002
385 #define CHSC_SCSC 0x0010
386 #define CHSC_SDA  0x0031
387
388 #define CHSC_SCPD_0_M 0x20000000
389 #define CHSC_SCPD_0_C 0x10000000
390 #define CHSC_SCPD_0_FMT 0x0f000000
391 #define CHSC_SCPD_0_CSSID 0x00ff0000
392 #define CHSC_SCPD_0_RFMT 0x00000f00
393 #define CHSC_SCPD_0_RES 0xc000f000
394 #define CHSC_SCPD_1_RES 0xffffff00
395 #define CHSC_SCPD_01_CHPID 0x000000ff
396 static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
397 {
398     uint16_t len = be16_to_cpu(req->len);
399     uint32_t param0 = be32_to_cpu(req->param0);
400     uint32_t param1 = be32_to_cpu(req->param1);
401     uint16_t resp_code;
402     int rfmt;
403     uint16_t cssid;
404     uint8_t f_chpid, l_chpid;
405     int desc_size;
406     int m;
407
408     rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
409     if ((rfmt == 0) ||  (rfmt == 1)) {
410         rfmt = !!(param0 & CHSC_SCPD_0_C);
411     }
412     if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
413         (param1 & CHSC_SCPD_1_RES) || req->param2) {
414         resp_code = 0x0003;
415         goto out_err;
416     }
417     if (param0 & CHSC_SCPD_0_FMT) {
418         resp_code = 0x0007;
419         goto out_err;
420     }
421     cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
422     m = param0 & CHSC_SCPD_0_M;
423     if (cssid != 0) {
424         if (!m || !css_present(cssid)) {
425             resp_code = 0x0008;
426             goto out_err;
427         }
428     }
429     f_chpid = param0 & CHSC_SCPD_01_CHPID;
430     l_chpid = param1 & CHSC_SCPD_01_CHPID;
431     if (l_chpid < f_chpid) {
432         resp_code = 0x0003;
433         goto out_err;
434     }
435     /* css_collect_chp_desc() is endian-aware */
436     desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
437                                      &res->data);
438     res->code = cpu_to_be16(0x0001);
439     res->len = cpu_to_be16(8 + desc_size);
440     res->param = cpu_to_be32(rfmt);
441     return;
442
443   out_err:
444     res->code = cpu_to_be16(resp_code);
445     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
446     res->param = cpu_to_be32(rfmt);
447 }
448
449 #define CHSC_SCSC_0_M 0x20000000
450 #define CHSC_SCSC_0_FMT 0x000f0000
451 #define CHSC_SCSC_0_CSSID 0x0000ff00
452 #define CHSC_SCSC_0_RES 0xdff000ff
453 static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
454 {
455     uint16_t len = be16_to_cpu(req->len);
456     uint32_t param0 = be32_to_cpu(req->param0);
457     uint8_t cssid;
458     uint16_t resp_code;
459     uint32_t general_chars[510];
460     uint32_t chsc_chars[508];
461
462     if (len != 0x0010) {
463         resp_code = 0x0003;
464         goto out_err;
465     }
466
467     if (param0 & CHSC_SCSC_0_FMT) {
468         resp_code = 0x0007;
469         goto out_err;
470     }
471     cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
472     if (cssid != 0) {
473         if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
474             resp_code = 0x0008;
475             goto out_err;
476         }
477     }
478     if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
479         resp_code = 0x0003;
480         goto out_err;
481     }
482     res->code = cpu_to_be16(0x0001);
483     res->len = cpu_to_be16(4080);
484     res->param = 0;
485
486     memset(general_chars, 0, sizeof(general_chars));
487     memset(chsc_chars, 0, sizeof(chsc_chars));
488
489     general_chars[0] = cpu_to_be32(0x03000000);
490     general_chars[1] = cpu_to_be32(0x00059000);
491
492     chsc_chars[0] = cpu_to_be32(0x40000000);
493     chsc_chars[3] = cpu_to_be32(0x00040000);
494
495     memcpy(res->data, general_chars, sizeof(general_chars));
496     memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
497     return;
498
499   out_err:
500     res->code = cpu_to_be16(resp_code);
501     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
502     res->param = 0;
503 }
504
505 #define CHSC_SDA_0_FMT 0x0f000000
506 #define CHSC_SDA_0_OC 0x0000ffff
507 #define CHSC_SDA_0_RES 0xf0ff0000
508 #define CHSC_SDA_OC_MCSSE 0x0
509 #define CHSC_SDA_OC_MSS 0x2
510 static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
511 {
512     uint16_t resp_code = 0x0001;
513     uint16_t len = be16_to_cpu(req->len);
514     uint32_t param0 = be32_to_cpu(req->param0);
515     uint16_t oc;
516     int ret;
517
518     if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
519         resp_code = 0x0003;
520         goto out;
521     }
522
523     if (param0 & CHSC_SDA_0_FMT) {
524         resp_code = 0x0007;
525         goto out;
526     }
527
528     oc = param0 & CHSC_SDA_0_OC;
529     switch (oc) {
530     case CHSC_SDA_OC_MCSSE:
531         ret = css_enable_mcsse();
532         if (ret == -EINVAL) {
533             resp_code = 0x0101;
534             goto out;
535         }
536         break;
537     case CHSC_SDA_OC_MSS:
538         ret = css_enable_mss();
539         if (ret == -EINVAL) {
540             resp_code = 0x0101;
541             goto out;
542         }
543         break;
544     default:
545         resp_code = 0x0003;
546         goto out;
547     }
548
549 out:
550     res->code = cpu_to_be16(resp_code);
551     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
552     res->param = 0;
553 }
554
555 static void ioinst_handle_chsc_unimplemented(ChscResp *res)
556 {
557     res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
558     res->code = cpu_to_be16(0x0004);
559     res->param = 0;
560 }
561
562 int ioinst_handle_chsc(CPUS390XState *env, uint32_t ipb)
563 {
564     ChscReq *req;
565     ChscResp *res;
566     uint64_t addr;
567     int reg;
568     uint16_t len;
569     uint16_t command;
570     hwaddr map_size = TARGET_PAGE_SIZE;
571     int ret = 0;
572
573     trace_ioinst("chsc");
574     reg = (ipb >> 20) & 0x00f;
575     addr = env->regs[reg];
576     /* Page boundary? */
577     if (addr & 0xfff) {
578         program_interrupt(env, PGM_SPECIFICATION, 2);
579         return -EIO;
580     }
581     req = s390_cpu_physical_memory_map(env, addr, &map_size, 1);
582     if (!req || map_size != TARGET_PAGE_SIZE) {
583         program_interrupt(env, PGM_SPECIFICATION, 2);
584         ret = -EIO;
585         goto out;
586     }
587     len = be16_to_cpu(req->len);
588     /* Length field valid? */
589     if ((len < 16) || (len > 4088) || (len & 7)) {
590         program_interrupt(env, PGM_OPERAND, 2);
591         ret = -EIO;
592         goto out;
593     }
594     memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
595     res = (void *)((char *)req + len);
596     command = be16_to_cpu(req->command);
597     trace_ioinst_chsc_cmd(command, len);
598     switch (command) {
599     case CHSC_SCSC:
600         ioinst_handle_chsc_scsc(req, res);
601         break;
602     case CHSC_SCPD:
603         ioinst_handle_chsc_scpd(req, res);
604         break;
605     case CHSC_SDA:
606         ioinst_handle_chsc_sda(req, res);
607         break;
608     default:
609         ioinst_handle_chsc_unimplemented(res);
610         break;
611     }
612
613 out:
614     s390_cpu_physical_memory_unmap(env, req, map_size, 1);
615     return ret;
616 }
617
618 int ioinst_handle_tpi(CPUS390XState *env, uint32_t ipb)
619 {
620     uint64_t addr;
621     int lowcore;
622     IOIntCode *int_code;
623     hwaddr len, orig_len;
624     int ret;
625
626     trace_ioinst("tpi");
627     addr = decode_basedisp_s(env, ipb);
628     lowcore = addr ? 0 : 1;
629     len = lowcore ? 8 /* two words */ : 12 /* three words */;
630     orig_len = len;
631     int_code = s390_cpu_physical_memory_map(env, addr, &len, 1);
632     if (!int_code || (len != orig_len)) {
633         program_interrupt(env, PGM_SPECIFICATION, 2);
634         ret = -EIO;
635         goto out;
636     }
637     ret = css_do_tpi(int_code, lowcore);
638 out:
639     s390_cpu_physical_memory_unmap(env, int_code, len, 1);
640     return ret;
641 }
642
643 #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
644 #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
645 #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
646 #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
647
648 int ioinst_handle_schm(CPUS390XState *env, uint64_t reg1, uint64_t reg2,
649                        uint32_t ipb)
650 {
651     uint8_t mbk;
652     int update;
653     int dct;
654
655     trace_ioinst("schm");
656
657     if (SCHM_REG1_RES(reg1)) {
658         program_interrupt(env, PGM_OPERAND, 2);
659         return -EIO;
660     }
661
662     mbk = SCHM_REG1_MBK(reg1);
663     update = SCHM_REG1_UPD(reg1);
664     dct = SCHM_REG1_DCT(reg1);
665
666     if (update && (reg2 & 0x0000000000000fff)) {
667         program_interrupt(env, PGM_OPERAND, 2);
668         return -EIO;
669     }
670
671     css_do_schm(mbk, update, dct, update ? reg2 : 0);
672
673     return 0;
674 }
675
676 int ioinst_handle_rsch(CPUS390XState *env, uint64_t reg1)
677 {
678     int cssid, ssid, schid, m;
679     SubchDev *sch;
680     int ret = -ENODEV;
681     int cc;
682
683     if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
684         program_interrupt(env, PGM_OPERAND, 2);
685         return -EIO;
686     }
687     trace_ioinst_sch_id("rsch", cssid, ssid, schid);
688     sch = css_find_subch(m, cssid, ssid, schid);
689     if (sch && css_subch_visible(sch)) {
690         ret = css_do_rsch(sch);
691     }
692     switch (ret) {
693     case -ENODEV:
694         cc = 3;
695         break;
696     case -EINVAL:
697         cc = 2;
698         break;
699     case 0:
700         cc = 0;
701         break;
702     default:
703         cc = 1;
704         break;
705     }
706
707     return cc;
708
709 }
710
711 #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
712 #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
713 #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
714 int ioinst_handle_rchp(CPUS390XState *env, uint64_t reg1)
715 {
716     int cc;
717     uint8_t cssid;
718     uint8_t chpid;
719     int ret;
720
721     if (RCHP_REG1_RES(reg1)) {
722         program_interrupt(env, PGM_OPERAND, 2);
723         return -EIO;
724     }
725
726     cssid = RCHP_REG1_CSSID(reg1);
727     chpid = RCHP_REG1_CHPID(reg1);
728
729     trace_ioinst_chp_id("rchp", cssid, chpid);
730
731     ret = css_do_rchp(cssid, chpid);
732
733     switch (ret) {
734     case -ENODEV:
735         cc = 3;
736         break;
737     case -EBUSY:
738         cc = 2;
739         break;
740     case 0:
741         cc = 0;
742         break;
743     default:
744         /* Invalid channel subsystem. */
745         program_interrupt(env, PGM_OPERAND, 2);
746         return -EIO;
747     }
748
749     return cc;
750 }
751
752 #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
753 int ioinst_handle_sal(CPUS390XState *env, uint64_t reg1)
754 {
755     /* We do not provide address limit checking, so let's suppress it. */
756     if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
757         program_interrupt(env, PGM_OPERAND, 2);
758         return -EIO;
759     }
760     return 0;
761 }