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" 14b30d05adSPekka Enberg 1520c64ecaSPekka Enberg #include <linux/virtio_ring.h> 1620c64ecaSPekka Enberg #include <linux/virtio_blk.h> 17427948d5SSasha Levin #include <linux/kernel.h> 18ebe9ac19SSasha Levin #include <linux/list.h> 193fdf659dSSasha Levin #include <linux/types.h> 200528c2a7SPekka Enberg #include <pthread.h> 214155ba8cSPekka Enberg 224749e795SSasha Levin #define VIRTIO_BLK_MAX_DEV 4 2310eca11dSPekka Enberg 243d7831a1SAsias He /* 253d7831a1SAsias He * the header and status consume too entries 263d7831a1SAsias He */ 273d7831a1SAsias He #define DISK_SEG_MAX (VIRTIO_BLK_QUEUE_SIZE - 2) 284059ad8bSAsias He #define VIRTIO_BLK_QUEUE_SIZE 256 29f41a132bSSasha Levin #define NUM_VIRT_QUEUES 1 3010eca11dSPekka Enberg 318b52f877SSasha Levin struct blk_dev_req { 324749e795SSasha Levin struct virt_queue *vq; 33fe2a70d1SSasha Levin struct blk_dev *bdev; 3469971b13SSasha Levin struct iovec iov[VIRTIO_BLK_QUEUE_SIZE]; 3569971b13SSasha Levin u16 out, in, head; 368b52f877SSasha Levin struct kvm *kvm; 374749e795SSasha Levin }; 384749e795SSasha Levin 39fe2a70d1SSasha Levin struct blk_dev { 400528c2a7SPekka Enberg pthread_mutex_t mutex; 418b52f877SSasha Levin 42ebe9ac19SSasha Levin struct list_head list; 438b52f877SSasha Levin struct list_head req_list; 440528c2a7SPekka Enberg 4502eca50cSAsias He struct virtio_device vdev; 4640ce993fSPekka Enberg struct virtio_blk_config blk_config; 4738605e1cSSasha Levin struct disk_image *disk; 48427948d5SSasha Levin u32 features; 4910eca11dSPekka Enberg 5045e47970SAsias He struct virt_queue vqs[NUM_VIRT_QUEUES]; 518b52f877SSasha Levin struct blk_dev_req reqs[VIRTIO_BLK_QUEUE_SIZE]; 52*5ac1178bSAsias He 53*5ac1178bSAsias He pthread_t io_thread; 54*5ac1178bSAsias He int io_efd; 55*5ac1178bSAsias He 56*5ac1178bSAsias He struct kvm *kvm; 57fbc2fbf9SPekka Enberg }; 58fbc2fbf9SPekka Enberg 59ebe9ac19SSasha Levin static LIST_HEAD(bdevs); 60bdbbcb63SAsias He static int compat_id = -1; 6140ce993fSPekka Enberg 628b52f877SSasha Levin void virtio_blk_complete(void *param, long len) 638b52f877SSasha Levin { 648b52f877SSasha Levin struct blk_dev_req *req = param; 658b52f877SSasha Levin struct blk_dev *bdev = req->bdev; 668b52f877SSasha Levin int queueid = req->vq - bdev->vqs; 673fdf659dSSasha Levin u8 *status; 688b52f877SSasha Levin 698b52f877SSasha Levin /* status */ 708b52f877SSasha Levin status = req->iov[req->out + req->in - 1].iov_base; 718b52f877SSasha Levin *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; 728b52f877SSasha Levin 738b52f877SSasha Levin mutex_lock(&bdev->mutex); 748b52f877SSasha Levin virt_queue__set_used_elem(req->vq, req->head, len); 758b52f877SSasha Levin mutex_unlock(&bdev->mutex); 768b52f877SSasha Levin 777ab3d207SSasha Levin if (virtio_queue__should_signal(&bdev->vqs[queueid])) 7802eca50cSAsias He bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid); 798b52f877SSasha Levin } 808b52f877SSasha Levin 818b52f877SSasha Levin static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req) 828b52f877SSasha Levin { 838b52f877SSasha Levin struct virtio_blk_outhdr *req_hdr; 8469971b13SSasha Levin ssize_t block_cnt; 8569971b13SSasha Levin struct blk_dev *bdev; 8669971b13SSasha Levin struct iovec *iov; 87f41a132bSSasha Levin u16 out, in; 884155ba8cSPekka Enberg 8969971b13SSasha Levin block_cnt = -1; 908b52f877SSasha Levin bdev = req->bdev; 918b52f877SSasha Levin iov = req->iov; 928b52f877SSasha Levin out = req->out; 938b52f877SSasha Levin in = req->in; 948b52f877SSasha Levin req_hdr = iov[0].iov_base; 9503110ff3SAsias He 968b52f877SSasha Levin switch (req_hdr->type) { 9703110ff3SAsias He case VIRTIO_BLK_T_IN: 9834239c78SAsias He block_cnt = disk_image__read(bdev->disk, req_hdr->sector, 9934239c78SAsias He iov + 1, in + out - 2, req); 100258dd093SPekka Enberg break; 10103110ff3SAsias He case VIRTIO_BLK_T_OUT: 10234239c78SAsias He block_cnt = disk_image__write(bdev->disk, req_hdr->sector, 10334239c78SAsias He iov + 1, in + out - 2, req); 104258dd093SPekka Enberg break; 10529084a74SPrasad Joshi case VIRTIO_BLK_T_FLUSH: 10629084a74SPrasad Joshi block_cnt = disk_image__flush(bdev->disk); 107fb434ac3SSasha Levin virtio_blk_complete(req, block_cnt); 10829084a74SPrasad Joshi break; 109ff6462e8SSasha Levin case VIRTIO_BLK_T_GET_ID: 110ff6462e8SSasha Levin block_cnt = VIRTIO_BLK_ID_BYTES; 11134239c78SAsias He disk_image__get_serial(bdev->disk, 11234239c78SAsias He (iov + 1)->iov_base, &block_cnt); 113fb434ac3SSasha Levin virtio_blk_complete(req, block_cnt); 114ff6462e8SSasha Levin break; 115258dd093SPekka Enberg default: 1168b52f877SSasha Levin pr_warning("request type %d", req_hdr->type); 11770b53f25SSasha Levin block_cnt = -1; 118407475bfSPekka Enberg break; 11903110ff3SAsias He } 1204155ba8cSPekka Enberg } 1214155ba8cSPekka Enberg 12269971b13SSasha Levin static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev) 12345e47970SAsias He { 1242fddfdb5SAsias He struct blk_dev_req *req; 1252fddfdb5SAsias He u16 head; 126407475bfSPekka Enberg 1272fddfdb5SAsias He while (virt_queue__available(vq)) { 1282fddfdb5SAsias He head = virt_queue__pop(vq); 1292fddfdb5SAsias He req = &bdev->reqs[head]; 13034239c78SAsias He req->head = virt_queue__get_head_iov(vq, req->iov, &req->out, 13134239c78SAsias He &req->in, head, kvm); 1322fddfdb5SAsias He req->vq = vq; 13345e47970SAsias He 1348b52f877SSasha Levin virtio_blk_do_io_request(kvm, req); 13569971b13SSasha Levin } 1364baf6f73SSasha Levin } 1370528c2a7SPekka Enberg 138427948d5SSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 139427948d5SSasha Levin { 140427948d5SSasha Levin struct blk_dev *bdev = dev; 141427948d5SSasha Levin 142427948d5SSasha Levin ((u8 *)(&bdev->blk_config))[offset] = data; 143427948d5SSasha Levin } 144427948d5SSasha Levin 145427948d5SSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 146427948d5SSasha Levin { 147427948d5SSasha Levin struct blk_dev *bdev = dev; 148427948d5SSasha Levin 149427948d5SSasha Levin return ((u8 *)(&bdev->blk_config))[offset]; 150427948d5SSasha Levin } 151427948d5SSasha Levin 152427948d5SSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 153427948d5SSasha Levin { 1547ab3d207SSasha Levin return 1UL << VIRTIO_BLK_F_SEG_MAX 1557ab3d207SSasha Levin | 1UL << VIRTIO_BLK_F_FLUSH 156754c8ce3SSasha Levin | 1UL << VIRTIO_RING_F_EVENT_IDX 157754c8ce3SSasha Levin | 1UL << VIRTIO_RING_F_INDIRECT_DESC; 158427948d5SSasha Levin } 159427948d5SSasha Levin 160427948d5SSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 161427948d5SSasha Levin { 162427948d5SSasha Levin struct blk_dev *bdev = dev; 163427948d5SSasha Levin 164427948d5SSasha Levin bdev->features = features; 165427948d5SSasha Levin } 166427948d5SSasha Levin 167427948d5SSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 168427948d5SSasha Levin { 169427948d5SSasha Levin struct blk_dev *bdev = dev; 170427948d5SSasha Levin struct virt_queue *queue; 171427948d5SSasha Levin void *p; 172427948d5SSasha Levin 173312c62d1SSasha Levin compat__remove_message(compat_id); 174427948d5SSasha Levin 175427948d5SSasha Levin queue = &bdev->vqs[vq]; 176427948d5SSasha Levin queue->pfn = pfn; 177427948d5SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 178427948d5SSasha Levin 179427948d5SSasha Levin vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 180427948d5SSasha Levin 181427948d5SSasha Levin return 0; 182427948d5SSasha Levin } 183427948d5SSasha Levin 184*5ac1178bSAsias He static void *virtio_blk_thread(void *dev) 185*5ac1178bSAsias He { 186*5ac1178bSAsias He struct blk_dev *bdev = dev; 187*5ac1178bSAsias He u64 data; 188*5ac1178bSAsias He 189*5ac1178bSAsias He while (1) { 190*5ac1178bSAsias He read(bdev->io_efd, &data, sizeof(u64)); 191*5ac1178bSAsias He virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev); 192*5ac1178bSAsias He } 193*5ac1178bSAsias He 194*5ac1178bSAsias He pthread_exit(NULL); 195*5ac1178bSAsias He return NULL; 196*5ac1178bSAsias He } 197*5ac1178bSAsias He 198427948d5SSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 199427948d5SSasha Levin { 200427948d5SSasha Levin struct blk_dev *bdev = dev; 201*5ac1178bSAsias He u64 data = 1; 202427948d5SSasha Levin 203*5ac1178bSAsias He write(bdev->io_efd, &data, sizeof(data)); 204427948d5SSasha Levin 205427948d5SSasha Levin return 0; 206427948d5SSasha Levin } 207427948d5SSasha Levin 208427948d5SSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 209427948d5SSasha Levin { 210427948d5SSasha Levin struct blk_dev *bdev = dev; 211427948d5SSasha Levin 212427948d5SSasha Levin return bdev->vqs[vq].pfn; 213427948d5SSasha Levin } 214427948d5SSasha Levin 215427948d5SSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 216427948d5SSasha Levin { 217ffcc904aSAsias He /* FIXME: dynamic */ 218427948d5SSasha Levin return VIRTIO_BLK_QUEUE_SIZE; 219427948d5SSasha Levin } 220427948d5SSasha Levin 221ffcc904aSAsias He static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 222ffcc904aSAsias He { 223ffcc904aSAsias He /* FIXME: dynamic */ 224ffcc904aSAsias He return size; 225ffcc904aSAsias He } 226ffcc904aSAsias He 2271c47ce69SSasha Levin static struct virtio_ops blk_dev_virtio_ops = (struct virtio_ops) { 2281c47ce69SSasha Levin .set_config = set_config, 2291c47ce69SSasha Levin .get_config = get_config, 2301c47ce69SSasha Levin .get_host_features = get_host_features, 2311c47ce69SSasha Levin .set_guest_features = set_guest_features, 2321c47ce69SSasha Levin .init_vq = init_vq, 2331c47ce69SSasha Levin .notify_vq = notify_vq, 2341c47ce69SSasha Levin .get_pfn_vq = get_pfn_vq, 2351c47ce69SSasha Levin .get_size_vq = get_size_vq, 236ffcc904aSAsias He .set_size_vq = set_size_vq, 2371c47ce69SSasha Levin }; 2381c47ce69SSasha Levin 2399f9207c5SSasha Levin static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk) 2404749e795SSasha Levin { 241fe2a70d1SSasha Levin struct blk_dev *bdev; 2422fddfdb5SAsias He unsigned int i; 2434749e795SSasha Levin 2444749e795SSasha Levin if (!disk) 2459f9207c5SSasha Levin return -EINVAL; 2464749e795SSasha Levin 247ebe9ac19SSasha Levin bdev = calloc(1, sizeof(struct blk_dev)); 248ebe9ac19SSasha Levin if (bdev == NULL) 2499f9207c5SSasha Levin return -ENOMEM; 2504749e795SSasha Levin 251fe2a70d1SSasha Levin *bdev = (struct blk_dev) { 2524749e795SSasha Levin .mutex = PTHREAD_MUTEX_INITIALIZER, 2534749e795SSasha Levin .disk = disk, 2544749e795SSasha Levin .blk_config = (struct virtio_blk_config) { 2554749e795SSasha Levin .capacity = disk->size / SECTOR_SIZE, 2563d7831a1SAsias He .seg_max = DISK_SEG_MAX, 2574749e795SSasha Levin }, 258*5ac1178bSAsias He .io_efd = eventfd(0, 0), 259*5ac1178bSAsias He .kvm = kvm, 260427948d5SSasha Levin }; 261427948d5SSasha Levin 26202eca50cSAsias He virtio_init(kvm, bdev, &bdev->vdev, &blk_dev_virtio_ops, 26302eca50cSAsias He VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK, PCI_CLASS_BLK); 264b30d05adSPekka Enberg 265ebe9ac19SSasha Levin list_add_tail(&bdev->list, &bdevs); 266ebe9ac19SSasha Levin 2672fddfdb5SAsias He for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) { 2682fddfdb5SAsias He bdev->reqs[i].bdev = bdev; 2692fddfdb5SAsias He bdev->reqs[i].kvm = kvm; 2702fddfdb5SAsias He } 2718b52f877SSasha Levin 272fb434ac3SSasha Levin disk_image__set_callback(bdev->disk, virtio_blk_complete); 273fb434ac3SSasha Levin 274*5ac1178bSAsias He pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev); 275d278197dSAsias He if (compat_id == -1) 27652f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK"); 277*5ac1178bSAsias He 2789f9207c5SSasha Levin return 0; 279b30d05adSPekka Enberg } 280bcb6aacaSPrasad Joshi 2819f9207c5SSasha Levin static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev) 282bcb6aacaSPrasad Joshi { 2839f9207c5SSasha Levin list_del(&bdev->list); 2849f9207c5SSasha Levin free(bdev); 285bcb6aacaSPrasad Joshi 2869f9207c5SSasha Levin return 0; 287bcb6aacaSPrasad Joshi } 288a0a1e3c2SPrasad Joshi 2899f9207c5SSasha Levin int virtio_blk__init(struct kvm *kvm) 2909f9207c5SSasha Levin { 2919f9207c5SSasha Levin int i, r = 0; 2929f9207c5SSasha Levin 2939f9207c5SSasha Levin for (i = 0; i < kvm->nr_disks; i++) { 2949f9207c5SSasha Levin r = virtio_blk__init_one(kvm, kvm->disks[i]); 2959f9207c5SSasha Levin if (r < 0) 2969f9207c5SSasha Levin goto cleanup; 2979f9207c5SSasha Levin } 2989f9207c5SSasha Levin 2999f9207c5SSasha Levin return 0; 3009f9207c5SSasha Levin cleanup: 3019f9207c5SSasha Levin return virtio_blk__exit(kvm); 3029f9207c5SSasha Levin } 3039f9207c5SSasha Levin 3049f9207c5SSasha Levin int virtio_blk__exit(struct kvm *kvm) 305a0a1e3c2SPrasad Joshi { 306ebe9ac19SSasha Levin while (!list_empty(&bdevs)) { 307ebe9ac19SSasha Levin struct blk_dev *bdev; 308a0a1e3c2SPrasad Joshi 309ebe9ac19SSasha Levin bdev = list_first_entry(&bdevs, struct blk_dev, list); 3109f9207c5SSasha Levin virtio_blk__exit_one(kvm, bdev); 311ebe9ac19SSasha Levin } 3129f9207c5SSasha Levin 3139f9207c5SSasha Levin return 0; 314a0a1e3c2SPrasad Joshi } 315