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 0 : 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 0 : rpc_bdev_virtio_detach_controller_cb(void *ctx, int errnum)
65 : {
66 0 : struct spdk_jsonrpc_request *request = ctx;
67 :
68 0 : 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 0 : spdk_jsonrpc_send_bool_response(request, true);
75 : }
76 :
77 : static void
78 0 : rpc_bdev_virtio_detach_controller(struct spdk_jsonrpc_request *request,
79 : const struct spdk_json_val *params)
80 : {
81 0 : struct rpc_remove_virtio_dev req = {NULL};
82 0 : int rc = 0;
83 :
84 0 : 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 0 : rc = bdev_virtio_blk_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
93 0 : if (rc == -ENODEV) {
94 0 : rc = bdev_virtio_scsi_dev_remove(req.name, rpc_bdev_virtio_detach_controller_cb, request);
95 : }
96 :
97 0 : if (rc != 0) {
98 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
99 : }
100 :
101 0 : cleanup:
102 0 : free(req.name);
103 0 : }
104 0 : SPDK_RPC_REGISTER("bdev_virtio_detach_controller",
105 : rpc_bdev_virtio_detach_controller, SPDK_RPC_RUNTIME)
106 :
107 : static void
108 0 : 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 0 : 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 0 : w = spdk_jsonrpc_begin_result(request);
120 0 : bdev_virtio_scsi_dev_list(w);
121 0 : spdk_jsonrpc_end_result(request, w);
122 : }
123 0 : 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 0 : free_rpc_bdev_virtio_attach_controller_ctx(struct rpc_bdev_virtio_attach_controller_ctx *req)
147 : {
148 0 : free(req->name);
149 0 : free(req->trtype);
150 0 : free(req->traddr);
151 0 : free(req->dev_type);
152 0 : free(req);
153 0 : }
154 :
155 : static void
156 0 : rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
157 : {
158 0 : struct rpc_bdev_virtio_attach_controller_ctx *req = ctx;
159 : struct spdk_json_write_ctx *w;
160 : size_t i;
161 :
162 0 : 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 0 : w = spdk_jsonrpc_begin_result(req->request);
170 0 : spdk_json_write_array_begin(w);
171 :
172 0 : for (i = 0; i < cnt; i++) {
173 0 : spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
174 : }
175 :
176 0 : spdk_json_write_array_end(w);
177 0 : spdk_jsonrpc_end_result(req->request, w);
178 :
179 0 : free_rpc_bdev_virtio_attach_controller_ctx(ctx);
180 : }
181 :
182 : static void
183 0 : 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 0 : struct spdk_bdev *bdev = NULL;
188 0 : struct spdk_pci_addr pci_addr;
189 0 : int rc = 0;
190 :
191 0 : req = calloc(1, sizeof(*req));
192 0 : if (!req) {
193 0 : SPDK_ERRLOG("calloc() failed\n");
194 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
195 0 : return;
196 : }
197 :
198 0 : 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 0 : 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 0 : } else if (strcmp(req->trtype, "user") == 0) {
220 0 : req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
221 0 : 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 0 : req->request = request;
236 0 : if (strcmp(req->dev_type, "blk") == 0) {
237 0 : if (strcmp(req->trtype, "pci") == 0) {
238 0 : bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
239 0 : } else if (strcmp(req->trtype, "user") == 0) {
240 0 : 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 0 : rc = bdev ? 0 : -EINVAL;
247 0 : rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
248 0 : } else if (strcmp(req->dev_type, "scsi") == 0) {
249 0 : 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 0 : } else if (strcmp(req->trtype, "user") == 0) {
252 0 : 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 0 : 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 0 : return;
269 :
270 0 : cleanup:
271 0 : free_rpc_bdev_virtio_attach_controller_ctx(req);
272 : }
273 0 : SPDK_RPC_REGISTER("bdev_virtio_attach_controller",
274 : rpc_bdev_virtio_attach_controller, SPDK_RPC_RUNTIME);
|