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