xref: /dpdk/examples/vhost_blk/vhost_blk_compat.c (revision 39f59f37ee410bbc43e88b3595108d9e2cffc132)
1c19beb3fSJin Yu /* SPDX-License-Identifier: BSD-3-Clause
2c19beb3fSJin Yu  * Copyright(c) 2010-2019 Intel Corporation
3c19beb3fSJin Yu  */
4c19beb3fSJin Yu 
5c19beb3fSJin Yu #ifndef _VHOST_BLK_COMPAT_H_
6c19beb3fSJin Yu #define _VHOST_BLK_COMPAT_H_
7c19beb3fSJin Yu 
8c19beb3fSJin Yu #include <sys/uio.h>
9c19beb3fSJin Yu #include <stdint.h>
10c19beb3fSJin Yu #include <linux/virtio_blk.h>
11c19beb3fSJin Yu #include <linux/virtio_ring.h>
12c19beb3fSJin Yu 
13c19beb3fSJin Yu #include <rte_vhost.h>
14c19beb3fSJin Yu #include "vhost_blk.h"
15c19beb3fSJin Yu #include "blk_spec.h"
16c19beb3fSJin Yu 
17c19beb3fSJin Yu #define VHOST_MAX_VQUEUES	256
18c19beb3fSJin Yu #define SPDK_VHOST_MAX_VQ_SIZE	1024
19c19beb3fSJin Yu 
20c19beb3fSJin Yu #define VHOST_USER_GET_CONFIG	24
21c19beb3fSJin Yu #define VHOST_USER_SET_CONFIG	25
22c19beb3fSJin Yu 
23c19beb3fSJin Yu static int
vhost_blk_get_config(struct vhost_block_dev * bdev,uint8_t * config,uint32_t len)24c19beb3fSJin Yu vhost_blk_get_config(struct vhost_block_dev *bdev, uint8_t *config,
25c19beb3fSJin Yu 			  uint32_t len)
26c19beb3fSJin Yu {
27c19beb3fSJin Yu 	struct virtio_blk_config blkcfg;
28c19beb3fSJin Yu 	uint32_t blk_size;
29c19beb3fSJin Yu 	uint64_t blkcnt;
30c19beb3fSJin Yu 
31c19beb3fSJin Yu 	if (bdev == NULL) {
32c19beb3fSJin Yu 		/* We can't just return -1 here as this GET_CONFIG message might
33c19beb3fSJin Yu 		 * be caused by a QEMU VM reboot. Returning -1 will indicate an
34c19beb3fSJin Yu 		 * error to QEMU, who might then decide to terminate itself.
35c19beb3fSJin Yu 		 * We don't want that. A simple reboot shouldn't break the
36c19beb3fSJin Yu 		 * system.
37c19beb3fSJin Yu 		 *
38c19beb3fSJin Yu 		 * Presenting a block device with block size 0 and block count 0
39c19beb3fSJin Yu 		 * doesn't cause any problems on QEMU side and the virtio-pci
40c19beb3fSJin Yu 		 * device is even still available inside the VM, but there will
41c19beb3fSJin Yu 		 * be no block device created for it - the kernel drivers will
42c19beb3fSJin Yu 		 * silently reject it.
43c19beb3fSJin Yu 		 */
44c19beb3fSJin Yu 		blk_size = 0;
45c19beb3fSJin Yu 		blkcnt = 0;
46c19beb3fSJin Yu 	} else {
47c19beb3fSJin Yu 		blk_size = bdev->blocklen;
48c19beb3fSJin Yu 		blkcnt = bdev->blockcnt;
49c19beb3fSJin Yu 	}
50c19beb3fSJin Yu 
51c19beb3fSJin Yu 	memset(&blkcfg, 0, sizeof(blkcfg));
52c19beb3fSJin Yu 	blkcfg.blk_size = blk_size;
53c19beb3fSJin Yu 	/* minimum I/O size in blocks */
54c19beb3fSJin Yu 	blkcfg.min_io_size = 1;
55c19beb3fSJin Yu 	/* expressed in 512 Bytes sectors */
56c19beb3fSJin Yu 	blkcfg.capacity = (blkcnt * blk_size) / 512;
57c19beb3fSJin Yu 	/* QEMU can overwrite this value when started */
58c19beb3fSJin Yu 	blkcfg.num_queues = VHOST_MAX_VQUEUES;
59c19beb3fSJin Yu 
60c19beb3fSJin Yu 	fprintf(stdout, "block device:blk_size = %d, blkcnt = %"PRIx64"\n",
61c19beb3fSJin Yu 		blk_size, blkcnt);
62c19beb3fSJin Yu 
63*39f59f37SThomas Monjalon 	memcpy(config, &blkcfg, RTE_MIN(len, sizeof(blkcfg)));
64c19beb3fSJin Yu 
65c19beb3fSJin Yu 	return 0;
66c19beb3fSJin Yu }
67c19beb3fSJin Yu 
68c19beb3fSJin Yu static enum rte_vhost_msg_result
extern_vhost_pre_msg_handler(int vid,void * _msg)69c19beb3fSJin Yu extern_vhost_pre_msg_handler(int vid, void *_msg)
70c19beb3fSJin Yu {
71c19beb3fSJin Yu 	char path[PATH_MAX];
72c19beb3fSJin Yu 	struct vhost_blk_ctrlr *ctrlr;
73c19beb3fSJin Yu 	struct vhost_user_msg *msg = _msg;
74c19beb3fSJin Yu 	int ret;
75c19beb3fSJin Yu 
76c19beb3fSJin Yu 	ret = rte_vhost_get_ifname(vid, path, PATH_MAX);
77c19beb3fSJin Yu 	if (ret) {
78c19beb3fSJin Yu 		fprintf(stderr, "Cannot get socket name\n");
79c19beb3fSJin Yu 		return -1;
80c19beb3fSJin Yu 	}
81c19beb3fSJin Yu 
82c19beb3fSJin Yu 	ctrlr = vhost_blk_ctrlr_find(path);
83c19beb3fSJin Yu 	if (!ctrlr) {
84c19beb3fSJin Yu 		fprintf(stderr, "Controller is not ready\n");
85c19beb3fSJin Yu 		return -1;
86c19beb3fSJin Yu 	}
87c19beb3fSJin Yu 
88c19beb3fSJin Yu 	switch ((int)msg->request) {
89c19beb3fSJin Yu 	case VHOST_USER_GET_VRING_BASE:
90c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_BASE:
91c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_ADDR:
92c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_NUM:
93c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_KICK:
94c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_CALL:
95c19beb3fSJin Yu 	case VHOST_USER_SET_MEM_TABLE:
96c19beb3fSJin Yu 		break;
97c19beb3fSJin Yu 	case VHOST_USER_GET_CONFIG: {
98c19beb3fSJin Yu 		int rc = 0;
99c19beb3fSJin Yu 
100c19beb3fSJin Yu 		rc = vhost_blk_get_config(ctrlr->bdev,
101c19beb3fSJin Yu 					  msg->payload.cfg.region,
102c19beb3fSJin Yu 					  msg->payload.cfg.size);
103c19beb3fSJin Yu 		if (rc != 0)
104c19beb3fSJin Yu 			msg->size = 0;
105c19beb3fSJin Yu 
106c19beb3fSJin Yu 		return RTE_VHOST_MSG_RESULT_REPLY;
107c19beb3fSJin Yu 	}
108c19beb3fSJin Yu 	case VHOST_USER_SET_CONFIG:
109c19beb3fSJin Yu 	default:
110c19beb3fSJin Yu 		break;
111c19beb3fSJin Yu 	}
112c19beb3fSJin Yu 
113c19beb3fSJin Yu 	return RTE_VHOST_MSG_RESULT_NOT_HANDLED;
114c19beb3fSJin Yu }
115c19beb3fSJin Yu 
116c19beb3fSJin Yu static enum rte_vhost_msg_result
extern_vhost_post_msg_handler(int vid,void * _msg)117c19beb3fSJin Yu extern_vhost_post_msg_handler(int vid, void *_msg)
118c19beb3fSJin Yu {
119c19beb3fSJin Yu 	char path[PATH_MAX];
120c19beb3fSJin Yu 	struct vhost_blk_ctrlr *ctrlr;
121c19beb3fSJin Yu 	struct vhost_user_msg *msg = _msg;
122c19beb3fSJin Yu 	int ret;
123c19beb3fSJin Yu 
124c19beb3fSJin Yu 	ret = rte_vhost_get_ifname(vid, path, PATH_MAX);
125c19beb3fSJin Yu 	if (ret) {
126c19beb3fSJin Yu 		fprintf(stderr, "Cannot get socket name\n");
127c19beb3fSJin Yu 		return -1;
128c19beb3fSJin Yu 	}
129c19beb3fSJin Yu 
130c19beb3fSJin Yu 	ctrlr = vhost_blk_ctrlr_find(path);
131c19beb3fSJin Yu 	if (!ctrlr) {
132c19beb3fSJin Yu 		fprintf(stderr, "Controller is not ready\n");
133c19beb3fSJin Yu 		return -1;
134c19beb3fSJin Yu 	}
135c19beb3fSJin Yu 
136c19beb3fSJin Yu 	switch (msg->request) {
137c19beb3fSJin Yu 	case VHOST_USER_SET_FEATURES:
138c19beb3fSJin Yu 	case VHOST_USER_SET_VRING_KICK:
139c19beb3fSJin Yu 	default:
140c19beb3fSJin Yu 		break;
141c19beb3fSJin Yu 	}
142c19beb3fSJin Yu 
143c19beb3fSJin Yu 	return RTE_VHOST_MSG_RESULT_NOT_HANDLED;
144c19beb3fSJin Yu }
145c19beb3fSJin Yu 
146c19beb3fSJin Yu struct rte_vhost_user_extern_ops g_extern_vhost_ops = {
147c19beb3fSJin Yu 	.pre_msg_handle = extern_vhost_pre_msg_handler,
148c19beb3fSJin Yu 	.post_msg_handle = extern_vhost_post_msg_handler,
149c19beb3fSJin Yu };
150c19beb3fSJin Yu 
151c19beb3fSJin Yu void
vhost_session_install_rte_compat_hooks(uint32_t vid)152c19beb3fSJin Yu vhost_session_install_rte_compat_hooks(uint32_t vid)
153c19beb3fSJin Yu {
154c19beb3fSJin Yu 	int rc;
155c19beb3fSJin Yu 
156c19beb3fSJin Yu 	rc = rte_vhost_extern_callback_register(vid, &g_extern_vhost_ops, NULL);
157c19beb3fSJin Yu 	if (rc != 0)
158c19beb3fSJin Yu 		fprintf(stderr,
159c19beb3fSJin Yu 			"rte_vhost_extern_callback_register() failed for vid = %d\n",
160c19beb3fSJin Yu 			vid);
161c19beb3fSJin Yu }
162c19beb3fSJin Yu 
163c19beb3fSJin Yu void
vhost_dev_install_rte_compat_hooks(const char * path)164c19beb3fSJin Yu vhost_dev_install_rte_compat_hooks(const char *path)
165c19beb3fSJin Yu {
166c19beb3fSJin Yu 	uint64_t protocol_features = 0;
167c19beb3fSJin Yu 
168c19beb3fSJin Yu 	rte_vhost_driver_get_protocol_features(path, &protocol_features);
169c19beb3fSJin Yu 	protocol_features |= (1ULL << VHOST_USER_PROTOCOL_F_CONFIG);
170c19beb3fSJin Yu 	protocol_features |= (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD);
171c19beb3fSJin Yu 	rte_vhost_driver_set_protocol_features(path, protocol_features);
172c19beb3fSJin Yu }
173c19beb3fSJin Yu 
174c19beb3fSJin Yu #endif
175