xref: /spdk/module/bdev/nvme/nvme_rpc.c (revision b30d57cdad6d2bc75cc1e4e2ebbcebcb0d98dcfa)
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/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 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)
493