Statistics
| Branch: | Revision:

root / hw / s390x / css.c @ 5d6c0c49

History | View | Annotate | Download (34.7 kB)

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