xref: /f-stack/dpdk/examples/vhost_blk/blk.c (revision 2d9fd380)
14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang  * Copyright(c) 2010-2019 Intel Corporation
34418919fSjohnjiang  */
44418919fSjohnjiang 
54418919fSjohnjiang /**
64418919fSjohnjiang  * This work is largely based on the "vhost-user-blk" implementation by
74418919fSjohnjiang  * SPDK(https://github.com/spdk/spdk).
84418919fSjohnjiang  */
94418919fSjohnjiang 
104418919fSjohnjiang #include <stdio.h>
114418919fSjohnjiang #include <stdint.h>
124418919fSjohnjiang #include <unistd.h>
134418919fSjohnjiang #include <assert.h>
144418919fSjohnjiang #include <ctype.h>
154418919fSjohnjiang #include <string.h>
164418919fSjohnjiang #include <stddef.h>
174418919fSjohnjiang 
184418919fSjohnjiang #include <rte_atomic.h>
194418919fSjohnjiang #include <rte_cycles.h>
204418919fSjohnjiang #include <rte_log.h>
214418919fSjohnjiang #include <rte_malloc.h>
224418919fSjohnjiang #include <rte_byteorder.h>
234418919fSjohnjiang #include <rte_string_fns.h>
244418919fSjohnjiang 
254418919fSjohnjiang #include "vhost_blk.h"
264418919fSjohnjiang #include "blk_spec.h"
274418919fSjohnjiang 
284418919fSjohnjiang static void
vhost_strcpy_pad(void * dst,const char * src,size_t size,int pad)294418919fSjohnjiang vhost_strcpy_pad(void *dst, const char *src, size_t size, int pad)
304418919fSjohnjiang {
314418919fSjohnjiang 	size_t len;
324418919fSjohnjiang 
334418919fSjohnjiang 	len = strlen(src);
344418919fSjohnjiang 	if (len < size) {
354418919fSjohnjiang 		memcpy(dst, src, len);
364418919fSjohnjiang 		memset((char *)dst + len, pad, size - len);
374418919fSjohnjiang 	} else {
384418919fSjohnjiang 		memcpy(dst, src, size);
394418919fSjohnjiang 	}
404418919fSjohnjiang }
414418919fSjohnjiang 
424418919fSjohnjiang static int
vhost_bdev_blk_readwrite(struct vhost_block_dev * bdev,struct vhost_blk_task * task,uint64_t lba_512,__rte_unused uint32_t xfer_len)434418919fSjohnjiang vhost_bdev_blk_readwrite(struct vhost_block_dev *bdev,
444418919fSjohnjiang 			  struct vhost_blk_task *task,
454418919fSjohnjiang 			  uint64_t lba_512, __rte_unused uint32_t xfer_len)
464418919fSjohnjiang {
474418919fSjohnjiang 	uint32_t i;
484418919fSjohnjiang 	uint64_t offset;
494418919fSjohnjiang 	uint32_t nbytes = 0;
504418919fSjohnjiang 
514418919fSjohnjiang 	offset = lba_512 * 512;
524418919fSjohnjiang 
53*2d9fd380Sjfb8856606 	/* iovs[0] is the head and iovs[iovs_cnt - 1] is the tail
54*2d9fd380Sjfb8856606 	 * Middle is the data range
55*2d9fd380Sjfb8856606 	 */
56*2d9fd380Sjfb8856606 	for (i = 1; i < task->iovs_cnt - 1; i++) {
574418919fSjohnjiang 		if (task->dxfer_dir == BLK_DIR_TO_DEV)
584418919fSjohnjiang 			memcpy(bdev->data + offset, task->iovs[i].iov_base,
594418919fSjohnjiang 			       task->iovs[i].iov_len);
604418919fSjohnjiang 		else
614418919fSjohnjiang 			memcpy(task->iovs[i].iov_base, bdev->data + offset,
624418919fSjohnjiang 			       task->iovs[i].iov_len);
634418919fSjohnjiang 		offset += task->iovs[i].iov_len;
644418919fSjohnjiang 		nbytes += task->iovs[i].iov_len;
654418919fSjohnjiang 	}
664418919fSjohnjiang 
674418919fSjohnjiang 	return nbytes;
684418919fSjohnjiang }
694418919fSjohnjiang 
704418919fSjohnjiang int
vhost_bdev_process_blk_commands(struct vhost_block_dev * bdev,struct vhost_blk_task * task)714418919fSjohnjiang vhost_bdev_process_blk_commands(struct vhost_block_dev *bdev,
724418919fSjohnjiang 				 struct vhost_blk_task *task)
734418919fSjohnjiang {
74*2d9fd380Sjfb8856606 	size_t used_len;
754418919fSjohnjiang 
764418919fSjohnjiang 	if (unlikely(task->data_len > (bdev->blockcnt * bdev->blocklen))) {
774418919fSjohnjiang 		fprintf(stderr, "read or write beyond capacity\n");
784418919fSjohnjiang 		return VIRTIO_BLK_S_UNSUPP;
794418919fSjohnjiang 	}
804418919fSjohnjiang 
814418919fSjohnjiang 	switch (task->req->type) {
824418919fSjohnjiang 	case VIRTIO_BLK_T_IN:
834418919fSjohnjiang 		if (unlikely(task->data_len == 0 ||
844418919fSjohnjiang 			(task->data_len & (512 - 1)) != 0)) {
854418919fSjohnjiang 			fprintf(stderr,
864418919fSjohnjiang 				"%s - passed IO buffer is not multiple of 512b"
874418919fSjohnjiang 				"(req_idx = %"PRIu16").\n",
884418919fSjohnjiang 				task->req->type ? "WRITE" : "READ",
89*2d9fd380Sjfb8856606 				task->req_idx);
904418919fSjohnjiang 			return VIRTIO_BLK_S_UNSUPP;
914418919fSjohnjiang 		}
924418919fSjohnjiang 
934418919fSjohnjiang 		task->dxfer_dir = BLK_DIR_FROM_DEV;
944418919fSjohnjiang 		vhost_bdev_blk_readwrite(bdev, task,
954418919fSjohnjiang 					 task->req->sector, task->data_len);
964418919fSjohnjiang 		break;
974418919fSjohnjiang 	case VIRTIO_BLK_T_OUT:
984418919fSjohnjiang 		if (unlikely(task->data_len == 0 ||
994418919fSjohnjiang 			(task->data_len & (512 - 1)) != 0)) {
1004418919fSjohnjiang 			fprintf(stderr,
1014418919fSjohnjiang 				"%s - passed IO buffer is not multiple of 512b"
1024418919fSjohnjiang 				"(req_idx = %"PRIu16").\n",
1034418919fSjohnjiang 				task->req->type ? "WRITE" : "READ",
104*2d9fd380Sjfb8856606 				task->req_idx);
1054418919fSjohnjiang 			return VIRTIO_BLK_S_UNSUPP;
1064418919fSjohnjiang 		}
1074418919fSjohnjiang 
1084418919fSjohnjiang 		task->dxfer_dir = BLK_DIR_TO_DEV;
1094418919fSjohnjiang 		vhost_bdev_blk_readwrite(bdev, task,
1104418919fSjohnjiang 					 task->req->sector, task->data_len);
1114418919fSjohnjiang 		break;
1124418919fSjohnjiang 	case VIRTIO_BLK_T_GET_ID:
1134418919fSjohnjiang 		if (!task->iovs_cnt || task->data_len)
1144418919fSjohnjiang 			return VIRTIO_BLK_S_UNSUPP;
115*2d9fd380Sjfb8856606 		used_len = RTE_MIN((size_t)VIRTIO_BLK_ID_BYTES, task->data_len);
1164418919fSjohnjiang 		vhost_strcpy_pad(task->iovs[0].iov_base,
1174418919fSjohnjiang 				 bdev->product_name, used_len, ' ');
1184418919fSjohnjiang 		break;
1194418919fSjohnjiang 	default:
1204418919fSjohnjiang 		fprintf(stderr, "unsupported cmd\n");
1214418919fSjohnjiang 		return VIRTIO_BLK_S_UNSUPP;
1224418919fSjohnjiang 	}
1234418919fSjohnjiang 
1244418919fSjohnjiang 	return VIRTIO_BLK_S_OK;
1254418919fSjohnjiang }
126