4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 #include "spdk/stdinc.h"
35 #include "spdk/string.h"
37 #include "spdk/util.h"
38 #include "spdk/bdev_module.h"
39 #include "spdk_internal/log.h"
41 #include "bdev_nvme.h"
43 #include "spdk/base64.h"
45 enum spdk_nvme_rpc_type
{
50 struct rpc_send_nvme_cmd_req
{
58 struct spdk_nvme_cmd
*cmdbuf
;
63 struct rpc_send_nvme_cmd_resp
{
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
;
78 free_rpc_send_nvme_cmd_ctx(struct rpc_send_nvme_cmd_ctx
*ctx
)
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
);
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
)
97 resp
->cpl_text
= malloc(spdk_base64_get_encoded_strlen(sizeof(*cpl
)) + 1);
98 if (!resp
->cpl_text
) {
101 spdk_base64_urlsafe_encode(resp
->cpl_text
, cpl
, sizeof(*cpl
));
103 if (req
->data_direction
== SPDK_NVME_DATA_CONTROLLER_TO_HOST
) {
105 resp
->data_text
= malloc(spdk_base64_get_encoded_strlen(req
->data_len
) + 1);
106 if (!resp
->data_text
) {
109 spdk_base64_urlsafe_encode(resp
->data_text
, req
->data
, req
->data_len
);
112 resp
->md_text
= malloc(spdk_base64_get_encoded_strlen(req
->md_len
) + 1);
113 if (!resp
->md_text
) {
116 spdk_base64_urlsafe_encode(resp
->md_text
, req
->md
, req
->md_len
);
124 spdk_rpc_send_nvme_cmd_complete(struct rpc_send_nvme_cmd_ctx
*ctx
, const struct spdk_nvme_cpl
*cpl
)
126 struct spdk_jsonrpc_request
*request
= ctx
->jsonrpc_request
;
127 struct spdk_json_write_ctx
*w
;
130 ret
= rpc_send_nvme_cmd_resp_construct(&ctx
->resp
, &ctx
->req
, cpl
);
132 spdk_jsonrpc_send_error_response(request
, SPDK_JSONRPC_ERROR_INTERNAL_ERROR
,
133 spdk_strerror(-ret
));
137 w
= spdk_jsonrpc_begin_result(request
);
142 spdk_json_write_object_begin(w
);
143 spdk_json_write_named_string(w
, "cpl", ctx
->resp
.cpl_text
);
145 if (ctx
->resp
.data_text
) {
146 spdk_json_write_named_string(w
, "data", ctx
->resp
.data_text
);
149 if (ctx
->resp
.md_text
) {
150 spdk_json_write_named_string(w
, "metadata", ctx
->resp
.md_text
);
153 spdk_json_write_object_end(w
);
154 spdk_jsonrpc_end_result(request
, w
);
157 free_rpc_send_nvme_cmd_ctx(ctx
);
162 nvme_rpc_bdev_nvme_cb(void *ref
, const struct spdk_nvme_cpl
*cpl
)
164 struct rpc_send_nvme_cmd_ctx
*ctx
= (struct rpc_send_nvme_cmd_ctx
*)ref
;
166 if (ctx
->ctrlr_io_ch
) {
167 spdk_put_io_channel(ctx
->ctrlr_io_ch
);
168 ctx
->ctrlr_io_ch
= NULL
;
171 spdk_rpc_send_nvme_cmd_complete(ctx
, cpl
);
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
)
178 struct nvme_bdev_ctrlr
*_nvme_ctrlr
= ctx
->nvme_bdev_ctrlr
;
181 ret
= spdk_nvme_ctrlr_cmd_admin_raw(_nvme_ctrlr
->ctrlr
, cmd
, buf
,
182 nbytes
, nvme_rpc_bdev_nvme_cb
, ctx
);
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
,
192 struct nvme_bdev_ctrlr
*_nvme_ctrlr
= ctx
->nvme_bdev_ctrlr
;
193 struct spdk_nvme_qpair
*io_qpair
;
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
);
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
);
202 spdk_put_io_channel(ctx
->ctrlr_io_ch
);
210 rpc_send_nvme_cmd_exec(struct rpc_send_nvme_cmd_ctx
*ctx
)
212 struct rpc_send_nvme_cmd_req
*req
= &ctx
->req
;
215 switch (req
->cmd_type
) {
217 ret
= nvme_rpc_admin_cmd_bdev_nvme(ctx
, req
->cmdbuf
, req
->data
,
218 req
->data_len
, req
->timeout_ms
);
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
);
230 rpc_decode_cmd_type(const struct spdk_json_val
*val
, void *out
)
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
;
239 SPDK_NOTICELOG("Invalid parameter value: cmd_type\n");
247 rpc_decode_data_direction(const struct spdk_json_val
*val
, void *out
)
249 int *data_direction
= out
;
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
;
256 SPDK_NOTICELOG("Invalid parameter value: data_direction\n");
264 rpc_decode_cmdbuf(const struct spdk_json_val
*val
, void *out
)
267 size_t text_strlen
, raw_len
;
268 struct spdk_nvme_cmd
*cmdbuf
, **_cmdbuf
= out
;
271 rc
= spdk_json_decode_string(val
, &text
);
273 return val
->type
== SPDK_JSON_VAL_STRING
? -ENOMEM
: -EINVAL
;
276 text_strlen
= strlen(text
);
277 raw_len
= spdk_base64_get_decoded_len(text_strlen
);
278 cmdbuf
= malloc(raw_len
);
284 rc
= spdk_base64_urlsafe_decode(cmdbuf
, &raw_len
, text
);
288 if (raw_len
!= sizeof(*cmdbuf
)) {
301 rpc_decode_data(const struct spdk_json_val
*val
, void *out
)
303 struct rpc_send_nvme_cmd_req
*req
= (struct rpc_send_nvme_cmd_req
*)out
;
308 rc
= spdk_json_decode_string(val
, &text
);
310 return val
->type
== SPDK_JSON_VAL_STRING
? -ENOMEM
: -EINVAL
;
312 text_strlen
= strlen(text
);
315 /* data_len is decoded by param "data_len" */
316 if (req
->data_len
!= spdk_base64_get_decoded_len(text_strlen
)) {
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
);
329 rc
= spdk_base64_urlsafe_decode(req
->data
, (size_t *)&req
->data_len
, text
);
337 rpc_decode_data_len(const struct spdk_json_val
*val
, void *out
)
339 struct rpc_send_nvme_cmd_req
*req
= (struct rpc_send_nvme_cmd_req
*)out
;
343 rc
= spdk_json_decode_uint32(val
, &data_len
);
349 /* data_len is decoded by param "data" */
350 if (req
->data_len
!= data_len
) {
354 req
->data_len
= data_len
;
355 req
->data
= spdk_dma_malloc(req
->data_len
> 0x1000 ? req
->data_len
: 0x1000, 0x1000, NULL
);
365 rpc_decode_metadata(const struct spdk_json_val
*val
, void *out
)
367 struct rpc_send_nvme_cmd_req
*req
= (struct rpc_send_nvme_cmd_req
*)out
;
372 rc
= spdk_json_decode_string(val
, &text
);
374 return rc
= val
->type
== SPDK_JSON_VAL_STRING
? -ENOMEM
: -EINVAL
;
376 text_strlen
= strlen(text
);
379 /* md_len is decoded by param "metadata_len" */
380 if (req
->md_len
!= spdk_base64_get_decoded_len(text_strlen
)) {
385 req
->md_len
= spdk_base64_get_decoded_len(text_strlen
);
386 req
->md
= spdk_dma_malloc(req
->md_len
, 0x1000, NULL
);
393 rc
= spdk_base64_urlsafe_decode(req
->md
, (size_t *)&req
->md_len
, text
);
401 rpc_decode_metadata_len(const struct spdk_json_val
*val
, void *out
)
403 struct rpc_send_nvme_cmd_req
*req
= (struct rpc_send_nvme_cmd_req
*)out
;
407 rc
= spdk_json_decode_uint32(val
, &md_len
);
413 /* md_len is decoded by param "metadata" */
414 if (req
->md_len
!= md_len
) {
418 req
->md_len
= md_len
;
419 req
->md
= spdk_dma_malloc(req
->md_len
, 0x1000, NULL
);
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},
441 spdk_rpc_send_nvme_cmd(struct spdk_jsonrpc_request
*request
,
442 const struct spdk_json_val
*params
)
444 struct rpc_send_nvme_cmd_ctx
*ctx
;
447 ctx
= calloc(1, sizeof(*ctx
));
449 SPDK_ERRLOG("Failed at Malloc ctx\n");
450 error_code
= SPDK_JSONRPC_ERROR_INTERNAL_ERROR
;
455 if (spdk_json_decode_object(params
, rpc_send_nvme_cmd_req_decoders
,
456 SPDK_COUNTOF(rpc_send_nvme_cmd_req_decoders
),
458 SPDK_ERRLOG("spdk_json_decode_object failed\n");
459 error_code
= SPDK_JSONRPC_ERROR_INVALID_PARAMS
;
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
;
472 ctx
->jsonrpc_request
= request
;
474 ret
= rpc_send_nvme_cmd_exec(ctx
);
476 SPDK_NOTICELOG("Failed at rpc_send_nvme_cmd_exec\n");
477 error_code
= SPDK_JSONRPC_ERROR_INTERNAL_ERROR
;
484 spdk_jsonrpc_send_error_response(request
, error_code
, spdk_strerror(-ret
));
485 free_rpc_send_nvme_cmd_ctx(ctx
);
488 SPDK_RPC_REGISTER("send_nvme_cmd", spdk_rpc_send_nvme_cmd
, SPDK_RPC_RUNTIME
)