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 int vhost_fd; 28a67da3beSAsias He struct virtio_device vdev; 29a67da3beSAsias He struct list_head list; 30a67da3beSAsias He struct kvm *kvm; 31a67da3beSAsias He }; 32a67da3beSAsias He 33c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 34a67da3beSAsias He { 35a67da3beSAsias He struct scsi_dev *sdev = dev; 36a67da3beSAsias He 37c5ae742bSSasha Levin return ((u8 *)(&sdev->config)); 38a67da3beSAsias He } 39a67da3beSAsias He 40e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev) 41e4730284SMartin Radev { 42e4730284SMartin Radev struct scsi_dev *sdev = dev; 43e4730284SMartin Radev 44e4730284SMartin Radev return sizeof(sdev->config); 45e4730284SMartin Radev } 46e4730284SMartin Radev 473c8f82b8SJean-Philippe Brucker static u64 get_host_features(struct kvm *kvm, void *dev) 48a67da3beSAsias He { 4913ea439aSJean-Philippe Brucker int r; 5013ea439aSJean-Philippe Brucker u64 features; 5113ea439aSJean-Philippe Brucker struct scsi_dev *sdev = dev; 5213ea439aSJean-Philippe Brucker 5313ea439aSJean-Philippe Brucker r = ioctl(sdev->vhost_fd, VHOST_GET_FEATURES, &features); 5413ea439aSJean-Philippe Brucker if (r != 0) 5513ea439aSJean-Philippe Brucker die_perror("VHOST_GET_FEATURES failed"); 5613ea439aSJean-Philippe Brucker 5713ea439aSJean-Philippe Brucker return features & 5813ea439aSJean-Philippe Brucker (1ULL << VIRTIO_RING_F_EVENT_IDX | \ 5913ea439aSJean-Philippe Brucker 1ULL << VIRTIO_RING_F_INDIRECT_DESC | \ 6013ea439aSJean-Philippe Brucker 1ULL << VIRTIO_F_ANY_LAYOUT); 61a67da3beSAsias He } 62a67da3beSAsias He 6395242e44SJean-Philippe Brucker static void notify_status(struct kvm *kvm, void *dev, u32 status) 6495242e44SJean-Philippe Brucker { 6513ea439aSJean-Philippe Brucker int r; 66867b15ccSJean-Philippe Brucker struct scsi_dev *sdev = dev; 67867b15ccSJean-Philippe Brucker struct virtio_device *vdev = &sdev->vdev; 68867b15ccSJean-Philippe Brucker struct virtio_scsi_config *conf = &sdev->config; 69b17552eeSAndre Przywara u16 endian = vdev->endian; 70867b15ccSJean-Philippe Brucker 7113e7d626SJean-Philippe Brucker if (status & VIRTIO__STATUS_START) { 7213ea439aSJean-Philippe Brucker r = ioctl(sdev->vhost_fd, VHOST_SET_FEATURES, 7313ea439aSJean-Philippe Brucker &sdev->vdev.features); 7413ea439aSJean-Philippe Brucker if (r != 0) 7513ea439aSJean-Philippe Brucker die_perror("VHOST_SET_FEATURES failed"); 7613ea439aSJean-Philippe Brucker 7713ea439aSJean-Philippe Brucker r = ioctl(sdev->vhost_fd, VHOST_SCSI_SET_ENDPOINT, 7813e7d626SJean-Philippe Brucker &sdev->target); 7913e7d626SJean-Philippe Brucker if (r != 0) 8013e7d626SJean-Philippe Brucker die("VHOST_SCSI_SET_ENDPOINT failed %d", errno); 8113e7d626SJean-Philippe Brucker } 8213e7d626SJean-Philippe Brucker 83867b15ccSJean-Philippe Brucker if (!(status & VIRTIO__STATUS_CONFIG)) 84867b15ccSJean-Philippe Brucker return; 85867b15ccSJean-Philippe Brucker 86b17552eeSAndre Przywara conf->num_queues = virtio_host_to_guest_u32(endian, NUM_VIRT_QUEUES - 2); 87b17552eeSAndre Przywara conf->seg_max = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_CDB_SIZE - 2); 88b17552eeSAndre Przywara conf->max_sectors = virtio_host_to_guest_u32(endian, 65535); 89b17552eeSAndre Przywara conf->cmd_per_lun = virtio_host_to_guest_u32(endian, 128); 90b17552eeSAndre Przywara conf->sense_size = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_SENSE_SIZE); 91b17552eeSAndre Przywara conf->cdb_size = virtio_host_to_guest_u32(endian, VIRTIO_SCSI_CDB_SIZE); 92b8420e8dSJean-Philippe Brucker conf->max_target = virtio_host_to_guest_u16(endian, 255); 93b17552eeSAndre Przywara conf->max_lun = virtio_host_to_guest_u32(endian, 16383); 94b17552eeSAndre Przywara conf->event_info_size = virtio_host_to_guest_u32(endian, sizeof(struct virtio_scsi_event)); 9595242e44SJean-Philippe Brucker } 9695242e44SJean-Philippe Brucker 97609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq) 98a67da3beSAsias He { 99a67da3beSAsias He struct scsi_dev *sdev = dev; 100a67da3beSAsias He struct virt_queue *queue; 101a67da3beSAsias He 102a67da3beSAsias He compat__remove_message(compat_id); 103a67da3beSAsias He 104a67da3beSAsias He queue = &sdev->vqs[vq]; 105a67da3beSAsias He 106609ee906SJean-Philippe Brucker virtio_init_device_vq(kvm, &sdev->vdev, queue, VIRTIO_SCSI_QUEUE_SIZE); 107a67da3beSAsias He 108a67da3beSAsias He if (sdev->vhost_fd == 0) 109a67da3beSAsias He return 0; 110a67da3beSAsias He 111745221e5SJean-Philippe Brucker virtio_vhost_set_vring(kvm, sdev->vhost_fd, vq, queue); 112a67da3beSAsias He return 0; 113a67da3beSAsias He } 114a67da3beSAsias He 115a67da3beSAsias He static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) 116a67da3beSAsias He { 117a67da3beSAsias He struct scsi_dev *sdev = dev; 118a67da3beSAsias He 119a67da3beSAsias He if (sdev->vhost_fd == 0) 120a67da3beSAsias He return; 121a67da3beSAsias He 122*46aaf3b8SJean-Philippe Brucker virtio_vhost_set_vring_irqfd(kvm, gsi, &sdev->vqs[vq]); 123a67da3beSAsias He } 124a67da3beSAsias He 125a67da3beSAsias He static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd) 126a67da3beSAsias He { 127a67da3beSAsias He struct scsi_dev *sdev = dev; 128a67da3beSAsias He 129a67da3beSAsias He if (sdev->vhost_fd == 0) 130a67da3beSAsias He return; 131a67da3beSAsias He 132676c0c8aSJean-Philippe Brucker virtio_vhost_set_vring_kick(kvm, sdev->vhost_fd, vq, efd); 133a67da3beSAsias He } 134a67da3beSAsias He 135a67da3beSAsias He static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 136a67da3beSAsias He { 137a67da3beSAsias He return 0; 138a67da3beSAsias He } 139a67da3beSAsias He 14053fbb17bSJean-Philippe Brucker static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq) 141a67da3beSAsias He { 142a67da3beSAsias He struct scsi_dev *sdev = dev; 143a67da3beSAsias He 14453fbb17bSJean-Philippe Brucker return &sdev->vqs[vq]; 145a67da3beSAsias He } 146a67da3beSAsias He 147a67da3beSAsias He static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 148a67da3beSAsias He { 149a67da3beSAsias He return VIRTIO_SCSI_QUEUE_SIZE; 150a67da3beSAsias He } 151a67da3beSAsias He 152a67da3beSAsias He static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 153a67da3beSAsias He { 154a67da3beSAsias He return size; 155a67da3beSAsias He } 156a67da3beSAsias He 15731e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev) 158b98ac591SJean-Philippe Brucker { 159b98ac591SJean-Philippe Brucker return NUM_VIRT_QUEUES; 160b98ac591SJean-Philippe Brucker } 161b98ac591SJean-Philippe Brucker 16215542babSAndre Przywara static struct virtio_ops scsi_dev_virtio_ops = { 163a67da3beSAsias He .get_config = get_config, 164e4730284SMartin Radev .get_config_size = get_config_size, 165a67da3beSAsias He .get_host_features = get_host_features, 166a67da3beSAsias He .init_vq = init_vq, 16753fbb17bSJean-Philippe Brucker .get_vq = get_vq, 168a67da3beSAsias He .get_size_vq = get_size_vq, 169a67da3beSAsias He .set_size_vq = set_size_vq, 17095242e44SJean-Philippe Brucker .notify_status = notify_status, 171a67da3beSAsias He .notify_vq = notify_vq, 172a67da3beSAsias He .notify_vq_gsi = notify_vq_gsi, 173a67da3beSAsias He .notify_vq_eventfd = notify_vq_eventfd, 174b98ac591SJean-Philippe Brucker .get_vq_count = get_vq_count, 175a67da3beSAsias He }; 176a67da3beSAsias He 177a67da3beSAsias He static void virtio_scsi_vhost_init(struct kvm *kvm, struct scsi_dev *sdev) 178a67da3beSAsias He { 179a67da3beSAsias He sdev->vhost_fd = open("/dev/vhost-scsi", O_RDWR); 180a67da3beSAsias He if (sdev->vhost_fd < 0) 181a67da3beSAsias He die_perror("Failed openning vhost-scsi device"); 182a67da3beSAsias He 183f84ab9ebSJean-Philippe Brucker virtio_vhost_init(kvm, sdev->vhost_fd); 184a67da3beSAsias He 185a67da3beSAsias He sdev->vdev.use_vhost = true; 186a67da3beSAsias He } 187a67da3beSAsias He 188a67da3beSAsias He 189a67da3beSAsias He static int virtio_scsi_init_one(struct kvm *kvm, struct disk_image *disk) 190a67da3beSAsias He { 191a67da3beSAsias He struct scsi_dev *sdev; 192db927775SAlexandru Elisei int r; 193a67da3beSAsias He 194a67da3beSAsias He if (!disk) 195a67da3beSAsias He return -EINVAL; 196a67da3beSAsias He 197a67da3beSAsias He sdev = calloc(1, sizeof(struct scsi_dev)); 198a67da3beSAsias He if (sdev == NULL) 199a67da3beSAsias He return -ENOMEM; 200a67da3beSAsias He 201a67da3beSAsias He *sdev = (struct scsi_dev) { 202a67da3beSAsias He .kvm = kvm, 203a67da3beSAsias He }; 20405755b29SAndre Przywara strlcpy((char *)&sdev->target.vhost_wwpn, disk->wwpn, sizeof(sdev->target.vhost_wwpn)); 205145a86feSJean-Philippe Brucker sdev->target.abi_version = VHOST_SCSI_ABI_VERSION; 206a67da3beSAsias He 207db927775SAlexandru Elisei list_add_tail(&sdev->list, &sdevs); 208db927775SAlexandru Elisei 209db927775SAlexandru Elisei r = virtio_init(kvm, sdev, &sdev->vdev, &scsi_dev_virtio_ops, 2109b46ebc5SRajnesh Kanwal kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_SCSI, 211ae06ce71SWill Deacon VIRTIO_ID_SCSI, PCI_CLASS_BLK); 212db927775SAlexandru Elisei if (r < 0) 213db927775SAlexandru Elisei return r; 214a67da3beSAsias He 215a67da3beSAsias He virtio_scsi_vhost_init(kvm, sdev); 216a67da3beSAsias He 217a67da3beSAsias He if (compat_id == -1) 21833e026a7SJean-Philippe Brucker compat_id = virtio_compat_add_message("virtio-scsi", "CONFIG_SCSI_VIRTIO"); 219a67da3beSAsias He 220a67da3beSAsias He return 0; 221a67da3beSAsias He } 222a67da3beSAsias He 223a67da3beSAsias He static int virtio_scsi_exit_one(struct kvm *kvm, struct scsi_dev *sdev) 224a67da3beSAsias He { 225a67da3beSAsias He int r; 226a67da3beSAsias He 227a67da3beSAsias He r = ioctl(sdev->vhost_fd, VHOST_SCSI_CLEAR_ENDPOINT, &sdev->target); 228a67da3beSAsias He if (r != 0) 229a67da3beSAsias He die("VHOST_SCSI_CLEAR_ENDPOINT failed %d", errno); 230a67da3beSAsias He 231a67da3beSAsias He list_del(&sdev->list); 232a67da3beSAsias He free(sdev); 233a67da3beSAsias He 234a67da3beSAsias He return 0; 235a67da3beSAsias He } 236a67da3beSAsias He 237a67da3beSAsias He int virtio_scsi_init(struct kvm *kvm) 238a67da3beSAsias He { 239a67da3beSAsias He int i, r = 0; 240a67da3beSAsias He 241a67da3beSAsias He for (i = 0; i < kvm->nr_disks; i++) { 242a67da3beSAsias He if (!kvm->disks[i]->wwpn) 243a67da3beSAsias He continue; 244a67da3beSAsias He r = virtio_scsi_init_one(kvm, kvm->disks[i]); 245a67da3beSAsias He if (r < 0) 246a67da3beSAsias He goto cleanup; 247a67da3beSAsias He } 248a67da3beSAsias He 249a67da3beSAsias He return 0; 250a67da3beSAsias He cleanup: 251db927775SAlexandru Elisei virtio_scsi_exit(kvm); 252db927775SAlexandru Elisei return r; 253a67da3beSAsias He } 25449a8afd1SSasha Levin virtio_dev_init(virtio_scsi_init); 255a67da3beSAsias He 256a67da3beSAsias He int virtio_scsi_exit(struct kvm *kvm) 257a67da3beSAsias He { 258a67da3beSAsias He while (!list_empty(&sdevs)) { 259a67da3beSAsias He struct scsi_dev *sdev; 260a67da3beSAsias He 261a67da3beSAsias He sdev = list_first_entry(&sdevs, struct scsi_dev, list); 262a67da3beSAsias He virtio_scsi_exit_one(kvm, sdev); 263a67da3beSAsias He } 264a67da3beSAsias He 265a67da3beSAsias He return 0; 266a67da3beSAsias He } 26749a8afd1SSasha Levin virtio_dev_exit(virtio_scsi_exit); 268