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