2 * Virtio SCSI dataplane
4 * Copyright Red Hat, Inc. 2014
7 * Fam Zheng <famz@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qapi/error.h"
16 #include "hw/virtio/virtio-scsi.h"
17 #include "qemu/error-report.h"
18 #include "sysemu/block-backend.h"
19 #include "hw/scsi/scsi.h"
20 #include "block/scsi.h"
21 #include "hw/virtio/virtio-bus.h"
22 #include "hw/virtio/virtio-access.h"
24 /* Context: QEMU global mutex held */
25 void virtio_scsi_dataplane_setup(VirtIOSCSI
*s
, Error
**errp
)
27 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
28 VirtIODevice
*vdev
= VIRTIO_DEVICE(s
);
29 BusState
*qbus
= qdev_get_parent_bus(DEVICE(vdev
));
30 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
32 if (vs
->conf
.iothread
) {
33 if (!k
->set_guest_notifiers
|| !k
->ioeventfd_assign
) {
35 "device is incompatible with iothread "
36 "(transport does not support notifiers)");
39 if (!virtio_device_ioeventfd_enabled(vdev
)) {
40 error_setg(errp
, "ioeventfd is required for iothread");
43 s
->ctx
= iothread_get_aio_context(vs
->conf
.iothread
);
45 if (!virtio_device_ioeventfd_enabled(vdev
)) {
48 s
->ctx
= qemu_get_aio_context();
52 static void virtio_scsi_data_plane_handle_cmd(VirtIODevice
*vdev
,
55 VirtIOSCSI
*s
= (VirtIOSCSI
*)vdev
;
57 assert(s
->ctx
&& s
->dataplane_started
);
58 virtio_scsi_handle_cmd_vq(s
, vq
);
61 static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice
*vdev
,
64 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
66 assert(s
->ctx
&& s
->dataplane_started
);
67 virtio_scsi_handle_ctrl_vq(s
, vq
);
70 static void virtio_scsi_data_plane_handle_event(VirtIODevice
*vdev
,
73 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
75 assert(s
->ctx
&& s
->dataplane_started
);
76 virtio_scsi_handle_event_vq(s
, vq
);
79 static int virtio_scsi_vring_init(VirtIOSCSI
*s
, VirtQueue
*vq
, int n
,
80 void (*fn
)(VirtIODevice
*vdev
, VirtQueue
*vq
))
82 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
85 /* Set up virtqueue notify */
86 rc
= virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), n
, true);
88 fprintf(stderr
, "virtio-scsi: Failed to set host notifier (%d)\n",
90 s
->dataplane_fenced
= true;
94 virtio_queue_aio_set_host_notifier_handler(vq
, s
->ctx
, fn
);
98 void virtio_scsi_dataplane_notify(VirtIODevice
*vdev
, VirtIOSCSIReq
*req
)
100 if (virtio_should_notify(vdev
, req
->vq
)) {
101 event_notifier_set(virtio_queue_get_guest_notifier(req
->vq
));
105 /* assumes s->ctx held */
106 static void virtio_scsi_clear_aio(VirtIOSCSI
*s
)
108 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
111 virtio_queue_aio_set_host_notifier_handler(vs
->ctrl_vq
, s
->ctx
, NULL
);
112 virtio_queue_aio_set_host_notifier_handler(vs
->event_vq
, s
->ctx
, NULL
);
113 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
114 virtio_queue_aio_set_host_notifier_handler(vs
->cmd_vqs
[i
], s
->ctx
, NULL
);
118 /* Context: QEMU global mutex held */
119 int virtio_scsi_dataplane_start(VirtIODevice
*vdev
)
123 BusState
*qbus
= qdev_get_parent_bus(DEVICE(vdev
));
124 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
125 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(vdev
);
126 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
128 if (s
->dataplane_started
||
129 s
->dataplane_starting
||
130 s
->dataplane_fenced
) {
134 s
->dataplane_starting
= true;
136 /* Set up guest notifier (irq) */
137 rc
= k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, true);
139 fprintf(stderr
, "virtio-scsi: Failed to set guest notifiers (%d), "
140 "ensure -enable-kvm is set\n", rc
);
141 goto fail_guest_notifiers
;
144 aio_context_acquire(s
->ctx
);
145 rc
= virtio_scsi_vring_init(s
, vs
->ctrl_vq
, 0,
146 virtio_scsi_data_plane_handle_ctrl
);
150 rc
= virtio_scsi_vring_init(s
, vs
->event_vq
, 1,
151 virtio_scsi_data_plane_handle_event
);
155 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
156 rc
= virtio_scsi_vring_init(s
, vs
->cmd_vqs
[i
], i
+ 2,
157 virtio_scsi_data_plane_handle_cmd
);
163 s
->dataplane_starting
= false;
164 s
->dataplane_started
= true;
165 aio_context_release(s
->ctx
);
169 virtio_scsi_clear_aio(s
);
170 aio_context_release(s
->ctx
);
171 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
172 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), i
, false);
174 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
175 fail_guest_notifiers
:
176 s
->dataplane_fenced
= true;
177 s
->dataplane_starting
= false;
178 s
->dataplane_started
= true;
182 /* Context: QEMU global mutex held */
183 void virtio_scsi_dataplane_stop(VirtIODevice
*vdev
)
185 BusState
*qbus
= qdev_get_parent_bus(DEVICE(vdev
));
186 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
187 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(vdev
);
188 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
191 if (!s
->dataplane_started
|| s
->dataplane_stopping
) {
195 /* Better luck next time. */
196 if (s
->dataplane_fenced
) {
197 s
->dataplane_fenced
= false;
198 s
->dataplane_started
= false;
201 s
->dataplane_stopping
= true;
203 aio_context_acquire(s
->ctx
);
205 virtio_scsi_clear_aio(s
);
207 blk_drain_all(); /* ensure there are no in-flight requests */
209 aio_context_release(s
->ctx
);
211 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
212 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), i
, false);
215 /* Clean up guest notifier (irq) */
216 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
217 s
->dataplane_stopping
= false;
218 s
->dataplane_started
= false;