1416b2c2dSAsias He #include "kvm/virtio-blk.h" 2b30d05adSPekka Enberg 331638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h" 45a24a9f2SPekka Enberg #include "kvm/disk-image.h" 54ef0f4d6SPekka Enberg #include "kvm/mutex.h" 6fe99fd4eSPekka Enberg #include "kvm/util.h" 78b1ff07eSPekka Enberg #include "kvm/kvm.h" 8b30d05adSPekka Enberg #include "kvm/pci.h" 9fb0957f2SSasha Levin #include "kvm/threadpool.h" 10ec75b82fSSasha Levin #include "kvm/ioeventfd.h" 11404d164bSSasha Levin #include "kvm/guest_compat.h" 12427948d5SSasha Levin #include "kvm/virtio-pci.h" 13f41a132bSSasha Levin #include "kvm/virtio.h" 14*1c47ce69SSasha Levin #include "kvm/virtio-trans.h" 15b30d05adSPekka Enberg 1620c64ecaSPekka Enberg #include <linux/virtio_ring.h> 1720c64ecaSPekka Enberg #include <linux/virtio_blk.h> 18427948d5SSasha Levin #include <linux/kernel.h> 19ebe9ac19SSasha Levin #include <linux/list.h> 203fdf659dSSasha Levin #include <linux/types.h> 210528c2a7SPekka Enberg #include <pthread.h> 224155ba8cSPekka Enberg 234749e795SSasha Levin #define VIRTIO_BLK_MAX_DEV 4 2410eca11dSPekka Enberg 253d7831a1SAsias He /* 263d7831a1SAsias He * the header and status consume too entries 273d7831a1SAsias He */ 283d7831a1SAsias He #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2) 29f41a132bSSasha Levin #define VIRTIO_BLK_QUEUE_SIZE 128 30f41a132bSSasha Levin #define NUM_VIRT_QUEUES 1 3110eca11dSPekka Enberg 328b52f877SSasha Levin struct blk_dev_req { 338b52f877SSasha Levin struct list_head list; 344749e795SSasha Levin struct virt_queue *vq; 35fe2a70d1SSasha Levin struct blk_dev *bdev; 3669971b13SSasha Levin struct iovec iov[VIRTIO_BLK_QUEUE_SIZE]; 3769971b13SSasha Levin u16 out, in, head; 388b52f877SSasha Levin struct kvm *kvm; 394749e795SSasha Levin }; 404749e795SSasha Levin 41fe2a70d1SSasha Levin struct blk_dev { 420528c2a7SPekka Enberg pthread_mutex_t mutex; 438b52f877SSasha Levin pthread_mutex_t req_mutex; 448b52f877SSasha Levin 45ebe9ac19SSasha Levin struct list_head list; 468b52f877SSasha Levin struct list_head req_list; 470528c2a7SPekka Enberg 48*1c47ce69SSasha Levin struct virtio_trans vtrans; 4940ce993fSPekka Enberg struct virtio_blk_config blk_config; 5038605e1cSSasha Levin struct disk_image *disk; 51427948d5SSasha Levin u32 features; 5210eca11dSPekka Enberg 5345e47970SAsias He struct virt_queue vqs[NUM_VIRT_QUEUES]; 548b52f877SSasha Levin struct blk_dev_req reqs[VIRTIO_BLK_QUEUE_SIZE]; 55fbc2fbf9SPekka Enberg }; 56fbc2fbf9SPekka Enberg 57ebe9ac19SSasha Levin static LIST_HEAD(bdevs); 58312c62d1SSasha Levin static int compat_id; 5940ce993fSPekka Enberg 608b52f877SSasha Levin static struct blk_dev_req *virtio_blk_req_pop(struct blk_dev *bdev) 614155ba8cSPekka Enberg { 628b52f877SSasha Levin struct blk_dev_req *req = NULL; 638b52f877SSasha Levin 648b52f877SSasha Levin mutex_lock(&bdev->req_mutex); 658b52f877SSasha Levin if (!list_empty(&bdev->req_list)) { 668b52f877SSasha Levin req = list_first_entry(&bdev->req_list, struct blk_dev_req, list); 678b52f877SSasha Levin list_del_init(&req->list); 688b52f877SSasha Levin } 698b52f877SSasha Levin mutex_unlock(&bdev->req_mutex); 708b52f877SSasha Levin 718b52f877SSasha Levin return req; 728b52f877SSasha Levin } 738b52f877SSasha Levin 748b52f877SSasha Levin static void virtio_blk_req_push(struct blk_dev *bdev, struct blk_dev_req *req) 758b52f877SSasha Levin { 768b52f877SSasha Levin mutex_lock(&bdev->req_mutex); 778b52f877SSasha Levin list_add(&req->list, &bdev->req_list); 788b52f877SSasha Levin mutex_unlock(&bdev->req_mutex); 798b52f877SSasha Levin } 808b52f877SSasha Levin 818b52f877SSasha Levin void virtio_blk_complete(void *param, long len) 828b52f877SSasha Levin { 838b52f877SSasha Levin struct blk_dev_req *req = param; 848b52f877SSasha Levin struct blk_dev *bdev = req->bdev; 858b52f877SSasha Levin int queueid = req->vq - bdev->vqs; 863fdf659dSSasha Levin u8 *status; 878b52f877SSasha Levin 888b52f877SSasha Levin /* status */ 898b52f877SSasha Levin status = req->iov[req->out + req->in - 1].iov_base; 908b52f877SSasha Levin *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; 918b52f877SSasha Levin 928b52f877SSasha Levin mutex_lock(&bdev->mutex); 938b52f877SSasha Levin virt_queue__set_used_elem(req->vq, req->head, len); 948b52f877SSasha Levin mutex_unlock(&bdev->mutex); 958b52f877SSasha Levin 96*1c47ce69SSasha Levin bdev->vtrans.trans_ops->signal_vq(req->kvm, &bdev->vtrans, queueid); 978b52f877SSasha Levin 988b52f877SSasha Levin virtio_blk_req_push(req->bdev, req); 998b52f877SSasha Levin } 1008b52f877SSasha Levin 1018b52f877SSasha Levin static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req) 1028b52f877SSasha Levin { 1038b52f877SSasha Levin struct virtio_blk_outhdr *req_hdr; 10469971b13SSasha Levin ssize_t block_cnt; 10569971b13SSasha Levin struct blk_dev *bdev; 10669971b13SSasha Levin struct iovec *iov; 107f41a132bSSasha Levin u16 out, in; 1084155ba8cSPekka Enberg 10969971b13SSasha Levin block_cnt = -1; 1108b52f877SSasha Levin bdev = req->bdev; 1118b52f877SSasha Levin iov = req->iov; 1128b52f877SSasha Levin out = req->out; 1138b52f877SSasha Levin in = req->in; 1148b52f877SSasha Levin req_hdr = iov[0].iov_base; 11503110ff3SAsias He 1168b52f877SSasha Levin switch (req_hdr->type) { 11703110ff3SAsias He case VIRTIO_BLK_T_IN: 1188b52f877SSasha Levin block_cnt = disk_image__read(bdev->disk, req_hdr->sector, iov + 1, 119fb434ac3SSasha Levin in + out - 2, req); 120258dd093SPekka Enberg break; 12103110ff3SAsias He case VIRTIO_BLK_T_OUT: 1228b52f877SSasha Levin block_cnt = disk_image__write(bdev->disk, req_hdr->sector, iov + 1, 123fb434ac3SSasha Levin in + out - 2, req); 124258dd093SPekka Enberg break; 12529084a74SPrasad Joshi case VIRTIO_BLK_T_FLUSH: 12629084a74SPrasad Joshi block_cnt = disk_image__flush(bdev->disk); 127fb434ac3SSasha Levin virtio_blk_complete(req, block_cnt); 12829084a74SPrasad Joshi break; 129ff6462e8SSasha Levin case VIRTIO_BLK_T_GET_ID: 130ff6462e8SSasha Levin block_cnt = VIRTIO_BLK_ID_BYTES; 131ff6462e8SSasha Levin disk_image__get_serial(bdev->disk, (iov + 1)->iov_base, &block_cnt); 132fb434ac3SSasha Levin virtio_blk_complete(req, block_cnt); 133ff6462e8SSasha Levin break; 134258dd093SPekka Enberg default: 1358b52f877SSasha Levin pr_warning("request type %d", req_hdr->type); 13670b53f25SSasha Levin block_cnt = -1; 137407475bfSPekka Enberg break; 13803110ff3SAsias He } 1394155ba8cSPekka Enberg } 1404155ba8cSPekka Enberg 14169971b13SSasha Levin static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev) 14245e47970SAsias He { 14369971b13SSasha Levin while (virt_queue__available(vq)) { 1448b52f877SSasha Levin struct blk_dev_req *req = virtio_blk_req_pop(bdev); 145407475bfSPekka Enberg 1468b52f877SSasha Levin *req = (struct blk_dev_req) { 14769971b13SSasha Levin .vq = vq, 14869971b13SSasha Levin .bdev = bdev, 1498b52f877SSasha Levin .kvm = kvm, 15069971b13SSasha Levin }; 1518b52f877SSasha Levin req->head = virt_queue__get_iov(vq, req->iov, &req->out, &req->in, kvm); 15245e47970SAsias He 1538b52f877SSasha Levin virtio_blk_do_io_request(kvm, req); 15469971b13SSasha Levin } 1554baf6f73SSasha Levin } 1560528c2a7SPekka Enberg 157427948d5SSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 158427948d5SSasha Levin { 159427948d5SSasha Levin struct blk_dev *bdev = dev; 160427948d5SSasha Levin 161427948d5SSasha Levin ((u8 *)(&bdev->blk_config))[offset] = data; 162427948d5SSasha Levin } 163427948d5SSasha Levin 164427948d5SSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 165427948d5SSasha Levin { 166427948d5SSasha Levin struct blk_dev *bdev = dev; 167427948d5SSasha Levin 168427948d5SSasha Levin return ((u8 *)(&bdev->blk_config))[offset]; 169427948d5SSasha Levin } 170427948d5SSasha Levin 171427948d5SSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 172427948d5SSasha Levin { 173427948d5SSasha Levin return 1UL << VIRTIO_BLK_F_SEG_MAX | 1UL << VIRTIO_BLK_F_FLUSH; 174427948d5SSasha Levin } 175427948d5SSasha Levin 176427948d5SSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 177427948d5SSasha Levin { 178427948d5SSasha Levin struct blk_dev *bdev = dev; 179427948d5SSasha Levin 180427948d5SSasha Levin bdev->features = features; 181427948d5SSasha Levin } 182427948d5SSasha Levin 183427948d5SSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 184427948d5SSasha Levin { 185427948d5SSasha Levin struct blk_dev *bdev = dev; 186427948d5SSasha Levin struct virt_queue *queue; 187427948d5SSasha Levin void *p; 188427948d5SSasha Levin 189312c62d1SSasha Levin compat__remove_message(compat_id); 190427948d5SSasha Levin 191427948d5SSasha Levin queue = &bdev->vqs[vq]; 192427948d5SSasha Levin queue->pfn = pfn; 193427948d5SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 194427948d5SSasha Levin 195427948d5SSasha Levin vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 196427948d5SSasha Levin 197427948d5SSasha Levin return 0; 198427948d5SSasha Levin } 199427948d5SSasha Levin 200427948d5SSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 201427948d5SSasha Levin { 202427948d5SSasha Levin struct blk_dev *bdev = dev; 203427948d5SSasha Levin 204427948d5SSasha Levin virtio_blk_do_io(kvm, &bdev->vqs[vq], bdev); 205427948d5SSasha Levin 206427948d5SSasha Levin return 0; 207427948d5SSasha Levin } 208427948d5SSasha Levin 209427948d5SSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 210427948d5SSasha Levin { 211427948d5SSasha Levin struct blk_dev *bdev = dev; 212427948d5SSasha Levin 213427948d5SSasha Levin return bdev->vqs[vq].pfn; 214427948d5SSasha Levin } 215427948d5SSasha Levin 216427948d5SSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 217427948d5SSasha Levin { 218427948d5SSasha Levin return VIRTIO_BLK_QUEUE_SIZE; 219427948d5SSasha Levin } 220427948d5SSasha Levin 221*1c47ce69SSasha Levin static struct virtio_ops blk_dev_virtio_ops = (struct virtio_ops) { 222*1c47ce69SSasha Levin .set_config = set_config, 223*1c47ce69SSasha Levin .get_config = get_config, 224*1c47ce69SSasha Levin .get_host_features = get_host_features, 225*1c47ce69SSasha Levin .set_guest_features = set_guest_features, 226*1c47ce69SSasha Levin .init_vq = init_vq, 227*1c47ce69SSasha Levin .notify_vq = notify_vq, 228*1c47ce69SSasha Levin .get_pfn_vq = get_pfn_vq, 229*1c47ce69SSasha Levin .get_size_vq = get_size_vq, 230*1c47ce69SSasha Levin }; 231*1c47ce69SSasha Levin 23243835ac9SSasha Levin void virtio_blk__init(struct kvm *kvm, struct disk_image *disk) 2334749e795SSasha Levin { 234fe2a70d1SSasha Levin struct blk_dev *bdev; 2358b52f877SSasha Levin size_t i; 2364749e795SSasha Levin 2374749e795SSasha Levin if (!disk) 2384749e795SSasha Levin return; 2394749e795SSasha Levin 240ebe9ac19SSasha Levin bdev = calloc(1, sizeof(struct blk_dev)); 241ebe9ac19SSasha Levin if (bdev == NULL) 242fe2a70d1SSasha Levin die("Failed allocating bdev"); 2434749e795SSasha Levin 244fe2a70d1SSasha Levin *bdev = (struct blk_dev) { 2454749e795SSasha Levin .mutex = PTHREAD_MUTEX_INITIALIZER, 2468b52f877SSasha Levin .req_mutex = PTHREAD_MUTEX_INITIALIZER, 2474749e795SSasha Levin .disk = disk, 2484749e795SSasha Levin .blk_config = (struct virtio_blk_config) { 2494749e795SSasha Levin .capacity = disk->size / SECTOR_SIZE, 2503d7831a1SAsias He .seg_max = DISK_SEG_MAX, 2514749e795SSasha Levin }, 252427948d5SSasha Levin }; 253427948d5SSasha Levin 254*1c47ce69SSasha Levin virtio_trans_init(&bdev->vtrans, VIRTIO_PCI); 255*1c47ce69SSasha Levin bdev->vtrans.trans_ops->init(kvm, &bdev->vtrans, bdev, PCI_DEVICE_ID_VIRTIO_BLK, 256*1c47ce69SSasha Levin VIRTIO_ID_BLOCK, PCI_CLASS_BLK); 257*1c47ce69SSasha Levin bdev->vtrans.virtio_ops = &blk_dev_virtio_ops; 258b30d05adSPekka Enberg 259ebe9ac19SSasha Levin list_add_tail(&bdev->list, &bdevs); 260ebe9ac19SSasha Levin 2618b52f877SSasha Levin INIT_LIST_HEAD(&bdev->req_list); 2628b52f877SSasha Levin for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) 2638b52f877SSasha Levin list_add(&bdev->reqs[i].list, &bdev->req_list); 2648b52f877SSasha Levin 265fb434ac3SSasha Levin disk_image__set_callback(bdev->disk, virtio_blk_complete); 266fb434ac3SSasha Levin 267312c62d1SSasha Levin if (compat_id != -1) 268312c62d1SSasha Levin compat_id = compat__add_message("virtio-blk device was not detected", 269404d164bSSasha Levin "While you have requested a virtio-blk device, " 270fc835ab3SSasha Levin "the guest kernel did not initialize it.\n" 271fc835ab3SSasha Levin "Please make sure that the guest kernel was " 272fc835ab3SSasha Levin "compiled with CONFIG_VIRTIO_BLK=y enabled " 273fc835ab3SSasha Levin "in its .config"); 274b30d05adSPekka Enberg } 275bcb6aacaSPrasad Joshi 276bcb6aacaSPrasad Joshi void virtio_blk__init_all(struct kvm *kvm) 277bcb6aacaSPrasad Joshi { 278bcb6aacaSPrasad Joshi int i; 279bcb6aacaSPrasad Joshi 280bcb6aacaSPrasad Joshi for (i = 0; i < kvm->nr_disks; i++) 281bcb6aacaSPrasad Joshi virtio_blk__init(kvm, kvm->disks[i]); 282bcb6aacaSPrasad Joshi } 283a0a1e3c2SPrasad Joshi 284a0a1e3c2SPrasad Joshi void virtio_blk__delete_all(struct kvm *kvm) 285a0a1e3c2SPrasad Joshi { 286ebe9ac19SSasha Levin while (!list_empty(&bdevs)) { 287ebe9ac19SSasha Levin struct blk_dev *bdev; 288a0a1e3c2SPrasad Joshi 289ebe9ac19SSasha Levin bdev = list_first_entry(&bdevs, struct blk_dev, list); 290ebe9ac19SSasha Levin list_del(&bdev->list); 291ebe9ac19SSasha Levin free(bdev); 292ebe9ac19SSasha Levin } 293a0a1e3c2SPrasad Joshi } 294