]> git.proxmox.com Git - mirror_qemu.git/blob - hw/scsi/vhost-scsi.c
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
[mirror_qemu.git] / hw / scsi / vhost-scsi.c
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/virtio/virtio-access.h"
30 #include "hw/fw-path-provider.h"
31 #include "hw/qdev-properties.h"
32 #include "qemu/cutils.h"
33 #include "sysemu/sysemu.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 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
80 ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version);
81 if (ret < 0) {
82 return -errno;
83 }
84 if (abi_version > VHOST_SCSI_ABI_VERSION) {
85 error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
86 " %d is greater than vhost_scsi userspace supports: %d,"
87 " please upgrade your version of QEMU", abi_version,
88 VHOST_SCSI_ABI_VERSION);
89 return -ENOSYS;
90 }
91
92 ret = vhost_scsi_common_start(vsc);
93 if (ret < 0) {
94 return ret;
95 }
96
97 ret = vhost_scsi_set_endpoint(s);
98 if (ret < 0) {
99 error_report("Error setting vhost-scsi endpoint");
100 vhost_scsi_common_stop(vsc);
101 }
102
103 return ret;
104 }
105
106 static void vhost_scsi_stop(VHostSCSI *s)
107 {
108 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
109
110 vhost_scsi_clear_endpoint(s);
111 vhost_scsi_common_stop(vsc);
112 }
113
114 static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
115 {
116 VHostSCSI *s = VHOST_SCSI(vdev);
117 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
118 bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
119
120 if (!vdev->vm_running) {
121 start = false;
122 }
123
124 if (vhost_dev_is_started(&vsc->dev) == start) {
125 return;
126 }
127
128 if (start) {
129 int ret;
130
131 ret = vhost_scsi_start(s);
132 if (ret < 0) {
133 error_report("unable to start vhost-scsi: %s", strerror(-ret));
134 exit(1);
135 }
136 } else {
137 vhost_scsi_stop(s);
138 }
139 }
140
141 static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
142 {
143 }
144
145 static int vhost_scsi_pre_save(void *opaque)
146 {
147 VHostSCSICommon *vsc = opaque;
148
149 /* At this point, backend must be stopped, otherwise
150 * it might keep writing to memory. */
151 assert(!vhost_dev_is_started(&vsc->dev));
152
153 return 0;
154 }
155
156 static const VMStateDescription vmstate_virtio_vhost_scsi = {
157 .name = "virtio-vhost_scsi",
158 .minimum_version_id = 1,
159 .version_id = 1,
160 .fields = (VMStateField[]) {
161 VMSTATE_VIRTIO_DEVICE,
162 VMSTATE_END_OF_LIST()
163 },
164 .pre_save = vhost_scsi_pre_save,
165 };
166
167 static void vhost_scsi_realize(DeviceState *dev, Error **errp)
168 {
169 VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
170 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
171 Error *err = NULL;
172 int vhostfd = -1;
173 int ret;
174 struct vhost_virtqueue *vqs = NULL;
175
176 if (!vs->conf.wwpn) {
177 error_setg(errp, "vhost-scsi: missing wwpn");
178 return;
179 }
180
181 if (vs->conf.vhostfd) {
182 vhostfd = monitor_fd_param(monitor_cur(), vs->conf.vhostfd, errp);
183 if (vhostfd == -1) {
184 error_prepend(errp, "vhost-scsi: unable to parse vhostfd: ");
185 return;
186 }
187 } else {
188 vhostfd = open("/dev/vhost-scsi", O_RDWR);
189 if (vhostfd < 0) {
190 error_setg(errp, "vhost-scsi: open vhost char device failed: %s",
191 strerror(errno));
192 return;
193 }
194 }
195
196 virtio_scsi_common_realize(dev,
197 vhost_dummy_handle_output,
198 vhost_dummy_handle_output,
199 vhost_dummy_handle_output,
200 &err);
201 if (err != NULL) {
202 error_propagate(errp, err);
203 goto close_fd;
204 }
205
206 if (!vsc->migratable) {
207 error_setg(&vsc->migration_blocker,
208 "vhost-scsi does not support migration in all cases. "
209 "When external environment supports it (Orchestrator migrates "
210 "target SCSI device state or use shared storage over network), "
211 "set 'migratable' property to true to enable migration.");
212 if (migrate_add_blocker(vsc->migration_blocker, errp) < 0) {
213 goto free_virtio;
214 }
215 }
216
217 vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
218 vqs = g_new0(struct vhost_virtqueue, vsc->dev.nvqs);
219 vsc->dev.vqs = vqs;
220 vsc->dev.vq_index = 0;
221 vsc->dev.backend_features = 0;
222
223 ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd,
224 VHOST_BACKEND_TYPE_KERNEL, 0, errp);
225 if (ret < 0) {
226 /*
227 * vhost_dev_init calls vhost_dev_cleanup on error, which closes
228 * vhostfd, don't double close it.
229 */
230 vhostfd = -1;
231 goto free_vqs;
232 }
233
234 /* At present, channel and lun both are 0 for bootable vhost-scsi disk */
235 vsc->channel = 0;
236 vsc->lun = 0;
237 /* Note: we can also get the minimum tpgt from kernel */
238 vsc->target = vs->conf.boot_tpgt;
239
240 return;
241
242 free_vqs:
243 g_free(vqs);
244 if (!vsc->migratable) {
245 migrate_del_blocker(vsc->migration_blocker);
246 }
247 free_virtio:
248 error_free(vsc->migration_blocker);
249 virtio_scsi_common_unrealize(dev);
250 close_fd:
251 if (vhostfd >= 0) {
252 close(vhostfd);
253 }
254 return;
255 }
256
257 static void vhost_scsi_unrealize(DeviceState *dev)
258 {
259 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
260 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
261 struct vhost_virtqueue *vqs = vsc->dev.vqs;
262
263 if (!vsc->migratable) {
264 migrate_del_blocker(vsc->migration_blocker);
265 error_free(vsc->migration_blocker);
266 }
267
268 /* This will stop vhost backend. */
269 vhost_scsi_set_status(vdev, 0);
270
271 vhost_dev_cleanup(&vsc->dev);
272 g_free(vqs);
273
274 virtio_scsi_common_unrealize(dev);
275 }
276
277 static struct vhost_dev *vhost_scsi_get_vhost(VirtIODevice *vdev)
278 {
279 VHostSCSI *s = VHOST_SCSI(vdev);
280 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
281 return &vsc->dev;
282 }
283
284 static Property vhost_scsi_properties[] = {
285 DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
286 DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
287 DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
288 DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues,
289 VIRTIO_SCSI_AUTO_NUM_QUEUES),
290 DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size,
291 128),
292 DEFINE_PROP_BOOL("seg_max_adjust", VirtIOSCSICommon, conf.seg_max_adjust,
293 true),
294 DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
295 0xFFFF),
296 DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
297 DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features,
298 VIRTIO_SCSI_F_T10_PI,
299 false),
300 DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false),
301 DEFINE_PROP_END_OF_LIST(),
302 };
303
304 static void vhost_scsi_class_init(ObjectClass *klass, void *data)
305 {
306 DeviceClass *dc = DEVICE_CLASS(klass);
307 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
308 FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass);
309
310 device_class_set_props(dc, vhost_scsi_properties);
311 dc->vmsd = &vmstate_virtio_vhost_scsi;
312 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
313 vdc->realize = vhost_scsi_realize;
314 vdc->unrealize = vhost_scsi_unrealize;
315 vdc->get_features = vhost_scsi_common_get_features;
316 vdc->set_config = vhost_scsi_common_set_config;
317 vdc->set_status = vhost_scsi_set_status;
318 vdc->get_vhost = vhost_scsi_get_vhost;
319 fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
320 }
321
322 static void vhost_scsi_instance_init(Object *obj)
323 {
324 VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
325
326 vsc->feature_bits = kernel_feature_bits;
327
328 device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
329 DEVICE(vsc));
330 }
331
332 static const TypeInfo vhost_scsi_info = {
333 .name = TYPE_VHOST_SCSI,
334 .parent = TYPE_VHOST_SCSI_COMMON,
335 .instance_size = sizeof(VHostSCSI),
336 .class_init = vhost_scsi_class_init,
337 .instance_init = vhost_scsi_instance_init,
338 .interfaces = (InterfaceInfo[]) {
339 { TYPE_FW_PATH_PROVIDER },
340 { }
341 },
342 };
343
344 static void virtio_register_types(void)
345 {
346 type_register_static(&vhost_scsi_info);
347 }
348
349 type_init(virtio_register_types)