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"
24
void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
26
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
27
VirtIODevice *vdev = VIRTIO_DEVICE(s);
28
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
29
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
31
if (vs->conf.iothread) {
32
if (!k->set_guest_notifiers || !k->ioeventfd_assign) {
34
"device is incompatible with iothread "
35
"(transport does not support notifiers)");
38
if (!virtio_device_ioeventfd_enabled(vdev)) {
39
error_setg(errp, "ioeventfd is required for iothread");
42
s->ctx = iothread_get_aio_context(vs->conf.iothread);
44
if (!virtio_device_ioeventfd_enabled(vdev)) {
47
s->ctx = qemu_get_aio_context();
51
static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
53
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
57
rc = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), n, true);
59
fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
61
s->dataplane_fenced = true;
69
static void virtio_scsi_dataplane_stop_bh(void *opaque)
71
VirtIOSCSI *s = opaque;
72
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
73
EventNotifier *host_notifier;
76
virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx);
77
host_notifier = virtio_queue_get_host_notifier(vs->ctrl_vq);
83
virtio_queue_host_notifier_read(host_notifier);
85
virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx);
86
host_notifier = virtio_queue_get_host_notifier(vs->event_vq);
87
virtio_queue_host_notifier_read(host_notifier);
89
for (i = 0; i < vs->conf.num_queues; i++) {
90
virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx);
91
host_notifier = virtio_queue_get_host_notifier(vs->cmd_vqs[i]);
92
virtio_queue_host_notifier_read(host_notifier);
97
int virtio_scsi_dataplane_start(VirtIODevice *vdev)
101
int vq_init_count = 0;
102
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
103
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
104
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
105
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
107
if (s->dataplane_started ||
108
s->dataplane_starting ||
109
s->dataplane_fenced) {
113
s->dataplane_starting = true;
116
rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true);
118
error_report("virtio-scsi: Failed to set guest notifiers (%d), "
119
"ensure -accel kvm is set.", rc);
120
goto fail_guest_notifiers;
127
memory_region_transaction_begin();
129
rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0);
131
goto fail_host_notifiers;
135
rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1);
137
goto fail_host_notifiers;
142
for (i = 0; i < vs->conf.num_queues; i++) {
143
rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2);
145
goto fail_host_notifiers;
150
memory_region_transaction_commit();
152
s->dataplane_starting = false;
153
s->dataplane_started = true;
156
if (s->bus.drain_count == 0) {
157
virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
158
virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
160
for (i = 0; i < vs->conf.num_queues; i++) {
161
virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
167
for (i = 0; i < vq_init_count; i++) {
168
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
175
memory_region_transaction_commit();
177
for (i = 0; i < vq_init_count; i++) {
178
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
180
k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
182
s->dataplane_fenced = true;
183
s->dataplane_starting = false;
184
s->dataplane_started = true;
189
void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
191
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
192
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
193
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
194
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
197
if (!s->dataplane_started || s->dataplane_stopping) {
202
if (s->dataplane_fenced) {
203
s->dataplane_fenced = false;
204
s->dataplane_started = false;
207
s->dataplane_stopping = true;
209
if (s->bus.drain_count == 0) {
210
aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
219
memory_region_transaction_begin();
221
for (i = 0; i < vs->conf.num_queues + 2; i++) {
222
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
229
memory_region_transaction_commit();
231
for (i = 0; i < vs->conf.num_queues + 2; i++) {
232
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
236
k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
237
s->dataplane_stopping = false;
238
s->dataplane_started = false;