master
c 414 lines 12.2 KB
Raw
1 /*
2 * vhost_scsi host device
3 *
4 * Copyright IBM, Corp. 2011
5 *
6 * Authors:
7 * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
8 *
9 * Changes for QEMU mainline + tcm_vhost kernel upstream:
10 * Nicholas Bellinger <nab@risingtidesystems.com>
11 *
12 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
13 * See the COPYING.LIB file in the top-level directory.
14 *
15 */
16
17 #include "qemu/osdep.h"
18 #include "standard-headers/linux/vhost_types.h"
19 #include <linux/vhost.h>
20 #include <sys/ioctl.h>
21 #include "qapi/error.h"
22 #include "qemu/error-report.h"
23 #include "qemu/module.h"
24 #include "monitor/monitor.h"
25 #include "migration/blocker.h"
26 #include "hw/virtio/vhost-scsi.h"
27 #include "hw/virtio/vhost.h"
28 #include "hw/virtio/virtio-scsi.h"
29 #include "hw/virtio/virtio-bus.h"
30 #include "hw/core/fw-path-provider.h"
31 #include "hw/core/qdev-properties.h"
32 #include "qemu/cutils.h"
33 #include "system/system.h"
34
35 /* Features supported by host kernel. */
36 static const int kernel_feature_bits[] = {
37 VIRTIO_F_NOTIFY_ON_EMPTY,
38 VIRTIO_RING_F_INDIRECT_DESC,
39 VIRTIO_RING_F_EVENT_IDX,
40 VIRTIO_SCSI_F_HOTPLUG,
41 VIRTIO_F_RING_RESET,
42 VIRTIO_F_IN_ORDER,
43 VIRTIO_F_NOTIFICATION_DATA,
44 VHOST_INVALID_FEATURE_BIT
45 };
46
47 static int vhost_scsi_set_endpoint(VHostSCSI *s)
48 {
49 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
50 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
51 const VhostOps *vhost_ops = vsc->dev.vhost_ops;
52 struct vhost_scsi_target backend;
53 int ret;
54
55 memset(&backend, 0, sizeof(backend));
56 pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
57 ret = vhost_ops->vhost_scsi_set_endpoint(&vsc->dev, &backend);
58 if (ret < 0) {
59 return -errno;
60 }
61 return 0;
62 }
63
64 static void vhost_scsi_clear_endpoint(VHostSCSI *s)
65 {
66 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
67 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
68 struct vhost_scsi_target backend;
69 const VhostOps *vhost_ops = vsc->dev.vhost_ops;
70
71 memset(&backend, 0, sizeof(backend));
72 pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
73 vhost_ops->vhost_scsi_clear_endpoint(&vsc->dev, &backend);
74 }
75
76 static int vhost_scsi_start(VHostSCSI *s)
77 {
78 int ret, abi_version;
79 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
80 const VhostOps *vhost_ops = vsc->dev.vhost_ops;
81 Error *local_err = NULL;
82
83 ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version);
84 if (ret < 0) {
85 return -errno;
86 }
87 if (abi_version > VHOST_SCSI_ABI_VERSION) {
88 error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
89 " %d is greater than vhost_scsi userspace supports: %d,"
90 " please upgrade your version of QEMU", abi_version,
91 VHOST_SCSI_ABI_VERSION);
92 return -ENOSYS;
93 }
94
95 ret = vhost_scsi_common_start(vsc, &local_err);
96 if (ret < 0) {
97 error_reportf_err(local_err, "Error starting vhost-scsi: ");
98 return ret;
99 }
100
101 ret = vhost_scsi_set_endpoint(s);
102 if (ret < 0) {
103 error_report("Error setting vhost-scsi endpoint");
104 vhost_scsi_common_stop(vsc);
105 }
106
107 return ret;
108 }
109
110 static void vhost_scsi_stop(VHostSCSI *s)
111 {
112 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
113
114 vhost_scsi_clear_endpoint(s);
115 vhost_scsi_common_stop(vsc);
116 }
117
118 static int vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
119 {
120 VHostSCSI *s = VHOST_SCSI(vdev);
121 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
122 bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
123
124 if (!vdev->vm_running) {
125 start = false;
126 }
127
128 if (vhost_dev_is_started(&vsc->dev) == start) {
129 return 0;
130 }
131
132 if (start) {
133 int ret;
134
135 ret = vhost_scsi_start(s);
136 if (ret < 0) {
137 error_report("unable to start vhost-scsi: %s", strerror(-ret));
138 exit(1);
139 }
140 } else {
141 vhost_scsi_stop(s);
142 }
143 return 0;
144 }
145
146 static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
147 {
148 }
149
150 static int vhost_scsi_pre_save(void *opaque)
151 {
152 VHostSCSICommon *vsc = opaque;
153
154 /* At this point, backend must be stopped, otherwise
155 * it might keep writing to memory. */
156 assert(!vhost_dev_is_started(&vsc->dev));
157
158 return 0;
159 }
160
161 static const VMStateDescription vmstate_virtio_vhost_scsi = {
162 .name = "virtio-vhost_scsi",
163 .minimum_version_id = 1,
164 .version_id = 1,
165 .fields = (const VMStateField[]) {
166 VMSTATE_VIRTIO_DEVICE,
167 VMSTATE_END_OF_LIST()
168 },
169 .pre_save = vhost_scsi_pre_save,
170 };
171
172 static int vhost_scsi_set_workers(VHostSCSICommon *vsc, bool per_virtqueue)
173 {
174 struct vhost_dev *dev = &vsc->dev;
175 struct vhost_vring_worker vq_worker;
176 struct vhost_worker_state worker;
177 int i, ret = 0;
178
179 /* Use default worker */
180 if (!per_virtqueue || dev->nvqs == VHOST_SCSI_VQ_NUM_FIXED + 1) {
181 return 0;
182 }
183
184 /*
185 * ctl/evt share the first worker since it will be rare for them
186 * to send cmds while IO is running.
187 */
188 for (i = VHOST_SCSI_VQ_NUM_FIXED + 1; i < dev->nvqs; i++) {
189 memset(&worker, 0, sizeof(worker));
190
191 ret = dev->vhost_ops->vhost_new_worker(dev, &worker);
192 if (ret == -ENOTTY) {
193 /*
194 * worker ioctls are not implemented so just ignore and
195 * and continue device setup.
196 */
197 warn_report("vhost-scsi: Backend supports a single worker. "
198 "Ignoring worker_per_virtqueue=true setting.");
199 ret = 0;
200 break;
201 } else if (ret) {
202 break;
203 }
204
205 memset(&vq_worker, 0, sizeof(vq_worker));
206 vq_worker.worker_id = worker.worker_id;
207 vq_worker.index = i;
208
209 ret = dev->vhost_ops->vhost_attach_vring_worker(dev, &vq_worker);
210 if (ret == -ENOTTY) {
211 /*
212 * It's a bug for the kernel to have supported the worker creation
213 * ioctl but not attach.
214 */
215 dev->vhost_ops->vhost_free_worker(dev, &worker);
216 break;
217 } else if (ret) {
218 break;
219 }
220 }
221
222 return ret;
223 }
224
225 static void vhost_scsi_realize(DeviceState *dev, Error **errp)
226 {
227 ERRP_GUARD();
228 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
229 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
230 Error *err = NULL;
231 int vhostfd = -1;
232 int ret;
233 struct vhost_virtqueue *vqs = NULL;
234
235 if (!vs->conf.wwpn) {
236 error_setg(errp, "vhost-scsi: missing wwpn");
237 return;
238 }
239
240 if (vs->conf.vhostfd) {
241 vhostfd = monitor_fd_param(monitor_cur(), vs->conf.vhostfd, errp);
242 if (vhostfd == -1) {
243 error_prepend(errp, "vhost-scsi: unable to parse vhostfd: ");
244 return;
245 }
246 } else {
247 vhostfd = open("/dev/vhost-scsi", O_RDWR);
248 if (vhostfd < 0) {
249 error_setg_file_open(errp, errno, "/dev/vhost-scsi");
250 return;
251 }
252 }
253
254 virtio_scsi_common_realize(dev,
255 vhost_dummy_handle_output,
256 vhost_dummy_handle_output,
257 vhost_dummy_handle_output,
258 &err);
259 if (err != NULL) {
260 error_propagate(errp, err);
261 goto close_fd;
262 }
263
264 if (!vsc->migratable) {
265 error_setg(&vsc->migration_blocker,
266 "vhost-scsi does not support migration in all cases. "
267 "When external environment supports it (Orchestrator migrates "
268 "target SCSI device state or use shared storage over network), "
269 "set 'migratable' property to true to enable migration.");
270 if (migrate_add_blocker_normal(&vsc->migration_blocker, errp) < 0) {
271 goto free_virtio;
272 }
273 }
274
275 vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
276 vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
277 vsc->dev.vqs = vqs;
278 vsc->dev.vq_index = 0;
279
280 ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd,
281 VHOST_BACKEND_TYPE_KERNEL, 0, errp);
282 if (ret < 0) {
283 /*
284 * vhost_dev_init calls vhost_dev_cleanup on error, which closes
285 * vhostfd, don't double close it.
286 */
287 vhostfd = -1;
288 goto free_vqs;
289 }
290
291 ret = vhost_scsi_set_workers(vsc, vs->conf.worker_per_virtqueue);
292 if (ret < 0) {
293 error_setg(errp, "vhost-scsi: vhost worker setup failed: %s",
294 strerror(-ret));
295 goto free_vqs;
296 }
297
298 /* At present, channel and lun both are 0 for bootable vhost-scsi disk */
299 vsc->channel = 0;
300 vsc->lun = 0;
301 /* Note: we can also get the minimum tpgt from kernel */
302 vsc->target = vs->conf.boot_tpgt;
303
304 return;
305
306 free_vqs:
307 g_free(vqs);
308 if (!vsc->migratable) {
309 migrate_del_blocker(&vsc->migration_blocker);
310 }
311 free_virtio:
312 virtio_scsi_common_unrealize(dev);
313 close_fd:
314 if (vhostfd >= 0) {
315 close(vhostfd);
316 }
317 }
318
319 static void vhost_scsi_unrealize(DeviceState *dev)
320 {
321 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
322 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
323 struct vhost_virtqueue *vqs = vsc->dev.vqs;
324
325 if (!vsc->migratable) {
326 migrate_del_blocker(&vsc->migration_blocker);
327 }
328
329 /* This will stop vhost backend. */
330 vhost_scsi_set_status(vdev, 0);
331
332 vhost_dev_cleanup(&vsc->dev);
333 g_free(vqs);
334
335 virtio_scsi_common_unrealize(dev);
336 }
337
338 static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev)
339 {
340 VHostSCSI *s = VHOST_SCSI(vdev);
341 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
342 return &vsc->dev;
343 }
344
345 static const Property vhost_scsi_properties[] = {
346 DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
347 DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
348 DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
349 DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
350 VIRTIO_SCSI_AUTO_NUM_QUEUES),
351 DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
352 128),
353 DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
354 true),
355 DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
356 0xFFFF),
357 DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
358 DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
359 VIRTIO_SCSI_F_T10_PI,
360 false),
361 DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features,
362 VIRTIO_SCSI_F_HOTPLUG,
363 false),
364 DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false),
365 DEFINE_PROP_BOOL("worker_per_virtqueue", VirtIOSCSICommon,
366 conf.worker_per_virtqueue, false),
367 };
368
369 static void vhost_scsi_class_init(ObjectClass *klass, const void *data)
370 {
371 DeviceClass *dc = DEVICE_CLASS(klass);
372 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
373 FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
374
375 device_class_set_props(dc, vhost_scsi_properties);
376 dc->vmsd = &vmstate_virtio_vhost_scsi;
377 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
378 vdc->realize = vhost_scsi_realize;
379 vdc->unrealize = vhost_scsi_unrealize;
380 vdc->get_features = vhost_scsi_common_get_features;
381 vdc->set_config = vhost_scsi_common_set_config;
382 vdc->set_status = vhost_scsi_set_status;
383 vdc->get_vhost = vhost_scsi_get_vhost;
384 fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
385 }
386
387 static void vhost_scsi_instance_init(Object *obj)
388 {
389 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
390
391 vsc->feature_bits = kernel_feature_bits;
392
393 device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
394 DEVICE(vsc));
395 }
396
397 static const TypeInfo vhost_scsi_info = {
398 .name = TYPE_VHOST_SCSI,
399 .parent = TYPE_VHOST_SCSI_COMMON,
400 .instance_size = sizeof(VHostSCSI),
401 .class_init = vhost_scsi_class_init,
402 .instance_init = vhost_scsi_instance_init,
403 .interfaces = (const InterfaceInfo[]) {
404 { TYPE_FW_PATH_PROVIDER },
405 { }
406 },
407 };
408
409 static void virtio_register_types(void)
410 {
411 type_register_static(&vhost_scsi_info);
412 }
413
414 type_init(virtio_register_types)