]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/module/bdev/nvme/nvme_rpc.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / module / 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_bdev_nvme_send_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_bdev_nvme_send_cmd_resp {
64 char *cpl_text;
65 char *data_text;
66 char *md_text;
67 };
68
69 struct rpc_bdev_nvme_send_cmd_ctx {
70 struct spdk_jsonrpc_request *jsonrpc_request;
71 struct rpc_bdev_nvme_send_cmd_req req;
72 struct rpc_bdev_nvme_send_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_bdev_nvme_send_cmd_ctx(struct rpc_bdev_nvme_send_cmd_ctx *ctx)
79 {
80 assert(ctx != NULL);
81
82 free(ctx->req.name);
83 free(ctx->req.cmdbuf);
84 spdk_free(ctx->req.data);
85 spdk_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_bdev_nvme_send_cmd_resp_construct(struct rpc_bdev_nvme_send_cmd_resp *resp,
94 struct rpc_bdev_nvme_send_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 rpc_bdev_nvme_send_cmd_complete(struct rpc_bdev_nvme_send_cmd_ctx *ctx,
125 const struct spdk_nvme_cpl *cpl)
126 {
127 struct spdk_jsonrpc_request *request = ctx->jsonrpc_request;
128 struct spdk_json_write_ctx *w;
129 int ret;
130
131 ret = rpc_bdev_nvme_send_cmd_resp_construct(&ctx->resp, &ctx->req, cpl);
132 if (ret) {
133 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
134 spdk_strerror(-ret));
135 goto out;
136 }
137
138 w = spdk_jsonrpc_begin_result(request);
139 spdk_json_write_object_begin(w);
140 spdk_json_write_named_string(w, "cpl", ctx->resp.cpl_text);
141
142 if (ctx->resp.data_text) {
143 spdk_json_write_named_string(w, "data", ctx->resp.data_text);
144 }
145
146 if (ctx->resp.md_text) {
147 spdk_json_write_named_string(w, "metadata", ctx->resp.md_text);
148 }
149
150 spdk_json_write_object_end(w);
151 spdk_jsonrpc_end_result(request, w);
152
153 out:
154 free_rpc_bdev_nvme_send_cmd_ctx(ctx);
155 return;
156 }
157
158 static void
159 nvme_rpc_bdev_nvme_cb(void *ref, const struct spdk_nvme_cpl *cpl)
160 {
161 struct rpc_bdev_nvme_send_cmd_ctx *ctx = (struct rpc_bdev_nvme_send_cmd_ctx *)ref;
162
163 if (ctx->ctrlr_io_ch) {
164 spdk_put_io_channel(ctx->ctrlr_io_ch);
165 ctx->ctrlr_io_ch = NULL;
166 }
167
168 rpc_bdev_nvme_send_cmd_complete(ctx, cpl);
169 }
170
171 static int
172 nvme_rpc_admin_cmd_bdev_nvme(struct rpc_bdev_nvme_send_cmd_ctx *ctx, struct spdk_nvme_cmd *cmd,
173 void *buf, uint32_t nbytes, uint32_t timeout_ms)
174 {
175 struct nvme_bdev_ctrlr *_nvme_ctrlr = ctx->nvme_bdev_ctrlr;
176 int ret;
177
178 ret = spdk_nvme_ctrlr_cmd_admin_raw(_nvme_ctrlr->ctrlr, cmd, buf,
179 nbytes, nvme_rpc_bdev_nvme_cb, ctx);
180
181 return ret;
182 }
183
184 static int
185 nvme_rpc_io_cmd_bdev_nvme(struct rpc_bdev_nvme_send_cmd_ctx *ctx, struct spdk_nvme_cmd *cmd,
186 void *buf, uint32_t nbytes, void *md_buf, uint32_t md_len,
187 uint32_t timeout_ms)
188 {
189 struct nvme_bdev_ctrlr *_nvme_ctrlr = ctx->nvme_bdev_ctrlr;
190 struct spdk_nvme_qpair *io_qpair;
191 int ret;
192
193 ctx->ctrlr_io_ch = spdk_get_io_channel(_nvme_ctrlr->ctrlr);
194 io_qpair = bdev_nvme_get_io_qpair(ctx->ctrlr_io_ch);
195
196 ret = spdk_nvme_ctrlr_cmd_io_raw_with_md(_nvme_ctrlr->ctrlr, io_qpair,
197 cmd, buf, nbytes, md_buf, nvme_rpc_bdev_nvme_cb, ctx);
198 if (ret) {
199 spdk_put_io_channel(ctx->ctrlr_io_ch);
200 }
201
202 return ret;
203
204 }
205
206 static int
207 rpc_bdev_nvme_send_cmd_exec(struct rpc_bdev_nvme_send_cmd_ctx *ctx)
208 {
209 struct rpc_bdev_nvme_send_cmd_req *req = &ctx->req;
210 int ret = -EINVAL;
211
212 switch (req->cmd_type) {
213 case NVME_ADMIN_CMD:
214 ret = nvme_rpc_admin_cmd_bdev_nvme(ctx, req->cmdbuf, req->data,
215 req->data_len, req->timeout_ms);
216 break;
217 case NVME_IO_CMD:
218 ret = nvme_rpc_io_cmd_bdev_nvme(ctx, req->cmdbuf, req->data,
219 req->data_len, req->md, req->md_len, req->timeout_ms);
220 break;
221 }
222
223 return ret;
224 }
225
226 static int
227 rpc_decode_cmd_type(const struct spdk_json_val *val, void *out)
228 {
229 int *cmd_type = out;
230
231 if (spdk_json_strequal(val, "admin") == true) {
232 *cmd_type = NVME_ADMIN_CMD;
233 } else if (spdk_json_strequal(val, "io") == true) {
234 *cmd_type = NVME_IO_CMD;
235 } else {
236 SPDK_NOTICELOG("Invalid parameter value: cmd_type\n");
237 return -EINVAL;
238 }
239
240 return 0;
241 }
242
243 static int
244 rpc_decode_data_direction(const struct spdk_json_val *val, void *out)
245 {
246 int *data_direction = out;
247
248 if (spdk_json_strequal(val, "h2c") == true) {
249 *data_direction = SPDK_NVME_DATA_HOST_TO_CONTROLLER;
250 } else if (spdk_json_strequal(val, "c2h") == true) {
251 *data_direction = SPDK_NVME_DATA_CONTROLLER_TO_HOST;
252 } else {
253 SPDK_NOTICELOG("Invalid parameter value: data_direction\n");
254 return -EINVAL;
255 }
256
257 return 0;
258 }
259
260 static int
261 rpc_decode_cmdbuf(const struct spdk_json_val *val, void *out)
262 {
263 char *text = NULL;
264 size_t text_strlen, raw_len;
265 struct spdk_nvme_cmd *cmdbuf, **_cmdbuf = out;
266 int rc;
267
268 rc = spdk_json_decode_string(val, &text);
269 if (rc) {
270 return val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
271 }
272
273 text_strlen = strlen(text);
274 raw_len = spdk_base64_get_decoded_len(text_strlen);
275 cmdbuf = malloc(raw_len);
276 if (!cmdbuf) {
277 rc = -ENOMEM;
278 goto out;
279 }
280
281 rc = spdk_base64_urlsafe_decode(cmdbuf, &raw_len, text);
282 if (rc) {
283 free(cmdbuf);
284 goto out;
285 }
286 if (raw_len != sizeof(*cmdbuf)) {
287 rc = -EINVAL;
288 free(cmdbuf);
289 goto out;
290 }
291
292 *_cmdbuf = cmdbuf;
293
294 out:
295 free(text);
296 return rc;
297 }
298
299 static int
300 rpc_decode_data(const struct spdk_json_val *val, void *out)
301 {
302 struct rpc_bdev_nvme_send_cmd_req *req = (struct rpc_bdev_nvme_send_cmd_req *)out;
303 char *text = NULL;
304 size_t text_strlen;
305 int rc;
306
307 rc = spdk_json_decode_string(val, &text);
308 if (rc) {
309 return val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
310 }
311 text_strlen = strlen(text);
312
313 if (req->data_len) {
314 /* data_len is decoded by param "data_len" */
315 if (req->data_len != spdk_base64_get_decoded_len(text_strlen)) {
316 rc = -EINVAL;
317 goto out;
318 }
319 } else {
320 req->data_len = spdk_base64_get_decoded_len(text_strlen);
321 req->data = spdk_malloc(req->data_len > 0x1000 ? req->data_len : 0x1000, 0x1000,
322 NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
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_bdev_nvme_send_cmd_req *req = (struct rpc_bdev_nvme_send_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_malloc(req->data_len > 0x1000 ? req->data_len : 0x1000, 0x1000,
356 NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
357 if (!req->data) {
358 rc = -ENOMEM;
359 }
360 }
361
362 return rc;
363 }
364
365 static int
366 rpc_decode_metadata(const struct spdk_json_val *val, void *out)
367 {
368 struct rpc_bdev_nvme_send_cmd_req *req = (struct rpc_bdev_nvme_send_cmd_req *)out;
369 char *text = NULL;
370 size_t text_strlen;
371 int rc;
372
373 rc = spdk_json_decode_string(val, &text);
374 if (rc) {
375 return rc = val->type == SPDK_JSON_VAL_STRING ? -ENOMEM : -EINVAL;
376 }
377 text_strlen = strlen(text);
378
379 if (req->md_len) {
380 /* md_len is decoded by param "metadata_len" */
381 if (req->md_len != spdk_base64_get_decoded_len(text_strlen)) {
382 rc = -EINVAL;
383 goto out;
384 }
385 } else {
386 req->md_len = spdk_base64_get_decoded_len(text_strlen);
387 req->md = spdk_malloc(req->md_len, 0x1000, NULL,
388 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
389 if (!req->md) {
390 rc = -ENOMEM;
391 goto out;
392 }
393 }
394
395 rc = spdk_base64_urlsafe_decode(req->md, (size_t *)&req->md_len, text);
396
397 out:
398 free(text);
399 return rc;
400 }
401
402 static int
403 rpc_decode_metadata_len(const struct spdk_json_val *val, void *out)
404 {
405 struct rpc_bdev_nvme_send_cmd_req *req = (struct rpc_bdev_nvme_send_cmd_req *)out;
406 uint32_t md_len;
407 int rc;
408
409 rc = spdk_json_decode_uint32(val, &md_len);
410 if (rc) {
411 return rc;
412 }
413
414 if (req->md_len) {
415 /* md_len is decoded by param "metadata" */
416 if (req->md_len != md_len) {
417 rc = -EINVAL;
418 }
419 } else {
420 req->md_len = md_len;
421 req->md = spdk_malloc(req->md_len, 0x1000, NULL,
422 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
423 if (!req->md) {
424 rc = -ENOMEM;
425 }
426 }
427
428 return rc;
429 }
430
431 static const struct spdk_json_object_decoder rpc_bdev_nvme_send_cmd_req_decoders[] = {
432 {"name", offsetof(struct rpc_bdev_nvme_send_cmd_req, name), spdk_json_decode_string},
433 {"cmd_type", offsetof(struct rpc_bdev_nvme_send_cmd_req, cmd_type), rpc_decode_cmd_type},
434 {"data_direction", offsetof(struct rpc_bdev_nvme_send_cmd_req, data_direction), rpc_decode_data_direction},
435 {"cmdbuf", offsetof(struct rpc_bdev_nvme_send_cmd_req, cmdbuf), rpc_decode_cmdbuf},
436 {"timeout_ms", offsetof(struct rpc_bdev_nvme_send_cmd_req, timeout_ms), spdk_json_decode_uint32, true},
437 {"data_len", 0, rpc_decode_data_len, true},
438 {"metadata_len", 0, rpc_decode_metadata_len, true},
439 {"data", 0, rpc_decode_data, true},
440 {"metadata", 0, rpc_decode_metadata, true},
441 };
442
443 static void
444 rpc_bdev_nvme_send_cmd(struct spdk_jsonrpc_request *request,
445 const struct spdk_json_val *params)
446 {
447 struct rpc_bdev_nvme_send_cmd_ctx *ctx;
448 int ret, error_code;
449
450 ctx = calloc(1, sizeof(*ctx));
451 if (!ctx) {
452 SPDK_ERRLOG("Failed at Malloc ctx\n");
453 error_code = SPDK_JSONRPC_ERROR_INTERNAL_ERROR;
454 ret = -ENOMEM;
455 goto invalid;
456 }
457
458 if (spdk_json_decode_object(params, rpc_bdev_nvme_send_cmd_req_decoders,
459 SPDK_COUNTOF(rpc_bdev_nvme_send_cmd_req_decoders),
460 &ctx->req)) {
461 SPDK_ERRLOG("spdk_json_decode_object failed\n");
462 error_code = SPDK_JSONRPC_ERROR_INVALID_PARAMS;
463 ret = -EINVAL;
464 goto invalid;
465 }
466
467 ctx->nvme_bdev_ctrlr = nvme_bdev_ctrlr_get_by_name(ctx->req.name);
468 if (ctx->nvme_bdev_ctrlr == NULL) {
469 SPDK_ERRLOG("Failed at device lookup\n");
470 error_code = SPDK_JSONRPC_ERROR_INVALID_PARAMS;
471 ret = -EINVAL;
472 goto invalid;
473 }
474
475 ctx->jsonrpc_request = request;
476
477 ret = rpc_bdev_nvme_send_cmd_exec(ctx);
478 if (ret < 0) {
479 SPDK_NOTICELOG("Failed at rpc_bdev_nvme_send_cmd_exec\n");
480 error_code = SPDK_JSONRPC_ERROR_INTERNAL_ERROR;
481 goto invalid;
482 }
483
484 return;
485
486 invalid:
487 spdk_jsonrpc_send_error_response(request, error_code, spdk_strerror(-ret));
488 free_rpc_bdev_nvme_send_cmd_ctx(ctx);
489 return;
490 }
491 SPDK_RPC_REGISTER("bdev_nvme_send_cmd", rpc_bdev_nvme_send_cmd, SPDK_RPC_RUNTIME)
492 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_send_cmd, send_nvme_cmd)