xref: /spdk/module/bdev/virtio/bdev_virtio_rpc.c (revision 6f338d4bf3a8a91b7abe377a605a321ea2b05bf7)
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