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