xref: /kvmtool/virtio/scsi.c (revision a67da3beff7afdf98679be09b0d8ce501bd71ac1)
1*a67da3beSAsias He #include "kvm/virtio-scsi.h"
2*a67da3beSAsias He #include "kvm/virtio-pci-dev.h"
3*a67da3beSAsias He #include "kvm/disk-image.h"
4*a67da3beSAsias He #include "kvm/kvm.h"
5*a67da3beSAsias He #include "kvm/pci.h"
6*a67da3beSAsias He #include "kvm/ioeventfd.h"
7*a67da3beSAsias He #include "kvm/guest_compat.h"
8*a67da3beSAsias He #include "kvm/virtio-pci.h"
9*a67da3beSAsias He #include "kvm/virtio.h"
10*a67da3beSAsias He 
11*a67da3beSAsias He #include <linux/kernel.h>
12*a67da3beSAsias He #include <linux/virtio_scsi.h>
13*a67da3beSAsias He #include <linux/vhost.h>
14*a67da3beSAsias He 
15*a67da3beSAsias He #define VIRTIO_SCSI_QUEUE_SIZE		128
16*a67da3beSAsias He #define NUM_VIRT_QUEUES			3
17*a67da3beSAsias He 
18*a67da3beSAsias He static LIST_HEAD(sdevs);
19*a67da3beSAsias He static int compat_id = -1;
20*a67da3beSAsias He 
21*a67da3beSAsias He struct scsi_dev {
22*a67da3beSAsias He 	struct virt_queue		vqs[NUM_VIRT_QUEUES];
23*a67da3beSAsias He 	struct virtio_scsi_config	config;
24*a67da3beSAsias He 	struct vhost_scsi_target	target;
25*a67da3beSAsias He 	u32				features;
26*a67da3beSAsias He 	int				vhost_fd;
27*a67da3beSAsias He 	struct virtio_device		vdev;
28*a67da3beSAsias He 	struct list_head		list;
29*a67da3beSAsias He 	struct kvm			*kvm;
30*a67da3beSAsias He };
31*a67da3beSAsias He 
32*a67da3beSAsias He static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
33*a67da3beSAsias He {
34*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
35*a67da3beSAsias He 
36*a67da3beSAsias He 	((u8 *)(&sdev->config))[offset] = data;
37*a67da3beSAsias He }
38*a67da3beSAsias He 
39*a67da3beSAsias He static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
40*a67da3beSAsias He {
41*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
42*a67da3beSAsias He 
43*a67da3beSAsias He 	return ((u8 *)(&sdev->config))[offset];
44*a67da3beSAsias He }
45*a67da3beSAsias He 
46*a67da3beSAsias He static u32 get_host_features(struct kvm *kvm, void *dev)
47*a67da3beSAsias He {
48*a67da3beSAsias He 	return	1UL << VIRTIO_RING_F_EVENT_IDX |
49*a67da3beSAsias He 		1UL << VIRTIO_RING_F_INDIRECT_DESC;
50*a67da3beSAsias He }
51*a67da3beSAsias He 
52*a67da3beSAsias He static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
53*a67da3beSAsias He {
54*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
55*a67da3beSAsias He 
56*a67da3beSAsias He 	sdev->features = features;
57*a67da3beSAsias He }
58*a67da3beSAsias He 
59*a67da3beSAsias He static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
60*a67da3beSAsias He {
61*a67da3beSAsias He 	struct vhost_vring_state state = { .index = vq };
62*a67da3beSAsias He 	struct vhost_vring_addr addr;
63*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
64*a67da3beSAsias He 	struct virt_queue *queue;
65*a67da3beSAsias He 	void *p;
66*a67da3beSAsias He 	int r;
67*a67da3beSAsias He 
68*a67da3beSAsias He 	compat__remove_message(compat_id);
69*a67da3beSAsias He 
70*a67da3beSAsias He 	queue		= &sdev->vqs[vq];
71*a67da3beSAsias He 	queue->pfn	= pfn;
72*a67da3beSAsias He 	p		= guest_pfn_to_host(kvm, queue->pfn);
73*a67da3beSAsias He 
74*a67da3beSAsias He 	vring_init(&queue->vring, VIRTIO_SCSI_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
75*a67da3beSAsias He 
76*a67da3beSAsias He 	if (sdev->vhost_fd == 0)
77*a67da3beSAsias He 		return 0;
78*a67da3beSAsias He 
79*a67da3beSAsias He 	state.num = queue->vring.num;
80*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_NUM, &state);
81*a67da3beSAsias He 	if (r < 0)
82*a67da3beSAsias He 		die_perror("VHOST_SET_VRING_NUM failed");
83*a67da3beSAsias He 	state.num = 0;
84*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_BASE, &state);
85*a67da3beSAsias He 	if (r < 0)
86*a67da3beSAsias He 		die_perror("VHOST_SET_VRING_BASE failed");
87*a67da3beSAsias He 
88*a67da3beSAsias He 	addr = (struct vhost_vring_addr) {
89*a67da3beSAsias He 		.index = vq,
90*a67da3beSAsias He 		.desc_user_addr = (u64)(unsigned long)queue->vring.desc,
91*a67da3beSAsias He 		.avail_user_addr = (u64)(unsigned long)queue->vring.avail,
92*a67da3beSAsias He 		.used_user_addr = (u64)(unsigned long)queue->vring.used,
93*a67da3beSAsias He 	};
94*a67da3beSAsias He 
95*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_ADDR, &addr);
96*a67da3beSAsias He 	if (r < 0)
97*a67da3beSAsias He 		die_perror("VHOST_SET_VRING_ADDR failed");
98*a67da3beSAsias He 
99*a67da3beSAsias He 	return 0;
100*a67da3beSAsias He }
101*a67da3beSAsias He 
102*a67da3beSAsias He static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
103*a67da3beSAsias He {
104*a67da3beSAsias He 	struct vhost_vring_file file;
105*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
106*a67da3beSAsias He 	struct kvm_irqfd irq;
107*a67da3beSAsias He 	int r;
108*a67da3beSAsias He 
109*a67da3beSAsias He 	if (sdev->vhost_fd == 0)
110*a67da3beSAsias He 		return;
111*a67da3beSAsias He 
112*a67da3beSAsias He 	irq = (struct kvm_irqfd) {
113*a67da3beSAsias He 		.gsi	= gsi,
114*a67da3beSAsias He 		.fd	= eventfd(0, 0),
115*a67da3beSAsias He 	};
116*a67da3beSAsias He 	file = (struct vhost_vring_file) {
117*a67da3beSAsias He 		.index	= vq,
118*a67da3beSAsias He 		.fd	= irq.fd,
119*a67da3beSAsias He 	};
120*a67da3beSAsias He 
121*a67da3beSAsias He 	r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq);
122*a67da3beSAsias He 	if (r < 0)
123*a67da3beSAsias He 		die_perror("KVM_IRQFD failed");
124*a67da3beSAsias He 
125*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_CALL, &file);
126*a67da3beSAsias He 	if (r < 0)
127*a67da3beSAsias He 		die_perror("VHOST_SET_VRING_CALL failed");
128*a67da3beSAsias He 
129*a67da3beSAsias He 	if (vq > 0)
130*a67da3beSAsias He 		return;
131*a67da3beSAsias He 
132*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SCSI_SET_ENDPOINT, &sdev->target);
133*a67da3beSAsias He 	if (r != 0)
134*a67da3beSAsias He 		die("VHOST_SCSI_SET_ENDPOINT failed %d", errno);
135*a67da3beSAsias He }
136*a67da3beSAsias He 
137*a67da3beSAsias He static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
138*a67da3beSAsias He {
139*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
140*a67da3beSAsias He 	struct vhost_vring_file file = {
141*a67da3beSAsias He 		.index	= vq,
142*a67da3beSAsias He 		.fd	= efd,
143*a67da3beSAsias He 	};
144*a67da3beSAsias He 	int r;
145*a67da3beSAsias He 
146*a67da3beSAsias He 	if (sdev->vhost_fd == 0)
147*a67da3beSAsias He 		return;
148*a67da3beSAsias He 
149*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_VRING_KICK, &file);
150*a67da3beSAsias He 	if (r < 0)
151*a67da3beSAsias He 		die_perror("VHOST_SET_VRING_KICK failed");
152*a67da3beSAsias He }
153*a67da3beSAsias He 
154*a67da3beSAsias He static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
155*a67da3beSAsias He {
156*a67da3beSAsias He 	return 0;
157*a67da3beSAsias He }
158*a67da3beSAsias He 
159*a67da3beSAsias He static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
160*a67da3beSAsias He {
161*a67da3beSAsias He 	struct scsi_dev *sdev = dev;
162*a67da3beSAsias He 
163*a67da3beSAsias He 	return sdev->vqs[vq].pfn;
164*a67da3beSAsias He }
165*a67da3beSAsias He 
166*a67da3beSAsias He static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
167*a67da3beSAsias He {
168*a67da3beSAsias He 	return VIRTIO_SCSI_QUEUE_SIZE;
169*a67da3beSAsias He }
170*a67da3beSAsias He 
171*a67da3beSAsias He static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
172*a67da3beSAsias He {
173*a67da3beSAsias He 	return size;
174*a67da3beSAsias He }
175*a67da3beSAsias He 
176*a67da3beSAsias He static struct virtio_ops scsi_dev_virtio_ops = (struct virtio_ops) {
177*a67da3beSAsias He 	.set_config		= set_config,
178*a67da3beSAsias He 	.get_config		= get_config,
179*a67da3beSAsias He 	.get_host_features	= get_host_features,
180*a67da3beSAsias He 	.set_guest_features	= set_guest_features,
181*a67da3beSAsias He 	.init_vq		= init_vq,
182*a67da3beSAsias He 	.get_pfn_vq		= get_pfn_vq,
183*a67da3beSAsias He 	.get_size_vq		= get_size_vq,
184*a67da3beSAsias He 	.set_size_vq		= set_size_vq,
185*a67da3beSAsias He 	.notify_vq		= notify_vq,
186*a67da3beSAsias He 	.notify_vq_gsi		= notify_vq_gsi,
187*a67da3beSAsias He 	.notify_vq_eventfd	= notify_vq_eventfd,
188*a67da3beSAsias He };
189*a67da3beSAsias He 
190*a67da3beSAsias He static void virtio_scsi_vhost_init(struct kvm *kvm, struct scsi_dev *sdev)
191*a67da3beSAsias He {
192*a67da3beSAsias He 	struct vhost_memory *mem;
193*a67da3beSAsias He 	u64 features;
194*a67da3beSAsias He 	int r;
195*a67da3beSAsias He 
196*a67da3beSAsias He 	sdev->vhost_fd = open("/dev/vhost-scsi", O_RDWR);
197*a67da3beSAsias He 	if (sdev->vhost_fd < 0)
198*a67da3beSAsias He 		die_perror("Failed openning vhost-scsi device");
199*a67da3beSAsias He 
200*a67da3beSAsias He 	mem = calloc(1, sizeof(*mem) + sizeof(struct vhost_memory_region));
201*a67da3beSAsias He 	if (mem == NULL)
202*a67da3beSAsias He 		die("Failed allocating memory for vhost memory map");
203*a67da3beSAsias He 
204*a67da3beSAsias He 	mem->nregions = 1;
205*a67da3beSAsias He 	mem->regions[0] = (struct vhost_memory_region) {
206*a67da3beSAsias He 		.guest_phys_addr	= 0,
207*a67da3beSAsias He 		.memory_size		= kvm->ram_size,
208*a67da3beSAsias He 		.userspace_addr		= (unsigned long)kvm->ram_start,
209*a67da3beSAsias He 	};
210*a67da3beSAsias He 
211*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_OWNER);
212*a67da3beSAsias He 	if (r != 0)
213*a67da3beSAsias He 		die_perror("VHOST_SET_OWNER failed");
214*a67da3beSAsias He 
215*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_GET_FEATURES, &features);
216*a67da3beSAsias He 	if (r != 0)
217*a67da3beSAsias He 		die_perror("VHOST_GET_FEATURES failed");
218*a67da3beSAsias He 
219*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_FEATURES, &features);
220*a67da3beSAsias He 	if (r != 0)
221*a67da3beSAsias He 		die_perror("VHOST_SET_FEATURES failed");
222*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SET_MEM_TABLE, mem);
223*a67da3beSAsias He 	if (r != 0)
224*a67da3beSAsias He 		die_perror("VHOST_SET_MEM_TABLE failed");
225*a67da3beSAsias He 
226*a67da3beSAsias He 	sdev->vdev.use_vhost = true;
227*a67da3beSAsias He 
228*a67da3beSAsias He 	free(mem);
229*a67da3beSAsias He }
230*a67da3beSAsias He 
231*a67da3beSAsias He 
232*a67da3beSAsias He static int virtio_scsi_init_one(struct kvm *kvm, struct disk_image *disk)
233*a67da3beSAsias He {
234*a67da3beSAsias He 	struct scsi_dev *sdev;
235*a67da3beSAsias He 
236*a67da3beSAsias He 	if (!disk)
237*a67da3beSAsias He 		return -EINVAL;
238*a67da3beSAsias He 
239*a67da3beSAsias He 	sdev = calloc(1, sizeof(struct scsi_dev));
240*a67da3beSAsias He 	if (sdev == NULL)
241*a67da3beSAsias He 		return -ENOMEM;
242*a67da3beSAsias He 
243*a67da3beSAsias He 	*sdev = (struct scsi_dev) {
244*a67da3beSAsias He 		.config	= (struct virtio_scsi_config) {
245*a67da3beSAsias He 			.num_queues	= NUM_VIRT_QUEUES - 2,
246*a67da3beSAsias He 			.seg_max	= VIRTIO_SCSI_CDB_SIZE - 2,
247*a67da3beSAsias He 			.max_sectors	= 65535,
248*a67da3beSAsias He 			.cmd_per_lun	= 128,
249*a67da3beSAsias He 			.sense_size	= VIRTIO_SCSI_SENSE_SIZE,
250*a67da3beSAsias He 			.cdb_size	= VIRTIO_SCSI_CDB_SIZE,
251*a67da3beSAsias He 			.max_channel	= 0,
252*a67da3beSAsias He 			.max_target	= 0,
253*a67da3beSAsias He 			.max_lun	= 16383,
254*a67da3beSAsias He 			.event_info_size = sizeof(struct virtio_scsi_event),
255*a67da3beSAsias He 		},
256*a67da3beSAsias He 		.kvm			= kvm,
257*a67da3beSAsias He 	};
258*a67da3beSAsias He 	strncpy((char *)&sdev->target.vhost_wwpn, disk->wwpn, sizeof(sdev->target.vhost_wwpn));
259*a67da3beSAsias He 	sdev->target.vhost_tpgt = strtol(disk->tpgt, NULL, 0);
260*a67da3beSAsias He 
261*a67da3beSAsias He 	virtio_init(kvm, sdev, &sdev->vdev, &scsi_dev_virtio_ops,
262*a67da3beSAsias He 		    VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_SCSI, VIRTIO_ID_SCSI, PCI_CLASS_BLK);
263*a67da3beSAsias He 
264*a67da3beSAsias He 	list_add_tail(&sdev->list, &sdevs);
265*a67da3beSAsias He 
266*a67da3beSAsias He 	virtio_scsi_vhost_init(kvm, sdev);
267*a67da3beSAsias He 
268*a67da3beSAsias He 	if (compat_id == -1)
269*a67da3beSAsias He 		compat_id = virtio_compat_add_message("virtio-scsi", "CONFIG_VIRTIO_SCSI");
270*a67da3beSAsias He 
271*a67da3beSAsias He 	return 0;
272*a67da3beSAsias He }
273*a67da3beSAsias He 
274*a67da3beSAsias He static int virtio_scsi_exit_one(struct kvm *kvm, struct scsi_dev *sdev)
275*a67da3beSAsias He {
276*a67da3beSAsias He 	int r;
277*a67da3beSAsias He 
278*a67da3beSAsias He 	r = ioctl(sdev->vhost_fd, VHOST_SCSI_CLEAR_ENDPOINT, &sdev->target);
279*a67da3beSAsias He 	if (r != 0)
280*a67da3beSAsias He 		die("VHOST_SCSI_CLEAR_ENDPOINT failed %d", errno);
281*a67da3beSAsias He 
282*a67da3beSAsias He 	list_del(&sdev->list);
283*a67da3beSAsias He 	free(sdev);
284*a67da3beSAsias He 
285*a67da3beSAsias He 	return 0;
286*a67da3beSAsias He }
287*a67da3beSAsias He 
288*a67da3beSAsias He int virtio_scsi_init(struct kvm *kvm)
289*a67da3beSAsias He {
290*a67da3beSAsias He 	int i, r = 0;
291*a67da3beSAsias He 
292*a67da3beSAsias He 	for (i = 0; i < kvm->nr_disks; i++) {
293*a67da3beSAsias He 		if (!kvm->disks[i]->wwpn)
294*a67da3beSAsias He 			continue;
295*a67da3beSAsias He 		r = virtio_scsi_init_one(kvm, kvm->disks[i]);
296*a67da3beSAsias He 		if (r < 0)
297*a67da3beSAsias He 			goto cleanup;
298*a67da3beSAsias He 	}
299*a67da3beSAsias He 
300*a67da3beSAsias He 	return 0;
301*a67da3beSAsias He cleanup:
302*a67da3beSAsias He 	return virtio_scsi_exit(kvm);
303*a67da3beSAsias He }
304*a67da3beSAsias He 
305*a67da3beSAsias He int virtio_scsi_exit(struct kvm *kvm)
306*a67da3beSAsias He {
307*a67da3beSAsias He 	while (!list_empty(&sdevs)) {
308*a67da3beSAsias He 		struct scsi_dev *sdev;
309*a67da3beSAsias He 
310*a67da3beSAsias He 		sdev = list_first_entry(&sdevs, struct scsi_dev, list);
311*a67da3beSAsias He 		virtio_scsi_exit_one(kvm, sdev);
312*a67da3beSAsias He 	}
313*a67da3beSAsias He 
314*a67da3beSAsias He 	return 0;
315*a67da3beSAsias He }
316