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 "scsi/constants.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 int virtio_scsi_set_host_notifier(VirtIOSCSI
*s
, VirtQueue
*vq
, int n
)
54 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
57 /* Set up virtqueue notify */
58 rc
= virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), n
, true);
60 fprintf(stderr
, "virtio-scsi: Failed to set host notifier (%d)\n",
62 s
->dataplane_fenced
= true;
69 /* Context: BH in IOThread */
70 static void virtio_scsi_dataplane_stop_bh(void *opaque
)
72 VirtIOSCSI
*s
= opaque
;
73 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
76 virtio_queue_aio_detach_host_notifier(vs
->ctrl_vq
, s
->ctx
);
77 virtio_queue_aio_detach_host_notifier(vs
->event_vq
, s
->ctx
);
78 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
79 virtio_queue_aio_detach_host_notifier(vs
->cmd_vqs
[i
], s
->ctx
);
83 /* Context: QEMU global mutex held */
84 int virtio_scsi_dataplane_start(VirtIODevice
*vdev
)
88 int vq_init_count
= 0;
89 BusState
*qbus
= qdev_get_parent_bus(DEVICE(vdev
));
90 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
91 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(vdev
);
92 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
94 if (s
->dataplane_started
||
95 s
->dataplane_starting
||
96 s
->dataplane_fenced
) {
100 s
->dataplane_starting
= true;
102 /* Set up guest notifier (irq) */
103 rc
= k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, true);
105 error_report("virtio-scsi: Failed to set guest notifiers (%d), "
106 "ensure -accel kvm is set.", rc
);
107 goto fail_guest_notifiers
;
111 * Batch all the host notifiers in a single transaction to avoid
112 * quadratic time complexity in address_space_update_ioeventfds().
114 memory_region_transaction_begin();
116 rc
= virtio_scsi_set_host_notifier(s
, vs
->ctrl_vq
, 0);
118 goto fail_host_notifiers
;
122 rc
= virtio_scsi_set_host_notifier(s
, vs
->event_vq
, 1);
124 goto fail_host_notifiers
;
129 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
130 rc
= virtio_scsi_set_host_notifier(s
, vs
->cmd_vqs
[i
], i
+ 2);
132 goto fail_host_notifiers
;
137 memory_region_transaction_commit();
140 * These fields are visible to the IOThread so we rely on implicit barriers
141 * in aio_context_acquire() on the write side and aio_notify_accept() on
144 s
->dataplane_starting
= false;
145 s
->dataplane_started
= true;
147 aio_context_acquire(s
->ctx
);
148 virtio_queue_aio_attach_host_notifier(vs
->ctrl_vq
, s
->ctx
);
149 virtio_queue_aio_attach_host_notifier_no_poll(vs
->event_vq
, s
->ctx
);
151 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
152 virtio_queue_aio_attach_host_notifier(vs
->cmd_vqs
[i
], s
->ctx
);
154 aio_context_release(s
->ctx
);
158 for (i
= 0; i
< vq_init_count
; i
++) {
159 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), i
, false);
163 * The transaction expects the ioeventfds to be open when it
164 * commits. Do it now, before the cleanup loop.
166 memory_region_transaction_commit();
168 for (i
= 0; i
< vq_init_count
; i
++) {
169 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus
), i
);
171 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
172 fail_guest_notifiers
:
173 s
->dataplane_fenced
= true;
174 s
->dataplane_starting
= false;
175 s
->dataplane_started
= true;
179 /* Context: QEMU global mutex held */
180 void virtio_scsi_dataplane_stop(VirtIODevice
*vdev
)
182 BusState
*qbus
= qdev_get_parent_bus(DEVICE(vdev
));
183 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
184 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(vdev
);
185 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
188 if (!s
->dataplane_started
|| s
->dataplane_stopping
) {
192 /* Better luck next time. */
193 if (s
->dataplane_fenced
) {
194 s
->dataplane_fenced
= false;
195 s
->dataplane_started
= false;
198 s
->dataplane_stopping
= true;
200 aio_context_acquire(s
->ctx
);
201 aio_wait_bh_oneshot(s
->ctx
, virtio_scsi_dataplane_stop_bh
, s
);
202 aio_context_release(s
->ctx
);
204 blk_drain_all(); /* ensure there are no in-flight requests */
207 * Batch all the host notifiers in a single transaction to avoid
208 * quadratic time complexity in address_space_update_ioeventfds().
210 memory_region_transaction_begin();
212 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
213 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus
), i
, false);
217 * The transaction expects the ioeventfds to be open when it
218 * commits. Do it now, before the cleanup loop.
220 memory_region_transaction_commit();
222 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
223 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus
), i
);
226 /* Clean up guest notifier (irq) */
227 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
228 s
->dataplane_stopping
= false;
229 s
->dataplane_started
= false;