]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/bdev/virtio/bdev_virtio_rpc.c
bump version to 15.2.11-pve1
[ceph.git] / ceph / src / spdk / lib / bdev / virtio / bdev_virtio_rpc.c
1 /*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
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/string.h"
37 #include "spdk/rpc.h"
38 #include "spdk/util.h"
39 #include "spdk_internal/log.h"
40
41 #include "bdev_virtio.h"
42
43 #define SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT 1
44 #define SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE 512
45
46 struct rpc_remove_virtio_dev {
47 char *name;
48 };
49
50 static const struct spdk_json_object_decoder rpc_remove_virtio_dev[] = {
51 {"name", offsetof(struct rpc_remove_virtio_dev, name), spdk_json_decode_string },
52 };
53
54 static void
55 spdk_rpc_remove_virtio_bdev_cb(void *ctx, int errnum)
56 {
57 struct spdk_jsonrpc_request *request = ctx;
58 struct spdk_json_write_ctx *w;
59
60 if (errnum != 0) {
61 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
62 spdk_strerror(-errnum));
63 return;
64 }
65
66 w = spdk_jsonrpc_begin_result(request);
67 if (w == NULL) {
68 return;
69 }
70
71 spdk_json_write_bool(w, true);
72 spdk_jsonrpc_end_result(request, w);
73 }
74
75 static void
76 spdk_rpc_remove_virtio_bdev(struct spdk_jsonrpc_request *request,
77 const struct spdk_json_val *params)
78 {
79 struct rpc_remove_virtio_dev req = {NULL};
80 int rc;
81
82 if (spdk_json_decode_object(params, rpc_remove_virtio_dev,
83 SPDK_COUNTOF(rpc_remove_virtio_dev),
84 &req)) {
85 rc = -EINVAL;
86 goto invalid;
87 }
88
89 rc = bdev_virtio_blk_dev_remove(req.name, spdk_rpc_remove_virtio_bdev_cb, request);
90 if (rc == -ENODEV) {
91 rc = bdev_virtio_scsi_dev_remove(req.name, spdk_rpc_remove_virtio_bdev_cb, request);
92 }
93
94 if (rc != 0) {
95 goto invalid;
96 }
97
98 free(req.name);
99
100 return;
101
102 invalid:
103 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
104 spdk_strerror(-rc));
105 free(req.name);
106 }
107 SPDK_RPC_REGISTER("remove_virtio_bdev", spdk_rpc_remove_virtio_bdev, SPDK_RPC_RUNTIME);
108
109 static void
110 spdk_rpc_get_virtio_scsi_devs(struct spdk_jsonrpc_request *request,
111 const struct spdk_json_val *params)
112 {
113 struct spdk_json_write_ctx *w;
114
115 if (params != NULL) {
116 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
117 "get_virtio_scsi_devs requires no parameters");
118 return;
119 }
120
121 w = spdk_jsonrpc_begin_result(request);
122 if (w == NULL) {
123 return;
124 }
125
126 bdev_virtio_scsi_dev_list(w);
127 spdk_jsonrpc_end_result(request, w);
128 }
129 SPDK_RPC_REGISTER("get_virtio_scsi_devs", spdk_rpc_get_virtio_scsi_devs, SPDK_RPC_RUNTIME)
130
131 struct rpc_construct_virtio_dev {
132 char *name;
133 char *trtype;
134 char *traddr;
135 char *dev_type;
136 uint32_t vq_count;
137 uint32_t vq_size;
138 struct spdk_jsonrpc_request *request;
139 };
140
141 static const struct spdk_json_object_decoder rpc_construct_virtio_dev[] = {
142 {"name", offsetof(struct rpc_construct_virtio_dev, name), spdk_json_decode_string },
143 {"trtype", offsetof(struct rpc_construct_virtio_dev, trtype), spdk_json_decode_string },
144 {"traddr", offsetof(struct rpc_construct_virtio_dev, traddr), spdk_json_decode_string },
145 {"dev_type", offsetof(struct rpc_construct_virtio_dev, dev_type), spdk_json_decode_string },
146 {"vq_count", offsetof(struct rpc_construct_virtio_dev, vq_count), spdk_json_decode_uint32, true },
147 {"vq_size", offsetof(struct rpc_construct_virtio_dev, vq_size), spdk_json_decode_uint32, true },
148 };
149
150 static void
151 free_rpc_construct_virtio_dev(struct rpc_construct_virtio_dev *req)
152 {
153 free(req->name);
154 free(req->trtype);
155 free(req->traddr);
156 free(req->dev_type);
157 free(req);
158 }
159
160 static void
161 spdk_rpc_create_virtio_dev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
162 {
163 struct rpc_construct_virtio_dev *req = ctx;
164 struct spdk_json_write_ctx *w;
165 size_t i;
166
167 if (result) {
168 spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
169 spdk_strerror(-result));
170 free_rpc_construct_virtio_dev(req);
171 return;
172 }
173
174 w = spdk_jsonrpc_begin_result(req->request);
175 if (w) {
176 spdk_json_write_array_begin(w);
177
178 for (i = 0; i < cnt; i++) {
179 spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
180 }
181
182 spdk_json_write_array_end(w);
183 spdk_jsonrpc_end_result(req->request, w);
184 }
185
186 free_rpc_construct_virtio_dev(ctx);
187 }
188
189 static void
190 spdk_rpc_construct_virtio_dev(struct spdk_jsonrpc_request *request,
191 const struct spdk_json_val *params)
192 {
193 struct rpc_construct_virtio_dev *req;
194 struct spdk_bdev *bdev;
195 struct spdk_pci_addr pci_addr;
196 bool pci;
197 int rc;
198
199 req = calloc(1, sizeof(*req));
200 if (!req) {
201 SPDK_ERRLOG("calloc() failed\n");
202 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(ENOMEM));
203 return;
204 }
205
206 if (spdk_json_decode_object(params, rpc_construct_virtio_dev,
207 SPDK_COUNTOF(rpc_construct_virtio_dev),
208 req)) {
209 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(EINVAL));
210 goto invalid;
211 }
212
213 if (strcmp(req->trtype, "pci") == 0) {
214 if (req->vq_count != 0 || req->vq_size != 0) {
215 SPDK_ERRLOG("VQ count or size is not allowed for PCI transport type\n");
216 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
217 "vq_count or vq_size is not allowed for PCI transport type.");
218 goto invalid;
219 }
220
221 if (spdk_pci_addr_parse(&pci_addr, req->traddr) != 0) {
222 SPDK_ERRLOG("Invalid PCI address '%s'\n", req->traddr);
223 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
224 "Invalid PCI address '%s'", req->traddr);
225 goto invalid;
226 }
227
228 pci = true;
229 } else if (strcmp(req->trtype, "user") == 0) {
230 req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
231 req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
232 pci = false;
233 } else {
234 SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
235 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
236 "Invalid trtype '%s'", req->trtype);
237 goto invalid;
238 }
239
240 req->request = request;
241 if (strcmp(req->dev_type, "blk") == 0) {
242 if (pci) {
243 bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
244 } else {
245 bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
246 }
247
248 /* Virtio blk doesn't use callback so call it manually to send result. */
249 rc = bdev ? 0 : -EINVAL;
250 spdk_rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
251 } else if (strcmp(req->dev_type, "scsi") == 0) {
252 if (pci) {
253 rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, spdk_rpc_create_virtio_dev_cb, req);
254 } else {
255 rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,
256 spdk_rpc_create_virtio_dev_cb, req);
257 }
258
259 if (rc < 0) {
260 /* In case of error callback is not called so do it manually to send result. */
261 spdk_rpc_create_virtio_dev_cb(req, rc, NULL, 0);
262 }
263 } else {
264 SPDK_ERRLOG("Invalid dev_type '%s'\n", req->dev_type);
265 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
266 "Invalid dev_type '%s'", req->dev_type);
267 goto invalid;
268 }
269
270 return;
271 invalid:
272 free_rpc_construct_virtio_dev(req);
273 }
274 SPDK_RPC_REGISTER("construct_virtio_dev", spdk_rpc_construct_virtio_dev, SPDK_RPC_RUNTIME);