xref: /spdk/lib/vhost/vhost_rpc.c (revision 122e284652f30a16911bce3f5bc9e562ce4d1595)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk_internal/log.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 
40 #include "spdk/scsi.h"
41 #include "spdk/vhost.h"
42 #include "vhost_internal.h"
43 #include "spdk/bdev.h"
44 
45 static void
46 json_scsi_dev_write(struct spdk_json_write_ctx *ctx, struct spdk_scsi_dev *dev)
47 {
48 	int l;
49 
50 	spdk_json_write_name(ctx, "id");
51 	spdk_json_write_int32(ctx, spdk_scsi_dev_get_id(dev));
52 
53 	spdk_json_write_name(ctx, "device_name");
54 	spdk_json_write_string(ctx, spdk_scsi_dev_get_name(dev));
55 
56 	spdk_json_write_name(ctx, "luns");
57 	spdk_json_write_array_begin(ctx);
58 
59 	for (l = 0; l < SPDK_SCSI_DEV_MAX_LUN; l++) {
60 		struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(dev, l);
61 
62 		if (!lun) {
63 			continue;
64 		}
65 
66 		spdk_json_write_object_begin(ctx);
67 
68 		spdk_json_write_name(ctx, "id");
69 		spdk_json_write_int32(ctx, spdk_scsi_lun_get_id(lun));
70 
71 		spdk_json_write_name(ctx, "name");
72 		spdk_json_write_string(ctx, spdk_scsi_lun_get_name(lun));
73 
74 		spdk_json_write_object_end(ctx);
75 	}
76 	spdk_json_write_array_end(ctx);
77 }
78 
79 static void
80 spdk_rpc_get_vhost_scsi_controllers(struct spdk_jsonrpc_request *request,
81 				    const struct spdk_json_val *params)
82 {
83 	struct spdk_json_write_ctx *w;
84 	struct spdk_vhost_dev *vdev = NULL;
85 	struct spdk_scsi_dev *dev;
86 	uint32_t i;
87 
88 	if (params != NULL) {
89 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
90 						 "get_vhost_scsi_controllers requires no parameters");
91 		return;
92 	}
93 
94 	w = spdk_jsonrpc_begin_result(request);
95 	if (w == NULL) {
96 		return;
97 	}
98 
99 	spdk_json_write_array_begin(w);
100 	while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) {
101 		if (vdev->type != SPDK_VHOST_DEV_T_SCSI) {
102 			continue;
103 		}
104 
105 		spdk_json_write_object_begin(w);
106 
107 		spdk_json_write_name(w, "ctrlr");
108 		spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev));
109 
110 		spdk_json_write_name(w, "cpu_mask");
111 		spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev));
112 
113 		spdk_json_write_name(w, "scsi_devs");
114 		spdk_json_write_array_begin(w);
115 
116 		for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; i++) {
117 			dev = spdk_vhost_scsi_dev_get_dev(vdev, i);
118 			if (!dev)
119 				continue;
120 
121 			spdk_json_write_object_begin(w);
122 			spdk_json_write_name(w, "scsi_dev_num");
123 			spdk_json_write_uint32(w, i);
124 			json_scsi_dev_write(w, dev);
125 			spdk_json_write_object_end(w);
126 		}
127 
128 		spdk_json_write_array_end(w); // devs
129 
130 		spdk_json_write_object_end(w); // ctrl
131 	}
132 	spdk_json_write_array_end(w);
133 	spdk_jsonrpc_end_result(request, w);
134 	return;
135 }
136 SPDK_RPC_REGISTER("get_vhost_scsi_controllers", spdk_rpc_get_vhost_scsi_controllers)
137 
138 struct rpc_vhost_scsi_ctrlr {
139 	char *ctrlr;
140 	char *cpumask;
141 };
142 
143 static void
144 free_rpc_vhost_scsi_ctrlr(struct rpc_vhost_scsi_ctrlr *req)
145 {
146 	free(req->ctrlr);
147 	free(req->cpumask);
148 }
149 
150 static const struct spdk_json_object_decoder rpc_construct_vhost_ctrlr[] = {
151 	{"ctrlr", offsetof(struct rpc_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
152 	{"cpumask", offsetof(struct rpc_vhost_scsi_ctrlr, cpumask), spdk_json_decode_string, true},
153 };
154 
155 static void
156 spdk_rpc_construct_vhost_scsi_controller(struct spdk_jsonrpc_request *request,
157 		const struct spdk_json_val *params)
158 {
159 	struct rpc_vhost_scsi_ctrlr req = {0};
160 	struct spdk_json_write_ctx *w;
161 	int rc;
162 	uint64_t cpumask;
163 
164 	if (spdk_json_decode_object(params, rpc_construct_vhost_ctrlr,
165 				    SPDK_COUNTOF(rpc_construct_vhost_ctrlr),
166 				    &req)) {
167 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
168 		rc = -EINVAL;
169 		goto invalid;
170 	}
171 
172 	cpumask = spdk_app_get_core_mask();
173 	if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) {
174 		rc = -EINVAL;
175 		goto invalid;
176 	}
177 
178 	rc = spdk_vhost_scsi_dev_construct(req.ctrlr, cpumask);
179 	if (rc < 0) {
180 		goto invalid;
181 	}
182 
183 	free_rpc_vhost_scsi_ctrlr(&req);
184 
185 	w = spdk_jsonrpc_begin_result(request);
186 	if (w == NULL) {
187 		return;
188 	}
189 
190 	spdk_json_write_bool(w, true);
191 	spdk_jsonrpc_end_result(request, w);
192 	return;
193 
194 invalid:
195 	free_rpc_vhost_scsi_ctrlr(&req);
196 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
197 }
198 SPDK_RPC_REGISTER("construct_vhost_scsi_controller", spdk_rpc_construct_vhost_scsi_controller)
199 
200 struct rpc_remove_vhost_scsi_ctrlr {
201 	char *ctrlr;
202 };
203 
204 static void
205 free_rpc_remove_vhost_scsi_ctrlr(struct rpc_remove_vhost_scsi_ctrlr *req)
206 {
207 	free(req->ctrlr);
208 }
209 
210 static const struct spdk_json_object_decoder rpc_remove_vhost_ctrlr[] = {
211 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr, ctrlr), spdk_json_decode_string },
212 };
213 
214 static void
215 spdk_rpc_remove_vhost_scsi_controller(struct spdk_jsonrpc_request *request,
216 				      const struct spdk_json_val *params)
217 {
218 	struct rpc_remove_vhost_scsi_ctrlr req = {NULL};
219 	struct spdk_json_write_ctx *w;
220 	struct spdk_vhost_dev *vdev;
221 	int rc;
222 
223 	if (spdk_json_decode_object(params, rpc_remove_vhost_ctrlr,
224 				    SPDK_COUNTOF(rpc_remove_vhost_ctrlr),
225 				    &req)) {
226 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
227 		rc = -EINVAL;
228 		goto invalid;
229 	}
230 
231 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
232 		rc = -ENODEV;
233 		goto invalid;
234 	}
235 
236 	rc = spdk_vhost_scsi_dev_remove(vdev);
237 	if (rc < 0) {
238 		goto invalid;
239 	}
240 
241 	free_rpc_remove_vhost_scsi_ctrlr(&req);
242 
243 	w = spdk_jsonrpc_begin_result(request);
244 	if (w == NULL) {
245 		return;
246 	}
247 
248 	spdk_json_write_bool(w, true);
249 	spdk_jsonrpc_end_result(request, w);
250 	return;
251 
252 invalid:
253 	free_rpc_remove_vhost_scsi_ctrlr(&req);
254 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
255 }
256 SPDK_RPC_REGISTER("remove_vhost_scsi_controller", spdk_rpc_remove_vhost_scsi_controller)
257 
258 
259 struct rpc_add_vhost_scsi_ctrlr_lun {
260 	char *ctrlr;
261 	uint32_t scsi_dev_num;
262 	char *lun_name;
263 };
264 
265 static void
266 free_rpc_add_vhost_scsi_ctrlr_lun(struct rpc_add_vhost_scsi_ctrlr_lun *req)
267 {
268 	free(req->ctrlr);
269 	free(req->lun_name);
270 }
271 
272 static const struct spdk_json_object_decoder rpc_vhost_add_lun[] = {
273 	{"ctrlr", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, ctrlr), spdk_json_decode_string },
274 	{"scsi_dev_num", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, scsi_dev_num), spdk_json_decode_uint32},
275 	{"lun_name", offsetof(struct rpc_add_vhost_scsi_ctrlr_lun, lun_name), spdk_json_decode_string },
276 };
277 
278 static void
279 spdk_rpc_add_vhost_scsi_lun(struct spdk_jsonrpc_request *request,
280 			    const struct spdk_json_val *params)
281 {
282 	struct rpc_add_vhost_scsi_ctrlr_lun req = {0};
283 	struct spdk_json_write_ctx *w;
284 	int rc;
285 
286 	if (spdk_json_decode_object(params, rpc_vhost_add_lun,
287 				    SPDK_COUNTOF(rpc_vhost_add_lun),
288 				    &req)) {
289 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
290 		rc = -EINVAL;
291 		goto invalid;
292 	}
293 
294 	rc = spdk_vhost_scsi_dev_add_dev(req.ctrlr, req.scsi_dev_num, req.lun_name);
295 	if (rc < 0) {
296 		goto invalid;
297 	}
298 
299 	free_rpc_add_vhost_scsi_ctrlr_lun(&req);
300 
301 	w = spdk_jsonrpc_begin_result(request);
302 	if (w == NULL) {
303 		return;
304 	}
305 
306 	spdk_json_write_bool(w, true);
307 	spdk_jsonrpc_end_result(request, w);
308 	return;
309 
310 invalid:
311 	free_rpc_add_vhost_scsi_ctrlr_lun(&req);
312 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
313 }
314 SPDK_RPC_REGISTER("add_vhost_scsi_lun", spdk_rpc_add_vhost_scsi_lun)
315 
316 struct rpc_remove_vhost_scsi_ctrlr_dev {
317 	char *ctrlr;
318 	uint32_t scsi_dev_num;
319 };
320 
321 static void
322 free_rpc_remove_vhost_scsi_ctrlr_dev(struct rpc_remove_vhost_scsi_ctrlr_dev *req)
323 {
324 	free(req->ctrlr);
325 }
326 
327 static const struct spdk_json_object_decoder rpc_vhost_remove_dev[] = {
328 	{"ctrlr", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, ctrlr), spdk_json_decode_string },
329 	{"scsi_dev_num", offsetof(struct rpc_remove_vhost_scsi_ctrlr_dev, scsi_dev_num), spdk_json_decode_uint32},
330 };
331 
332 static void
333 spdk_rpc_remove_vhost_scsi_dev(struct spdk_jsonrpc_request *request,
334 			       const struct spdk_json_val *params)
335 {
336 	struct rpc_remove_vhost_scsi_ctrlr_dev req = {0};
337 	struct spdk_json_write_ctx *w;
338 	struct spdk_vhost_dev *vdev;
339 	int rc;
340 
341 	if (spdk_json_decode_object(params, rpc_vhost_remove_dev,
342 				    SPDK_COUNTOF(rpc_vhost_remove_dev),
343 				    &req)) {
344 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
345 		rc = -EINVAL;
346 		goto invalid;
347 	}
348 
349 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
350 		rc = -ENODEV;
351 		goto invalid;
352 	}
353 
354 	rc = spdk_vhost_scsi_dev_remove_dev(vdev, req.scsi_dev_num);
355 	if (rc < 0) {
356 		goto invalid;
357 	}
358 
359 	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);
360 
361 	w = spdk_jsonrpc_begin_result(request);
362 	if (w == NULL) {
363 		return;
364 	}
365 
366 	spdk_json_write_bool(w, true);
367 	spdk_jsonrpc_end_result(request, w);
368 	return;
369 
370 invalid:
371 	free_rpc_remove_vhost_scsi_ctrlr_dev(&req);
372 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
373 }
374 SPDK_RPC_REGISTER("remove_vhost_scsi_dev", spdk_rpc_remove_vhost_scsi_dev)
375 
376 struct rpc_vhost_blk_ctrlr {
377 	char *ctrlr;
378 	char *dev_name;
379 	char *cpumask;
380 	bool readonly;
381 };
382 
383 static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
384 	{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
385 	{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
386 	{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
387 	{"readonly", offsetof(struct rpc_vhost_blk_ctrlr, readonly), spdk_json_decode_bool, true},
388 };
389 
390 static void
391 free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
392 {
393 	free(req->ctrlr);
394 	free(req->dev_name);
395 	free(req->cpumask);
396 }
397 
398 static void
399 spdk_rpc_construct_vhost_blk_controller(struct spdk_jsonrpc_request *request,
400 					const struct spdk_json_val *params)
401 {
402 	struct rpc_vhost_blk_ctrlr req = {0};
403 	struct spdk_json_write_ctx *w;
404 	int rc;
405 	uint64_t cpumask;
406 
407 	if (spdk_json_decode_object(params, rpc_construct_vhost_blk_ctrlr,
408 				    SPDK_COUNTOF(rpc_construct_vhost_blk_ctrlr),
409 				    &req)) {
410 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
411 		rc = -EINVAL;
412 		goto invalid;
413 	}
414 
415 	cpumask = spdk_app_get_core_mask();
416 	if (req.cpumask != NULL && spdk_vhost_parse_core_mask(req.cpumask, &cpumask)) {
417 		rc = -EINVAL;
418 		goto invalid;
419 	}
420 
421 	rc = spdk_vhost_blk_construct(req.ctrlr, cpumask, req.dev_name, req.readonly);
422 	if (rc < 0) {
423 		goto invalid;
424 	}
425 
426 	free_rpc_vhost_blk_ctrlr(&req);
427 
428 	w = spdk_jsonrpc_begin_result(request);
429 	if (w == NULL) {
430 		return;
431 	}
432 
433 	spdk_json_write_bool(w, true);
434 	spdk_jsonrpc_end_result(request, w);
435 	return;
436 
437 invalid:
438 	free_rpc_vhost_blk_ctrlr(&req);
439 	spdk_jsonrpc_send_error_response(request,
440 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
441 
442 }
443 SPDK_RPC_REGISTER("construct_vhost_blk_controller", spdk_rpc_construct_vhost_blk_controller)
444 
445 struct rpc_remove_vhost_blk_ctrlr {
446 	char *ctrlr;
447 };
448 
449 static const struct spdk_json_object_decoder rpc_remove_vhost_blk_ctrlr[] = {
450 	{"ctrlr", offsetof(struct rpc_remove_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
451 };
452 
453 static void
454 free_rpc_remove_vhost_blk_ctrlr(struct rpc_remove_vhost_blk_ctrlr *req)
455 {
456 	free(req->ctrlr);
457 }
458 
459 static void
460 spdk_rpc_remove_vhost_blk_controller(struct spdk_jsonrpc_request *request,
461 				     const struct spdk_json_val *params)
462 {
463 	struct rpc_remove_vhost_blk_ctrlr req = {NULL};
464 	struct spdk_json_write_ctx *w;
465 	struct spdk_vhost_dev *vdev;
466 	int rc;
467 
468 	if (spdk_json_decode_object(params, rpc_remove_vhost_blk_ctrlr,
469 				    SPDK_COUNTOF(rpc_remove_vhost_blk_ctrlr), &req)) {
470 		SPDK_TRACELOG(SPDK_TRACE_DEBUG, "spdk_json_decode_object failed\n");
471 		rc = -EINVAL;
472 		goto invalid;
473 	}
474 
475 	if (!(vdev = spdk_vhost_dev_find(req.ctrlr))) {
476 		rc = -ENODEV;
477 		goto invalid;
478 	}
479 
480 	rc = spdk_vhost_blk_destroy(vdev);
481 	if (rc < 0) {
482 		goto invalid;
483 	}
484 
485 	free_rpc_remove_vhost_blk_ctrlr(&req);
486 
487 	w = spdk_jsonrpc_begin_result(request);
488 	if (w == NULL) {
489 		return;
490 	}
491 
492 	spdk_json_write_bool(w, true);
493 	spdk_jsonrpc_end_result(request, w);
494 	return;
495 
496 invalid:
497 	free_rpc_remove_vhost_blk_ctrlr(&req);
498 	spdk_jsonrpc_send_error_response(request,
499 					 SPDK_JSONRPC_ERROR_INVALID_PARAMS, strerror(-rc));
500 
501 }
502 SPDK_RPC_REGISTER("remove_vhost_blk_controller", spdk_rpc_remove_vhost_blk_controller)
503 
504 static void
505 spdk_rpc_get_vhost_blk_controllers(struct spdk_jsonrpc_request *request,
506 				   const struct spdk_json_val *params)
507 {
508 	struct spdk_json_write_ctx *w;
509 	struct spdk_vhost_dev *vdev = NULL;
510 	struct spdk_bdev *bdev;
511 
512 	if (params != NULL) {
513 		spdk_jsonrpc_send_error_response(request,
514 						 SPDK_JSONRPC_ERROR_INVALID_PARAMS,
515 						 "get_vhost_block_controllers requires no parameters");
516 		return;
517 	}
518 
519 	w = spdk_jsonrpc_begin_result(request);
520 	if (w == NULL) {
521 		return;
522 	}
523 
524 	spdk_json_write_array_begin(w);
525 	while ((vdev = spdk_vhost_dev_next(vdev)) != NULL) {
526 		if (vdev->type != SPDK_VHOST_DEV_T_BLK)
527 			continue;
528 		spdk_json_write_object_begin(w);
529 
530 		spdk_json_write_name(w, "ctrlr");
531 		spdk_json_write_string(w, spdk_vhost_dev_get_name(vdev));
532 
533 		spdk_json_write_name(w, "cpu_mask");
534 		spdk_json_write_string_fmt(w, "%#" PRIx64, spdk_vhost_dev_get_cpumask(vdev));
535 
536 		spdk_json_write_name(w, "readonly");
537 		spdk_json_write_bool(w, spdk_vhost_blk_get_readonly(vdev));
538 
539 		bdev = spdk_vhost_blk_get_dev(vdev);
540 		spdk_json_write_name(w, "bdev");
541 		if (bdev)
542 			spdk_json_write_string(w, spdk_bdev_get_name(bdev));
543 		else
544 			spdk_json_write_null(w);
545 
546 		spdk_json_write_object_end(w);
547 	}
548 	spdk_json_write_array_end(w);
549 	spdk_jsonrpc_end_result(request, w);
550 }
551 SPDK_RPC_REGISTER("get_vhost_blk_controllers", spdk_rpc_get_vhost_blk_controllers)
552