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