1416b2c2dSAsias He #include "kvm/virtio-blk.h" 2b30d05adSPekka Enberg 331638bcaSCyrill Gorcunov #include "kvm/virtio-pci-dev.h" 45a24a9f2SPekka Enberg #include "kvm/disk-image.h" 539d6af07SAsias He #include "kvm/virtio.h" 64ef0f4d6SPekka Enberg #include "kvm/mutex.h" 7fe99fd4eSPekka Enberg #include "kvm/util.h" 88b1ff07eSPekka Enberg #include "kvm/kvm.h" 9b30d05adSPekka Enberg #include "kvm/pci.h" 10fb0957f2SSasha Levin #include "kvm/threadpool.h" 11ec75b82fSSasha Levin #include "kvm/ioeventfd.h" 12404d164bSSasha Levin #include "kvm/guest_compat.h" 13*427948d5SSasha Levin #include "kvm/virtio-pci.h" 14b30d05adSPekka Enberg 1520c64ecaSPekka Enberg #include <linux/virtio_ring.h> 1620c64ecaSPekka Enberg #include <linux/virtio_blk.h> 170528c2a7SPekka Enberg 18*427948d5SSasha 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 #define NUM_VIRT_QUEUES 1 2510eca11dSPekka Enberg 2603110ff3SAsias He #define VIRTIO_BLK_QUEUE_SIZE 128 273d7831a1SAsias He /* 283d7831a1SAsias He * the header and status consume too entries 293d7831a1SAsias He */ 303d7831a1SAsias He #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2) 3110eca11dSPekka Enberg 32fe2a70d1SSasha Levin struct blk_dev_job { 334749e795SSasha Levin struct virt_queue *vq; 34fe2a70d1SSasha Levin struct blk_dev *bdev; 3569971b13SSasha Levin struct iovec iov[VIRTIO_BLK_QUEUE_SIZE]; 3669971b13SSasha Levin u16 out, in, head; 37df0c7f57SSasha Levin struct thread_pool__job job_id; 384749e795SSasha Levin }; 394749e795SSasha Levin 40fe2a70d1SSasha Levin struct blk_dev { 410528c2a7SPekka Enberg pthread_mutex_t mutex; 42ebe9ac19SSasha Levin struct list_head list; 430528c2a7SPekka Enberg 44*427948d5SSasha Levin struct virtio_pci vpci; 4540ce993fSPekka Enberg struct virtio_blk_config blk_config; 4638605e1cSSasha Levin struct disk_image *disk; 47404d164bSSasha Levin int compat_id; 48*427948d5SSasha Levin u32 features; 4910eca11dSPekka Enberg 5045e47970SAsias He struct virt_queue vqs[NUM_VIRT_QUEUES]; 5169971b13SSasha Levin struct blk_dev_job jobs[VIRTIO_BLK_QUEUE_SIZE]; 5269971b13SSasha Levin u16 job_idx; 53fbc2fbf9SPekka Enberg }; 54fbc2fbf9SPekka Enberg 55ebe9ac19SSasha Levin static LIST_HEAD(bdevs); 5640ce993fSPekka Enberg 5769971b13SSasha Levin static void virtio_blk_do_io_request(struct kvm *kvm, void *param) 584155ba8cSPekka Enberg { 594155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 603fdf659dSSasha Levin u8 *status; 6169971b13SSasha Levin ssize_t block_cnt; 6269971b13SSasha Levin struct blk_dev_job *job; 6369971b13SSasha Levin struct blk_dev *bdev; 6469971b13SSasha Levin struct virt_queue *queue; 6569971b13SSasha Levin struct iovec *iov; 6669971b13SSasha Levin u16 out, in, head; 674155ba8cSPekka Enberg 6869971b13SSasha Levin block_cnt = -1; 6969971b13SSasha Levin job = param; 7069971b13SSasha Levin bdev = job->bdev; 7169971b13SSasha Levin queue = job->vq; 7269971b13SSasha Levin iov = job->iov; 7369971b13SSasha Levin out = job->out; 7469971b13SSasha Levin in = job->in; 7569971b13SSasha Levin head = job->head; 7645e47970SAsias He req = iov[0].iov_base; 7703110ff3SAsias He 78258dd093SPekka Enberg switch (req->type) { 7903110ff3SAsias He case VIRTIO_BLK_T_IN: 80b8861977SAsias He block_cnt = disk_image__read(bdev->disk, req->sector, iov + 1, in + out - 2); 81258dd093SPekka Enberg break; 8203110ff3SAsias He case VIRTIO_BLK_T_OUT: 83b8861977SAsias He block_cnt = disk_image__write(bdev->disk, req->sector, iov + 1, in + out - 2); 84258dd093SPekka Enberg break; 8529084a74SPrasad Joshi case VIRTIO_BLK_T_FLUSH: 8629084a74SPrasad Joshi block_cnt = disk_image__flush(bdev->disk); 8729084a74SPrasad Joshi break; 88ff6462e8SSasha Levin case VIRTIO_BLK_T_GET_ID: 89ff6462e8SSasha Levin block_cnt = VIRTIO_BLK_ID_BYTES; 90ff6462e8SSasha Levin disk_image__get_serial(bdev->disk, (iov + 1)->iov_base, &block_cnt); 91ff6462e8SSasha Levin break; 92258dd093SPekka Enberg default: 934542f276SCyrill Gorcunov pr_warning("request type %d", req->type); 9470b53f25SSasha Levin block_cnt = -1; 95407475bfSPekka Enberg break; 9603110ff3SAsias He } 9703110ff3SAsias He 9845e47970SAsias He /* status */ 9945e47970SAsias He status = iov[out + in - 1].iov_base; 10070b53f25SSasha Levin *status = (block_cnt < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; 10103110ff3SAsias He 10269971b13SSasha Levin mutex_lock(&bdev->mutex); 10345e47970SAsias He virt_queue__set_used_elem(queue, head, block_cnt); 10469971b13SSasha Levin mutex_unlock(&bdev->mutex); 1054155ba8cSPekka Enberg 106*427948d5SSasha Levin virtio_pci__signal_vq(kvm, &bdev->vpci, queue - bdev->vqs); 1074155ba8cSPekka Enberg } 1084155ba8cSPekka Enberg 10969971b13SSasha Levin static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev) 11045e47970SAsias He { 11169971b13SSasha Levin while (virt_queue__available(vq)) { 11269971b13SSasha Levin struct blk_dev_job *job = &bdev->jobs[bdev->job_idx++ % VIRTIO_BLK_QUEUE_SIZE]; 113407475bfSPekka Enberg 11469971b13SSasha Levin *job = (struct blk_dev_job) { 11569971b13SSasha Levin .vq = vq, 11669971b13SSasha Levin .bdev = bdev, 11769971b13SSasha Levin }; 11869971b13SSasha Levin job->head = virt_queue__get_iov(vq, job->iov, &job->out, &job->in, kvm); 11945e47970SAsias He 12069971b13SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_blk_do_io_request, job); 12169971b13SSasha Levin thread_pool__do_job(&job->job_id); 12269971b13SSasha Levin } 1234baf6f73SSasha Levin } 1240528c2a7SPekka Enberg 125ec75b82fSSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 126ec75b82fSSasha Levin { 12769971b13SSasha Levin struct blk_dev *bdev = param; 128ec75b82fSSasha Levin 12969971b13SSasha Levin virtio_blk_do_io(kvm, &bdev->vqs[0], bdev); 130ec75b82fSSasha Levin } 131ec75b82fSSasha Levin 132*427948d5SSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 133*427948d5SSasha Levin { 134*427948d5SSasha Levin struct blk_dev *bdev = dev; 135*427948d5SSasha Levin 136*427948d5SSasha Levin ((u8 *)(&bdev->blk_config))[offset] = data; 137*427948d5SSasha Levin } 138*427948d5SSasha Levin 139*427948d5SSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 140*427948d5SSasha Levin { 141*427948d5SSasha Levin struct blk_dev *bdev = dev; 142*427948d5SSasha Levin 143*427948d5SSasha Levin return ((u8 *)(&bdev->blk_config))[offset]; 144*427948d5SSasha Levin } 145*427948d5SSasha Levin 146*427948d5SSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 147*427948d5SSasha Levin { 148*427948d5SSasha Levin return 1UL << VIRTIO_BLK_F_SEG_MAX | 1UL << VIRTIO_BLK_F_FLUSH; 149*427948d5SSasha Levin } 150*427948d5SSasha Levin 151*427948d5SSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 152*427948d5SSasha Levin { 153*427948d5SSasha Levin struct blk_dev *bdev = dev; 154*427948d5SSasha Levin 155*427948d5SSasha Levin bdev->features = features; 156*427948d5SSasha Levin } 157*427948d5SSasha Levin 158*427948d5SSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 159*427948d5SSasha Levin { 160*427948d5SSasha Levin struct blk_dev *bdev = dev; 161*427948d5SSasha Levin struct virt_queue *queue; 162*427948d5SSasha Levin void *p; 163*427948d5SSasha Levin struct ioevent ioevent; 164*427948d5SSasha Levin 165*427948d5SSasha Levin compat__remove_message(bdev->compat_id); 166*427948d5SSasha Levin 167*427948d5SSasha Levin queue = &bdev->vqs[vq]; 168*427948d5SSasha Levin queue->pfn = pfn; 169*427948d5SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 170*427948d5SSasha Levin 171*427948d5SSasha Levin vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 172*427948d5SSasha Levin 173*427948d5SSasha Levin ioevent = (struct ioevent) { 174*427948d5SSasha Levin .io_addr = bdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 175*427948d5SSasha Levin .io_len = sizeof(u16), 176*427948d5SSasha Levin .fn = ioevent_callback, 177*427948d5SSasha Levin .fn_ptr = bdev, 178*427948d5SSasha Levin .datamatch = vq, 179*427948d5SSasha Levin .fn_kvm = kvm, 180*427948d5SSasha Levin .fd = eventfd(0, 0), 181*427948d5SSasha Levin }; 182*427948d5SSasha Levin 183*427948d5SSasha Levin ioeventfd__add_event(&ioevent); 184*427948d5SSasha Levin 185*427948d5SSasha Levin return 0; 186*427948d5SSasha Levin } 187*427948d5SSasha Levin 188*427948d5SSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 189*427948d5SSasha Levin { 190*427948d5SSasha Levin struct blk_dev *bdev = dev; 191*427948d5SSasha Levin 192*427948d5SSasha Levin virtio_blk_do_io(kvm, &bdev->vqs[vq], bdev); 193*427948d5SSasha Levin 194*427948d5SSasha Levin return 0; 195*427948d5SSasha Levin } 196*427948d5SSasha Levin 197*427948d5SSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 198*427948d5SSasha Levin { 199*427948d5SSasha Levin struct blk_dev *bdev = dev; 200*427948d5SSasha Levin 201*427948d5SSasha Levin return bdev->vqs[vq].pfn; 202*427948d5SSasha Levin } 203*427948d5SSasha Levin 204*427948d5SSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 205*427948d5SSasha Levin { 206*427948d5SSasha Levin return VIRTIO_BLK_QUEUE_SIZE; 207*427948d5SSasha Levin } 208*427948d5SSasha Levin 20943835ac9SSasha Levin void virtio_blk__init(struct kvm *kvm, struct disk_image *disk) 2104749e795SSasha Levin { 211fe2a70d1SSasha Levin struct blk_dev *bdev; 2124749e795SSasha Levin 2134749e795SSasha Levin if (!disk) 2144749e795SSasha Levin return; 2154749e795SSasha Levin 216ebe9ac19SSasha Levin bdev = calloc(1, sizeof(struct blk_dev)); 217ebe9ac19SSasha Levin if (bdev == NULL) 218fe2a70d1SSasha Levin die("Failed allocating bdev"); 2194749e795SSasha Levin 220fe2a70d1SSasha Levin *bdev = (struct blk_dev) { 2214749e795SSasha Levin .mutex = PTHREAD_MUTEX_INITIALIZER, 2224749e795SSasha Levin .disk = disk, 2234749e795SSasha Levin .blk_config = (struct virtio_blk_config) { 2244749e795SSasha Levin .capacity = disk->size / SECTOR_SIZE, 2253d7831a1SAsias He .seg_max = DISK_SEG_MAX, 2264749e795SSasha Levin }, 227*427948d5SSasha Levin }; 228*427948d5SSasha Levin 229*427948d5SSasha Levin virtio_pci__init(kvm, &bdev->vpci, bdev, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK); 230*427948d5SSasha Levin bdev->vpci.ops = (struct virtio_pci_ops) { 231*427948d5SSasha Levin .set_config = set_config, 232*427948d5SSasha Levin .get_config = get_config, 233*427948d5SSasha Levin .get_host_features = get_host_features, 234*427948d5SSasha Levin .set_guest_features = set_guest_features, 235*427948d5SSasha Levin .init_vq = init_vq, 236*427948d5SSasha Levin .notify_vq = notify_vq, 237*427948d5SSasha Levin .get_pfn_vq = get_pfn_vq, 238*427948d5SSasha Levin .get_size_vq = get_size_vq, 239b30d05adSPekka Enberg }; 240b30d05adSPekka Enberg 241ebe9ac19SSasha Levin list_add_tail(&bdev->list, &bdevs); 242ebe9ac19SSasha Levin 243404d164bSSasha Levin bdev->compat_id = compat__add_message("virtio-blk device was not detected", 244404d164bSSasha Levin "While you have requested a virtio-blk device, " 245404d164bSSasha Levin "the guest kernel didn't seem to detect it.\n" 246404d164bSSasha Levin "Please make sure that the kernel was compiled" 247404d164bSSasha Levin "with CONFIG_VIRTIO_BLK."); 248b30d05adSPekka Enberg } 249bcb6aacaSPrasad Joshi 250bcb6aacaSPrasad Joshi void virtio_blk__init_all(struct kvm *kvm) 251bcb6aacaSPrasad Joshi { 252bcb6aacaSPrasad Joshi int i; 253bcb6aacaSPrasad Joshi 254bcb6aacaSPrasad Joshi for (i = 0; i < kvm->nr_disks; i++) 255bcb6aacaSPrasad Joshi virtio_blk__init(kvm, kvm->disks[i]); 256bcb6aacaSPrasad Joshi } 257a0a1e3c2SPrasad Joshi 258a0a1e3c2SPrasad Joshi void virtio_blk__delete_all(struct kvm *kvm) 259a0a1e3c2SPrasad Joshi { 260ebe9ac19SSasha Levin while (!list_empty(&bdevs)) { 261ebe9ac19SSasha Levin struct blk_dev *bdev; 262a0a1e3c2SPrasad Joshi 263ebe9ac19SSasha Levin bdev = list_first_entry(&bdevs, struct blk_dev, list); 264*427948d5SSasha Levin ioeventfd__del_event(bdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 0); 265ebe9ac19SSasha Levin list_del(&bdev->list); 266ebe9ac19SSasha Levin free(bdev); 267ebe9ac19SSasha Levin } 268a0a1e3c2SPrasad Joshi } 269