xref: /spdk/module/bdev/virtio/bdev_virtio_rpc.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
307fe6a43SSeth Howell  *   All rights reserved.
407fe6a43SSeth Howell  */
507fe6a43SSeth Howell 
607fe6a43SSeth Howell #include "spdk/stdinc.h"
707fe6a43SSeth Howell 
807fe6a43SSeth Howell #include "spdk/string.h"
907fe6a43SSeth Howell #include "spdk/rpc.h"
1007fe6a43SSeth Howell #include "spdk/util.h"
114e8e97c8STomasz Zawadzki #include "spdk/log.h"
122f600ca7SJin Yu #include "spdk/thread.h"
1307fe6a43SSeth Howell 
1407fe6a43SSeth Howell #include "bdev_virtio.h"
1507fe6a43SSeth Howell 
1607fe6a43SSeth Howell #define SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT		1
1707fe6a43SSeth Howell #define SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE		512
1807fe6a43SSeth Howell 
192f600ca7SJin Yu struct rpc_bdev_virtio_blk_hotplug {
202f600ca7SJin Yu 	bool enabled;
212f600ca7SJin Yu 	uint64_t period_us;
222f600ca7SJin Yu };
232f600ca7SJin Yu 
242f600ca7SJin Yu static const struct spdk_json_object_decoder rpc_bdev_virtio_blk_hotplug_decoders[] = {
252f600ca7SJin Yu 	{"enable", offsetof(struct rpc_bdev_virtio_blk_hotplug, enabled), spdk_json_decode_bool, false},
262f600ca7SJin Yu 	{"period_us", offsetof(struct rpc_bdev_virtio_blk_hotplug, period_us), spdk_json_decode_uint64, true},
272f600ca7SJin Yu };
282f600ca7SJin Yu 
292f600ca7SJin Yu static void
rpc_bdev_virtio_blk_set_hotplug(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)302f600ca7SJin Yu rpc_bdev_virtio_blk_set_hotplug(struct spdk_jsonrpc_request *request,
312f600ca7SJin Yu 				const struct spdk_json_val *params)
322f600ca7SJin Yu {
332f600ca7SJin Yu 	struct rpc_bdev_virtio_blk_hotplug req = {false, 0};
342f600ca7SJin Yu 	int rc;
352f600ca7SJin Yu 
362f600ca7SJin Yu 	if (spdk_json_decode_object(params, rpc_bdev_virtio_blk_hotplug_decoders,
372f600ca7SJin Yu 				    SPDK_COUNTOF(rpc_bdev_virtio_blk_hotplug_decoders), &req)) {
382f600ca7SJin Yu 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
392f600ca7SJin Yu 		rc = -EINVAL;
402f600ca7SJin Yu 		goto invalid;
412f600ca7SJin Yu 	}
422f600ca7SJin Yu 
432f600ca7SJin Yu 	rc = bdev_virtio_pci_blk_set_hotplug(req.enabled, req.period_us);
442f600ca7SJin Yu 	if (rc) {
452f600ca7SJin Yu 		goto invalid;
462f600ca7SJin Yu 	}
472f600ca7SJin Yu 
482f600ca7SJin Yu 	spdk_jsonrpc_send_bool_response(request, true);
492f600ca7SJin Yu 	return;
502f600ca7SJin Yu invalid:
512f600ca7SJin Yu 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
522f600ca7SJin Yu }
532f600ca7SJin Yu SPDK_RPC_REGISTER("bdev_virtio_blk_set_hotplug", rpc_bdev_virtio_blk_set_hotplug, SPDK_RPC_RUNTIME)
542f600ca7SJin Yu 
5507fe6a43SSeth Howell struct rpc_remove_virtio_dev {
5607fe6a43SSeth Howell 	char *name;
5707fe6a43SSeth Howell };
5807fe6a43SSeth Howell 
5907fe6a43SSeth Howell static const struct spdk_json_object_decoder rpc_remove_virtio_dev[] = {
6007fe6a43SSeth Howell 	{"name", offsetof(struct rpc_remove_virtio_dev, name), spdk_json_decode_string },
6107fe6a43SSeth Howell };
6207fe6a43SSeth Howell 
6307fe6a43SSeth Howell static void
rpc_bdev_virtio_detach_controller_cb(void * ctx,int errnum)64406d9482SSeth Howell rpc_bdev_virtio_detach_controller_cb(void *ctx, int errnum)
6507fe6a43SSeth Howell {
6607fe6a43SSeth Howell 	struct spdk_jsonrpc_request *request = ctx;
6707fe6a43SSeth Howell 
6807fe6a43SSeth Howell 	if (errnum != 0) {
6907fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
7007fe6a43SSeth Howell 						 spdk_strerror(-errnum));
7107fe6a43SSeth Howell 		return;
7207fe6a43SSeth Howell 	}
7307fe6a43SSeth Howell 
74d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
7507fe6a43SSeth Howell }
7607fe6a43SSeth Howell 
7707fe6a43SSeth Howell static void
rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)78406d9482SSeth Howell rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request *request,
7907fe6a43SSeth Howell 				  const struct spdk_json_val *params)
8007fe6a43SSeth Howell {
8107fe6a43SSeth Howell 	struct rpc_remove_virtio_dev req = {NULL};
8207fe6a43SSeth Howell 	int rc = 0;
8307fe6a43SSeth Howell 
8407fe6a43SSeth Howell 	if (spdk_json_decode_object(params, rpc_remove_virtio_dev,
8507fe6a43SSeth Howell 				    SPDK_COUNTOF(rpc_remove_virtio_dev),
8607fe6a43SSeth Howell 				    &req)) {
8707fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
8807fe6a43SSeth Howell 						 "spdk_json_decode_object failed");
8907fe6a43SSeth Howell 		goto cleanup;
9007fe6a43SSeth Howell 	}
9107fe6a43SSeth Howell 
92406d9482SSeth Howell 	rc = bdev_virtio_blk_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
9307fe6a43SSeth Howell 	if (rc == -ENODEV) {
94406d9482SSeth Howell 		rc = bdev_virtio_scsi_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
9507fe6a43SSeth Howell 	}
9607fe6a43SSeth Howell 
9707fe6a43SSeth Howell 	if (rc != 0) {
9807fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
9907fe6a43SSeth Howell 	}
10007fe6a43SSeth Howell 
10107fe6a43SSeth Howell cleanup:
10207fe6a43SSeth Howell 	free(req.name);
10307fe6a43SSeth Howell }
104c1b87b3dSMaciej Wawryk SPDK_RPC_REGISTER("bdev_virtio_detach_controller",
105406d9482SSeth Howell 		  rpc_bdev_virtio_detach_controller, SPDK_RPC_RUNTIME)
10607fe6a43SSeth Howell 
10707fe6a43SSeth Howell static void
rpc_bdev_virtio_scsi_get_devices(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)108406d9482SSeth Howell rpc_bdev_virtio_scsi_get_devices(struct spdk_jsonrpc_request *request,
10907fe6a43SSeth Howell 				 const struct spdk_json_val *params)
11007fe6a43SSeth Howell {
11107fe6a43SSeth Howell 	struct spdk_json_write_ctx *w;
11207fe6a43SSeth Howell 
11307fe6a43SSeth Howell 	if (params != NULL) {
11407fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
115c2a4f329SMaciej Wawryk 						 "bdev_virtio_scsi_get_devices requires no parameters");
11607fe6a43SSeth Howell 		return;
11707fe6a43SSeth Howell 	}
11807fe6a43SSeth Howell 
11907fe6a43SSeth Howell 	w = spdk_jsonrpc_begin_result(request);
12007fe6a43SSeth Howell 	bdev_virtio_scsi_dev_list(w);
12107fe6a43SSeth Howell 	spdk_jsonrpc_end_result(request, w);
12207fe6a43SSeth Howell }
123c2a4f329SMaciej Wawryk SPDK_RPC_REGISTER("bdev_virtio_scsi_get_devices",
124406d9482SSeth Howell 		  rpc_bdev_virtio_scsi_get_devices, SPDK_RPC_RUNTIME)
12507fe6a43SSeth Howell 
126406d9482SSeth Howell struct rpc_bdev_virtio_attach_controller_ctx {
12707fe6a43SSeth Howell 	char *name;
12807fe6a43SSeth Howell 	char *trtype;
12907fe6a43SSeth Howell 	char *traddr;
13007fe6a43SSeth Howell 	char *dev_type;
13107fe6a43SSeth Howell 	uint32_t vq_count;
13207fe6a43SSeth Howell 	uint32_t vq_size;
13307fe6a43SSeth Howell 	struct spdk_jsonrpc_request *request;
13407fe6a43SSeth Howell };
13507fe6a43SSeth Howell 
136406d9482SSeth Howell static const struct spdk_json_object_decoder rpc_bdev_virtio_attach_controller_ctx[] = {
137406d9482SSeth Howell 	{"name", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, name), spdk_json_decode_string },
138406d9482SSeth Howell 	{"trtype", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, trtype), spdk_json_decode_string },
139406d9482SSeth Howell 	{"traddr", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, traddr), spdk_json_decode_string },
140406d9482SSeth Howell 	{"dev_type", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, dev_type), spdk_json_decode_string },
141406d9482SSeth Howell 	{"vq_count", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_count), spdk_json_decode_uint32, true },
142406d9482SSeth Howell 	{"vq_size", offsetof(struct rpc_bdev_virtio_attach_controller_ctx, vq_size), spdk_json_decode_uint32, true },
14307fe6a43SSeth Howell };
14407fe6a43SSeth Howell 
14507fe6a43SSeth Howell static void
free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx * req)146406d9482SSeth Howell free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx *req)
14707fe6a43SSeth Howell {
14807fe6a43SSeth Howell 	free(req->name);
14907fe6a43SSeth Howell 	free(req->trtype);
15007fe6a43SSeth Howell 	free(req->traddr);
15107fe6a43SSeth Howell 	free(req->dev_type);
15207fe6a43SSeth Howell 	free(req);
15307fe6a43SSeth Howell }
15407fe6a43SSeth Howell 
15507fe6a43SSeth Howell static void
rpc_create_virtio_dev_cb(void * ctx,int result,struct spdk_bdev ** bdevs,size_t cnt)156406d9482SSeth Howell rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
15707fe6a43SSeth Howell {
158406d9482SSeth Howell 	struct rpc_bdev_virtio_attach_controller_ctx *req = ctx;
15907fe6a43SSeth Howell 	struct spdk_json_write_ctx *w;
16007fe6a43SSeth Howell 	size_t i;
16107fe6a43SSeth Howell 
16207fe6a43SSeth Howell 	if (result) {
16307fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
16407fe6a43SSeth Howell 						 spdk_strerror(-result));
165406d9482SSeth Howell 		free_rpc_bdev_virtio_attach_controller_ctx(req);
16607fe6a43SSeth Howell 		return;
16707fe6a43SSeth Howell 	}
16807fe6a43SSeth Howell 
16907fe6a43SSeth Howell 	w = spdk_jsonrpc_begin_result(req->request);
17007fe6a43SSeth Howell 	spdk_json_write_array_begin(w);
17107fe6a43SSeth Howell 
17207fe6a43SSeth Howell 	for (i = 0; i < cnt; i++) {
17307fe6a43SSeth Howell 		spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
17407fe6a43SSeth Howell 	}
17507fe6a43SSeth Howell 
17607fe6a43SSeth Howell 	spdk_json_write_array_end(w);
17707fe6a43SSeth Howell 	spdk_jsonrpc_end_result(req->request, w);
17807fe6a43SSeth Howell 
179406d9482SSeth Howell 	free_rpc_bdev_virtio_attach_controller_ctx(ctx);
18007fe6a43SSeth Howell }
18107fe6a43SSeth Howell 
18207fe6a43SSeth Howell static void
rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request * request,const struct spdk_json_val * params)183406d9482SSeth Howell rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
18407fe6a43SSeth Howell 				  const struct spdk_json_val *params)
18507fe6a43SSeth Howell {
186406d9482SSeth Howell 	struct rpc_bdev_virtio_attach_controller_ctx *req;
187295e54d1SChangpeng Liu 	struct spdk_bdev *bdev = NULL;
18807fe6a43SSeth Howell 	struct spdk_pci_addr pci_addr;
1898b260d5cSChangpeng Liu 	int rc = 0;
19007fe6a43SSeth Howell 
19107fe6a43SSeth Howell 	req = calloc(1, sizeof(*req));
19207fe6a43SSeth Howell 	if (!req) {
19307fe6a43SSeth Howell 		SPDK_ERRLOG("calloc() failed\n");
19407fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
19507fe6a43SSeth Howell 		return;
19607fe6a43SSeth Howell 	}
19707fe6a43SSeth Howell 
198406d9482SSeth Howell 	if (spdk_json_decode_object(params, rpc_bdev_virtio_attach_controller_ctx,
199406d9482SSeth Howell 				    SPDK_COUNTOF(rpc_bdev_virtio_attach_controller_ctx),
20007fe6a43SSeth Howell 				    req)) {
20107fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
20207fe6a43SSeth Howell 						 "spdk_json_decode_object failed");
20307fe6a43SSeth Howell 		goto cleanup;
20407fe6a43SSeth Howell 	}
20507fe6a43SSeth Howell 
20607fe6a43SSeth Howell 	if (strcmp(req->trtype, "pci") == 0) {
20707fe6a43SSeth Howell 		if (req->vq_count != 0 || req->vq_size != 0) {
20807fe6a43SSeth Howell 			SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n");
20907fe6a43SSeth Howell 			spdk_jsonrpc_send_error_response(request, EINVAL,
21007fe6a43SSeth Howell 							 "vq_count or vq_size is not allowed for PCI transport type.");
21107fe6a43SSeth Howell 			goto cleanup;
21207fe6a43SSeth Howell 		}
21307fe6a43SSeth Howell 
21407fe6a43SSeth Howell 		if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) {
21507fe6a43SSeth Howell 			SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr);
21607fe6a43SSeth Howell 			spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr);
21707fe6a43SSeth Howell 			goto cleanup;
21807fe6a43SSeth Howell 		}
21907fe6a43SSeth Howell 	} else if (strcmp(req->trtype, "user") == 0) {
22007fe6a43SSeth Howell 		req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
22107fe6a43SSeth Howell 		req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
222295e54d1SChangpeng Liu 	} else if (strcmp(req->trtype, "vfio-user") == 0) {
223295e54d1SChangpeng Liu 		if (req->vq_count != 0 || req->vq_size != 0) {
224295e54d1SChangpeng Liu 			SPDK_ERRLOG("VQ count or size is not allowed for vfio-user transport type\n");
225295e54d1SChangpeng Liu 			spdk_jsonrpc_send_error_response(request, EINVAL,
226295e54d1SChangpeng Liu 							 "vq_count or vq_size is not allowed for vfio-user transport type.");
227295e54d1SChangpeng Liu 			goto cleanup;
228295e54d1SChangpeng Liu 		}
22907fe6a43SSeth Howell 	} else {
23007fe6a43SSeth Howell 		SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
23107fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype);
23207fe6a43SSeth Howell 		goto cleanup;
23307fe6a43SSeth Howell 	}
23407fe6a43SSeth Howell 
23507fe6a43SSeth Howell 	req->request = request;
23607fe6a43SSeth Howell 	if (strcmp(req->dev_type, "blk") == 0) {
237295e54d1SChangpeng Liu 		if (strcmp(req->trtype, "pci") == 0) {
23807fe6a43SSeth Howell 			bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
239295e54d1SChangpeng Liu 		} else if (strcmp(req->trtype, "user") == 0) {
24007fe6a43SSeth Howell 			bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
241295e54d1SChangpeng Liu 		} else if (strcmp(req->trtype, "vfio-user") == 0) {
242295e54d1SChangpeng Liu 			bdev = bdev_virtio_vfio_user_blk_dev_create(req->name, req->traddr);
24307fe6a43SSeth Howell 		}
24407fe6a43SSeth Howell 
24507fe6a43SSeth Howell 		/* Virtio blk doesn't use callback so call it manually to send result. */
24607fe6a43SSeth Howell 		rc = bdev ? 0 : -EINVAL;
247406d9482SSeth Howell 		rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
24807fe6a43SSeth Howell 	} else if (strcmp(req->dev_type, "scsi") == 0) {
249295e54d1SChangpeng Liu 		if (strcmp(req->trtype, "pci") == 0) {
250406d9482SSeth Howell 			rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
2518b260d5cSChangpeng Liu 		} else if (strcmp(req->trtype, "user") == 0) {
25207fe6a43SSeth Howell 			rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
253406d9482SSeth Howell 							      rpc_create_virtio_dev_cb, req);
2548b260d5cSChangpeng Liu 		} else if (strcmp(req->trtype, "vfio-user") == 0) {
2558b260d5cSChangpeng Liu 			rc = bdev_vfio_user_scsi_dev_create(req->name, req->traddr, rpc_create_virtio_dev_cb, req);
25607fe6a43SSeth Howell 		}
25707fe6a43SSeth Howell 
25807fe6a43SSeth Howell 		if (rc < 0) {
25907fe6a43SSeth Howell 			/* In case of error callback is not called so do it manually to send result. */
260406d9482SSeth Howell 			rpc_create_virtio_dev_cb(req, rc, NULL, 0);
26107fe6a43SSeth Howell 		}
26207fe6a43SSeth Howell 	} else {
26307fe6a43SSeth Howell 		SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type);
26407fe6a43SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid dev_type '%s'", req->dev_type);
26507fe6a43SSeth Howell 		goto cleanup;
26607fe6a43SSeth Howell 	}
26707fe6a43SSeth Howell 
26807fe6a43SSeth Howell 	return;
26907fe6a43SSeth Howell 
27007fe6a43SSeth Howell cleanup:
271406d9482SSeth Howell 	free_rpc_bdev_virtio_attach_controller_ctx(req);
27207fe6a43SSeth Howell }
2732aed03f0SMaciej Wawryk SPDK_RPC_REGISTER("bdev_virtio_attach_controller",
274406d9482SSeth Howell 		  rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME);
275