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