1 #include "kvm/virtio-scsi.h"
2 #include "kvm/virtio-pci-dev.h"
3 #include "kvm/disk-image.h"
4 #include "kvm/irq.h"
5 #include "kvm/kvm.h"
6 #include "kvm/pci.h"
7 #include "kvm/ioeventfd.h"
8 #include "kvm/guest_compat.h"
9 #include "kvm/virtio-pci.h"
10 #include "kvm/virtio.h"
11 #include "kvm/strbuf.h"
12
13 #include <linux/kernel.h>
14 #include <linux/virtio_scsi.h>
15 #include <linux/vhost.h>
16
17 #define VIRTIO_SCSI_QUEUE_SIZE 128
18 #define NUM_VIRT_QUEUES 3
19
20 static LIST_HEAD(sdevs);
21 static int compat_id = -1;
22
23 struct scsi_dev {
24 struct virt_queue vqs[NUM_VIRT_QUEUES];
25 struct virtio_scsi_config config;
26 struct vhost_scsi_target target;
27 int vhost_fd;
28 struct virtio_device vdev;
29 struct list_head list;
30 struct kvm *kvm;
31 };
32
get_config(struct kvm * kvm,void * dev)33 static u8 *get_config(struct kvm *kvm, void *dev)
34 {
35 struct scsi_dev *sdev = dev;
36
37 return ((u8 *)(&sdev->config));
38 }
39
get_config_size(struct kvm * kvm,void * dev)40 static size_t get_config_size(struct kvm *kvm, void *dev)
41 {
42 struct scsi_dev *sdev = dev;
43
44 return sizeof(sdev->config);
45 }
46
get_host_features(struct kvm * kvm,void * dev)47 static u64 get_host_features(struct kvm *kvm, void *dev)
48 {
49 int r;
50 u64 features;
51 struct scsi_dev *sdev = dev;
52
53 r = ioctl(sdev->vhost_fd, VHOST_GET_FEATURES, &features);
54 if (r != 0)
55 die_perror("VHOST_GET_FEATURES failed");
56
57 return features &
58 (1ULL << VIRTIO_RING_F_EVENT_IDX | \
59 1ULL << VIRTIO_RING_F_INDIRECT_DESC | \
60 1ULL << VIRTIO_F_ANY_LAYOUT);
61 }
62
notify_status(struct kvm * kvm,void * dev,u32 status)63 static void notify_status(struct kvm *kvm, void *dev, u32 status)
64 {
65 int r;
66 struct scsi_dev *sdev = dev;
67 struct virtio_device *vdev = &sdev->vdev;
68 struct virtio_scsi_config *conf = &sdev->config;
69 u16 endian = vdev->endian;
70
71 if (status & VIRTIO__STATUS_START) {
72 r = virtio_vhost_set_features(sdev->vhost_fd, sdev->vdev.features);
73 if (r != 0)
74 die_perror("VHOST_SET_FEATURES failed");
75
76 r = ioctl(sdev->vhost_fd, VHOST_SCSI_SET_ENDPOINT,
77 &sdev->target);
78 if (r != 0)
79 die("VHOST_SCSI_SET_ENDPOINT failed %d", errno);
80 }
81
82 if (!(status & VIRTIO__STATUS_CONFIG))
83 return;
84
85 conf->num_queues = virtio_host_to_guest_u32(endian, NUM_VIRT_QUEUES - 2);
86 conf->seg_max = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_CDB_SIZE - 2);
87 conf->max_sectors = virtio_host_to_guest_u32(endian, 65535);
88 conf->cmd_per_lun = virtio_host_to_guest_u32(endian, 128);
89 conf->sense_size = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_SENSE_SIZE);
90 conf->cdb_size = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_CDB_SIZE);
91 conf->max_target = virtio_host_to_guest_u16(endian, 255);
92 conf->max_lun = virtio_host_to_guest_u32(endian, 16383);
93 conf->event_info_size = virtio_host_to_guest_u32(endian, sizeof(struct virtio_scsi_event));
94 }
95
init_vq(struct kvm * kvm,void * dev,u32 vq)96 static int init_vq(struct kvm *kvm, void *dev, u32 vq)
97 {
98 struct scsi_dev *sdev = dev;
99 struct virt_queue *queue;
100
101 compat__remove_message(compat_id);
102
103 queue = &sdev->vqs[vq];
104
105 virtio_init_device_vq(kvm, &sdev->vdev, queue, VIRTIO_SCSI_QUEUE_SIZE);
106
107 if (sdev->vhost_fd == 0)
108 return 0;
109
110 virtio_vhost_set_vring(kvm, sdev->vhost_fd, vq, queue);
111 return 0;
112 }
113
notify_vq_gsi(struct kvm * kvm,void * dev,u32 vq,u32 gsi)114 static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
115 {
116 struct scsi_dev *sdev = dev;
117
118 if (sdev->vhost_fd == 0)
119 return;
120
121 virtio_vhost_set_vring_irqfd(kvm, gsi, &sdev->vqs[vq]);
122 }
123
notify_vq_eventfd(struct kvm * kvm,void * dev,u32 vq,u32 efd)124 static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
125 {
126 struct scsi_dev *sdev = dev;
127
128 if (sdev->vhost_fd == 0)
129 return;
130
131 virtio_vhost_set_vring_kick(kvm, sdev->vhost_fd, vq, efd);
132 }
133
notify_vq(struct kvm * kvm,void * dev,u32 vq)134 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
135 {
136 return 0;
137 }
138
get_vq(struct kvm * kvm,void * dev,u32 vq)139 static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
140 {
141 struct scsi_dev *sdev = dev;
142
143 return &sdev->vqs[vq];
144 }
145
get_size_vq(struct kvm * kvm,void * dev,u32 vq)146 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
147 {
148 return VIRTIO_SCSI_QUEUE_SIZE;
149 }
150
set_size_vq(struct kvm * kvm,void * dev,u32 vq,int size)151 static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
152 {
153 return size;
154 }
155
get_vq_count(struct kvm * kvm,void * dev)156 static unsigned int get_vq_count(struct kvm *kvm, void *dev)
157 {
158 return NUM_VIRT_QUEUES;
159 }
160
161 static struct virtio_ops scsi_dev_virtio_ops = {
162 .get_config = get_config,
163 .get_config_size = get_config_size,
164 .get_host_features = get_host_features,
165 .init_vq = init_vq,
166 .get_vq = get_vq,
167 .get_size_vq = get_size_vq,
168 .set_size_vq = set_size_vq,
169 .notify_status = notify_status,
170 .notify_vq = notify_vq,
171 .notify_vq_gsi = notify_vq_gsi,
172 .notify_vq_eventfd = notify_vq_eventfd,
173 .get_vq_count = get_vq_count,
174 };
175
virtio_scsi_vhost_init(struct kvm * kvm,struct scsi_dev * sdev)176 static void virtio_scsi_vhost_init(struct kvm *kvm, struct scsi_dev *sdev)
177 {
178 sdev->vhost_fd = open("/dev/vhost-scsi", O_RDWR);
179 if (sdev->vhost_fd < 0)
180 die_perror("Failed openning vhost-scsi device");
181
182 virtio_vhost_init(kvm, sdev->vhost_fd);
183
184 sdev->vdev.use_vhost = true;
185 }
186
187
virtio_scsi_init_one(struct kvm * kvm,struct disk_image * disk)188 static int virtio_scsi_init_one(struct kvm *kvm, struct disk_image *disk)
189 {
190 struct scsi_dev *sdev;
191 int r;
192
193 if (!disk)
194 return -EINVAL;
195
196 sdev = calloc(1, sizeof(struct scsi_dev));
197 if (sdev == NULL)
198 return -ENOMEM;
199
200 *sdev = (struct scsi_dev) {
201 .kvm = kvm,
202 };
203 strlcpy((char *)&sdev->target.vhost_wwpn, disk->wwpn, sizeof(sdev->target.vhost_wwpn));
204 sdev->target.abi_version = VHOST_SCSI_ABI_VERSION;
205
206 list_add_tail(&sdev->list, &sdevs);
207
208 r = virtio_init(kvm, sdev, &sdev->vdev, &scsi_dev_virtio_ops,
209 kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_SCSI,
210 VIRTIO_ID_SCSI, PCI_CLASS_BLK);
211 if (r < 0)
212 return r;
213
214 virtio_scsi_vhost_init(kvm, sdev);
215
216 if (compat_id == -1)
217 compat_id = virtio_compat_add_message("virtio-scsi", "CONFIG_SCSI_VIRTIO");
218
219 return 0;
220 }
221
virtio_scsi_exit_one(struct kvm * kvm,struct scsi_dev * sdev)222 static int virtio_scsi_exit_one(struct kvm *kvm, struct scsi_dev *sdev)
223 {
224 int r;
225
226 r = ioctl(sdev->vhost_fd, VHOST_SCSI_CLEAR_ENDPOINT, &sdev->target);
227 if (r != 0)
228 die("VHOST_SCSI_CLEAR_ENDPOINT failed %d", errno);
229
230 list_del(&sdev->list);
231 free(sdev);
232
233 return 0;
234 }
235
virtio_scsi_init(struct kvm * kvm)236 int virtio_scsi_init(struct kvm *kvm)
237 {
238 int i, r = 0;
239
240 for (i = 0; i < kvm->nr_disks; i++) {
241 if (!kvm->disks[i]->wwpn)
242 continue;
243 r = virtio_scsi_init_one(kvm, kvm->disks[i]);
244 if (r < 0)
245 goto cleanup;
246 }
247
248 return 0;
249 cleanup:
250 virtio_scsi_exit(kvm);
251 return r;
252 }
253 virtio_dev_init(virtio_scsi_init);
254
virtio_scsi_exit(struct kvm * kvm)255 int virtio_scsi_exit(struct kvm *kvm)
256 {
257 while (!list_empty(&sdevs)) {
258 struct scsi_dev *sdev;
259
260 sdev = list_first_entry(&sdevs, struct scsi_dev, list);
261 virtio_scsi_exit_one(kvm, sdev);
262 }
263
264 return 0;
265 }
266 virtio_dev_exit(virtio_scsi_exit);
267