]> git.proxmox.com Git - mirror_qemu.git/blob - hw/scsi/virtio-scsi-dataplane.c
alsaaudio: reintroduce default recording settings
[mirror_qemu.git] / hw / scsi / virtio-scsi-dataplane.c
1 /*
2 * Virtio SCSI dataplane
3 *
4 * Copyright Red Hat, Inc. 2014
5 *
6 * Authors:
7 * Fam Zheng <famz@redhat.com>
8 *
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.
11 *
12 */
13
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"
23
24 /* Context: QEMU global mutex held */
25 void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
26 {
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);
31
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;
38 }
39 if (!virtio_device_ioeventfd_enabled(vdev)) {
40 error_setg(errp, "ioeventfd is required for iothread");
41 return;
42 }
43 s->ctx = iothread_get_aio_context(vs->conf.iothread);
44 } else {
45 if (!virtio_device_ioeventfd_enabled(vdev)) {
46 return;
47 }
48 s->ctx = qemu_get_aio_context();
49 }
50 }
51
52 static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
53 {
54 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
55 int rc;
56
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;
64 }
65
66 return 0;
67 }
68
69 /* Context: BH in IOThread */
70 static void virtio_scsi_dataplane_stop_bh(void *opaque)
71 {
72 VirtIOSCSI *s = opaque;
73 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
74 int i;
75
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);
80 }
81 }
82
83 /* Context: QEMU global mutex held */
84 int virtio_scsi_dataplane_start(VirtIODevice *vdev)
85 {
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);
93
94 if (s->dataplane_started ||
95 s->dataplane_starting ||
96 s->dataplane_fenced) {
97 return 0;
98 }
99
100 s->dataplane_starting = true;
101
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;
108 }
109
110 /*
111 * Batch all the host notifiers in a single transaction to avoid
112 * quadratic time complexity in address_space_update_ioeventfds().
113 */
114 memory_region_transaction_begin();
115
116 rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0);
117 if (rc != 0) {
118 goto fail_host_notifiers;
119 }
120
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;
125 }
126
127 vq_init_count++;
128
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;
133 }
134 vq_init_count++;
135 }
136
137 memory_region_transaction_commit();
138
139 /*
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
142 * the read side.
143 */
144 s->dataplane_starting = false;
145 s->dataplane_started = true;
146
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);
150
151 for (i = 0; i < vs->conf.num_queues; i++) {
152 virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
153 }
154 aio_context_release(s->ctx);
155 return 0;
156
157 fail_host_notifiers:
158 for (i = 0; i < vq_init_count; i++) {
159 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
160 }
161
162 /*
163 * The transaction expects the ioeventfds to be open when it
164 * commits. Do it now, before the cleanup loop.
165 */
166 memory_region_transaction_commit();
167
168 for (i = 0; i < vq_init_count; i++) {
169 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
170 }
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;
176 return -ENOSYS;
177 }
178
179 /* Context: QEMU global mutex held */
180 void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
181 {
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);
186 int i;
187
188 if (!s->dataplane_started || s->dataplane_stopping) {
189 return;
190 }
191
192 /* Better luck next time. */
193 if (s->dataplane_fenced) {
194 s->dataplane_fenced = false;
195 s->dataplane_started = false;
196 return;
197 }
198 s->dataplane_stopping = true;
199
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);
203
204 blk_drain_all(); /* ensure there are no in-flight requests */
205
206 /*
207 * Batch all the host notifiers in a single transaction to avoid
208 * quadratic time complexity in address_space_update_ioeventfds().
209 */
210 memory_region_transaction_begin();
211
212 for (i = 0; i < vs->conf.num_queues + 2; i++) {
213 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
214 }
215
216 /*
217 * The transaction expects the ioeventfds to be open when it
218 * commits. Do it now, before the cleanup loop.
219 */
220 memory_region_transaction_commit();
221
222 for (i = 0; i < vs->conf.num_queues + 2; i++) {
223 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
224 }
225
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;
230 }