]>
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" | |
21 | #include "qemu/typedefs.h" | |
22 | #include "qom/object.h" | |
23 | #include "hw/fw-path-provider.h" | |
24 | #include "hw/qdev-core.h" | |
25 | #include "hw/virtio/vhost.h" | |
26 | #include "hw/virtio/vhost-backend.h" | |
27 | #include "hw/virtio/vhost-user-scsi.h" | |
28 | #include "hw/virtio/virtio.h" | |
29 | #include "hw/virtio/virtio-access.h" | |
30 | #include "chardev/char-fe.h" | |
31 | ||
32 | /* Features supported by the host application */ | |
33 | static const int user_feature_bits[] = { | |
34 | VIRTIO_F_NOTIFY_ON_EMPTY, | |
35 | VIRTIO_RING_F_INDIRECT_DESC, | |
36 | VIRTIO_RING_F_EVENT_IDX, | |
37 | VIRTIO_SCSI_F_HOTPLUG, | |
38 | VHOST_INVALID_FEATURE_BIT | |
39 | }; | |
40 | ||
41 | static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) | |
42 | { | |
43 | VHostUserSCSI *s = (VHostUserSCSI *)vdev; | |
44 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
45 | bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running; | |
46 | ||
47 | if (vsc->dev.started == start) { | |
48 | return; | |
49 | } | |
50 | ||
51 | if (start) { | |
52 | int ret; | |
53 | ||
54 | ret = vhost_scsi_common_start(vsc); | |
55 | if (ret < 0) { | |
56 | error_report("unable to start vhost-user-scsi: %s", strerror(-ret)); | |
57 | exit(1); | |
58 | } | |
59 | } else { | |
60 | vhost_scsi_common_stop(vsc); | |
61 | } | |
62 | } | |
63 | ||
64 | static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) | |
65 | { | |
66 | } | |
67 | ||
68 | static void vhost_user_scsi_realize(DeviceState *dev, Error **errp) | |
69 | { | |
70 | VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); | |
71 | VHostUserSCSI *s = VHOST_USER_SCSI(dev); | |
72 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
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 | ||
89 | vsc->dev.nvqs = 2 + vs->conf.num_queues; | |
90 | vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs); | |
91 | vsc->dev.vq_index = 0; | |
92 | vsc->dev.backend_features = 0; | |
93 | ||
94 | ret = vhost_dev_init(&vsc->dev, (void *)&vs->conf.chardev, | |
95 | VHOST_BACKEND_TYPE_USER, 0); | |
96 | if (ret < 0) { | |
97 | error_setg(errp, "vhost-user-scsi: vhost initialization failed: %s", | |
98 | strerror(-ret)); | |
99 | return; | |
100 | } | |
101 | ||
102 | /* Channel and lun both are 0 for bootable vhost-user-scsi disk */ | |
103 | vsc->channel = 0; | |
104 | vsc->lun = 0; | |
105 | vsc->target = vs->conf.boot_tpgt; | |
106 | } | |
107 | ||
108 | static void vhost_user_scsi_unrealize(DeviceState *dev, Error **errp) | |
109 | { | |
110 | VirtIODevice *vdev = VIRTIO_DEVICE(dev); | |
111 | VHostUserSCSI *s = VHOST_USER_SCSI(dev); | |
112 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); | |
113 | ||
114 | /* This will stop the vhost backend. */ | |
115 | vhost_user_scsi_set_status(vdev, 0); | |
116 | ||
117 | vhost_dev_cleanup(&vsc->dev); | |
118 | g_free(vsc->dev.vqs); | |
119 | ||
120 | virtio_scsi_common_unrealize(dev, errp); | |
121 | } | |
122 | ||
123 | static uint64_t vhost_user_scsi_get_features(VirtIODevice *vdev, | |
124 | uint64_t features, Error **errp) | |
125 | { | |
126 | VHostUserSCSI *s = VHOST_USER_SCSI(vdev); | |
127 | ||
128 | /* Turn on predefined features supported by this device */ | |
129 | features |= s->host_features; | |
130 | ||
131 | return vhost_scsi_common_get_features(vdev, features, errp); | |
132 | } | |
133 | ||
134 | static Property vhost_user_scsi_properties[] = { | |
135 | DEFINE_PROP_CHR("chardev", VirtIOSCSICommon, conf.chardev), | |
136 | DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0), | |
137 | DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1), | |
138 | DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors, | |
139 | 0xFFFF), | |
140 | DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128), | |
141 | DEFINE_PROP_BIT64("hotplug", VHostUserSCSI, host_features, | |
142 | VIRTIO_SCSI_F_HOTPLUG, | |
143 | true), | |
144 | DEFINE_PROP_BIT64("param_change", VHostUserSCSI, host_features, | |
145 | VIRTIO_SCSI_F_CHANGE, | |
146 | true), | |
147 | DEFINE_PROP_END_OF_LIST(), | |
148 | }; | |
149 | ||
150 | static const VMStateDescription vmstate_vhost_scsi = { | |
151 | .name = "virtio-scsi", | |
152 | .minimum_version_id = 1, | |
153 | .version_id = 1, | |
154 | .fields = (VMStateField[]) { | |
155 | VMSTATE_VIRTIO_DEVICE, | |
156 | VMSTATE_END_OF_LIST() | |
157 | }, | |
158 | }; | |
159 | ||
160 | static void vhost_user_scsi_class_init(ObjectClass *klass, void *data) | |
161 | { | |
162 | DeviceClass *dc = DEVICE_CLASS(klass); | |
163 | VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); | |
164 | FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(klass); | |
165 | ||
166 | dc->props = vhost_user_scsi_properties; | |
167 | dc->vmsd = &vmstate_vhost_scsi; | |
168 | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); | |
169 | vdc->realize = vhost_user_scsi_realize; | |
170 | vdc->unrealize = vhost_user_scsi_unrealize; | |
171 | vdc->get_features = vhost_user_scsi_get_features; | |
172 | vdc->set_config = vhost_scsi_common_set_config; | |
173 | vdc->set_status = vhost_user_scsi_set_status; | |
174 | fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path; | |
175 | } | |
176 | ||
177 | static void vhost_user_scsi_instance_init(Object *obj) | |
178 | { | |
179 | VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj); | |
180 | ||
181 | vsc->feature_bits = user_feature_bits; | |
182 | ||
183 | /* Add the bootindex property for this object */ | |
184 | device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL, | |
185 | DEVICE(vsc), NULL); | |
186 | } | |
187 | ||
188 | static const TypeInfo vhost_user_scsi_info = { | |
189 | .name = TYPE_VHOST_USER_SCSI, | |
190 | .parent = TYPE_VHOST_SCSI_COMMON, | |
191 | .instance_size = sizeof(VHostUserSCSI), | |
192 | .class_init = vhost_user_scsi_class_init, | |
193 | .instance_init = vhost_user_scsi_instance_init, | |
194 | .interfaces = (InterfaceInfo[]) { | |
195 | { TYPE_FW_PATH_PROVIDER }, | |
196 | { } | |
197 | }, | |
198 | }; | |
199 | ||
200 | static void virtio_register_types(void) | |
201 | { | |
202 | type_register_static(&vhost_user_scsi_info); | |
203 | } | |
204 | ||
205 | type_init(virtio_register_types) |