1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2019 Intel Corporation 3 */ 4 5 /** 6 * This work is largely based on the "vhost-user-blk" implementation by 7 * SPDK(https://github.com/spdk/spdk). 8 */ 9 10 #include <stdio.h> 11 #include <stdint.h> 12 #include <unistd.h> 13 #include <assert.h> 14 #include <ctype.h> 15 #include <string.h> 16 #include <stddef.h> 17 18 #include <rte_cycles.h> 19 #include <rte_log.h> 20 #include <rte_malloc.h> 21 #include <rte_byteorder.h> 22 #include <rte_string_fns.h> 23 24 #include "vhost_blk.h" 25 #include "blk_spec.h" 26 27 static void 28 vhost_strcpy_pad(void *dst, const char *src, size_t size, int pad) 29 { 30 size_t len; 31 32 len = strlen(src); 33 if (len < size) { 34 memcpy(dst, src, len); 35 memset((char *)dst + len, pad, size - len); 36 } else { 37 memcpy(dst, src, size); 38 } 39 } 40 41 static int 42 vhost_bdev_blk_readwrite(struct vhost_block_dev *bdev, 43 struct vhost_blk_task *task, 44 uint64_t lba_512, __rte_unused uint32_t xfer_len) 45 { 46 uint32_t i; 47 uint64_t offset; 48 uint32_t nbytes = 0; 49 50 offset = lba_512 * 512; 51 52 /* iovs[0] is the head and iovs[iovs_cnt - 1] is the tail 53 * Middle is the data range 54 */ 55 for (i = 1; i < task->iovs_cnt - 1; i++) { 56 if (task->dxfer_dir == BLK_DIR_TO_DEV) 57 memcpy(bdev->data + offset, task->iovs[i].iov_base, 58 task->iovs[i].iov_len); 59 else 60 memcpy(task->iovs[i].iov_base, bdev->data + offset, 61 task->iovs[i].iov_len); 62 offset += task->iovs[i].iov_len; 63 nbytes += task->iovs[i].iov_len; 64 } 65 66 return nbytes; 67 } 68 69 int 70 vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev, 71 struct vhost_blk_task *task) 72 { 73 size_t used_len; 74 75 if (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) { 76 fprintf(stderr, "read or write beyond capacity\n"); 77 return VIRTIO_BLK_S_UNSUPP; 78 } 79 80 switch (task->req->type) { 81 case VIRTIO_BLK_T_IN: 82 if (unlikely(task->data_len == 0 || 83 (task->data_len & (512 - 1)) != 0)) { 84 fprintf(stderr, 85 "%s - passed IO buffer is not multiple of 512b" 86 "(req_idx = %"PRIu16").\n", 87 task->req->type ? "WRITE" : "READ", 88 task->req_idx); 89 return VIRTIO_BLK_S_UNSUPP; 90 } 91 92 task->dxfer_dir = BLK_DIR_FROM_DEV; 93 vhost_bdev_blk_readwrite(bdev, task, 94 task->req->sector, task->data_len); 95 break; 96 case VIRTIO_BLK_T_OUT: 97 if (unlikely(task->data_len == 0 || 98 (task->data_len & (512 - 1)) != 0)) { 99 fprintf(stderr, 100 "%s - passed IO buffer is not multiple of 512b" 101 "(req_idx = %"PRIu16").\n", 102 task->req->type ? "WRITE" : "READ", 103 task->req_idx); 104 return VIRTIO_BLK_S_UNSUPP; 105 } 106 107 task->dxfer_dir = BLK_DIR_TO_DEV; 108 vhost_bdev_blk_readwrite(bdev, task, 109 task->req->sector, task->data_len); 110 break; 111 case VIRTIO_BLK_T_GET_ID: 112 if (!task->iovs_cnt || task->data_len) 113 return VIRTIO_BLK_S_UNSUPP; 114 used_len = RTE_MIN((size_t)VIRTIO_BLK_ID_BYTES, task->data_len); 115 vhost_strcpy_pad(task->iovs[0].iov_base, 116 bdev->product_name, used_len, ' '); 117 break; 118 default: 119 fprintf(stderr, "unsupported cmd\n"); 120 return VIRTIO_BLK_S_UNSUPP; 121 } 122 123 return VIRTIO_BLK_S_OK; 124 } 125