]> git.proxmox.com Git - mirror_qemu.git/blame - hw/scsi/virtio-scsi-dataplane.c
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
[mirror_qemu.git] / hw / scsi / virtio-scsi-dataplane.c
CommitLineData
91cb1c9b
FZ
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
9b8bfe21 14#include "qemu/osdep.h"
ad07cd69 15#include "qapi/error.h"
91cb1c9b
FZ
16#include "hw/virtio/virtio-scsi.h"
17#include "qemu/error-report.h"
4be74634 18#include "sysemu/block-backend.h"
a9c94277 19#include "hw/scsi/scsi.h"
08e2c9f1 20#include "scsi/constants.h"
a9c94277 21#include "hw/virtio/virtio-bus.h"
91cb1c9b 22#include "hw/virtio/virtio-access.h"
91cb1c9b
FZ
23
24/* Context: QEMU global mutex held */
ad07cd69 25void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
91cb1c9b 26{
91cb1c9b 27 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
ad07cd69
PB
28 VirtIODevice *vdev = VIRTIO_DEVICE(s);
29 BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
30 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
91cb1c9b 31
ad07cd69
PB
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();
91cb1c9b
FZ
49 }
50}
51
61fc57bf 52static int virtio_scsi_set_host_notifier(VirtIOSCSI *s, VirtQueue *vq, int n)
91cb1c9b
FZ
53{
54 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s)));
6d2c8316 55 int rc;
91cb1c9b
FZ
56
57 /* Set up virtqueue notify */
b1f0a33d 58 rc = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), n, true);
6d2c8316
CH
59 if (rc != 0) {
60 fprintf(stderr, "virtio-scsi: Failed to set host notifier (%d)\n",
61 rc);
4adea804 62 s->dataplane_fenced = true;
e24a47c5 63 return rc;
91cb1c9b 64 }
196d4fc5 65
e24a47c5 66 return 0;
91cb1c9b
FZ
67}
68
184b9623
SH
69/* Context: BH in IOThread */
70static void virtio_scsi_dataplane_stop_bh(void *opaque)
361dcc79 71{
184b9623 72 VirtIOSCSI *s = opaque;
361dcc79 73 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
bd58ab40 74 EventNotifier *host_notifier;
361dcc79
CH
75 int i;
76
db608fb7 77 virtio_queue_aio_detach_host_notifier(vs->ctrl_vq, s->ctx);
bd58ab40
SH
78 host_notifier = virtio_queue_get_host_notifier(vs->ctrl_vq);
79
80 /*
81 * Test and clear notifier after disabling event, in case poll callback
82 * didn't have time to run.
83 */
84 virtio_queue_host_notifier_read(host_notifier);
85
db608fb7 86 virtio_queue_aio_detach_host_notifier(vs->event_vq, s->ctx);
bd58ab40
SH
87 host_notifier = virtio_queue_get_host_notifier(vs->event_vq);
88 virtio_queue_host_notifier_read(host_notifier);
89
e24a47c5 90 for (i = 0; i < vs->conf.num_queues; i++) {
db608fb7 91 virtio_queue_aio_detach_host_notifier(vs->cmd_vqs[i], s->ctx);
bd58ab40
SH
92 host_notifier = virtio_queue_get_host_notifier(vs->cmd_vqs[i]);
93 virtio_queue_host_notifier_read(host_notifier);
361dcc79
CH
94 }
95}
96
91cb1c9b 97/* Context: QEMU global mutex held */
ad07cd69 98int virtio_scsi_dataplane_start(VirtIODevice *vdev)
91cb1c9b
FZ
99{
100 int i;
101 int rc;
dec2bb14 102 int vq_init_count = 0;
ad07cd69 103 BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
91cb1c9b 104 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
ad07cd69
PB
105 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
106 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
91cb1c9b
FZ
107
108 if (s->dataplane_started ||
109 s->dataplane_starting ||
ad07cd69
PB
110 s->dataplane_fenced) {
111 return 0;
91cb1c9b
FZ
112 }
113
114 s->dataplane_starting = true;
115
116 /* Set up guest notifier (irq) */
117 rc = k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, true);
118 if (rc != 0) {
a1d30f28
TH
119 error_report("virtio-scsi: Failed to set guest notifiers (%d), "
120 "ensure -accel kvm is set.", rc);
361dcc79 121 goto fail_guest_notifiers;
91cb1c9b
FZ
122 }
123
9cf4fd87
GK
124 /*
125 * Batch all the host notifiers in a single transaction to avoid
126 * quadratic time complexity in address_space_update_ioeventfds().
127 */
c4f5dcc4
GK
128 memory_region_transaction_begin();
129
61fc57bf
GK
130 rc = virtio_scsi_set_host_notifier(s, vs->ctrl_vq, 0);
131 if (rc != 0) {
132 goto fail_host_notifiers;
361dcc79 133 }
dec2bb14
ML
134
135 vq_init_count++;
61fc57bf
GK
136 rc = virtio_scsi_set_host_notifier(s, vs->event_vq, 1);
137 if (rc != 0) {
138 goto fail_host_notifiers;
361dcc79 139 }
dec2bb14
ML
140
141 vq_init_count++;
61fc57bf 142
91cb1c9b 143 for (i = 0; i < vs->conf.num_queues; i++) {
61fc57bf 144 rc = virtio_scsi_set_host_notifier(s, vs->cmd_vqs[i], i + 2);
e24a47c5 145 if (rc) {
61fc57bf 146 goto fail_host_notifiers;
361dcc79 147 }
dec2bb14 148 vq_init_count++;
91cb1c9b
FZ
149 }
150
c4f5dcc4
GK
151 memory_region_transaction_commit();
152
9a4b6a63
SH
153 /*
154 * These fields are visible to the IOThread so we rely on implicit barriers
155 * in aio_context_acquire() on the write side and aio_notify_accept() on
156 * the read side.
157 */
158 s->dataplane_starting = false;
159 s->dataplane_started = true;
160
766aa2de
SH
161 if (s->bus.drain_count == 0) {
162 aio_context_acquire(s->ctx);
163 virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
164 virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
61fc57bf 165
766aa2de
SH
166 for (i = 0; i < vs->conf.num_queues; i++) {
167 virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
168 }
169 aio_context_release(s->ctx);
61fc57bf 170 }
ad07cd69 171 return 0;
361dcc79 172
61fc57bf 173fail_host_notifiers:
dec2bb14 174 for (i = 0; i < vq_init_count; i++) {
21a4d962 175 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
c4f5dcc4
GK
176 }
177
9cf4fd87
GK
178 /*
179 * The transaction expects the ioeventfds to be open when it
180 * commits. Do it now, before the cleanup loop.
181 */
c4f5dcc4
GK
182 memory_region_transaction_commit();
183
184 for (i = 0; i < vq_init_count; i++) {
76143618 185 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
361dcc79
CH
186 }
187 k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
188fail_guest_notifiers:
e24a47c5 189 s->dataplane_fenced = true;
361dcc79 190 s->dataplane_starting = false;
e24a47c5 191 s->dataplane_started = true;
ad07cd69 192 return -ENOSYS;
91cb1c9b
FZ
193}
194
195/* Context: QEMU global mutex held */
ad07cd69 196void virtio_scsi_dataplane_stop(VirtIODevice *vdev)
91cb1c9b 197{
ad07cd69 198 BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
91cb1c9b 199 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
ad07cd69
PB
200 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
201 VirtIOSCSI *s = VIRTIO_SCSI(vdev);
21a4d962 202 int i;
91cb1c9b 203
e24a47c5
PB
204 if (!s->dataplane_started || s->dataplane_stopping) {
205 return;
206 }
207
4adea804
CH
208 /* Better luck next time. */
209 if (s->dataplane_fenced) {
210 s->dataplane_fenced = false;
e24a47c5 211 s->dataplane_started = false;
91cb1c9b
FZ
212 return;
213 }
214 s->dataplane_stopping = true;
91cb1c9b 215
766aa2de
SH
216 if (s->bus.drain_count == 0) {
217 aio_wait_bh_oneshot(s->ctx, virtio_scsi_dataplane_stop_bh, s);
218 }
91cb1c9b 219
4be74634 220 blk_drain_all(); /* ensure there are no in-flight requests */
91cb1c9b 221
9cf4fd87
GK
222 /*
223 * Batch all the host notifiers in a single transaction to avoid
224 * quadratic time complexity in address_space_update_ioeventfds().
225 */
c4f5dcc4
GK
226 memory_region_transaction_begin();
227
91cb1c9b 228 for (i = 0; i < vs->conf.num_queues + 2; i++) {
21a4d962 229 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
c4f5dcc4
GK
230 }
231
9cf4fd87
GK
232 /*
233 * The transaction expects the ioeventfds to be open when it
234 * commits. Do it now, before the cleanup loop.
235 */
c4f5dcc4
GK
236 memory_region_transaction_commit();
237
238 for (i = 0; i < vs->conf.num_queues + 2; i++) {
76143618 239 virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
91cb1c9b
FZ
240 }
241
242 /* Clean up guest notifier (irq) */
243 k->set_guest_notifiers(qbus->parent, vs->conf.num_queues + 2, false);
244 s->dataplane_stopping = false;
245 s->dataplane_started = false;
246}