xref: /openbmc/qemu/hw/s390x/css.c (revision a719a27c)
1 /*
2  * Channel subsystem base support.
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 <hw/qdev.h>
13 #include "qemu/bitops.h"
14 #include "exec/address-spaces.h"
15 #include "cpu.h"
16 #include "ioinst.h"
17 #include "css.h"
18 #include "trace.h"
19 
20 typedef struct CrwContainer {
21     CRW crw;
22     QTAILQ_ENTRY(CrwContainer) sibling;
23 } CrwContainer;
24 
25 typedef struct ChpInfo {
26     uint8_t in_use;
27     uint8_t type;
28     uint8_t is_virtual;
29 } ChpInfo;
30 
31 typedef struct SubchSet {
32     SubchDev *sch[MAX_SCHID + 1];
33     unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)];
34     unsigned long devnos_used[BITS_TO_LONGS(MAX_SCHID + 1)];
35 } SubchSet;
36 
37 typedef struct CssImage {
38     SubchSet *sch_set[MAX_SSID + 1];
39     ChpInfo chpids[MAX_CHPID + 1];
40 } CssImage;
41 
42 typedef struct ChannelSubSys {
43     QTAILQ_HEAD(, CrwContainer) pending_crws;
44     bool do_crw_mchk;
45     bool crws_lost;
46     uint8_t max_cssid;
47     uint8_t max_ssid;
48     bool chnmon_active;
49     uint64_t chnmon_area;
50     CssImage *css[MAX_CSSID + 1];
51     uint8_t default_cssid;
52 } ChannelSubSys;
53 
54 static ChannelSubSys *channel_subsys;
55 
56 int css_create_css_image(uint8_t cssid, bool default_image)
57 {
58     trace_css_new_image(cssid, default_image ? "(default)" : "");
59     if (cssid > MAX_CSSID) {
60         return -EINVAL;
61     }
62     if (channel_subsys->css[cssid]) {
63         return -EBUSY;
64     }
65     channel_subsys->css[cssid] = g_malloc0(sizeof(CssImage));
66     if (default_image) {
67         channel_subsys->default_cssid = cssid;
68     }
69     return 0;
70 }
71 
72 uint16_t css_build_subchannel_id(SubchDev *sch)
73 {
74     if (channel_subsys->max_cssid > 0) {
75         return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
76     }
77     return (sch->ssid << 1) | 1;
78 }
79 
80 static void css_inject_io_interrupt(SubchDev *sch)
81 {
82     S390CPU *cpu = s390_cpu_addr2state(0);
83     uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;
84 
85     trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
86                            sch->curr_status.pmcw.intparm, isc, "");
87     s390_io_interrupt(cpu,
88                       css_build_subchannel_id(sch),
89                       sch->schid,
90                       sch->curr_status.pmcw.intparm,
91                       isc << 27);
92 }
93 
94 void css_conditional_io_interrupt(SubchDev *sch)
95 {
96     /*
97      * If the subchannel is not currently status pending, make it pending
98      * with alert status.
99      */
100     if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) {
101         S390CPU *cpu = s390_cpu_addr2state(0);
102         uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11;
103 
104         trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid,
105                                sch->curr_status.pmcw.intparm, isc,
106                                "(unsolicited)");
107         sch->curr_status.scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL;
108         sch->curr_status.scsw.ctrl |=
109             SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
110         /* Inject an I/O interrupt. */
111         s390_io_interrupt(cpu,
112                           css_build_subchannel_id(sch),
113                           sch->schid,
114                           sch->curr_status.pmcw.intparm,
115                           isc << 27);
116     }
117 }
118 
119 void css_adapter_interrupt(uint8_t isc)
120 {
121     S390CPU *cpu = s390_cpu_addr2state(0);
122     uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
123 
124     trace_css_adapter_interrupt(isc);
125     s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
126 }
127 
128 static void sch_handle_clear_func(SubchDev *sch)
129 {
130     PMCW *p = &sch->curr_status.pmcw;
131     SCSW *s = &sch->curr_status.scsw;
132     int path;
133 
134     /* Path management: In our simple css, we always choose the only path. */
135     path = 0x80;
136 
137     /* Reset values prior to 'issuing the clear signal'. */
138     p->lpum = 0;
139     p->pom = 0xff;
140     s->flags &= ~SCSW_FLAGS_MASK_PNO;
141 
142     /* We always 'attempt to issue the clear signal', and we always succeed. */
143     sch->channel_prog = 0x0;
144     sch->last_cmd_valid = false;
145     s->ctrl &= ~SCSW_ACTL_CLEAR_PEND;
146     s->ctrl |= SCSW_STCTL_STATUS_PEND;
147 
148     s->dstat = 0;
149     s->cstat = 0;
150     p->lpum = path;
151 
152 }
153 
154 static void sch_handle_halt_func(SubchDev *sch)
155 {
156 
157     PMCW *p = &sch->curr_status.pmcw;
158     SCSW *s = &sch->curr_status.scsw;
159     int path;
160 
161     /* Path management: In our simple css, we always choose the only path. */
162     path = 0x80;
163 
164     /* We always 'attempt to issue the halt signal', and we always succeed. */
165     sch->channel_prog = 0x0;
166     sch->last_cmd_valid = false;
167     s->ctrl &= ~SCSW_ACTL_HALT_PEND;
168     s->ctrl |= SCSW_STCTL_STATUS_PEND;
169 
170     if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) ||
171         !((s->ctrl & SCSW_ACTL_START_PEND) ||
172           (s->ctrl & SCSW_ACTL_SUSP))) {
173         s->dstat = SCSW_DSTAT_DEVICE_END;
174     }
175     s->cstat = 0;
176     p->lpum = path;
177 
178 }
179 
180 static void copy_sense_id_to_guest(SenseId *dest, SenseId *src)
181 {
182     int i;
183 
184     dest->reserved = src->reserved;
185     dest->cu_type = cpu_to_be16(src->cu_type);
186     dest->cu_model = src->cu_model;
187     dest->dev_type = cpu_to_be16(src->dev_type);
188     dest->dev_model = src->dev_model;
189     dest->unused = src->unused;
190     for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) {
191         dest->ciw[i].type = src->ciw[i].type;
192         dest->ciw[i].command = src->ciw[i].command;
193         dest->ciw[i].count = cpu_to_be16(src->ciw[i].count);
194     }
195 }
196 
197 static CCW1 copy_ccw_from_guest(hwaddr addr)
198 {
199     CCW1 tmp;
200     CCW1 ret;
201 
202     cpu_physical_memory_read(addr, &tmp, sizeof(tmp));
203     ret.cmd_code = tmp.cmd_code;
204     ret.flags = tmp.flags;
205     ret.count = be16_to_cpu(tmp.count);
206     ret.cda = be32_to_cpu(tmp.cda);
207 
208     return ret;
209 }
210 
211 static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
212 {
213     int ret;
214     bool check_len;
215     int len;
216     CCW1 ccw;
217 
218     if (!ccw_addr) {
219         return -EIO;
220     }
221 
222     ccw = copy_ccw_from_guest(ccw_addr);
223 
224     /* Check for invalid command codes. */
225     if ((ccw.cmd_code & 0x0f) == 0) {
226         return -EINVAL;
227     }
228     if (((ccw.cmd_code & 0x0f) == CCW_CMD_TIC) &&
229         ((ccw.cmd_code & 0xf0) != 0)) {
230         return -EINVAL;
231     }
232 
233     if (ccw.flags & CCW_FLAG_SUSPEND) {
234         return -EINPROGRESS;
235     }
236 
237     check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC));
238 
239     /* Look at the command. */
240     switch (ccw.cmd_code) {
241     case CCW_CMD_NOOP:
242         /* Nothing to do. */
243         ret = 0;
244         break;
245     case CCW_CMD_BASIC_SENSE:
246         if (check_len) {
247             if (ccw.count != sizeof(sch->sense_data)) {
248                 ret = -EINVAL;
249                 break;
250             }
251         }
252         len = MIN(ccw.count, sizeof(sch->sense_data));
253         cpu_physical_memory_write(ccw.cda, sch->sense_data, len);
254         sch->curr_status.scsw.count = ccw.count - len;
255         memset(sch->sense_data, 0, sizeof(sch->sense_data));
256         ret = 0;
257         break;
258     case CCW_CMD_SENSE_ID:
259     {
260         SenseId sense_id;
261 
262         copy_sense_id_to_guest(&sense_id, &sch->id);
263         /* Sense ID information is device specific. */
264         if (check_len) {
265             if (ccw.count != sizeof(sense_id)) {
266                 ret = -EINVAL;
267                 break;
268             }
269         }
270         len = MIN(ccw.count, sizeof(sense_id));
271         /*
272          * Only indicate 0xff in the first sense byte if we actually
273          * have enough place to store at least bytes 0-3.
274          */
275         if (len >= 4) {
276             sense_id.reserved = 0xff;
277         } else {
278             sense_id.reserved = 0;
279         }
280         cpu_physical_memory_write(ccw.cda, &sense_id, len);
281         sch->curr_status.scsw.count = ccw.count - len;
282         ret = 0;
283         break;
284     }
285     case CCW_CMD_TIC:
286         if (sch->last_cmd_valid && (sch->last_cmd.cmd_code == CCW_CMD_TIC)) {
287             ret = -EINVAL;
288             break;
289         }
290         if (ccw.flags & (CCW_FLAG_CC | CCW_FLAG_DC)) {
291             ret = -EINVAL;
292             break;
293         }
294         sch->channel_prog = ccw.cda;
295         ret = -EAGAIN;
296         break;
297     default:
298         if (sch->ccw_cb) {
299             /* Handle device specific commands. */
300             ret = sch->ccw_cb(sch, ccw);
301         } else {
302             ret = -ENOSYS;
303         }
304         break;
305     }
306     sch->last_cmd = ccw;
307     sch->last_cmd_valid = true;
308     if (ret == 0) {
309         if (ccw.flags & CCW_FLAG_CC) {
310             sch->channel_prog += 8;
311             ret = -EAGAIN;
312         }
313     }
314 
315     return ret;
316 }
317 
318 static void sch_handle_start_func(SubchDev *sch, ORB *orb)
319 {
320 
321     PMCW *p = &sch->curr_status.pmcw;
322     SCSW *s = &sch->curr_status.scsw;
323     int path;
324     int ret;
325 
326     /* Path management: In our simple css, we always choose the only path. */
327     path = 0x80;
328 
329     if (!(s->ctrl & SCSW_ACTL_SUSP)) {
330         /* Look at the orb and try to execute the channel program. */
331         assert(orb != NULL); /* resume does not pass an orb */
332         p->intparm = orb->intparm;
333         if (!(orb->lpm & path)) {
334             /* Generate a deferred cc 3 condition. */
335             s->flags |= SCSW_FLAGS_MASK_CC;
336             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
337             s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND);
338             return;
339         }
340     } else {
341         s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND);
342     }
343     sch->last_cmd_valid = false;
344     do {
345         ret = css_interpret_ccw(sch, sch->channel_prog);
346         switch (ret) {
347         case -EAGAIN:
348             /* ccw chain, continue processing */
349             break;
350         case 0:
351             /* success */
352             s->ctrl &= ~SCSW_ACTL_START_PEND;
353             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
354             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
355                     SCSW_STCTL_STATUS_PEND;
356             s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
357             break;
358         case -ENOSYS:
359             /* unsupported command, generate unit check (command reject) */
360             s->ctrl &= ~SCSW_ACTL_START_PEND;
361             s->dstat = SCSW_DSTAT_UNIT_CHECK;
362             /* Set sense bit 0 in ecw0. */
363             sch->sense_data[0] = 0x80;
364             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
365             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
366                     SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
367             break;
368         case -EFAULT:
369             /* memory problem, generate channel data check */
370             s->ctrl &= ~SCSW_ACTL_START_PEND;
371             s->cstat = SCSW_CSTAT_DATA_CHECK;
372             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
373             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
374                     SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
375             break;
376         case -EBUSY:
377             /* subchannel busy, generate deferred cc 1 */
378             s->flags &= ~SCSW_FLAGS_MASK_CC;
379             s->flags |= (1 << 8);
380             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
381             s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
382             break;
383         case -EINPROGRESS:
384             /* channel program has been suspended */
385             s->ctrl &= ~SCSW_ACTL_START_PEND;
386             s->ctrl |= SCSW_ACTL_SUSP;
387             break;
388         default:
389             /* error, generate channel program check */
390             s->ctrl &= ~SCSW_ACTL_START_PEND;
391             s->cstat = SCSW_CSTAT_PROG_CHECK;
392             s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
393             s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
394                     SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
395             break;
396         }
397     } while (ret == -EAGAIN);
398 
399 }
400 
401 /*
402  * On real machines, this would run asynchronously to the main vcpus.
403  * We might want to make some parts of the ssch handling (interpreting
404  * read/writes) asynchronous later on if we start supporting more than
405  * our current very simple devices.
406  */
407 static void do_subchannel_work(SubchDev *sch, ORB *orb)
408 {
409 
410     SCSW *s = &sch->curr_status.scsw;
411 
412     if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) {
413         sch_handle_clear_func(sch);
414     } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) {
415         sch_handle_halt_func(sch);
416     } else if (s->ctrl & SCSW_FCTL_START_FUNC) {
417         sch_handle_start_func(sch, orb);
418     } else {
419         /* Cannot happen. */
420         return;
421     }
422     css_inject_io_interrupt(sch);
423 }
424 
425 static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src)
426 {
427     int i;
428 
429     dest->intparm = cpu_to_be32(src->intparm);
430     dest->flags = cpu_to_be16(src->flags);
431     dest->devno = cpu_to_be16(src->devno);
432     dest->lpm = src->lpm;
433     dest->pnom = src->pnom;
434     dest->lpum = src->lpum;
435     dest->pim = src->pim;
436     dest->mbi = cpu_to_be16(src->mbi);
437     dest->pom = src->pom;
438     dest->pam = src->pam;
439     for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) {
440         dest->chpid[i] = src->chpid[i];
441     }
442     dest->chars = cpu_to_be32(src->chars);
443 }
444 
445 static void copy_scsw_to_guest(SCSW *dest, const SCSW *src)
446 {
447     dest->flags = cpu_to_be16(src->flags);
448     dest->ctrl = cpu_to_be16(src->ctrl);
449     dest->cpa = cpu_to_be32(src->cpa);
450     dest->dstat = src->dstat;
451     dest->cstat = src->cstat;
452     dest->count = cpu_to_be16(src->count);
453 }
454 
455 static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
456 {
457     int i;
458 
459     copy_pmcw_to_guest(&dest->pmcw, &src->pmcw);
460     copy_scsw_to_guest(&dest->scsw, &src->scsw);
461     dest->mba = cpu_to_be64(src->mba);
462     for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
463         dest->mda[i] = src->mda[i];
464     }
465 }
466 
467 int css_do_stsch(SubchDev *sch, SCHIB *schib)
468 {
469     /* Use current status. */
470     copy_schib_to_guest(schib, &sch->curr_status);
471     return 0;
472 }
473 
474 static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src)
475 {
476     int i;
477 
478     dest->intparm = be32_to_cpu(src->intparm);
479     dest->flags = be16_to_cpu(src->flags);
480     dest->devno = be16_to_cpu(src->devno);
481     dest->lpm = src->lpm;
482     dest->pnom = src->pnom;
483     dest->lpum = src->lpum;
484     dest->pim = src->pim;
485     dest->mbi = be16_to_cpu(src->mbi);
486     dest->pom = src->pom;
487     dest->pam = src->pam;
488     for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) {
489         dest->chpid[i] = src->chpid[i];
490     }
491     dest->chars = be32_to_cpu(src->chars);
492 }
493 
494 static void copy_scsw_from_guest(SCSW *dest, const SCSW *src)
495 {
496     dest->flags = be16_to_cpu(src->flags);
497     dest->ctrl = be16_to_cpu(src->ctrl);
498     dest->cpa = be32_to_cpu(src->cpa);
499     dest->dstat = src->dstat;
500     dest->cstat = src->cstat;
501     dest->count = be16_to_cpu(src->count);
502 }
503 
504 static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src)
505 {
506     int i;
507 
508     copy_pmcw_from_guest(&dest->pmcw, &src->pmcw);
509     copy_scsw_from_guest(&dest->scsw, &src->scsw);
510     dest->mba = be64_to_cpu(src->mba);
511     for (i = 0; i < ARRAY_SIZE(dest->mda); i++) {
512         dest->mda[i] = src->mda[i];
513     }
514 }
515 
516 int css_do_msch(SubchDev *sch, SCHIB *orig_schib)
517 {
518     SCSW *s = &sch->curr_status.scsw;
519     PMCW *p = &sch->curr_status.pmcw;
520     int ret;
521     SCHIB schib;
522 
523     if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) {
524         ret = 0;
525         goto out;
526     }
527 
528     if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
529         ret = -EINPROGRESS;
530         goto out;
531     }
532 
533     if (s->ctrl &
534         (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) {
535         ret = -EBUSY;
536         goto out;
537     }
538 
539     copy_schib_from_guest(&schib, orig_schib);
540     /* Only update the program-modifiable fields. */
541     p->intparm = schib.pmcw.intparm;
542     p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
543                   PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
544                   PMCW_FLAGS_MASK_MP);
545     p->flags |= schib.pmcw.flags &
546             (PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
547              PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
548              PMCW_FLAGS_MASK_MP);
549     p->lpm = schib.pmcw.lpm;
550     p->mbi = schib.pmcw.mbi;
551     p->pom = schib.pmcw.pom;
552     p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
553     p->chars |= schib.pmcw.chars &
554             (PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE);
555     sch->curr_status.mba = schib.mba;
556 
557     ret = 0;
558 
559 out:
560     return ret;
561 }
562 
563 int css_do_xsch(SubchDev *sch)
564 {
565     SCSW *s = &sch->curr_status.scsw;
566     PMCW *p = &sch->curr_status.pmcw;
567     int ret;
568 
569     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
570         ret = -ENODEV;
571         goto out;
572     }
573 
574     if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) ||
575         ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
576         (!(s->ctrl &
577            (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) ||
578         (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) {
579         ret = -EINPROGRESS;
580         goto out;
581     }
582 
583     if (s->ctrl & SCSW_CTRL_MASK_STCTL) {
584         ret = -EBUSY;
585         goto out;
586     }
587 
588     /* Cancel the current operation. */
589     s->ctrl &= ~(SCSW_FCTL_START_FUNC |
590                  SCSW_ACTL_RESUME_PEND |
591                  SCSW_ACTL_START_PEND |
592                  SCSW_ACTL_SUSP);
593     sch->channel_prog = 0x0;
594     sch->last_cmd_valid = false;
595     s->dstat = 0;
596     s->cstat = 0;
597     ret = 0;
598 
599 out:
600     return ret;
601 }
602 
603 int css_do_csch(SubchDev *sch)
604 {
605     SCSW *s = &sch->curr_status.scsw;
606     PMCW *p = &sch->curr_status.pmcw;
607     int ret;
608 
609     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
610         ret = -ENODEV;
611         goto out;
612     }
613 
614     /* Trigger the clear function. */
615     s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
616     s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_CLEAR_FUNC;
617 
618     do_subchannel_work(sch, NULL);
619     ret = 0;
620 
621 out:
622     return ret;
623 }
624 
625 int css_do_hsch(SubchDev *sch)
626 {
627     SCSW *s = &sch->curr_status.scsw;
628     PMCW *p = &sch->curr_status.pmcw;
629     int ret;
630 
631     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
632         ret = -ENODEV;
633         goto out;
634     }
635 
636     if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) ||
637         (s->ctrl & (SCSW_STCTL_PRIMARY |
638                     SCSW_STCTL_SECONDARY |
639                     SCSW_STCTL_ALERT))) {
640         ret = -EINPROGRESS;
641         goto out;
642     }
643 
644     if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
645         ret = -EBUSY;
646         goto out;
647     }
648 
649     /* Trigger the halt function. */
650     s->ctrl |= SCSW_FCTL_HALT_FUNC;
651     s->ctrl &= ~SCSW_FCTL_START_FUNC;
652     if (((s->ctrl & SCSW_CTRL_MASK_ACTL) ==
653          (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) &&
654         ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) {
655         s->ctrl &= ~SCSW_STCTL_STATUS_PEND;
656     }
657     s->ctrl |= SCSW_ACTL_HALT_PEND;
658 
659     do_subchannel_work(sch, NULL);
660     ret = 0;
661 
662 out:
663     return ret;
664 }
665 
666 static void css_update_chnmon(SubchDev *sch)
667 {
668     if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_MME)) {
669         /* Not active. */
670         return;
671     }
672     /* The counter is conveniently located at the beginning of the struct. */
673     if (sch->curr_status.pmcw.chars & PMCW_CHARS_MASK_MBFC) {
674         /* Format 1, per-subchannel area. */
675         uint32_t count;
676 
677         count = ldl_phys(&address_space_memory, sch->curr_status.mba);
678         count++;
679         stl_phys(&address_space_memory, sch->curr_status.mba, count);
680     } else {
681         /* Format 0, global area. */
682         uint32_t offset;
683         uint16_t count;
684 
685         offset = sch->curr_status.pmcw.mbi << 5;
686         count = lduw_phys(&address_space_memory,
687                           channel_subsys->chnmon_area + offset);
688         count++;
689         stw_phys(&address_space_memory,
690                  channel_subsys->chnmon_area + offset, count);
691     }
692 }
693 
694 int css_do_ssch(SubchDev *sch, ORB *orb)
695 {
696     SCSW *s = &sch->curr_status.scsw;
697     PMCW *p = &sch->curr_status.pmcw;
698     int ret;
699 
700     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
701         ret = -ENODEV;
702         goto out;
703     }
704 
705     if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
706         ret = -EINPROGRESS;
707         goto out;
708     }
709 
710     if (s->ctrl & (SCSW_FCTL_START_FUNC |
711                    SCSW_FCTL_HALT_FUNC |
712                    SCSW_FCTL_CLEAR_FUNC)) {
713         ret = -EBUSY;
714         goto out;
715     }
716 
717     /* If monitoring is active, update counter. */
718     if (channel_subsys->chnmon_active) {
719         css_update_chnmon(sch);
720     }
721     sch->channel_prog = orb->cpa;
722     /* Trigger the start function. */
723     s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
724     s->flags &= ~SCSW_FLAGS_MASK_PNO;
725 
726     do_subchannel_work(sch, orb);
727     ret = 0;
728 
729 out:
730     return ret;
731 }
732 
733 static void copy_irb_to_guest(IRB *dest, const IRB *src)
734 {
735     int i;
736 
737     copy_scsw_to_guest(&dest->scsw, &src->scsw);
738 
739     for (i = 0; i < ARRAY_SIZE(dest->esw); i++) {
740         dest->esw[i] = cpu_to_be32(src->esw[i]);
741     }
742     for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
743         dest->ecw[i] = cpu_to_be32(src->ecw[i]);
744     }
745     for (i = 0; i < ARRAY_SIZE(dest->emw); i++) {
746         dest->emw[i] = cpu_to_be32(src->emw[i]);
747     }
748 }
749 
750 int css_do_tsch(SubchDev *sch, IRB *target_irb)
751 {
752     SCSW *s = &sch->curr_status.scsw;
753     PMCW *p = &sch->curr_status.pmcw;
754     uint16_t stctl;
755     uint16_t fctl;
756     uint16_t actl;
757     IRB irb;
758     int ret;
759 
760     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
761         ret = 3;
762         goto out;
763     }
764 
765     stctl = s->ctrl & SCSW_CTRL_MASK_STCTL;
766     fctl = s->ctrl & SCSW_CTRL_MASK_FCTL;
767     actl = s->ctrl & SCSW_CTRL_MASK_ACTL;
768 
769     /* Prepare the irb for the guest. */
770     memset(&irb, 0, sizeof(IRB));
771 
772     /* Copy scsw from current status. */
773     memcpy(&irb.scsw, s, sizeof(SCSW));
774     if (stctl & SCSW_STCTL_STATUS_PEND) {
775         if (s->cstat & (SCSW_CSTAT_DATA_CHECK |
776                         SCSW_CSTAT_CHN_CTRL_CHK |
777                         SCSW_CSTAT_INTF_CTRL_CHK)) {
778             irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF;
779             irb.esw[0] = 0x04804000;
780         } else {
781             irb.esw[0] = 0x00800000;
782         }
783         /* If a unit check is pending, copy sense data. */
784         if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) &&
785             (p->chars & PMCW_CHARS_MASK_CSENSE)) {
786             irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
787             memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data));
788             irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8);
789         }
790     }
791     /* Store the irb to the guest. */
792     copy_irb_to_guest(target_irb, &irb);
793 
794     /* Clear conditions on subchannel, if applicable. */
795     if (stctl & SCSW_STCTL_STATUS_PEND) {
796         s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
797         if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) ||
798             ((fctl & SCSW_FCTL_HALT_FUNC) &&
799              (actl & SCSW_ACTL_SUSP))) {
800             s->ctrl &= ~SCSW_CTRL_MASK_FCTL;
801         }
802         if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) {
803             s->flags &= ~SCSW_FLAGS_MASK_PNO;
804             s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
805                          SCSW_ACTL_START_PEND |
806                          SCSW_ACTL_HALT_PEND |
807                          SCSW_ACTL_CLEAR_PEND |
808                          SCSW_ACTL_SUSP);
809         } else {
810             if ((actl & SCSW_ACTL_SUSP) &&
811                 (fctl & SCSW_FCTL_START_FUNC)) {
812                 s->flags &= ~SCSW_FLAGS_MASK_PNO;
813                 if (fctl & SCSW_FCTL_HALT_FUNC) {
814                     s->ctrl &= ~(SCSW_ACTL_RESUME_PEND |
815                                  SCSW_ACTL_START_PEND |
816                                  SCSW_ACTL_HALT_PEND |
817                                  SCSW_ACTL_CLEAR_PEND |
818                                  SCSW_ACTL_SUSP);
819                 } else {
820                     s->ctrl &= ~SCSW_ACTL_RESUME_PEND;
821                 }
822             }
823         }
824         /* Clear pending sense data. */
825         if (p->chars & PMCW_CHARS_MASK_CSENSE) {
826             memset(sch->sense_data, 0 , sizeof(sch->sense_data));
827         }
828     }
829 
830     ret = ((stctl & SCSW_STCTL_STATUS_PEND) == 0);
831 
832 out:
833     return ret;
834 }
835 
836 static void copy_crw_to_guest(CRW *dest, const CRW *src)
837 {
838     dest->flags = cpu_to_be16(src->flags);
839     dest->rsid = cpu_to_be16(src->rsid);
840 }
841 
842 int css_do_stcrw(CRW *crw)
843 {
844     CrwContainer *crw_cont;
845     int ret;
846 
847     crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws);
848     if (crw_cont) {
849         QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling);
850         copy_crw_to_guest(crw, &crw_cont->crw);
851         g_free(crw_cont);
852         ret = 0;
853     } else {
854         /* List was empty, turn crw machine checks on again. */
855         memset(crw, 0, sizeof(*crw));
856         channel_subsys->do_crw_mchk = true;
857         ret = 1;
858     }
859 
860     return ret;
861 }
862 
863 int css_do_tpi(IOIntCode *int_code, int lowcore)
864 {
865     /* No pending interrupts for !KVM. */
866     return 0;
867  }
868 
869 int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid,
870                          int rfmt, void *buf)
871 {
872     int i, desc_size;
873     uint32_t words[8];
874     uint32_t chpid_type_word;
875     CssImage *css;
876 
877     if (!m && !cssid) {
878         css = channel_subsys->css[channel_subsys->default_cssid];
879     } else {
880         css = channel_subsys->css[cssid];
881     }
882     if (!css) {
883         return 0;
884     }
885     desc_size = 0;
886     for (i = f_chpid; i <= l_chpid; i++) {
887         if (css->chpids[i].in_use) {
888             chpid_type_word = 0x80000000 | (css->chpids[i].type << 8) | i;
889             if (rfmt == 0) {
890                 words[0] = cpu_to_be32(chpid_type_word);
891                 words[1] = 0;
892                 memcpy(buf + desc_size, words, 8);
893                 desc_size += 8;
894             } else if (rfmt == 1) {
895                 words[0] = cpu_to_be32(chpid_type_word);
896                 words[1] = 0;
897                 words[2] = 0;
898                 words[3] = 0;
899                 words[4] = 0;
900                 words[5] = 0;
901                 words[6] = 0;
902                 words[7] = 0;
903                 memcpy(buf + desc_size, words, 32);
904                 desc_size += 32;
905             }
906         }
907     }
908     return desc_size;
909 }
910 
911 void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo)
912 {
913     /* dct is currently ignored (not really meaningful for our devices) */
914     /* TODO: Don't ignore mbk. */
915     if (update && !channel_subsys->chnmon_active) {
916         /* Enable measuring. */
917         channel_subsys->chnmon_area = mbo;
918         channel_subsys->chnmon_active = true;
919     }
920     if (!update && channel_subsys->chnmon_active) {
921         /* Disable measuring. */
922         channel_subsys->chnmon_area = 0;
923         channel_subsys->chnmon_active = false;
924     }
925 }
926 
927 int css_do_rsch(SubchDev *sch)
928 {
929     SCSW *s = &sch->curr_status.scsw;
930     PMCW *p = &sch->curr_status.pmcw;
931     int ret;
932 
933     if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) {
934         ret = -ENODEV;
935         goto out;
936     }
937 
938     if (s->ctrl & SCSW_STCTL_STATUS_PEND) {
939         ret = -EINPROGRESS;
940         goto out;
941     }
942 
943     if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) ||
944         (s->ctrl & SCSW_ACTL_RESUME_PEND) ||
945         (!(s->ctrl & SCSW_ACTL_SUSP))) {
946         ret = -EINVAL;
947         goto out;
948     }
949 
950     /* If monitoring is active, update counter. */
951     if (channel_subsys->chnmon_active) {
952         css_update_chnmon(sch);
953     }
954 
955     s->ctrl |= SCSW_ACTL_RESUME_PEND;
956     do_subchannel_work(sch, NULL);
957     ret = 0;
958 
959 out:
960     return ret;
961 }
962 
963 int css_do_rchp(uint8_t cssid, uint8_t chpid)
964 {
965     uint8_t real_cssid;
966 
967     if (cssid > channel_subsys->max_cssid) {
968         return -EINVAL;
969     }
970     if (channel_subsys->max_cssid == 0) {
971         real_cssid = channel_subsys->default_cssid;
972     } else {
973         real_cssid = cssid;
974     }
975     if (!channel_subsys->css[real_cssid]) {
976         return -EINVAL;
977     }
978 
979     if (!channel_subsys->css[real_cssid]->chpids[chpid].in_use) {
980         return -ENODEV;
981     }
982 
983     if (!channel_subsys->css[real_cssid]->chpids[chpid].is_virtual) {
984         fprintf(stderr,
985                 "rchp unsupported for non-virtual chpid %x.%02x!\n",
986                 real_cssid, chpid);
987         return -ENODEV;
988     }
989 
990     /* We don't really use a channel path, so we're done here. */
991     css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT,
992                   channel_subsys->max_cssid > 0 ? 1 : 0, chpid);
993     if (channel_subsys->max_cssid > 0) {
994         css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8);
995     }
996     return 0;
997 }
998 
999 bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
1000 {
1001     SubchSet *set;
1002     uint8_t real_cssid;
1003 
1004     real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid;
1005     if (real_cssid > MAX_CSSID || ssid > MAX_SSID ||
1006         !channel_subsys->css[real_cssid] ||
1007         !channel_subsys->css[real_cssid]->sch_set[ssid]) {
1008         return true;
1009     }
1010     set = channel_subsys->css[real_cssid]->sch_set[ssid];
1011     return schid > find_last_bit(set->schids_used,
1012                                  (MAX_SCHID + 1) / sizeof(unsigned long));
1013 }
1014 
1015 static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
1016 {
1017     CssImage *css;
1018 
1019     trace_css_chpid_add(cssid, chpid, type);
1020     if (cssid > MAX_CSSID) {
1021         return -EINVAL;
1022     }
1023     css = channel_subsys->css[cssid];
1024     if (!css) {
1025         return -EINVAL;
1026     }
1027     if (css->chpids[chpid].in_use) {
1028         return -EEXIST;
1029     }
1030     css->chpids[chpid].in_use = 1;
1031     css->chpids[chpid].type = type;
1032     css->chpids[chpid].is_virtual = 1;
1033 
1034     css_generate_chp_crws(cssid, chpid);
1035 
1036     return 0;
1037 }
1038 
1039 void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type)
1040 {
1041     PMCW *p = &sch->curr_status.pmcw;
1042     SCSW *s = &sch->curr_status.scsw;
1043     int i;
1044     CssImage *css = channel_subsys->css[sch->cssid];
1045 
1046     assert(css != NULL);
1047     memset(p, 0, sizeof(PMCW));
1048     p->flags |= PMCW_FLAGS_MASK_DNV;
1049     p->devno = sch->devno;
1050     /* single path */
1051     p->pim = 0x80;
1052     p->pom = 0xff;
1053     p->pam = 0x80;
1054     p->chpid[0] = chpid;
1055     if (!css->chpids[chpid].in_use) {
1056         css_add_virtual_chpid(sch->cssid, chpid, type);
1057     }
1058 
1059     memset(s, 0, sizeof(SCSW));
1060     sch->curr_status.mba = 0;
1061     for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) {
1062         sch->curr_status.mda[i] = 0;
1063     }
1064 }
1065 
1066 SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid)
1067 {
1068     uint8_t real_cssid;
1069 
1070     real_cssid = (!m && (cssid == 0)) ? channel_subsys->default_cssid : cssid;
1071 
1072     if (!channel_subsys->css[real_cssid]) {
1073         return NULL;
1074     }
1075 
1076     if (!channel_subsys->css[real_cssid]->sch_set[ssid]) {
1077         return NULL;
1078     }
1079 
1080     return channel_subsys->css[real_cssid]->sch_set[ssid]->sch[schid];
1081 }
1082 
1083 bool css_subch_visible(SubchDev *sch)
1084 {
1085     if (sch->ssid > channel_subsys->max_ssid) {
1086         return false;
1087     }
1088 
1089     if (sch->cssid != channel_subsys->default_cssid) {
1090         return (channel_subsys->max_cssid > 0);
1091     }
1092 
1093     return true;
1094 }
1095 
1096 bool css_present(uint8_t cssid)
1097 {
1098     return (channel_subsys->css[cssid] != NULL);
1099 }
1100 
1101 bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno)
1102 {
1103     if (!channel_subsys->css[cssid]) {
1104         return false;
1105     }
1106     if (!channel_subsys->css[cssid]->sch_set[ssid]) {
1107         return false;
1108     }
1109 
1110     return !!test_bit(devno,
1111                       channel_subsys->css[cssid]->sch_set[ssid]->devnos_used);
1112 }
1113 
1114 void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
1115                       uint16_t devno, SubchDev *sch)
1116 {
1117     CssImage *css;
1118     SubchSet *s_set;
1119 
1120     trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid,
1121                            devno);
1122     if (!channel_subsys->css[cssid]) {
1123         fprintf(stderr,
1124                 "Suspicious call to %s (%x.%x.%04x) for non-existing css!\n",
1125                 __func__, cssid, ssid, schid);
1126         return;
1127     }
1128     css = channel_subsys->css[cssid];
1129 
1130     if (!css->sch_set[ssid]) {
1131         css->sch_set[ssid] = g_malloc0(sizeof(SubchSet));
1132     }
1133     s_set = css->sch_set[ssid];
1134 
1135     s_set->sch[schid] = sch;
1136     if (sch) {
1137         set_bit(schid, s_set->schids_used);
1138         set_bit(devno, s_set->devnos_used);
1139     } else {
1140         clear_bit(schid, s_set->schids_used);
1141         clear_bit(devno, s_set->devnos_used);
1142     }
1143 }
1144 
1145 void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid)
1146 {
1147     CrwContainer *crw_cont;
1148 
1149     trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : "");
1150     /* TODO: Maybe use a static crw pool? */
1151     crw_cont = g_try_malloc0(sizeof(CrwContainer));
1152     if (!crw_cont) {
1153         channel_subsys->crws_lost = true;
1154         return;
1155     }
1156     crw_cont->crw.flags = (rsc << 8) | erc;
1157     if (chain) {
1158         crw_cont->crw.flags |= CRW_FLAGS_MASK_C;
1159     }
1160     crw_cont->crw.rsid = rsid;
1161     if (channel_subsys->crws_lost) {
1162         crw_cont->crw.flags |= CRW_FLAGS_MASK_R;
1163         channel_subsys->crws_lost = false;
1164     }
1165 
1166     QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling);
1167 
1168     if (channel_subsys->do_crw_mchk) {
1169         S390CPU *cpu = s390_cpu_addr2state(0);
1170 
1171         channel_subsys->do_crw_mchk = false;
1172         /* Inject crw pending machine check. */
1173         s390_crw_mchk(cpu);
1174     }
1175 }
1176 
1177 void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
1178                            int hotplugged, int add)
1179 {
1180     uint8_t guest_cssid;
1181     bool chain_crw;
1182 
1183     if (add && !hotplugged) {
1184         return;
1185     }
1186     if (channel_subsys->max_cssid == 0) {
1187         /* Default cssid shows up as 0. */
1188         guest_cssid = (cssid == channel_subsys->default_cssid) ? 0 : cssid;
1189     } else {
1190         /* Show real cssid to the guest. */
1191         guest_cssid = cssid;
1192     }
1193     /*
1194      * Only notify for higher subchannel sets/channel subsystems if the
1195      * guest has enabled it.
1196      */
1197     if ((ssid > channel_subsys->max_ssid) ||
1198         (guest_cssid > channel_subsys->max_cssid) ||
1199         ((channel_subsys->max_cssid == 0) &&
1200          (cssid != channel_subsys->default_cssid))) {
1201         return;
1202     }
1203     chain_crw = (channel_subsys->max_ssid > 0) ||
1204             (channel_subsys->max_cssid > 0);
1205     css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid);
1206     if (chain_crw) {
1207         css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0,
1208                       (guest_cssid << 8) | (ssid << 4));
1209     }
1210 }
1211 
1212 void css_generate_chp_crws(uint8_t cssid, uint8_t chpid)
1213 {
1214     /* TODO */
1215 }
1216 
1217 int css_enable_mcsse(void)
1218 {
1219     trace_css_enable_facility("mcsse");
1220     channel_subsys->max_cssid = MAX_CSSID;
1221     return 0;
1222 }
1223 
1224 int css_enable_mss(void)
1225 {
1226     trace_css_enable_facility("mss");
1227     channel_subsys->max_ssid = MAX_SSID;
1228     return 0;
1229 }
1230 
1231 static void css_init(void)
1232 {
1233     channel_subsys = g_malloc0(sizeof(*channel_subsys));
1234     QTAILQ_INIT(&channel_subsys->pending_crws);
1235     channel_subsys->do_crw_mchk = true;
1236     channel_subsys->crws_lost = false;
1237     channel_subsys->chnmon_active = false;
1238 }
1239 machine_init(css_init);
1240 
1241 void css_reset_sch(SubchDev *sch)
1242 {
1243     PMCW *p = &sch->curr_status.pmcw;
1244 
1245     p->intparm = 0;
1246     p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA |
1247                   PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME |
1248                   PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF);
1249     p->flags |= PMCW_FLAGS_MASK_DNV;
1250     p->devno = sch->devno;
1251     p->pim = 0x80;
1252     p->lpm = p->pim;
1253     p->pnom = 0;
1254     p->lpum = 0;
1255     p->mbi = 0;
1256     p->pom = 0xff;
1257     p->pam = 0x80;
1258     p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME |
1259                   PMCW_CHARS_MASK_CSENSE);
1260 
1261     memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw));
1262     sch->curr_status.mba = 0;
1263 
1264     sch->channel_prog = 0x0;
1265     sch->last_cmd_valid = false;
1266     sch->thinint_active = false;
1267 }
1268 
1269 void css_reset(void)
1270 {
1271     CrwContainer *crw_cont;
1272 
1273     /* Clean up monitoring. */
1274     channel_subsys->chnmon_active = false;
1275     channel_subsys->chnmon_area = 0;
1276 
1277     /* Clear pending CRWs. */
1278     while ((crw_cont = QTAILQ_FIRST(&channel_subsys->pending_crws))) {
1279         QTAILQ_REMOVE(&channel_subsys->pending_crws, crw_cont, sibling);
1280         g_free(crw_cont);
1281     }
1282     channel_subsys->do_crw_mchk = true;
1283     channel_subsys->crws_lost = false;
1284 
1285     /* Reset maximum ids. */
1286     channel_subsys->max_cssid = 0;
1287     channel_subsys->max_ssid = 0;
1288 }
1289