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 "hw/virtio/virtio-scsi.h"
15 #include "qemu/error-report.h"
16 #include <hw/scsi/scsi.h>
17 #include <block/scsi.h>
18 #include <hw/virtio/virtio-bus.h>
19 #include "hw/virtio/virtio-access.h"
22 /* Context: QEMU global mutex held */
23 void virtio_scsi_set_iothread(VirtIOSCSI
*s
, IOThread
*iothread
)
25 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
26 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
27 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
30 s
->ctx
= iothread_get_aio_context(vs
->conf
.iothread
);
32 /* Don't try if transport does not support notifiers. */
33 if (!k
->set_guest_notifiers
|| !k
->set_host_notifier
) {
34 fprintf(stderr
, "virtio-scsi: Failed to set iothread "
35 "(transport does not support notifiers)");
40 static VirtIOSCSIVring
*virtio_scsi_vring_init(VirtIOSCSI
*s
,
42 EventNotifierHandler
*handler
,
45 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
46 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
47 VirtIOSCSIVring
*r
= g_slice_new(VirtIOSCSIVring
);
49 /* Set up virtqueue notify */
50 if (k
->set_host_notifier(qbus
->parent
, n
, true) != 0) {
51 fprintf(stderr
, "virtio-scsi: Failed to set host notifier\n");
54 r
->host_notifier
= *virtio_queue_get_host_notifier(vq
);
55 r
->guest_notifier
= *virtio_queue_get_guest_notifier(vq
);
56 aio_set_event_notifier(s
->ctx
, &r
->host_notifier
, handler
);
60 if (!vring_setup(&r
->vring
, VIRTIO_DEVICE(s
), n
)) {
61 fprintf(stderr
, "virtio-scsi: VRing setup failed\n");
67 VirtIOSCSIReq
*virtio_scsi_pop_req_vring(VirtIOSCSI
*s
,
68 VirtIOSCSIVring
*vring
)
70 VirtIOSCSIReq
*req
= virtio_scsi_init_req(s
, NULL
);
74 r
= vring_pop((VirtIODevice
*)s
, &vring
->vring
, &req
->elem
);
76 virtio_scsi_free_req(req
);
82 void virtio_scsi_vring_push_notify(VirtIOSCSIReq
*req
)
84 vring_push(&req
->vring
->vring
, &req
->elem
,
85 req
->qsgl
.size
+ req
->resp_iov
.size
);
86 event_notifier_set(&req
->vring
->guest_notifier
);
89 static void virtio_scsi_iothread_handle_ctrl(EventNotifier
*notifier
)
91 VirtIOSCSIVring
*vring
= container_of(notifier
,
92 VirtIOSCSIVring
, host_notifier
);
93 VirtIOSCSI
*s
= VIRTIO_SCSI(vring
->parent
);
96 event_notifier_test_and_clear(notifier
);
97 while ((req
= virtio_scsi_pop_req_vring(s
, vring
))) {
98 virtio_scsi_handle_ctrl_req(s
, req
);
102 static void virtio_scsi_iothread_handle_event(EventNotifier
*notifier
)
104 VirtIOSCSIVring
*vring
= container_of(notifier
,
105 VirtIOSCSIVring
, host_notifier
);
106 VirtIOSCSI
*s
= vring
->parent
;
107 VirtIODevice
*vdev
= VIRTIO_DEVICE(s
);
109 event_notifier_test_and_clear(notifier
);
111 if (!(vdev
->status
& VIRTIO_CONFIG_S_DRIVER_OK
)) {
115 if (s
->events_dropped
) {
116 virtio_scsi_push_event(s
, NULL
, VIRTIO_SCSI_T_NO_EVENT
, 0);
120 static void virtio_scsi_iothread_handle_cmd(EventNotifier
*notifier
)
122 VirtIOSCSIVring
*vring
= container_of(notifier
,
123 VirtIOSCSIVring
, host_notifier
);
124 VirtIOSCSI
*s
= (VirtIOSCSI
*)vring
->parent
;
127 event_notifier_test_and_clear(notifier
);
128 while ((req
= virtio_scsi_pop_req_vring(s
, vring
))) {
129 virtio_scsi_handle_cmd_req(s
, req
);
133 /* Context: QEMU global mutex held */
134 void virtio_scsi_dataplane_start(VirtIOSCSI
*s
)
138 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
139 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
140 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
142 if (s
->dataplane_started
||
143 s
->dataplane_starting
||
144 s
->ctx
!= iothread_get_aio_context(vs
->conf
.iothread
)) {
148 s
->dataplane_starting
= true;
150 /* Set up guest notifier (irq) */
151 rc
= k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, true);
153 fprintf(stderr
, "virtio-scsi: Failed to set guest notifiers, "
154 "ensure -enable-kvm is set\n");
158 aio_context_acquire(s
->ctx
);
159 s
->ctrl_vring
= virtio_scsi_vring_init(s
, vs
->ctrl_vq
,
160 virtio_scsi_iothread_handle_ctrl
,
162 s
->event_vring
= virtio_scsi_vring_init(s
, vs
->event_vq
,
163 virtio_scsi_iothread_handle_event
,
165 s
->cmd_vrings
= g_malloc0(sizeof(VirtIOSCSIVring
) * vs
->conf
.num_queues
);
166 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
168 virtio_scsi_vring_init(s
, vs
->cmd_vqs
[i
],
169 virtio_scsi_iothread_handle_cmd
,
173 aio_context_release(s
->ctx
);
174 s
->dataplane_starting
= false;
175 s
->dataplane_started
= true;
178 /* Context: QEMU global mutex held */
179 void virtio_scsi_dataplane_stop(VirtIOSCSI
*s
)
181 BusState
*qbus
= BUS(qdev_get_parent_bus(DEVICE(s
)));
182 VirtioBusClass
*k
= VIRTIO_BUS_GET_CLASS(qbus
);
183 VirtIODevice
*vdev
= VIRTIO_DEVICE(s
);
184 VirtIOSCSICommon
*vs
= VIRTIO_SCSI_COMMON(s
);
187 if (!s
->dataplane_started
|| s
->dataplane_stopping
) {
190 s
->dataplane_stopping
= true;
191 assert(s
->ctx
== iothread_get_aio_context(vs
->conf
.iothread
));
193 aio_context_acquire(s
->ctx
);
195 aio_set_event_notifier(s
->ctx
, &s
->ctrl_vring
->host_notifier
, NULL
);
196 aio_set_event_notifier(s
->ctx
, &s
->event_vring
->host_notifier
, NULL
);
197 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
198 aio_set_event_notifier(s
->ctx
, &s
->cmd_vrings
[i
]->host_notifier
, NULL
);
201 bdrv_drain_all(); /* ensure there are no in-flight requests */
203 aio_context_release(s
->ctx
);
205 /* Sync vring state back to virtqueue so that non-dataplane request
206 * processing can continue when we disable the host notifier below.
208 vring_teardown(&s
->ctrl_vring
->vring
, vdev
, 0);
209 vring_teardown(&s
->event_vring
->vring
, vdev
, 1);
210 for (i
= 0; i
< vs
->conf
.num_queues
; i
++) {
211 vring_teardown(&s
->cmd_vrings
[i
]->vring
, vdev
, 2 + i
);
214 for (i
= 0; i
< vs
->conf
.num_queues
+ 2; i
++) {
215 k
->set_host_notifier(qbus
->parent
, i
, false);
218 /* Clean up guest notifier (irq) */
219 k
->set_guest_notifiers(qbus
->parent
, vs
->conf
.num_queues
+ 2, false);
220 s
->dataplane_stopping
= false;
221 s
->dataplane_started
= false;