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