semihosting: Create semihost_sys_poll_one
[qemu/rayw.git] / hw / scsi / virtio-scsi-dataplane.c
blob8bb6e6acfce6d712f41a57ee815436e1dd5e6a1d
1 /*
2 * Virtio SCSI dataplane
4 * Copyright Red Hat, Inc. 2014
6 * Authors:
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) {
34 error_setg(errp,
35 "device is incompatible with iothread "
36 "(transport does not support notifiers)");
37 return;
39 if (!virtio_device_ioeventfd_enabled(vdev)) {
40 error_setg(errp, "ioeventfd is required for iothread");
41 return;
43 s->ctx = iothread_get_aio_context(vs->conf.iothread);
44 } else {
45 if (!virtio_device_ioeventfd_enabled(vdev)) {
46 return;
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)));
55 int rc;
57 /* Set up virtqueue notify */
58 rc = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), n, true);
59 if (rc != 0) {
60 fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
61 rc);
62 s->dataplane_fenced = true;
63 return rc;
66 return 0;
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);
74 int i;
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)
86 int i;
87 int rc;
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) {
97 return 0;
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);
104 if (rc != 0) {
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);
117 if (rc != 0) {
118 goto fail_host_notifiers;
121 vq_init_count++;
122 rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1);
123 if (rc != 0) {
124 goto fail_host_notifiers;
127 vq_init_count++;
129 for (i = 0; i < vs->conf.num_queues; i++) {
130 rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2);
131 if (rc) {
132 goto fail_host_notifiers;
134 vq_init_count++;
137 memory_region_transaction_commit();
139 aio_context_acquire(s->ctx);
140 virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
141 virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
143 for (i = 0; i < vs->conf.num_queues; i++) {
144 virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
147 s->dataplane_starting = false;
148 s->dataplane_started = true;
149 aio_context_release(s->ctx);
150 return 0;
152 fail_host_notifiers:
153 for (i = 0; i < vq_init_count; i++) {
154 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
158 * The transaction expects the ioeventfds to be open when it
159 * commits. Do it now, before the cleanup loop.
161 memory_region_transaction_commit();
163 for (i = 0; i < vq_init_count; i++) {
164 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
166 k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
167 fail_guest_notifiers:
168 s->dataplane_fenced = true;
169 s->dataplane_starting = false;
170 s->dataplane_started = true;
171 return -ENOSYS;
174 /* Context: QEMU global mutex held */
175 void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
177 BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
178 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
179 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
180 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
181 int i;
183 if (!s->dataplane_started || s->dataplane_stopping) {
184 return;
187 /* Better luck next time. */
188 if (s->dataplane_fenced) {
189 s->dataplane_fenced = false;
190 s->dataplane_started = false;
191 return;
193 s->dataplane_stopping = true;
195 aio_context_acquire(s->ctx);
196 aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
197 aio_context_release(s->ctx);
199 blk_drain_all(); /* ensure there are no in-flight requests */
202 * Batch all the host notifiers in a single transaction to avoid
203 * quadratic time complexity in address_space_update_ioeventfds().
205 memory_region_transaction_begin();
207 for (i = 0; i < vs->conf.num_queues + 2; i++) {
208 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
212 * The transaction expects the ioeventfds to be open when it
213 * commits. Do it now, before the cleanup loop.
215 memory_region_transaction_commit();
217 for (i = 0; i < vs->conf.num_queues + 2; i++) {
218 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
221 /* Clean up guest notifier (irq) */
222 k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
223 s->dataplane_stopping = false;
224 s->dataplane_started = false;