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