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 "hw/virtio/virtio-scsi.h"
16 #include "qemu/error-report.h"
17 #include "sysemu/block-backend.h"
18 #include <hw/scsi/scsi.h>
19 #include <block/scsi.h>
20 #include <hw/virtio/virtio-bus.h>
21 #include "hw/virtio/virtio-access.h"
23 /* Context: QEMU global mutex held */
24 void virtio_scsi_set_iothread(VirtIOSCSI
*s
, IOThread
*iothread
)
26 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
27 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
28 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
31 s
->ctx
= iothread_get_aio_context(vs
->conf
.iothread
);
33 /* Don't try if transport does not support notifiers. */
34 if (!k
->set_guest_notifiers
|| !k
->set_host_notifier
) {
35 fprintf(stderr
, "virtio-scsi: Failed to set iothread "
36 "(transport does not support notifiers)");
41 static void virtio_scsi_data_plane_handle_cmd(VirtIODevice
*vdev
,
44 VirtIOSCSI
*s
= (VirtIOSCSI
*)vdev
;
46 assert(s
->ctx
&& s
->dataplane_started
);
47 virtio_scsi_handle_cmd_vq(s
, vq
);
50 static void virtio_scsi_data_plane_handle_ctrl(VirtIODevice
*vdev
,
53 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
55 assert(s
->ctx
&& s
->dataplane_started
);
56 virtio_scsi_handle_ctrl_vq(s
, vq
);
59 static void virtio_scsi_data_plane_handle_event(VirtIODevice
*vdev
,
62 VirtIOSCSI
*s
= VIRTIO_SCSI(vdev
);
64 assert(s
->ctx
&& s
->dataplane_started
);
65 virtio_scsi_handle_event_vq(s
, vq
);
68 static int virtio_scsi_vring_init(VirtIOSCSI
*s
, VirtQueue
*vq
, int n
,
69 void (*fn
)(VirtIODevice
*vdev
, VirtQueue
*vq
))
71 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
72 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
75 /* Set up virtqueue notify */
76 rc
= k
->set_host_notifier(qbus
->parent
, n
, true);
78 fprintf(stderr
, "virtio-scsi: Failed to set host notifier (%d)\n",
80 s
->dataplane_fenced
= true;
84 virtio_queue_aio_set_host_notifier_handler(vq
, s
->ctx
, true, true);
85 virtio_set_queue_aio(vq
, fn
);
89 void virtio_scsi_dataplane_notify(VirtIODevice
*vdev
, VirtIOSCSIReq
*req
)
91 if (virtio_should_notify(vdev
, req
->vq
)) {
92 event_notifier_set(virtio_queue_get_guest_notifier(req
->vq
));
96 /* assumes s->ctx held */
97 static void virtio_scsi_clear_aio(VirtIOSCSI
*s
)
99 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
102 virtio_queue_aio_set_host_notifier_handler(vs
->ctrl_vq
, s
->ctx
, false, false);
103 virtio_set_queue_aio(vs
->ctrl_vq
, NULL
);
104 virtio_queue_aio_set_host_notifier_handler(vs
->event_vq
, s
->ctx
, false, false);
105 virtio_set_queue_aio(vs
->event_vq
, NULL
);
106 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
107 virtio_queue_aio_set_host_notifier_handler(vs
->cmd_vqs
[i
], s
->ctx
, false, false);
108 virtio_set_queue_aio(vs
->cmd_vqs
[i
], NULL
);
112 /* Context: QEMU global mutex held */
113 void virtio_scsi_dataplane_start(VirtIOSCSI
*s
)
117 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
118 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
119 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
121 if (s
->dataplane_started
||
122 s
->dataplane_starting
||
123 s
->dataplane_fenced
||
124 s
->ctx
!= iothread_get_aio_context(vs
->conf
.iothread
)) {
128 s
->dataplane_starting
= true;
130 /* Set up guest notifier (irq) */
131 rc
= k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, true);
133 fprintf(stderr
, "virtio-scsi: Failed to set guest notifiers (%d), "
134 "ensure -enable-kvm is set\n", rc
);
135 goto fail_guest_notifiers
;
138 aio_context_acquire(s
->ctx
);
139 rc
= virtio_scsi_vring_init(s
, vs
->ctrl_vq
, 0,
140 virtio_scsi_data_plane_handle_ctrl
);
144 rc
= virtio_scsi_vring_init(s
, vs
->event_vq
, 1,
145 virtio_scsi_data_plane_handle_event
);
149 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
150 rc
= virtio_scsi_vring_init(s
, vs
->cmd_vqs
[i
], i
+ 2,
151 virtio_scsi_data_plane_handle_cmd
);
157 s
->dataplane_starting
= false;
158 s
->dataplane_started
= true;
159 aio_context_release(s
->ctx
);
163 virtio_scsi_clear_aio(s
);
164 aio_context_release(s
->ctx
);
165 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
166 k
->set_host_notifier(qbus
->parent
, i
, false);
168 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
169 fail_guest_notifiers
:
170 s
->dataplane_fenced
= true;
171 s
->dataplane_starting
= false;
172 s
->dataplane_started
= true;
175 /* Context: QEMU global mutex held */
176 void virtio_scsi_dataplane_stop(VirtIOSCSI
*s
)
178 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
179 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
180 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
183 if (!s
->dataplane_started
|| s
->dataplane_stopping
) {
187 /* Better luck next time. */
188 if (s
->dataplane_fenced
) {
189 s
->dataplane_fenced
= false;
190 s
->dataplane_started
= false;
193 s
->dataplane_stopping
= true;
194 assert(s
->ctx
== iothread_get_aio_context(vs
->conf
.iothread
));
196 aio_context_acquire(s
->ctx
);
198 virtio_scsi_clear_aio(s
);
200 blk_drain_all(); /* ensure there are no in-flight requests */
202 aio_context_release(s
->ctx
);
204 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
205 k
->set_host_notifier(qbus
->parent
, i
, false);
208 /* Clean up guest notifier (irq) */
209 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
210 s
->dataplane_stopping
= false;
211 s
->dataplane_started
= false;