1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Finite state machine for vfio-ccw device handling
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright IBM Corp. 2017
6*4882a593Smuzhiyun * Copyright Red Hat, Inc. 2019
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
9*4882a593Smuzhiyun * Cornelia Huck <cohuck@redhat.com>
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/vfio.h>
13*4882a593Smuzhiyun #include <linux/mdev.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "ioasm.h"
16*4882a593Smuzhiyun #include "vfio_ccw_private.h"
17*4882a593Smuzhiyun
fsm_io_helper(struct vfio_ccw_private * private)18*4882a593Smuzhiyun static int fsm_io_helper(struct vfio_ccw_private *private)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun struct subchannel *sch;
21*4882a593Smuzhiyun union orb *orb;
22*4882a593Smuzhiyun int ccode;
23*4882a593Smuzhiyun __u8 lpm;
24*4882a593Smuzhiyun unsigned long flags;
25*4882a593Smuzhiyun int ret;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun sch = private->sch;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun spin_lock_irqsave(sch->lock, flags);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm);
32*4882a593Smuzhiyun if (!orb) {
33*4882a593Smuzhiyun ret = -EIO;
34*4882a593Smuzhiyun goto out;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(5, "stIO");
38*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(5, dev_name(&sch->dev));
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* Issue "Start Subchannel" */
41*4882a593Smuzhiyun ccode = ssch(sch->schid, orb);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun VFIO_CCW_HEX_EVENT(5, &ccode, sizeof(ccode));
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun switch (ccode) {
46*4882a593Smuzhiyun case 0:
47*4882a593Smuzhiyun /*
48*4882a593Smuzhiyun * Initialize device status information
49*4882a593Smuzhiyun */
50*4882a593Smuzhiyun sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND;
51*4882a593Smuzhiyun ret = 0;
52*4882a593Smuzhiyun private->state = VFIO_CCW_STATE_CP_PENDING;
53*4882a593Smuzhiyun break;
54*4882a593Smuzhiyun case 1: /* Status pending */
55*4882a593Smuzhiyun case 2: /* Busy */
56*4882a593Smuzhiyun ret = -EBUSY;
57*4882a593Smuzhiyun break;
58*4882a593Smuzhiyun case 3: /* Device/path not operational */
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun lpm = orb->cmd.lpm;
61*4882a593Smuzhiyun if (lpm != 0)
62*4882a593Smuzhiyun sch->lpm &= ~lpm;
63*4882a593Smuzhiyun else
64*4882a593Smuzhiyun sch->lpm = 0;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (cio_update_schib(sch))
67*4882a593Smuzhiyun ret = -ENODEV;
68*4882a593Smuzhiyun else
69*4882a593Smuzhiyun ret = sch->lpm ? -EACCES : -ENODEV;
70*4882a593Smuzhiyun break;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun default:
73*4882a593Smuzhiyun ret = ccode;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun out:
76*4882a593Smuzhiyun spin_unlock_irqrestore(sch->lock, flags);
77*4882a593Smuzhiyun return ret;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
fsm_do_halt(struct vfio_ccw_private * private)80*4882a593Smuzhiyun static int fsm_do_halt(struct vfio_ccw_private *private)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun struct subchannel *sch;
83*4882a593Smuzhiyun unsigned long flags;
84*4882a593Smuzhiyun int ccode;
85*4882a593Smuzhiyun int ret;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun sch = private->sch;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun spin_lock_irqsave(sch->lock, flags);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, "haltIO");
92*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev));
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* Issue "Halt Subchannel" */
95*4882a593Smuzhiyun ccode = hsch(sch->schid);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode));
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun switch (ccode) {
100*4882a593Smuzhiyun case 0:
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun * Initialize device status information
103*4882a593Smuzhiyun */
104*4882a593Smuzhiyun sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND;
105*4882a593Smuzhiyun ret = 0;
106*4882a593Smuzhiyun break;
107*4882a593Smuzhiyun case 1: /* Status pending */
108*4882a593Smuzhiyun case 2: /* Busy */
109*4882a593Smuzhiyun ret = -EBUSY;
110*4882a593Smuzhiyun break;
111*4882a593Smuzhiyun case 3: /* Device not operational */
112*4882a593Smuzhiyun ret = -ENODEV;
113*4882a593Smuzhiyun break;
114*4882a593Smuzhiyun default:
115*4882a593Smuzhiyun ret = ccode;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun spin_unlock_irqrestore(sch->lock, flags);
118*4882a593Smuzhiyun return ret;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
fsm_do_clear(struct vfio_ccw_private * private)121*4882a593Smuzhiyun static int fsm_do_clear(struct vfio_ccw_private *private)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct subchannel *sch;
124*4882a593Smuzhiyun unsigned long flags;
125*4882a593Smuzhiyun int ccode;
126*4882a593Smuzhiyun int ret;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun sch = private->sch;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun spin_lock_irqsave(sch->lock, flags);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, "clearIO");
133*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev));
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* Issue "Clear Subchannel" */
136*4882a593Smuzhiyun ccode = csch(sch->schid);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode));
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun switch (ccode) {
141*4882a593Smuzhiyun case 0:
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun * Initialize device status information
144*4882a593Smuzhiyun */
145*4882a593Smuzhiyun sch->schib.scsw.cmd.actl = SCSW_ACTL_CLEAR_PEND;
146*4882a593Smuzhiyun /* TODO: check what else we might need to clear */
147*4882a593Smuzhiyun ret = 0;
148*4882a593Smuzhiyun break;
149*4882a593Smuzhiyun case 3: /* Device not operational */
150*4882a593Smuzhiyun ret = -ENODEV;
151*4882a593Smuzhiyun break;
152*4882a593Smuzhiyun default:
153*4882a593Smuzhiyun ret = ccode;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun spin_unlock_irqrestore(sch->lock, flags);
156*4882a593Smuzhiyun return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
fsm_notoper(struct vfio_ccw_private * private,enum vfio_ccw_event event)159*4882a593Smuzhiyun static void fsm_notoper(struct vfio_ccw_private *private,
160*4882a593Smuzhiyun enum vfio_ccw_event event)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun struct subchannel *sch = private->sch;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, "notoper");
165*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev));
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * TODO:
169*4882a593Smuzhiyun * Probably we should send the machine check to the guest.
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun css_sched_sch_todo(sch, SCH_TODO_UNREG);
172*4882a593Smuzhiyun private->state = VFIO_CCW_STATE_NOT_OPER;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /*
176*4882a593Smuzhiyun * No operation action.
177*4882a593Smuzhiyun */
fsm_nop(struct vfio_ccw_private * private,enum vfio_ccw_event event)178*4882a593Smuzhiyun static void fsm_nop(struct vfio_ccw_private *private,
179*4882a593Smuzhiyun enum vfio_ccw_event event)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
fsm_io_error(struct vfio_ccw_private * private,enum vfio_ccw_event event)183*4882a593Smuzhiyun static void fsm_io_error(struct vfio_ccw_private *private,
184*4882a593Smuzhiyun enum vfio_ccw_event event)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun pr_err("vfio-ccw: FSM: I/O request from state:%d\n", private->state);
187*4882a593Smuzhiyun private->io_region->ret_code = -EIO;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
fsm_io_busy(struct vfio_ccw_private * private,enum vfio_ccw_event event)190*4882a593Smuzhiyun static void fsm_io_busy(struct vfio_ccw_private *private,
191*4882a593Smuzhiyun enum vfio_ccw_event event)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun private->io_region->ret_code = -EBUSY;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
fsm_io_retry(struct vfio_ccw_private * private,enum vfio_ccw_event event)196*4882a593Smuzhiyun static void fsm_io_retry(struct vfio_ccw_private *private,
197*4882a593Smuzhiyun enum vfio_ccw_event event)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun private->io_region->ret_code = -EAGAIN;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
fsm_async_error(struct vfio_ccw_private * private,enum vfio_ccw_event event)202*4882a593Smuzhiyun static void fsm_async_error(struct vfio_ccw_private *private,
203*4882a593Smuzhiyun enum vfio_ccw_event event)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun struct ccw_cmd_region *cmd_region = private->cmd_region;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun pr_err("vfio-ccw: FSM: %s request from state:%d\n",
208*4882a593Smuzhiyun cmd_region->command == VFIO_CCW_ASYNC_CMD_HSCH ? "halt" :
209*4882a593Smuzhiyun cmd_region->command == VFIO_CCW_ASYNC_CMD_CSCH ? "clear" :
210*4882a593Smuzhiyun "<unknown>", private->state);
211*4882a593Smuzhiyun cmd_region->ret_code = -EIO;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
fsm_async_retry(struct vfio_ccw_private * private,enum vfio_ccw_event event)214*4882a593Smuzhiyun static void fsm_async_retry(struct vfio_ccw_private *private,
215*4882a593Smuzhiyun enum vfio_ccw_event event)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun private->cmd_region->ret_code = -EAGAIN;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
fsm_disabled_irq(struct vfio_ccw_private * private,enum vfio_ccw_event event)220*4882a593Smuzhiyun static void fsm_disabled_irq(struct vfio_ccw_private *private,
221*4882a593Smuzhiyun enum vfio_ccw_event event)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun struct subchannel *sch = private->sch;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun * An interrupt in a disabled state means a previous disable was not
227*4882a593Smuzhiyun * successful - should not happen, but we try to disable again.
228*4882a593Smuzhiyun */
229*4882a593Smuzhiyun cio_disable_subchannel(sch);
230*4882a593Smuzhiyun }
get_schid(struct vfio_ccw_private * p)231*4882a593Smuzhiyun inline struct subchannel_id get_schid(struct vfio_ccw_private *p)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun return p->sch->schid;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun /*
237*4882a593Smuzhiyun * Deal with the ccw command request from the userspace.
238*4882a593Smuzhiyun */
fsm_io_request(struct vfio_ccw_private * private,enum vfio_ccw_event event)239*4882a593Smuzhiyun static void fsm_io_request(struct vfio_ccw_private *private,
240*4882a593Smuzhiyun enum vfio_ccw_event event)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun union orb *orb;
243*4882a593Smuzhiyun union scsw *scsw = &private->scsw;
244*4882a593Smuzhiyun struct ccw_io_region *io_region = private->io_region;
245*4882a593Smuzhiyun struct mdev_device *mdev = private->mdev;
246*4882a593Smuzhiyun char *errstr = "request";
247*4882a593Smuzhiyun struct subchannel_id schid = get_schid(private);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun private->state = VFIO_CCW_STATE_CP_PROCESSING;
250*4882a593Smuzhiyun memcpy(scsw, io_region->scsw_area, sizeof(*scsw));
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) {
253*4882a593Smuzhiyun orb = (union orb *)io_region->orb_area;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* Don't try to build a cp if transport mode is specified. */
256*4882a593Smuzhiyun if (orb->tm.b) {
257*4882a593Smuzhiyun io_region->ret_code = -EOPNOTSUPP;
258*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
259*4882a593Smuzhiyun "%pUl (%x.%x.%04x): transport mode\n",
260*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
261*4882a593Smuzhiyun schid.ssid, schid.sch_no);
262*4882a593Smuzhiyun errstr = "transport mode";
263*4882a593Smuzhiyun goto err_out;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev),
266*4882a593Smuzhiyun orb);
267*4882a593Smuzhiyun if (io_region->ret_code) {
268*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
269*4882a593Smuzhiyun "%pUl (%x.%x.%04x): cp_init=%d\n",
270*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
271*4882a593Smuzhiyun schid.ssid, schid.sch_no,
272*4882a593Smuzhiyun io_region->ret_code);
273*4882a593Smuzhiyun errstr = "cp init";
274*4882a593Smuzhiyun goto err_out;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun io_region->ret_code = cp_prefetch(&private->cp);
278*4882a593Smuzhiyun if (io_region->ret_code) {
279*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
280*4882a593Smuzhiyun "%pUl (%x.%x.%04x): cp_prefetch=%d\n",
281*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
282*4882a593Smuzhiyun schid.ssid, schid.sch_no,
283*4882a593Smuzhiyun io_region->ret_code);
284*4882a593Smuzhiyun errstr = "cp prefetch";
285*4882a593Smuzhiyun cp_free(&private->cp);
286*4882a593Smuzhiyun goto err_out;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /* Start channel program and wait for I/O interrupt. */
290*4882a593Smuzhiyun io_region->ret_code = fsm_io_helper(private);
291*4882a593Smuzhiyun if (io_region->ret_code) {
292*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
293*4882a593Smuzhiyun "%pUl (%x.%x.%04x): fsm_io_helper=%d\n",
294*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
295*4882a593Smuzhiyun schid.ssid, schid.sch_no,
296*4882a593Smuzhiyun io_region->ret_code);
297*4882a593Smuzhiyun errstr = "cp fsm_io_helper";
298*4882a593Smuzhiyun cp_free(&private->cp);
299*4882a593Smuzhiyun goto err_out;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun return;
302*4882a593Smuzhiyun } else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) {
303*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
304*4882a593Smuzhiyun "%pUl (%x.%x.%04x): halt on io_region\n",
305*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
306*4882a593Smuzhiyun schid.ssid, schid.sch_no);
307*4882a593Smuzhiyun /* halt is handled via the async cmd region */
308*4882a593Smuzhiyun io_region->ret_code = -EOPNOTSUPP;
309*4882a593Smuzhiyun goto err_out;
310*4882a593Smuzhiyun } else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) {
311*4882a593Smuzhiyun VFIO_CCW_MSG_EVENT(2,
312*4882a593Smuzhiyun "%pUl (%x.%x.%04x): clear on io_region\n",
313*4882a593Smuzhiyun mdev_uuid(mdev), schid.cssid,
314*4882a593Smuzhiyun schid.ssid, schid.sch_no);
315*4882a593Smuzhiyun /* clear is handled via the async cmd region */
316*4882a593Smuzhiyun io_region->ret_code = -EOPNOTSUPP;
317*4882a593Smuzhiyun goto err_out;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun err_out:
321*4882a593Smuzhiyun private->state = VFIO_CCW_STATE_IDLE;
322*4882a593Smuzhiyun trace_vfio_ccw_fsm_io_request(scsw->cmd.fctl, schid,
323*4882a593Smuzhiyun io_region->ret_code, errstr);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /*
327*4882a593Smuzhiyun * Deal with an async request from userspace.
328*4882a593Smuzhiyun */
fsm_async_request(struct vfio_ccw_private * private,enum vfio_ccw_event event)329*4882a593Smuzhiyun static void fsm_async_request(struct vfio_ccw_private *private,
330*4882a593Smuzhiyun enum vfio_ccw_event event)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun struct ccw_cmd_region *cmd_region = private->cmd_region;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun switch (cmd_region->command) {
335*4882a593Smuzhiyun case VFIO_CCW_ASYNC_CMD_HSCH:
336*4882a593Smuzhiyun cmd_region->ret_code = fsm_do_halt(private);
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun case VFIO_CCW_ASYNC_CMD_CSCH:
339*4882a593Smuzhiyun cmd_region->ret_code = fsm_do_clear(private);
340*4882a593Smuzhiyun break;
341*4882a593Smuzhiyun default:
342*4882a593Smuzhiyun /* should not happen? */
343*4882a593Smuzhiyun cmd_region->ret_code = -EINVAL;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun trace_vfio_ccw_fsm_async_request(get_schid(private),
347*4882a593Smuzhiyun cmd_region->command,
348*4882a593Smuzhiyun cmd_region->ret_code);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /*
352*4882a593Smuzhiyun * Got an interrupt for a normal io (state busy).
353*4882a593Smuzhiyun */
fsm_irq(struct vfio_ccw_private * private,enum vfio_ccw_event event)354*4882a593Smuzhiyun static void fsm_irq(struct vfio_ccw_private *private,
355*4882a593Smuzhiyun enum vfio_ccw_event event)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun struct irb *irb = this_cpu_ptr(&cio_irb);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(6, "IRQ");
360*4882a593Smuzhiyun VFIO_CCW_TRACE_EVENT(6, dev_name(&private->sch->dev));
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun memcpy(&private->irb, irb, sizeof(*irb));
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun queue_work(vfio_ccw_work_q, &private->io_work);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (private->completion)
367*4882a593Smuzhiyun complete(private->completion);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /*
371*4882a593Smuzhiyun * Device statemachine
372*4882a593Smuzhiyun */
373*4882a593Smuzhiyun fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = {
374*4882a593Smuzhiyun [VFIO_CCW_STATE_NOT_OPER] = {
375*4882a593Smuzhiyun [VFIO_CCW_EVENT_NOT_OPER] = fsm_nop,
376*4882a593Smuzhiyun [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
377*4882a593Smuzhiyun [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error,
378*4882a593Smuzhiyun [VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq,
379*4882a593Smuzhiyun },
380*4882a593Smuzhiyun [VFIO_CCW_STATE_STANDBY] = {
381*4882a593Smuzhiyun [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
382*4882a593Smuzhiyun [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
383*4882a593Smuzhiyun [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error,
384*4882a593Smuzhiyun [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
385*4882a593Smuzhiyun },
386*4882a593Smuzhiyun [VFIO_CCW_STATE_IDLE] = {
387*4882a593Smuzhiyun [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
388*4882a593Smuzhiyun [VFIO_CCW_EVENT_IO_REQ] = fsm_io_request,
389*4882a593Smuzhiyun [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request,
390*4882a593Smuzhiyun [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
391*4882a593Smuzhiyun },
392*4882a593Smuzhiyun [VFIO_CCW_STATE_CP_PROCESSING] = {
393*4882a593Smuzhiyun [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
394*4882a593Smuzhiyun [VFIO_CCW_EVENT_IO_REQ] = fsm_io_retry,
395*4882a593Smuzhiyun [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_retry,
396*4882a593Smuzhiyun [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
397*4882a593Smuzhiyun },
398*4882a593Smuzhiyun [VFIO_CCW_STATE_CP_PENDING] = {
399*4882a593Smuzhiyun [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
400*4882a593Smuzhiyun [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
401*4882a593Smuzhiyun [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request,
402*4882a593Smuzhiyun [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
403*4882a593Smuzhiyun },
404*4882a593Smuzhiyun };
405