xref: /spdk/module/bdev/virtio/bdev_virtio_rpc.c (revision 488570ebd418ba07c9e69e65106dcc964f3bb41b)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/string.h"
9 #include "spdk/rpc.h"
10 #include "spdk/util.h"
11 #include "spdk/log.h"
12 #include "spdk/thread.h"
13 
14 #include "bdev_virtio.h"
15 
16 #define SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT		1
17 #define SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE		512
18 
19 struct rpc_bdev_virtio_blk_hotplug {
20 	bool enabled;
21 	uint64_t period_us;
22 };
23 
24 static const struct spdk_json_object_decoder rpc_bdev_virtio_blk_hotplug_decoders[] = {
25 	{"enable", offsetof(struct rpc_bdev_virtio_blk_hotplug, enabled), spdk_json_decode_bool, false},
26 	{"period_us", offsetof(struct rpc_bdev_virtio_blk_hotplug, period_us), spdk_json_decode_uint64, true},
27 };
28 
29 static void
30 rpc_bdev_virtio_blk_set_hotplug(struct spdk_jsonrpc_request *request,
31 				const struct spdk_json_val *params)
32 {
33 	struct rpc_bdev_virtio_blk_hotplug req = {false, 0};
34 	int rc;
35 
36 	if (spdk_json_decode_object(params, rpc_bdev_virtio_blk_hotplug_decoders,
37 				    SPDK_COUNTOF(rpc_bdev_virtio_blk_hotplug_decoders), &req)) {
38 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
39 		rc = -EINVAL;
40 		goto invalid;
41 	}
42 
43 	rc = bdev_virtio_pci_blk_set_hotplug(req.enabled, req.period_us);
44 	if (rc) {
45 		goto invalid;
46 	}
47 
48 	spdk_jsonrpc_send_bool_response(request, true);
49 	return;
50 invalid:
51 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
52 }
53 SPDK_RPC_REGISTER("bdev_virtio_blk_set_hotplug", rpc_bdev_virtio_blk_set_hotplug, SPDK_RPC_RUNTIME)
54 
55 struct rpc_remove_virtio_dev {
56 	char *name;
57 };
58 
59 static const struct spdk_json_object_decoder rpc_remove_virtio_dev[] = {
60 	{"name", offsetof(struct rpc_remove_virtio_dev, name), spdk_json_decode_string },
61 };
62 
63 static void
64 rpc_bdev_virtio_detach_controller_cb(void *ctx, int errnum)
65 {
66 	struct spdk_jsonrpc_request *request = ctx;
67 
68 	if (errnum != 0) {
69 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
70 						 spdk_strerror(-errnum));
71 		return;
72 	}
73 
74 	spdk_jsonrpc_send_bool_response(request, true);
75 }
76 
77 static void
78 rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request *request,
79 				  const struct spdk_json_val *params)
80 {
81 	struct rpc_remove_virtio_dev req = {NULL};
82 	int rc = 0;
83 
84 	if (spdk_json_decode_object(params, rpc_remove_virtio_dev,
85 				    SPDK_COUNTOF(rpc_remove_virtio_dev),
86 				    &req)) {
87 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
88 						 "spdk_json_decode_object failed");
89 		goto cleanup;
90 	}
91 
92 	rc = bdev_virtio_blk_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
93 	if (rc == -ENODEV) {
94 		rc = bdev_virtio_scsi_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
95 	}
96 
97 	if (rc != 0) {
98 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
99 	}
100 
101 cleanup:
102 	free(req.name);
103 }
104 SPDK_RPC_REGISTER("bdev_virtio_detach_controller",
105 		  rpc_bdev_virtio_detach_controller, SPDK_RPC_RUNTIME)
106 
107 static void
108 rpc_bdev_virtio_scsi_get_devices(struct spdk_jsonrpc_request *request,
109 				 const struct spdk_json_val *params)
110 {
111 	struct spdk_json_write_ctx *w;
112 
113 	if (params != NULL) {
114 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
115 						 "bdev_virtio_scsi_get_devices requires no parameters");
116 		return;
117 	}
118 
119 	w = spdk_jsonrpc_begin_result(request);
120 	bdev_virtio_scsi_dev_list(w);
121 	spdk_jsonrpc_end_result(request, w);
122 }
123 SPDK_RPC_REGISTER("bdev_virtio_scsi_get_devices",
124 		  rpc_bdev_virtio_scsi_get_devices, SPDK_RPC_RUNTIME)
125 
126 struct rpc_bdev_virtio_attach_controller_ctx {
127 	char *name;
128 	char *trtype;
129 	char *traddr;
130 	char *dev_type;
131 	uint32_t vq_count;
132 	uint32_t vq_size;
133 	struct spdk_jsonrpc_request *request;
134 };
135 
136 static const struct spdk_json_object_decoder rpc_bdev_virtio_attach_controller_ctx[] = {
137 	{"name", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, name), spdk_json_decode_string },
138 	{"trtype", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, trtype), spdk_json_decode_string },
139 	{"traddr", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, traddr), spdk_json_decode_string },
140 	{"dev_type", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, dev_type), spdk_json_decode_string },
141 	{"vq_count", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_count), spdk_json_decode_uint32, true },
142 	{"vq_size", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_size), spdk_json_decode_uint32, true },
143 };
144 
145 static void
146 free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx *req)
147 {
148 	free(req->name);
149 	free(req->trtype);
150 	free(req->traddr);
151 	free(req->dev_type);
152 	free(req);
153 }
154 
155 static void
156 rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
157 {
158 	struct rpc_bdev_virtio_attach_controller_ctx *req = ctx;
159 	struct spdk_json_write_ctx *w;
160 	size_t i;
161 
162 	if (result) {
163 		spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
164 						 spdk_strerror(-result));
165 		free_rpc_bdev_virtio_attach_controller_ctx(req);
166 		return;
167 	}
168 
169 	w = spdk_jsonrpc_begin_result(req->request);
170 	spdk_json_write_array_begin(w);
171 
172 	for (i = 0; i < cnt; i++) {
173 		spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
174 	}
175 
176 	spdk_json_write_array_end(w);
177 	spdk_jsonrpc_end_result(req->request, w);
178 
179 	free_rpc_bdev_virtio_attach_controller_ctx(ctx);
180 }
181 
182 static void
183 rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
184 				  const struct spdk_json_val *params)
185 {
186 	struct rpc_bdev_virtio_attach_controller_ctx *req;
187 	struct spdk_bdev *bdev;
188 	struct spdk_pci_addr pci_addr;
189 	bool pci;
190 	int rc;
191 
192 	req = calloc(1, sizeof(*req));
193 	if (!req) {
194 		SPDK_ERRLOG("calloc() failed\n");
195 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
196 		return;
197 	}
198 
199 	if (spdk_json_decode_object(params, rpc_bdev_virtio_attach_controller_ctx,
200 				    SPDK_COUNTOF(rpc_bdev_virtio_attach_controller_ctx),
201 				    req)) {
202 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
203 						 "spdk_json_decode_object failed");
204 		goto cleanup;
205 	}
206 
207 	if (strcmp(req->trtype, "pci") == 0) {
208 		if (req->vq_count != 0 || req->vq_size != 0) {
209 			SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n");
210 			spdk_jsonrpc_send_error_response(request, EINVAL,
211 							 "vq_count or vq_size is not allowed for PCI transport type.");
212 			goto cleanup;
213 		}
214 
215 		if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) {
216 			SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr);
217 			spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr);
218 			goto cleanup;
219 		}
220 
221 		pci = true;
222 	} else if (strcmp(req->trtype, "user") == 0) {
223 		req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
224 		req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
225 		pci = false;
226 	} else {
227 		SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
228 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype);
229 		goto cleanup;
230 	}
231 
232 	req->request = request;
233 	if (strcmp(req->dev_type, "blk") == 0) {
234 		if (pci) {
235 			bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
236 		} else {
237 			bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
238 		}
239 
240 		/* Virtio blk doesn't use callback so call it manually to send result. */
241 		rc = bdev ? 0 : -EINVAL;
242 		rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
243 	} else if (strcmp(req->dev_type, "scsi") == 0) {
244 		if (pci) {
245 			rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
246 		} else {
247 			rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
248 							      rpc_create_virtio_dev_cb, req);
249 		}
250 
251 		if (rc < 0) {
252 			/* In case of error callback is not called so do it manually to send result. */
253 			rpc_create_virtio_dev_cb(req, rc, NULL, 0);
254 		}
255 	} else {
256 		SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type);
257 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid dev_type '%s'", req->dev_type);
258 		goto cleanup;
259 	}
260 
261 	return;
262 
263 cleanup:
264 	free_rpc_bdev_virtio_attach_controller_ctx(req);
265 }
266 SPDK_RPC_REGISTER("bdev_virtio_attach_controller",
267 		  rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME);
268