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