]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/bdev/nvme/nvme_rpc.c
bump version to 15.2.11-pve1
[ceph.git] / ceph / src / spdk / lib / bdev / nvme / nvme_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 #include "spdk/string.h"
36 #include "spdk/rpc.h"
37 #include "spdk/util.h"
38 #include "spdk/bdev_module.h"
39 #include "spdk_internal/log.h"
40
41 #include "bdev_nvme.h"
42 #include "common.h"
43 #include "spdk/base64.h"
44
45 enum spdk_nvme_rpc_type {
46 NVME_ADMIN_CMD = 1,
47 NVME_IO_CMD,
48 };
49
50 struct rpc_send_nvme_cmd_req {
51 char *name;
52 int cmd_type;
53 int data_direction;
54 uint32_t timeout_ms;
55 uint32_t data_len;
56 uint32_t md_len;
57
58 struct spdk_nvme_cmd *cmdbuf;
59 char *data;
60 char *md;
61 };
62
63 struct rpc_send_nvme_cmd_resp {
64 char *cpl_text;
65 char *data_text;
66 char *md_text;
67 };
68
69 struct rpc_send_nvme_cmd_ctx {
70 struct spdk_jsonrpc_request *jsonrpc_request;
71 struct rpc_send_nvme_cmd_req req;
72 struct rpc_send_nvme_cmd_resp resp;
73 struct nvme_bdev_ctrlr *nvme_bdev_ctrlr;
74 struct spdk_io_channel *ctrlr_io_ch;
75 };
76
77 static void
78 free_rpc_send_nvme_cmd_ctx(struct rpc_send_nvme_cmd_ctx *ctx)
79 {
80 assert(ctx != NULL);
81
82 free(ctx->req.name);
83 free(ctx->req.cmdbuf);
84 spdk_dma_free(ctx->req.data);
85 spdk_dma_free(ctx->req.md);
86 free(ctx->resp.cpl_text);
87 free(ctx->resp.data_text);
88 free(ctx->resp.md_text);
89 free(ctx);
90 }
91
92 static int
93 rpc_send_nvme_cmd_resp_construct(struct rpc_send_nvme_cmd_resp *resp,
94 struct rpc_send_nvme_cmd_req *req,
95 const struct spdk_nvme_cpl *cpl)
96 {
97 resp->cpl_text = malloc(spdk_base64_get_encoded_strlen(sizeof(*cpl)) + 1);
98 if (!resp->cpl_text) {
99 return -ENOMEM;
100 }
101 spdk_base64_urlsafe_encode(resp->cpl_text, cpl, sizeof(*cpl));
102
103 if (req->data_direction == SPDK_NVME_DATA_CONTROLLER_TO_HOST) {
104 if (req->data_len) {
105 resp->data_text = malloc(spdk_base64_get_encoded_strlen(req->data_len) + 1);
106 if (!resp->data_text) {
107 return -ENOMEM;
108 }
109 spdk_base64_urlsafe_encode(resp->data_text, req->data, req->data_len);
110 }
111 if (req->md_len) {
112 resp->md_text = malloc(spdk_base64_get_encoded_strlen(req->md_len) + 1);
113 if (!resp->md_text) {
114 return -ENOMEM;
115 }
116 spdk_base64_urlsafe_encode(resp->md_text, req->md, req->md_len);
117 }
118 }
119
120 return 0;
121 }
122
123 static void
124 spdk_rpc_send_nvme_cmd_complete(struct rpc_send_nvme_cmd_ctx *ctx, const struct spdk_nvme_cpl *cpl)
125 {
126 struct spdk_jsonrpc_request *request = ctx->jsonrpc_request;
127 struct spdk_json_write_ctx *w;
128 int ret;
129
130 ret = rpc_send_nvme_cmd_resp_construct(&ctx->resp, &ctx->req, cpl);
131 if (ret) {
132 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
133 spdk_strerror(-ret));
134 goto out;
135 }
136
137 w = spdk_jsonrpc_begin_result(request);
138 if (w == NULL) {
139 goto out;
140 }
141
142 spdk_json_write_object_begin(w);
143 spdk_json_write_named_string(w, "cpl", ctx->resp.cpl_text);
144
145 if (ctx->resp.data_text) {
146 spdk_json_write_named_string(w, "data", ctx->resp.data_text);
147 }
148
149 if (ctx->resp.md_text) {
150 spdk_json_write_named_string(w, "metadata", ctx->resp.md_text);
151 }
152
153 spdk_json_write_object_end(w);
154 spdk_jsonrpc_end_result(request, w);
155
156 out:
157 free_rpc_send_nvme_cmd_ctx(ctx);
158 return;
159 }
160
161 static void
162 nvme_rpc_bdev_nvme_cb(void *ref, const struct spdk_nvme_cpl *cpl)
163 {
164 struct rpc_send_nvme_cmd_ctx *ctx = (struct rpc_send_nvme_cmd_ctx *)ref;
165
166 if (ctx->ctrlr_io_ch) {
167 spdk_put_io_channel(ctx->ctrlr_io_ch);
168 ctx->ctrlr_io_ch = NULL;
169 }
170
171 spdk_rpc_send_nvme_cmd_complete(ctx, cpl);
172 }
173
174 static int
175 nvme_rpc_admin_cmd_bdev_nvme(struct rpc_send_nvme_cmd_ctx *ctx, struct spdk_nvme_cmd *cmd,
176 void *buf, uint32_t nbytes, uint32_t timeout_ms)
177 {
178 struct nvme_bdev_ctrlr *_nvme_ctrlr = ctx->nvme_bdev_ctrlr;
179 int ret;
180
181 ret = spdk_nvme_ctrlr_cmd_admin_raw(_nvme_ctrlr->ctrlr, cmd, buf,
182 nbytes, nvme_rpc_bdev_nvme_cb, ctx);
183
184 return ret;
185 }
186
187 static int
188 nvme_rpc_io_cmd_bdev_nvme(struct rpc_send_nvme_cmd_ctx *ctx, struct spdk_nvme_cmd *cmd,
189 void *buf, uint32_t nbytes, void *md_buf, uint32_t md_len,
190 uint32_t timeout_ms)
191 {
192 struct nvme_bdev_ctrlr *_nvme_ctrlr = ctx->nvme_bdev_ctrlr;
193 struct spdk_nvme_qpair *io_qpair;
194 int ret;
195
196 ctx->ctrlr_io_ch = spdk_get_io_channel(_nvme_ctrlr->ctrlr);
197 io_qpair = spdk_bdev_nvme_get_io_qpair(ctx->ctrlr_io_ch);
198
199 ret = spdk_nvme_ctrlr_cmd_io_raw_with_md(_nvme_ctrlr->ctrlr, io_qpair,
200 cmd, buf, nbytes, md_buf, nvme_rpc_bdev_nvme_cb, ctx);
201 if (ret) {
202 spdk_put_io_channel(ctx->ctrlr_io_ch);
203 }
204
205 return ret;
206
207 }
208
209 static int
210 rpc_send_nvme_cmd_exec(struct rpc_send_nvme_cmd_ctx *ctx)
211 {
212 struct rpc_send_nvme_cmd_req *req = &ctx->req;
213 int ret = -EINVAL;
214
215 switch (req->cmd_type) {
216 case NVME_ADMIN_CMD:
217 ret = nvme_rpc_admin_cmd_bdev_nvme(ctx, req->cmdbuf, req->data,
218 req->data_len, req->timeout_ms);
219 break;
220 case NVME_IO_CMD:
221 ret = nvme_rpc_io_cmd_bdev_nvme(ctx, req->cmdbuf, req->data,
222 req->data_len, req->md, req->md_len, req->timeout_ms);
223 break;
224 }
225
226 return ret;
227 }
228
229 static int
230 rpc_decode_cmd_type(const struct spdk_json_val *val, void *out)
231 {
232 int *cmd_type = out;
233
234 if (spdk_json_strequal(val, "admin") == true) {
235 *cmd_type = NVME_ADMIN_CMD;
236 } else if (spdk_json_strequal(val, "io") == true) {
237 *cmd_type = NVME_IO_CMD;
238 } else {
239 SPDK_NOTICELOG("Invalid parameter value: cmd_type\n");
240 return -EINVAL;
241 }
242
243 return 0;
244 }
245
246 static int
247 rpc_decode_data_direction(const struct spdk_json_val *val, void *out)
248 {
249 int *data_direction = out;
250
251 if (spdk_json_strequal(val, "h2c") == true) {
252 *data_direction = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
253 } else if (spdk_json_strequal(val, "c2h") == true) {
254 *data_direction = SPDK_NVME_DATA_CONTROLLER_TO_HOST;
255 } else {
256 SPDK_NOTICELOG("Invalid parameter value: data_direction\n");
257 return -EINVAL;
258 }
259
260 return 0;
261 }
262
263 static int
264 rpc_decode_cmdbuf(const struct spdk_json_val *val, void *out)
265 {
266 char *text = NULL;
267 size_t text_strlen, raw_len;
268 struct spdk_nvme_cmd *cmdbuf, **_cmdbuf = out;
269 int rc;
270
271 rc = spdk_json_decode_string(val, &text);
272 if (rc) {
273 return val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
274 }
275
276 text_strlen = strlen(text);
277 raw_len = spdk_base64_get_decoded_len(text_strlen);
278 cmdbuf = malloc(raw_len);
279 if (!cmdbuf) {
280 rc = -ENOMEM;
281 goto out;
282 }
283
284 rc = spdk_base64_urlsafe_decode(cmdbuf, &raw_len, text);
285 if (rc) {
286 goto out;
287 }
288 if (raw_len != sizeof(*cmdbuf)) {
289 rc = -EINVAL;
290 goto out;
291 }
292
293 *_cmdbuf = cmdbuf;
294
295 out:
296 free(text);
297 return rc;
298 }
299
300 static int
301 rpc_decode_data(const struct spdk_json_val *val, void *out)
302 {
303 struct rpc_send_nvme_cmd_req *req = (struct rpc_send_nvme_cmd_req *)out;
304 char *text = NULL;
305 size_t text_strlen;
306 int rc;
307
308 rc = spdk_json_decode_string(val, &text);
309 if (rc) {
310 return val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
311 }
312 text_strlen = strlen(text);
313
314 if (req->data_len) {
315 /* data_len is decoded by param "data_len" */
316 if (req->data_len != spdk_base64_get_decoded_len(text_strlen)) {
317 rc = -EINVAL;
318 goto out;
319 }
320 } else {
321 req->data_len = spdk_base64_get_decoded_len(text_strlen);
322 req->data = spdk_dma_malloc(req->data_len > 0x1000 ? req->data_len : 0x1000, 0x1000, NULL);
323 if (!req->data) {
324 rc = -ENOMEM;
325 goto out;
326 }
327 }
328
329 rc = spdk_base64_urlsafe_decode(req->data, (size_t *)&req->data_len, text);
330
331 out:
332 free(text);
333 return rc;
334 }
335
336 static int
337 rpc_decode_data_len(const struct spdk_json_val *val, void *out)
338 {
339 struct rpc_send_nvme_cmd_req *req = (struct rpc_send_nvme_cmd_req *)out;
340 uint32_t data_len;
341 int rc;
342
343 rc = spdk_json_decode_uint32(val, &data_len);
344 if (rc) {
345 return rc;
346 }
347
348 if (req->data_len) {
349 /* data_len is decoded by param "data" */
350 if (req->data_len != data_len) {
351 rc = -EINVAL;
352 }
353 } else {
354 req->data_len = data_len;
355 req->data = spdk_dma_malloc(req->data_len > 0x1000 ? req->data_len : 0x1000, 0x1000, NULL);
356 if (!req->data) {
357 rc = -ENOMEM;
358 }
359 }
360
361 return rc;
362 }
363
364 static int
365 rpc_decode_metadata(const struct spdk_json_val *val, void *out)
366 {
367 struct rpc_send_nvme_cmd_req *req = (struct rpc_send_nvme_cmd_req *)out;
368 char *text = NULL;
369 size_t text_strlen;
370 int rc;
371
372 rc = spdk_json_decode_string(val, &text);
373 if (rc) {
374 return rc = val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
375 }
376 text_strlen = strlen(text);
377
378 if (req->md_len) {
379 /* md_len is decoded by param "metadata_len" */
380 if (req->md_len != spdk_base64_get_decoded_len(text_strlen)) {
381 rc = -EINVAL;
382 goto out;
383 }
384 } else {
385 req->md_len = spdk_base64_get_decoded_len(text_strlen);
386 req->md = spdk_dma_malloc(req->md_len, 0x1000, NULL);
387 if (!req->md) {
388 rc = -ENOMEM;
389 goto out;
390 }
391 }
392
393 rc = spdk_base64_urlsafe_decode(req->md, (size_t *)&req->md_len, text);
394
395 out:
396 free(text);
397 return rc;
398 }
399
400 static int
401 rpc_decode_metadata_len(const struct spdk_json_val *val, void *out)
402 {
403 struct rpc_send_nvme_cmd_req *req = (struct rpc_send_nvme_cmd_req *)out;
404 uint32_t md_len;
405 int rc;
406
407 rc = spdk_json_decode_uint32(val, &md_len);
408 if (rc) {
409 return rc;
410 }
411
412 if (req->md_len) {
413 /* md_len is decoded by param "metadata" */
414 if (req->md_len != md_len) {
415 rc = -EINVAL;
416 }
417 } else {
418 req->md_len = md_len;
419 req->md = spdk_dma_malloc(req->md_len, 0x1000, NULL);
420 if (!req->md) {
421 rc = -ENOMEM;
422 }
423 }
424
425 return rc;
426 }
427
428 static const struct spdk_json_object_decoder rpc_send_nvme_cmd_req_decoders[] = {
429 {"name", offsetof(struct rpc_send_nvme_cmd_req, name), spdk_json_decode_string},
430 {"cmd_type", offsetof(struct rpc_send_nvme_cmd_req, cmd_type), rpc_decode_cmd_type},
431 {"data_direction", offsetof(struct rpc_send_nvme_cmd_req, data_direction), rpc_decode_data_direction},
432 {"cmdbuf", offsetof(struct rpc_send_nvme_cmd_req, cmdbuf), rpc_decode_cmdbuf},
433 {"timeout_ms", offsetof(struct rpc_send_nvme_cmd_req, timeout_ms), spdk_json_decode_uint32, true},
434 {"data_len", 0, rpc_decode_data_len, true},
435 {"metadata_len", 0, rpc_decode_metadata_len, true},
436 {"data", 0, rpc_decode_data, true},
437 {"metadata", 0, rpc_decode_metadata, true},
438 };
439
440 static void
441 spdk_rpc_send_nvme_cmd(struct spdk_jsonrpc_request *request,
442 const struct spdk_json_val *params)
443 {
444 struct rpc_send_nvme_cmd_ctx *ctx;
445 int ret, error_code;
446
447 ctx = calloc(1, sizeof(*ctx));
448 if (!ctx) {
449 SPDK_ERRLOG("Failed at Malloc ctx\n");
450 error_code = SPDK_JSONRPC_ERROR_INTERNAL_ERROR;
451 ret = -ENOMEM;
452 goto invalid;
453 }
454
455 if (spdk_json_decode_object(params, rpc_send_nvme_cmd_req_decoders,
456 SPDK_COUNTOF(rpc_send_nvme_cmd_req_decoders),
457 &ctx->req)) {
458 SPDK_ERRLOG("spdk_json_decode_object failed\n");
459 error_code = SPDK_JSONRPC_ERROR_INVALID_PARAMS;
460 ret = -EINVAL;
461 goto invalid;
462 }
463
464 ctx->nvme_bdev_ctrlr = nvme_bdev_ctrlr_get_by_name(ctx->req.name);
465 if (ctx->nvme_bdev_ctrlr == NULL) {
466 SPDK_ERRLOG("Failed at device lookup\n");
467 error_code = SPDK_JSONRPC_ERROR_INVALID_PARAMS;
468 ret = -EINVAL;
469 goto invalid;
470 }
471
472 ctx->jsonrpc_request = request;
473
474 ret = rpc_send_nvme_cmd_exec(ctx);
475 if (ret < 0) {
476 SPDK_NOTICELOG("Failed at rpc_send_nvme_cmd_exec\n");
477 error_code = SPDK_JSONRPC_ERROR_INTERNAL_ERROR;
478 goto invalid;
479 }
480
481 return;
482
483 invalid:
484 spdk_jsonrpc_send_error_response(request, error_code, spdk_strerror(-ret));
485 free_rpc_send_nvme_cmd_ctx(ctx);
486 return;
487 }
488 SPDK_RPC_REGISTER("send_nvme_cmd", spdk_rpc_send_nvme_cmd, SPDK_RPC_RUNTIME)