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