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 for (i = 0; i < task->iovs_cnt; i++) { 54 if (task->dxfer_dir == BLK_DIR_TO_DEV) 55 memcpy(bdev->data + offset, task->iovs[i].iov_base, 56 task->iovs[i].iov_len); 57 else 58 memcpy(task->iovs[i].iov_base, bdev->data + offset, 59 task->iovs[i].iov_len); 60 offset += task->iovs[i].iov_len; 61 nbytes += task->iovs[i].iov_len; 62 } 63 64 return nbytes; 65 } 66 67 int 68 vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev, 69 struct vhost_blk_task *task) 70 { 71 int used_len; 72 73 if (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) { 74 fprintf(stderr, "read or write beyond capacity\n"); 75 return VIRTIO_BLK_S_UNSUPP; 76 } 77 78 switch (task->req->type) { 79 case VIRTIO_BLK_T_IN: 80 if (unlikely(task->data_len == 0 || 81 (task->data_len & (512 - 1)) != 0)) { 82 fprintf(stderr, 83 "%s - passed IO buffer is not multiple of 512b" 84 "(req_idx = %"PRIu16").\n", 85 task->req->type ? "WRITE" : "READ", 86 task->head_idx); 87 return VIRTIO_BLK_S_UNSUPP; 88 } 89 90 task->dxfer_dir = BLK_DIR_FROM_DEV; 91 vhost_bdev_blk_readwrite(bdev, task, 92 task->req->sector, task->data_len); 93 break; 94 case VIRTIO_BLK_T_OUT: 95 if (unlikely(task->data_len == 0 || 96 (task->data_len & (512 - 1)) != 0)) { 97 fprintf(stderr, 98 "%s - passed IO buffer is not multiple of 512b" 99 "(req_idx = %"PRIu16").\n", 100 task->req->type ? "WRITE" : "READ", 101 task->head_idx); 102 return VIRTIO_BLK_S_UNSUPP; 103 } 104 105 if (task->readtype) { 106 fprintf(stderr, "type isn't right\n"); 107 return VIRTIO_BLK_S_IOERR; 108 } 109 task->dxfer_dir = BLK_DIR_TO_DEV; 110 vhost_bdev_blk_readwrite(bdev, task, 111 task->req->sector, task->data_len); 112 break; 113 case VIRTIO_BLK_T_GET_ID: 114 if (!task->iovs_cnt || task->data_len) 115 return VIRTIO_BLK_S_UNSUPP; 116 used_len = min(VIRTIO_BLK_ID_BYTES, task->data_len); 117 vhost_strcpy_pad(task->iovs[0].iov_base, 118 bdev->product_name, used_len, ' '); 119 break; 120 default: 121 fprintf(stderr, "unsupported cmd\n"); 122 return VIRTIO_BLK_S_UNSUPP; 123 } 124 125 return VIRTIO_BLK_S_OK; 126 } 127