xref: /spdk/module/bdev/virtio/bdev_virtio_rpc.c (revision 588dfe314bb83d86effdf67ec42837b11c2620bf)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2017 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 = NULL;
188 	struct spdk_pci_addr pci_addr;
189 	int rc = 0;
190 
191 	req = calloc(1, sizeof(*req));
192 	if (!req) {
193 		SPDK_ERRLOG("calloc() failed\n");
194 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
195 		return;
196 	}
197 
198 	if (spdk_json_decode_object(params, rpc_bdev_virtio_attach_controller_ctx,
199 				    SPDK_COUNTOF(rpc_bdev_virtio_attach_controller_ctx),
200 				    req)) {
201 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
202 						 "spdk_json_decode_object failed");
203 		goto cleanup;
204 	}
205 
206 	if (strcmp(req->trtype, "pci") == 0) {
207 		if (req->vq_count != 0 || req->vq_size != 0) {
208 			SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n");
209 			spdk_jsonrpc_send_error_response(request, EINVAL,
210 							 "vq_count or vq_size is not allowed for PCI transport type.");
211 			goto cleanup;
212 		}
213 
214 		if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) {
215 			SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr);
216 			spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr);
217 			goto cleanup;
218 		}
219 	} else if (strcmp(req->trtype, "user") == 0) {
220 		req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
221 		req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
222 	} else if (strcmp(req->trtype, "vfio-user") == 0) {
223 		if (req->vq_count != 0 || req->vq_size != 0) {
224 			SPDK_ERRLOG("VQ count or size is not allowed for vfio-user transport type\n");
225 			spdk_jsonrpc_send_error_response(request, EINVAL,
226 							 "vq_count or vq_size is not allowed for vfio-user transport type.");
227 			goto cleanup;
228 		}
229 	} else {
230 		SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
231 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype);
232 		goto cleanup;
233 	}
234 
235 	req->request = request;
236 	if (strcmp(req->dev_type, "blk") == 0) {
237 		if (strcmp(req->trtype, "pci") == 0) {
238 			bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
239 		} else if (strcmp(req->trtype, "user") == 0) {
240 			bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
241 		} else if (strcmp(req->trtype, "vfio-user") == 0) {
242 			bdev = bdev_virtio_vfio_user_blk_dev_create(req->name, req->traddr);
243 		}
244 
245 		/* Virtio blk doesn't use callback so call it manually to send result. */
246 		rc = bdev ? 0 : -EINVAL;
247 		rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
248 	} else if (strcmp(req->dev_type, "scsi") == 0) {
249 		if (strcmp(req->trtype, "pci") == 0) {
250 			rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
251 		} else if (strcmp(req->trtype, "user") == 0) {
252 			rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
253 							      rpc_create_virtio_dev_cb, req);
254 		} else if (strcmp(req->trtype, "vfio-user") == 0) {
255 			rc = bdev_vfio_user_scsi_dev_create(req->name, req->traddr, rpc_create_virtio_dev_cb, req);
256 		}
257 
258 		if (rc < 0) {
259 			/* In case of error callback is not called so do it manually to send result. */
260 			rpc_create_virtio_dev_cb(req, rc, NULL, 0);
261 		}
262 	} else {
263 		SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type);
264 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid dev_type '%s'", req->dev_type);
265 		goto cleanup;
266 	}
267 
268 	return;
269 
270 cleanup:
271 	free_rpc_bdev_virtio_attach_controller_ctx(req);
272 }
273 SPDK_RPC_REGISTER("bdev_virtio_attach_controller",
274 		  rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME);
275