Branch data Line data Source code
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 : 0 : rpc_bdev_virtio_blk_set_hotplug(struct spdk_jsonrpc_request *request,
31 : : const struct spdk_json_val *params)
32 : : {
33 : 0 : struct rpc_bdev_virtio_blk_hotplug req = {false, 0};
34 : : int rc;
35 : :
36 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_bdev_virtio_blk_hotplug_decoders,
37 : : SPDK_COUNTOF(rpc_bdev_virtio_blk_hotplug_decoders), &req)) {
38 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
39 : 0 : rc = -EINVAL;
40 : 0 : goto invalid;
41 : : }
42 : :
43 [ # # ]: 0 : rc = bdev_virtio_pci_blk_set_hotplug(req.enabled, req.period_us);
44 [ # # ]: 0 : if (rc) {
45 : 0 : goto invalid;
46 : : }
47 : :
48 : 0 : spdk_jsonrpc_send_bool_response(request, true);
49 : 0 : return;
50 : 0 : invalid:
51 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
52 : : }
53 : 2048 : 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 : 6 : rpc_bdev_virtio_detach_controller_cb(void *ctx, int errnum)
65 : : {
66 : 6 : struct spdk_jsonrpc_request *request = ctx;
67 : :
68 [ - + ]: 6 : if (errnum != 0) {
69 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
70 : : spdk_strerror(-errnum));
71 : 0 : return;
72 : : }
73 : :
74 : 6 : spdk_jsonrpc_send_bool_response(request, true);
75 : : }
76 : :
77 : : static void
78 : 6 : rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request *request,
79 : : const struct spdk_json_val *params)
80 : : {
81 : 6 : struct rpc_remove_virtio_dev req = {NULL};
82 : 6 : int rc = 0;
83 : :
84 [ - + ]: 6 : if (spdk_json_decode_object(params, rpc_remove_virtio_dev,
85 : : SPDK_COUNTOF(rpc_remove_virtio_dev),
86 : : &req)) {
87 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
88 : : "spdk_json_decode_object failed");
89 : 0 : goto cleanup;
90 : : }
91 : :
92 : 6 : rc = bdev_virtio_blk_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
93 [ + + ]: 6 : if (rc == -ENODEV) {
94 : 3 : rc = bdev_virtio_scsi_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
95 : : }
96 : :
97 [ + - ]: 6 : if (rc != 0) {
98 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
99 : : }
100 : :
101 : 6 : cleanup:
102 : 6 : free(req.name);
103 : 6 : }
104 : 2048 : SPDK_RPC_REGISTER("bdev_virtio_detach_controller",
105 : : rpc_bdev_virtio_detach_controller, SPDK_RPC_RUNTIME)
106 : :
107 : : static void
108 : 255 : 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 [ - + ]: 255 : if (params != NULL) {
114 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
115 : : "bdev_virtio_scsi_get_devices requires no parameters");
116 : 0 : return;
117 : : }
118 : :
119 : 255 : w = spdk_jsonrpc_begin_result(request);
120 : 255 : bdev_virtio_scsi_dev_list(w);
121 : 255 : spdk_jsonrpc_end_result(request, w);
122 : : }
123 : 2048 : 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 : 23 : free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx *req)
147 : : {
148 : 23 : free(req->name);
149 : 23 : free(req->trtype);
150 : 23 : free(req->traddr);
151 : 23 : free(req->dev_type);
152 : 23 : free(req);
153 : 23 : }
154 : :
155 : : static void
156 : 23 : rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
157 : : {
158 : 23 : struct rpc_bdev_virtio_attach_controller_ctx *req = ctx;
159 : : struct spdk_json_write_ctx *w;
160 : : size_t i;
161 : :
162 [ - + ]: 23 : if (result) {
163 : 0 : spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
164 : : spdk_strerror(-result));
165 : 0 : free_rpc_bdev_virtio_attach_controller_ctx(req);
166 : 0 : return;
167 : : }
168 : :
169 : 23 : w = spdk_jsonrpc_begin_result(req->request);
170 : 23 : spdk_json_write_array_begin(w);
171 : :
172 [ + + ]: 57 : for (i = 0; i < cnt; i++) {
173 : 34 : spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
174 : : }
175 : :
176 : 23 : spdk_json_write_array_end(w);
177 : 23 : spdk_jsonrpc_end_result(req->request, w);
178 : :
179 : 23 : free_rpc_bdev_virtio_attach_controller_ctx(ctx);
180 : : }
181 : :
182 : : static void
183 : 23 : 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 : 23 : struct spdk_bdev *bdev = NULL;
188 : 0 : struct spdk_pci_addr pci_addr;
189 : 23 : int rc = 0;
190 : :
191 : 23 : req = calloc(1, sizeof(*req));
192 [ - + ]: 23 : if (!req) {
193 : 0 : SPDK_ERRLOG("calloc() failed\n");
194 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
195 : 23 : return;
196 : : }
197 : :
198 [ - + ]: 23 : if (spdk_json_decode_object(params, rpc_bdev_virtio_attach_controller_ctx,
199 : : SPDK_COUNTOF(rpc_bdev_virtio_attach_controller_ctx),
200 : : req)) {
201 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
202 : : "spdk_json_decode_object failed");
203 : 0 : goto cleanup;
204 : : }
205 : :
206 [ - + - + ]: 23 : if (strcmp(req->trtype, "pci") == 0) {
207 [ # # # # ]: 0 : if (req->vq_count != 0 || req->vq_size != 0) {
208 : 0 : SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n");
209 : 0 : spdk_jsonrpc_send_error_response(request, EINVAL,
210 : : "vq_count or vq_size is not allowed for PCI transport type.");
211 : 0 : goto cleanup;
212 : : }
213 : :
214 [ # # ]: 0 : if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) {
215 : 0 : SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr);
216 : 0 : spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr);
217 : 0 : goto cleanup;
218 : : }
219 [ - + + - ]: 23 : } else if (strcmp(req->trtype, "user") == 0) {
220 [ + + ]: 23 : req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
221 [ + + ]: 23 : req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
222 [ # # # # ]: 0 : } else if (strcmp(req->trtype, "vfio-user") == 0) {
223 [ # # # # ]: 0 : if (req->vq_count != 0 || req->vq_size != 0) {
224 : 0 : SPDK_ERRLOG("VQ count or size is not allowed for vfio-user transport type\n");
225 : 0 : spdk_jsonrpc_send_error_response(request, EINVAL,
226 : : "vq_count or vq_size is not allowed for vfio-user transport type.");
227 : 0 : goto cleanup;
228 : : }
229 : : } else {
230 : 0 : SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
231 : 0 : spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype);
232 : 0 : goto cleanup;
233 : : }
234 : :
235 : 23 : req->request = request;
236 [ - + + + ]: 23 : if (strcmp(req->dev_type, "blk") == 0) {
237 [ - + - + ]: 11 : if (strcmp(req->trtype, "pci") == 0) {
238 : 0 : bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
239 [ - + + - ]: 11 : } else if (strcmp(req->trtype, "user") == 0) {
240 : 11 : bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
241 [ # # # # ]: 0 : } else if (strcmp(req->trtype, "vfio-user") == 0) {
242 : 0 : 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 [ + - ]: 11 : rc = bdev ? 0 : -EINVAL;
247 : 11 : rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
248 [ - + + - ]: 12 : } else if (strcmp(req->dev_type, "scsi") == 0) {
249 [ - + - + ]: 12 : if (strcmp(req->trtype, "pci") == 0) {
250 : 0 : rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
251 [ - + + - ]: 12 : } else if (strcmp(req->trtype, "user") == 0) {
252 : 12 : 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 [ # # # # ]: 0 : } else if (strcmp(req->trtype, "vfio-user") == 0) {
255 : 0 : rc = bdev_vfio_user_scsi_dev_create(req->name, req->traddr, rpc_create_virtio_dev_cb, req);
256 : : }
257 : :
258 [ - + ]: 12 : if (rc < 0) {
259 : : /* In case of error callback is not called so do it manually to send result. */
260 : 0 : rpc_create_virtio_dev_cb(req, rc, NULL, 0);
261 : : }
262 : : } else {
263 : 0 : SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type);
264 : 0 : spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid dev_type '%s'", req->dev_type);
265 : 0 : goto cleanup;
266 : : }
267 : :
268 : 23 : return;
269 : :
270 : 0 : cleanup:
271 : 0 : free_rpc_bdev_virtio_attach_controller_ctx(req);
272 : : }
273 : 2048 : SPDK_RPC_REGISTER("bdev_virtio_attach_controller",
274 : : rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME);
|