]>
Commit | Line | Data |
---|---|---|
f12c1ebd FF |
1 | /* |
2 | * vhost-user-scsi host device | |
3 | * | |
4 | * Copyright (c) 2016 Nutanix Inc. All rights reserved. | |
5 | * | |
6 | * Author: | |
7 | * Felipe Franciosi <[email protected]> | |
8 | * | |
9 | * This work is largely based on the "vhost-scsi" implementation by: | |
10 | * Stefan Hajnoczi <[email protected]> | |
11 | * Nicholas Bellinger <[email protected]> | |
12 | * | |
13 | * This work is licensed under the terms of the GNU LGPL, version 2 or later. | |
14 | * See the COPYING.LIB file in the top-level directory. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include "qemu/osdep.h" | |
19 | #include "qapi/error.h" | |
20 | #include "qemu/error-report.h" | |
f12c1ebd FF |
21 | #include "qom/object.h" |
22 | #include "hw/fw-path-provider.h" | |
23 | #include "hw/qdev-core.h" | |
24 | #include "hw/virtio/vhost.h" | |
25 | #include "hw/virtio/vhost-backend.h" | |
26 | #include "hw/virtio/vhost-user-scsi.h" | |
27 | #include "hw/virtio/virtio.h" | |
28 | #include "hw/virtio/virtio-access.h" | |
29 | #include "chardev/char-fe.h" | |
30 | ||
31 | /* Features supported by the host application */ | |
32 | static const int user_feature_bits[] = { | |
33 | VIRTIO_F_NOTIFY_ON_EMPTY, | |
34 | VIRTIO_RING_F_INDIRECT_DESC, | |
35 | VIRTIO_RING_F_EVENT_IDX, | |
36 | VIRTIO_SCSI_F_HOTPLUG, | |
37 | VHOST_INVALID_FEATURE_BIT | |
38 | }; | |
39 | ||
40 | static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) | |
41 | { | |
42 | VHostUserSCSI *s = (VHostUserSCSI *)vdev; | |
43 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
44 | bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running; | |
45 | ||
46 | if (vsc->dev.started == start) { | |
47 | return; | |
48 | } | |
49 | ||
50 | if (start) { | |
51 | int ret; | |
52 | ||
53 | ret = vhost_scsi_common_start(vsc); | |
54 | if (ret < 0) { | |
55 | error_report("unable to start vhost-user-scsi: %s", strerror(-ret)); | |
56 | exit(1); | |
57 | } | |
58 | } else { | |
59 | vhost_scsi_common_stop(vsc); | |
60 | } | |
61 | } | |
62 | ||
63 | static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) | |
64 | { | |
65 | } | |
66 | ||
67 | static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) | |
68 | { | |
69 | VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); | |
70 | VHostUserSCSI *s = VHOST_USER_SCSI(dev); | |
71 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
4d0cf552 | 72 | VhostUserState *user; |
f12c1ebd FF |
73 | Error *err = NULL; |
74 | int ret; | |
75 | ||
76 | if (!vs->conf.chardev.chr) { | |
77 | error_setg(errp, "vhost-user-scsi: missing chardev"); | |
78 | return; | |
79 | } | |
80 | ||
81 | virtio_scsi_common_realize(dev, vhost_dummy_handle_output, | |
82 | vhost_dummy_handle_output, | |
83 | vhost_dummy_handle_output, &err); | |
84 | if (err != NULL) { | |
85 | error_propagate(errp, err); | |
86 | return; | |
87 | } | |
88 | ||
4d0cf552 TB |
89 | user = vhost_user_init(); |
90 | if (!user) { | |
91 | error_setg(errp, "vhost-user-scsi: failed to init vhost_user"); | |
92 | return; | |
93 | } | |
94 | user->chr = &vs->conf.chardev; | |
95 | ||
f12c1ebd FF |
96 | vsc->dev.nvqs = 2 + vs->conf.num_queues; |
97 | vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); | |
98 | vsc->dev.vq_index = 0; | |
99 | vsc->dev.backend_features = 0; | |
100 | ||
4d0cf552 | 101 | ret = vhost_dev_init(&vsc->dev, user, |
f12c1ebd FF |
102 | VHOST_BACKEND_TYPE_USER, 0); |
103 | if (ret < 0) { | |
104 | error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s", | |
105 | strerror(-ret)); | |
4d0cf552 TB |
106 | vhost_user_cleanup(user); |
107 | g_free(user); | |
f12c1ebd FF |
108 | return; |
109 | } | |
110 | ||
4d0cf552 TB |
111 | s->vhost_user = user; |
112 | ||
f12c1ebd FF |
113 | /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ |
114 | vsc->channel = 0; | |
115 | vsc->lun = 0; | |
116 | vsc->target = vs->conf.boot_tpgt; | |
117 | } | |
118 | ||
119 | static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) | |
120 | { | |
121 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
122 | VHostUserSCSI *s = VHOST_USER_SCSI(dev); | |
123 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
124 | ||
125 | /* This will stop the vhost backend. */ | |
126 | vhost_user_scsi_set_status(vdev, 0); | |
127 | ||
128 | vhost_dev_cleanup(&vsc->dev); | |
129 | g_free(vsc->dev.vqs); | |
130 | ||
131 | virtio_scsi_common_unrealize(dev, errp); | |
4d0cf552 TB |
132 | |
133 | if (s->vhost_user) { | |
134 | vhost_user_cleanup(s->vhost_user); | |
135 | g_free(s->vhost_user); | |
136 | s->vhost_user = NULL; | |
137 | } | |
f12c1ebd FF |
138 | } |
139 | ||
140 | static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev, | |
141 | uint64_t features, Error **errp) | |
142 | { | |
143 | VHostUserSCSI *s = VHOST_USER_SCSI(vdev); | |
144 | ||
145 | /* Turn on predefined features supported by this device */ | |
146 | features |= s->host_features; | |
147 | ||
148 | return vhost_scsi_common_get_features(vdev, features, errp); | |
149 | } | |
150 | ||
151 | static Property vhost_user_scsi_properties[] = { | |
152 | DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev), | |
153 | DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0), | |
154 | DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1), | |
92003610 DS |
155 | DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSICommon, conf.virtqueue_size, |
156 | 128), | |
f12c1ebd FF |
157 | DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors, |
158 | 0xFFFF), | |
159 | DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128), | |
160 | DEFINE_PROP_BIT64("hotplug", VHostUserSCSI, host_features, | |
161 | VIRTIO_SCSI_F_HOTPLUG, | |
162 | true), | |
163 | DEFINE_PROP_BIT64("param_change", VHostUserSCSI, host_features, | |
164 | VIRTIO_SCSI_F_CHANGE, | |
165 | true), | |
166 | DEFINE_PROP_END_OF_LIST(), | |
167 | }; | |
168 | ||
169 | static const VMStateDescription vmstate_vhost_scsi = { | |
170 | .name = "virtio-scsi", | |
171 | .minimum_version_id = 1, | |
172 | .version_id = 1, | |
173 | .fields = (VMStateField[]) { | |
174 | VMSTATE_VIRTIO_DEVICE, | |
175 | VMSTATE_END_OF_LIST() | |
176 | }, | |
177 | }; | |
178 | ||
179 | static void vhost_user_scsi_class_init(ObjectClass *klass, void *data) | |
180 | { | |
181 | DeviceClass *dc = DEVICE_CLASS(klass); | |
182 | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); | |
183 | FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass); | |
184 | ||
185 | dc->props = vhost_user_scsi_properties; | |
186 | dc->vmsd = &vmstate_vhost_scsi; | |
187 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); | |
188 | vdc->realize = vhost_user_scsi_realize; | |
189 | vdc->unrealize = vhost_user_scsi_unrealize; | |
190 | vdc->get_features = vhost_user_scsi_get_features; | |
191 | vdc->set_config = vhost_scsi_common_set_config; | |
192 | vdc->set_status = vhost_user_scsi_set_status; | |
193 | fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; | |
194 | } | |
195 | ||
196 | static void vhost_user_scsi_instance_init(Object *obj) | |
197 | { | |
198 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj); | |
199 | ||
200 | vsc->feature_bits = user_feature_bits; | |
201 | ||
202 | /* Add the bootindex property for this object */ | |
203 | device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL, | |
204 | DEVICE(vsc), NULL); | |
205 | } | |
206 | ||
207 | static const TypeInfo vhost_user_scsi_info = { | |
208 | .name = TYPE_VHOST_USER_SCSI, | |
209 | .parent = TYPE_VHOST_SCSI_COMMON, | |
210 | .instance_size = sizeof(VHostUserSCSI), | |
211 | .class_init = vhost_user_scsi_class_init, | |
212 | .instance_init = vhost_user_scsi_instance_init, | |
213 | .interfaces = (InterfaceInfo[]) { | |
214 | { TYPE_FW_PATH_PROVIDER }, | |
215 | { } | |
216 | }, | |
217 | }; | |
218 | ||
219 | static void virtio_register_types(void) | |
220 | { | |
221 | type_register_static(&vhost_user_scsi_info); | |
222 | } | |
223 | ||
224 | type_init(virtio_register_types) |