xref: /f-stack/dpdk/examples/vhost_blk/blk.c (revision 4418919f)
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