xref: /dpdk/examples/vhost_blk/blk.c (revision 69a3c6319140b34fb714fa5bd6990cceb2ea2997)
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
vhost_strcpy_pad(void * dst,const char * src,size_t size,int pad)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
vhost_bdev_blk_readwrite(struct vhost_block_dev * bdev,struct vhost_blk_task * task,uint64_t lba_512,__rte_unused uint32_t xfer_len)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
vhost_bdev_process_blk_commands(struct vhost_block_dev * bdev,struct vhost_blk_task * task)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