1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2019-2021 Mellanox Technologies LTD. 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 36 #include "bdev_nvme.h" 37 #include "common.h" 38 39 #include "spdk/config.h" 40 41 #include "spdk/string.h" 42 #include "spdk/rpc.h" 43 #include "spdk/util.h" 44 45 #include "spdk/log.h" 46 #include "spdk/bdev_module.h" 47 48 struct open_descriptors { 49 void *desc; 50 struct spdk_bdev *bdev; 51 TAILQ_ENTRY(open_descriptors) tqlst; 52 struct spdk_thread *thread; 53 }; 54 typedef TAILQ_HEAD(, open_descriptors) open_descriptors_t; 55 56 static int 57 rpc_decode_action_on_timeout(const struct spdk_json_val *val, void *out) 58 { 59 enum spdk_bdev_timeout_action *action = out; 60 61 if (spdk_json_strequal(val, "none") == true) { 62 *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE; 63 } else if (spdk_json_strequal(val, "abort") == true) { 64 *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT; 65 } else if (spdk_json_strequal(val, "reset") == true) { 66 *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET; 67 } else { 68 SPDK_NOTICELOG("Invalid parameter value: action_on_timeout\n"); 69 return -EINVAL; 70 } 71 72 return 0; 73 } 74 75 static const struct spdk_json_object_decoder rpc_bdev_nvme_options_decoders[] = { 76 {"action_on_timeout", offsetof(struct spdk_bdev_nvme_opts, action_on_timeout), rpc_decode_action_on_timeout, true}, 77 {"timeout_us", offsetof(struct spdk_bdev_nvme_opts, timeout_us), spdk_json_decode_uint64, true}, 78 {"keep_alive_timeout_ms", offsetof(struct spdk_bdev_nvme_opts, keep_alive_timeout_ms), spdk_json_decode_uint32, true}, 79 {"retry_count", offsetof(struct spdk_bdev_nvme_opts, retry_count), spdk_json_decode_uint32, true}, 80 {"arbitration_burst", offsetof(struct spdk_bdev_nvme_opts, arbitration_burst), spdk_json_decode_uint32, true}, 81 {"low_priority_weight", offsetof(struct spdk_bdev_nvme_opts, low_priority_weight), spdk_json_decode_uint32, true}, 82 {"medium_priority_weight", offsetof(struct spdk_bdev_nvme_opts, medium_priority_weight), spdk_json_decode_uint32, true}, 83 {"high_priority_weight", offsetof(struct spdk_bdev_nvme_opts, high_priority_weight), spdk_json_decode_uint32, true}, 84 {"nvme_adminq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_adminq_poll_period_us), spdk_json_decode_uint64, true}, 85 {"nvme_ioq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_ioq_poll_period_us), spdk_json_decode_uint64, true}, 86 {"io_queue_requests", offsetof(struct spdk_bdev_nvme_opts, io_queue_requests), spdk_json_decode_uint32, true}, 87 {"delay_cmd_submit", offsetof(struct spdk_bdev_nvme_opts, delay_cmd_submit), spdk_json_decode_bool, true}, 88 }; 89 90 static void 91 rpc_bdev_nvme_set_options(struct spdk_jsonrpc_request *request, 92 const struct spdk_json_val *params) 93 { 94 struct spdk_bdev_nvme_opts opts; 95 int rc; 96 97 bdev_nvme_get_opts(&opts); 98 if (params && spdk_json_decode_object(params, rpc_bdev_nvme_options_decoders, 99 SPDK_COUNTOF(rpc_bdev_nvme_options_decoders), 100 &opts)) { 101 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 102 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 103 "spdk_json_decode_object failed"); 104 return; 105 } 106 107 rc = bdev_nvme_set_opts(&opts); 108 if (rc) { 109 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 110 return; 111 } 112 113 spdk_jsonrpc_send_bool_response(request, true); 114 115 return; 116 } 117 SPDK_RPC_REGISTER("bdev_nvme_set_options", rpc_bdev_nvme_set_options, 118 SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME) 119 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_set_options, set_bdev_nvme_options) 120 121 struct rpc_bdev_nvme_hotplug { 122 bool enabled; 123 uint64_t period_us; 124 }; 125 126 static const struct spdk_json_object_decoder rpc_bdev_nvme_hotplug_decoders[] = { 127 {"enable", offsetof(struct rpc_bdev_nvme_hotplug, enabled), spdk_json_decode_bool, false}, 128 {"period_us", offsetof(struct rpc_bdev_nvme_hotplug, period_us), spdk_json_decode_uint64, true}, 129 }; 130 131 static void 132 rpc_bdev_nvme_set_hotplug_done(void *ctx) 133 { 134 struct spdk_jsonrpc_request *request = ctx; 135 136 spdk_jsonrpc_send_bool_response(request, true); 137 } 138 139 static void 140 rpc_bdev_nvme_set_hotplug(struct spdk_jsonrpc_request *request, 141 const struct spdk_json_val *params) 142 { 143 struct rpc_bdev_nvme_hotplug req = {false, 0}; 144 int rc; 145 146 if (spdk_json_decode_object(params, rpc_bdev_nvme_hotplug_decoders, 147 SPDK_COUNTOF(rpc_bdev_nvme_hotplug_decoders), &req)) { 148 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 149 rc = -EINVAL; 150 goto invalid; 151 } 152 153 rc = bdev_nvme_set_hotplug(req.enabled, req.period_us, rpc_bdev_nvme_set_hotplug_done, 154 request); 155 if (rc) { 156 goto invalid; 157 } 158 159 return; 160 invalid: 161 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc)); 162 } 163 SPDK_RPC_REGISTER("bdev_nvme_set_hotplug", rpc_bdev_nvme_set_hotplug, SPDK_RPC_RUNTIME) 164 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_set_hotplug, set_bdev_nvme_hotplug) 165 166 struct rpc_bdev_nvme_attach_controller { 167 char *name; 168 char *trtype; 169 char *adrfam; 170 char *traddr; 171 char *trsvcid; 172 char *priority; 173 char *subnqn; 174 char *hostnqn; 175 char *hostaddr; 176 char *hostsvcid; 177 bool prchk_reftag; 178 bool prchk_guard; 179 struct spdk_nvme_ctrlr_opts opts; 180 }; 181 182 static void 183 free_rpc_bdev_nvme_attach_controller(struct rpc_bdev_nvme_attach_controller *req) 184 { 185 free(req->name); 186 free(req->trtype); 187 free(req->adrfam); 188 free(req->traddr); 189 free(req->trsvcid); 190 free(req->priority); 191 free(req->subnqn); 192 free(req->hostnqn); 193 free(req->hostaddr); 194 free(req->hostsvcid); 195 } 196 197 static const struct spdk_json_object_decoder rpc_bdev_nvme_attach_controller_decoders[] = { 198 {"name", offsetof(struct rpc_bdev_nvme_attach_controller, name), spdk_json_decode_string}, 199 {"trtype", offsetof(struct rpc_bdev_nvme_attach_controller, trtype), spdk_json_decode_string}, 200 {"traddr", offsetof(struct rpc_bdev_nvme_attach_controller, traddr), spdk_json_decode_string}, 201 202 {"adrfam", offsetof(struct rpc_bdev_nvme_attach_controller, adrfam), spdk_json_decode_string, true}, 203 {"trsvcid", offsetof(struct rpc_bdev_nvme_attach_controller, trsvcid), spdk_json_decode_string, true}, 204 {"priority", offsetof(struct rpc_bdev_nvme_attach_controller, priority), spdk_json_decode_string, true}, 205 {"subnqn", offsetof(struct rpc_bdev_nvme_attach_controller, subnqn), spdk_json_decode_string, true}, 206 {"hostnqn", offsetof(struct rpc_bdev_nvme_attach_controller, hostnqn), spdk_json_decode_string, true}, 207 {"hostaddr", offsetof(struct rpc_bdev_nvme_attach_controller, hostaddr), spdk_json_decode_string, true}, 208 {"hostsvcid", offsetof(struct rpc_bdev_nvme_attach_controller, hostsvcid), spdk_json_decode_string, true}, 209 210 {"prchk_reftag", offsetof(struct rpc_bdev_nvme_attach_controller, prchk_reftag), spdk_json_decode_bool, true}, 211 {"prchk_guard", offsetof(struct rpc_bdev_nvme_attach_controller, prchk_guard), spdk_json_decode_bool, true}, 212 {"hdgst", offsetof(struct rpc_bdev_nvme_attach_controller, opts.header_digest), spdk_json_decode_bool, true}, 213 {"ddgst", offsetof(struct rpc_bdev_nvme_attach_controller, opts.data_digest), spdk_json_decode_bool, true} 214 }; 215 216 #define NVME_MAX_BDEVS_PER_RPC 128 217 218 struct rpc_bdev_nvme_attach_controller_ctx { 219 struct rpc_bdev_nvme_attach_controller req; 220 uint32_t count; 221 const char *names[NVME_MAX_BDEVS_PER_RPC]; 222 struct spdk_jsonrpc_request *request; 223 }; 224 225 static void 226 rpc_bdev_nvme_attach_controller_done(void *cb_ctx, size_t bdev_count, int rc) 227 { 228 struct rpc_bdev_nvme_attach_controller_ctx *ctx = cb_ctx; 229 struct spdk_jsonrpc_request *request = ctx->request; 230 struct spdk_json_write_ctx *w; 231 size_t i; 232 233 if (rc < 0) { 234 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 235 goto exit; 236 } 237 238 w = spdk_jsonrpc_begin_result(request); 239 spdk_json_write_array_begin(w); 240 for (i = 0; i < bdev_count; i++) { 241 spdk_json_write_string(w, ctx->names[i]); 242 } 243 spdk_json_write_array_end(w); 244 spdk_jsonrpc_end_result(request, w); 245 246 exit: 247 free_rpc_bdev_nvme_attach_controller(&ctx->req); 248 free(ctx); 249 } 250 251 static void 252 rpc_bdev_nvme_attach_controller(struct spdk_jsonrpc_request *request, 253 const struct spdk_json_val *params) 254 { 255 struct rpc_bdev_nvme_attach_controller_ctx *ctx; 256 struct spdk_nvme_transport_id trid = {}; 257 struct spdk_nvme_host_id hostid = {}; 258 uint32_t prchk_flags = 0; 259 struct nvme_bdev_ctrlr *ctrlr = NULL; 260 size_t len, maxlen; 261 int rc; 262 263 ctx = calloc(1, sizeof(*ctx)); 264 if (!ctx) { 265 spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); 266 return; 267 } 268 269 spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.opts, sizeof(ctx->req.opts)); 270 271 if (spdk_json_decode_object(params, rpc_bdev_nvme_attach_controller_decoders, 272 SPDK_COUNTOF(rpc_bdev_nvme_attach_controller_decoders), 273 &ctx->req)) { 274 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 275 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 276 "spdk_json_decode_object failed"); 277 goto cleanup; 278 } 279 280 /* Parse trstring */ 281 rc = spdk_nvme_transport_id_populate_trstring(&trid, ctx->req.trtype); 282 if (rc < 0) { 283 SPDK_ERRLOG("Failed to parse trtype: %s\n", ctx->req.trtype); 284 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s", 285 ctx->req.trtype); 286 goto cleanup; 287 } 288 289 /* Parse trtype */ 290 rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype); 291 assert(rc == 0); 292 293 ctrlr = nvme_bdev_ctrlr_get_by_name(ctx->req.name); 294 295 /* Parse traddr */ 296 maxlen = sizeof(trid.traddr); 297 len = strnlen(ctx->req.traddr, maxlen); 298 if (len == maxlen) { 299 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "traddr too long: %s", 300 ctx->req.traddr); 301 goto cleanup; 302 } 303 memcpy(trid.traddr, ctx->req.traddr, len + 1); 304 305 /* Parse adrfam */ 306 if (ctx->req.adrfam) { 307 rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam); 308 if (rc < 0) { 309 SPDK_ERRLOG("Failed to parse adrfam: %s\n", ctx->req.adrfam); 310 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s", 311 ctx->req.adrfam); 312 goto cleanup; 313 } 314 } 315 316 /* Parse trsvcid */ 317 if (ctx->req.trsvcid) { 318 maxlen = sizeof(trid.trsvcid); 319 len = strnlen(ctx->req.trsvcid, maxlen); 320 if (len == maxlen) { 321 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "trsvcid too long: %s", 322 ctx->req.trsvcid); 323 goto cleanup; 324 } 325 memcpy(trid.trsvcid, ctx->req.trsvcid, len + 1); 326 } 327 328 /* Parse priority for the NVMe-oF transport connection */ 329 if (ctx->req.priority) { 330 trid.priority = spdk_strtol(ctx->req.priority, 10); 331 } 332 333 /* Parse subnqn */ 334 if (ctx->req.subnqn) { 335 maxlen = sizeof(trid.subnqn); 336 len = strnlen(ctx->req.subnqn, maxlen); 337 if (len == maxlen) { 338 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "subnqn too long: %s", 339 ctx->req.subnqn); 340 goto cleanup; 341 } 342 memcpy(trid.subnqn, ctx->req.subnqn, len + 1); 343 } 344 345 if (ctrlr && (ctx->req.hostaddr || ctx->req.hostnqn || ctx->req.hostsvcid || ctx->req.prchk_guard || 346 ctx->req.prchk_reftag)) { 347 goto conflicting_arguments; 348 } 349 350 if (ctx->req.hostaddr) { 351 maxlen = sizeof(hostid.hostaddr); 352 len = strnlen(ctx->req.hostaddr, maxlen); 353 if (len == maxlen) { 354 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostaddr too long: %s", 355 ctx->req.hostaddr); 356 goto cleanup; 357 } 358 memcpy(hostid.hostaddr, ctx->req.hostaddr, len + 1); 359 } 360 361 if (ctx->req.hostsvcid) { 362 maxlen = sizeof(hostid.hostsvcid); 363 len = strnlen(ctx->req.hostsvcid, maxlen); 364 if (len == maxlen) { 365 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostsvcid too long: %s", 366 ctx->req.hostsvcid); 367 goto cleanup; 368 } 369 memcpy(hostid.hostsvcid, ctx->req.hostsvcid, len + 1); 370 } 371 372 if (ctx->req.prchk_reftag) { 373 prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG; 374 } 375 376 if (ctx->req.prchk_guard) { 377 prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD; 378 } 379 380 ctx->request = request; 381 ctx->count = NVME_MAX_BDEVS_PER_RPC; 382 rc = bdev_nvme_create(&trid, &hostid, ctx->req.name, ctx->names, ctx->count, ctx->req.hostnqn, 383 prchk_flags, rpc_bdev_nvme_attach_controller_done, ctx, &ctx->req.opts); 384 if (rc) { 385 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 386 goto cleanup; 387 } 388 389 return; 390 391 conflicting_arguments: 392 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, 393 "Invalid agrgument list. Existing controller name cannot be combined with host information or PI options.\n"); 394 cleanup: 395 free_rpc_bdev_nvme_attach_controller(&ctx->req); 396 free(ctx); 397 } 398 SPDK_RPC_REGISTER("bdev_nvme_attach_controller", rpc_bdev_nvme_attach_controller, 399 SPDK_RPC_RUNTIME) 400 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_attach_controller, construct_nvme_bdev) 401 402 static void 403 rpc_dump_nvme_controller_info(struct spdk_json_write_ctx *w, 404 struct nvme_bdev_ctrlr *nvme_bdev_ctrlr) 405 { 406 struct spdk_nvme_transport_id *trid; 407 408 trid = nvme_bdev_ctrlr->connected_trid; 409 410 spdk_json_write_object_begin(w); 411 spdk_json_write_named_string(w, "name", nvme_bdev_ctrlr->name); 412 413 #ifdef SPDK_CONFIG_NVME_CUSE 414 size_t cuse_name_size = 128; 415 char cuse_name[cuse_name_size]; 416 417 int rc = spdk_nvme_cuse_get_ctrlr_name(nvme_bdev_ctrlr->ctrlr, cuse_name, &cuse_name_size); 418 if (rc == 0) { 419 spdk_json_write_named_string(w, "cuse_device", cuse_name); 420 } 421 #endif 422 423 spdk_json_write_named_object_begin(w, "trid"); 424 nvme_bdev_dump_trid_json(trid, w); 425 spdk_json_write_object_end(w); 426 427 spdk_json_write_object_end(w); 428 } 429 430 struct rpc_bdev_nvme_get_controllers { 431 char *name; 432 }; 433 434 static void 435 free_rpc_bdev_nvme_get_controllers(struct rpc_bdev_nvme_get_controllers *r) 436 { 437 free(r->name); 438 } 439 440 static const struct spdk_json_object_decoder rpc_bdev_nvme_get_controllers_decoders[] = { 441 {"name", offsetof(struct rpc_bdev_nvme_get_controllers, name), spdk_json_decode_string, true}, 442 }; 443 444 static void 445 rpc_bdev_nvme_get_controllers(struct spdk_jsonrpc_request *request, 446 const struct spdk_json_val *params) 447 { 448 struct rpc_bdev_nvme_get_controllers req = {}; 449 struct spdk_json_write_ctx *w; 450 struct nvme_bdev_ctrlr *ctrlr = NULL; 451 452 if (params && spdk_json_decode_object(params, rpc_bdev_nvme_get_controllers_decoders, 453 SPDK_COUNTOF(rpc_bdev_nvme_get_controllers_decoders), 454 &req)) { 455 SPDK_ERRLOG("spdk_json_decode_object failed\n"); 456 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 457 "spdk_json_decode_object failed"); 458 goto cleanup; 459 } 460 461 if (req.name) { 462 ctrlr = nvme_bdev_ctrlr_get_by_name(req.name); 463 if (ctrlr == NULL) { 464 SPDK_ERRLOG("ctrlr '%s' does not exist\n", req.name); 465 spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Controller %s does not exist", req.name); 466 goto cleanup; 467 } 468 } 469 470 w = spdk_jsonrpc_begin_result(request); 471 spdk_json_write_array_begin(w); 472 473 if (ctrlr != NULL) { 474 rpc_dump_nvme_controller_info(w, ctrlr); 475 } else { 476 for (ctrlr = nvme_bdev_first_ctrlr(); ctrlr; ctrlr = nvme_bdev_next_ctrlr(ctrlr)) { 477 rpc_dump_nvme_controller_info(w, ctrlr); 478 } 479 } 480 481 spdk_json_write_array_end(w); 482 483 spdk_jsonrpc_end_result(request, w); 484 485 cleanup: 486 free_rpc_bdev_nvme_get_controllers(&req); 487 } 488 SPDK_RPC_REGISTER("bdev_nvme_get_controllers", rpc_bdev_nvme_get_controllers, SPDK_RPC_RUNTIME) 489 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_get_controllers, get_nvme_controllers) 490 491 struct rpc_bdev_nvme_detach_controller { 492 char *name; 493 char *trtype; 494 char *adrfam; 495 char *traddr; 496 char *trsvcid; 497 char *subnqn; 498 }; 499 500 static void 501 free_rpc_bdev_nvme_detach_controller(struct rpc_bdev_nvme_detach_controller *req) 502 { 503 free(req->name); 504 free(req->trtype); 505 free(req->adrfam); 506 free(req->traddr); 507 free(req->trsvcid); 508 free(req->subnqn); 509 } 510 511 static const struct spdk_json_object_decoder rpc_bdev_nvme_detach_controller_decoders[] = { 512 {"name", offsetof(struct rpc_bdev_nvme_detach_controller, name), spdk_json_decode_string}, 513 {"trtype", offsetof(struct rpc_bdev_nvme_detach_controller, trtype), spdk_json_decode_string, true}, 514 {"traddr", offsetof(struct rpc_bdev_nvme_detach_controller, traddr), spdk_json_decode_string, true}, 515 {"adrfam", offsetof(struct rpc_bdev_nvme_detach_controller, adrfam), spdk_json_decode_string, true}, 516 {"trsvcid", offsetof(struct rpc_bdev_nvme_detach_controller, trsvcid), spdk_json_decode_string, true}, 517 {"subnqn", offsetof(struct rpc_bdev_nvme_detach_controller, subnqn), spdk_json_decode_string, true}, 518 }; 519 520 static void 521 rpc_bdev_nvme_detach_controller(struct spdk_jsonrpc_request *request, 522 const struct spdk_json_val *params) 523 { 524 struct rpc_bdev_nvme_detach_controller req = {NULL}; 525 struct spdk_nvme_transport_id trid = {}; 526 size_t len, maxlen; 527 int rc = 0; 528 bool all_trid_entries, one_trid_entry; 529 530 if (spdk_json_decode_object(params, rpc_bdev_nvme_detach_controller_decoders, 531 SPDK_COUNTOF(rpc_bdev_nvme_detach_controller_decoders), 532 &req)) { 533 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 534 "spdk_json_decode_object failed"); 535 goto cleanup; 536 } 537 538 all_trid_entries = req.trtype && req.traddr && req.adrfam && req.trsvcid && req.subnqn; 539 one_trid_entry = req.trtype || req.traddr || req.adrfam || req.trsvcid || req.subnqn; 540 541 if (all_trid_entries ^ one_trid_entry) { 542 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 543 "trtype, traddr, adrfam, trsvcid, subnqn must all be provided together or not at all."); 544 goto cleanup; 545 } 546 547 if (all_trid_entries) { 548 /* Parse trtype */ 549 rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, req.trtype); 550 if (rc < 0) { 551 SPDK_ERRLOG("Failed to parse trtype: %s\n", req.trtype); 552 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s", 553 req.trtype); 554 goto cleanup; 555 } 556 557 /* Parse traddr */ 558 maxlen = sizeof(trid.traddr); 559 len = strnlen(req.traddr, maxlen); 560 if (len == maxlen) { 561 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "traddr too long: %s", 562 req.traddr); 563 goto cleanup; 564 } 565 memcpy(trid.traddr, req.traddr, len + 1); 566 567 rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, req.adrfam); 568 if (rc < 0) { 569 SPDK_ERRLOG("Failed to parse adrfam: %s\n", req.adrfam); 570 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s", 571 req.adrfam); 572 goto cleanup; 573 } 574 575 maxlen = sizeof(trid.trsvcid); 576 len = strnlen(req.trsvcid, maxlen); 577 if (len == maxlen) { 578 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "trsvcid too long: %s", 579 req.trsvcid); 580 goto cleanup; 581 } 582 memcpy(trid.trsvcid, req.trsvcid, len + 1); 583 584 maxlen = sizeof(trid.subnqn); 585 len = strnlen(req.subnqn, maxlen); 586 if (len == maxlen) { 587 spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "subnqn too long: %s", 588 req.subnqn); 589 goto cleanup; 590 } 591 memcpy(trid.subnqn, req.subnqn, len + 1); 592 rc = bdev_nvme_delete(req.name, &trid); 593 } else { 594 rc = bdev_nvme_delete(req.name, NULL); 595 } 596 597 if (rc != 0) { 598 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 599 goto cleanup; 600 } 601 602 spdk_jsonrpc_send_bool_response(request, true); 603 604 cleanup: 605 free_rpc_bdev_nvme_detach_controller(&req); 606 } 607 SPDK_RPC_REGISTER("bdev_nvme_detach_controller", rpc_bdev_nvme_detach_controller, 608 SPDK_RPC_RUNTIME) 609 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_detach_controller, delete_nvme_controller) 610 611 struct rpc_apply_firmware { 612 char *filename; 613 char *bdev_name; 614 }; 615 616 static void 617 free_rpc_apply_firmware(struct rpc_apply_firmware *req) 618 { 619 free(req->filename); 620 free(req->bdev_name); 621 } 622 623 static const struct spdk_json_object_decoder rpc_apply_firmware_decoders[] = { 624 {"filename", offsetof(struct rpc_apply_firmware, filename), spdk_json_decode_string}, 625 {"bdev_name", offsetof(struct rpc_apply_firmware, bdev_name), spdk_json_decode_string}, 626 }; 627 628 struct firmware_update_info { 629 void *fw_image; 630 void *p; 631 unsigned int size; 632 unsigned int size_remaining; 633 unsigned int offset; 634 unsigned int transfer; 635 636 void *desc; 637 struct spdk_io_channel *ch; 638 struct spdk_jsonrpc_request *request; 639 struct spdk_nvme_ctrlr *ctrlr; 640 open_descriptors_t desc_head; 641 struct rpc_apply_firmware *req; 642 }; 643 644 static void 645 _apply_firmware_cleanup(void *ctx) 646 { 647 struct spdk_bdev_desc *desc = ctx; 648 649 spdk_bdev_close(desc); 650 } 651 652 static void 653 apply_firmware_cleanup(void *cb_arg) 654 { 655 struct open_descriptors *opt, *tmp; 656 struct firmware_update_info *firm_ctx = cb_arg; 657 658 if (!firm_ctx) { 659 return; 660 } 661 662 if (firm_ctx->fw_image) { 663 spdk_free(firm_ctx->fw_image); 664 } 665 666 if (firm_ctx->req) { 667 free_rpc_apply_firmware(firm_ctx->req); 668 free(firm_ctx->req); 669 } 670 671 if (firm_ctx->ch) { 672 spdk_put_io_channel(firm_ctx->ch); 673 } 674 675 TAILQ_FOREACH_SAFE(opt, &firm_ctx->desc_head, tqlst, tmp) { 676 TAILQ_REMOVE(&firm_ctx->desc_head, opt, tqlst); 677 /* Close the underlying bdev on its same opened thread. */ 678 if (opt->thread && opt->thread != spdk_get_thread()) { 679 spdk_thread_send_msg(opt->thread, _apply_firmware_cleanup, opt->desc); 680 } else { 681 spdk_bdev_close(opt->desc); 682 } 683 free(opt); 684 } 685 free(firm_ctx); 686 } 687 688 static void 689 apply_firmware_complete_reset(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 690 { 691 struct spdk_json_write_ctx *w; 692 struct firmware_update_info *firm_ctx = cb_arg; 693 694 spdk_bdev_free_io(bdev_io); 695 696 if (!success) { 697 spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 698 "firmware commit failed."); 699 apply_firmware_cleanup(firm_ctx); 700 return; 701 } 702 703 if (spdk_nvme_ctrlr_reset(firm_ctx->ctrlr) != 0) { 704 spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 705 "Controller reset failed."); 706 apply_firmware_cleanup(firm_ctx); 707 return; 708 } 709 710 w = spdk_jsonrpc_begin_result(firm_ctx->request); 711 spdk_json_write_string(w, "firmware commit succeeded. Controller reset in progress."); 712 spdk_jsonrpc_end_result(firm_ctx->request, w); 713 apply_firmware_cleanup(firm_ctx); 714 } 715 716 static void 717 apply_firmware_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) 718 { 719 struct spdk_nvme_cmd cmd = {}; 720 struct spdk_nvme_fw_commit fw_commit; 721 int slot = 0; 722 int rc; 723 struct firmware_update_info *firm_ctx = cb_arg; 724 enum spdk_nvme_fw_commit_action commit_action = SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG; 725 726 if (!success) { 727 spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 728 "firmware download failed ."); 729 spdk_bdev_free_io(bdev_io); 730 apply_firmware_cleanup(firm_ctx); 731 return; 732 } 733 734 firm_ctx->p += firm_ctx->transfer; 735 firm_ctx->offset += firm_ctx->transfer; 736 firm_ctx->size_remaining -= firm_ctx->transfer; 737 738 switch (firm_ctx->size_remaining) { 739 case 0: 740 /* firmware download completed. Commit firmware */ 741 memset(&fw_commit, 0, sizeof(struct spdk_nvme_fw_commit)); 742 fw_commit.fs = slot; 743 fw_commit.ca = commit_action; 744 745 cmd.opc = SPDK_NVME_OPC_FIRMWARE_COMMIT; 746 memcpy(&cmd.cdw10, &fw_commit, sizeof(uint32_t)); 747 rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, NULL, 0, 748 apply_firmware_complete_reset, firm_ctx); 749 if (rc) { 750 spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 751 "firmware commit failed."); 752 spdk_bdev_free_io(bdev_io); 753 apply_firmware_cleanup(firm_ctx); 754 return; 755 } 756 break; 757 default: 758 firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096); 759 cmd.opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; 760 761 cmd.cdw10 = spdk_nvme_bytes_to_numd(firm_ctx->transfer); 762 cmd.cdw11 = firm_ctx->offset >> 2; 763 rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, firm_ctx->p, 764 firm_ctx->transfer, apply_firmware_complete, firm_ctx); 765 if (rc) { 766 spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 767 "firmware download failed."); 768 spdk_bdev_free_io(bdev_io); 769 apply_firmware_cleanup(firm_ctx); 770 return; 771 } 772 break; 773 } 774 } 775 776 static void 777 apply_firmware_open_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) 778 { 779 } 780 781 static void 782 rpc_bdev_nvme_apply_firmware(struct spdk_jsonrpc_request *request, 783 const struct spdk_json_val *params) 784 { 785 int rc; 786 int fd = -1; 787 struct stat fw_stat; 788 struct spdk_nvme_ctrlr *ctrlr; 789 char msg[1024]; 790 struct spdk_bdev *bdev; 791 struct spdk_bdev *bdev2; 792 struct open_descriptors *opt; 793 struct spdk_bdev_desc *desc; 794 struct spdk_nvme_cmd *cmd; 795 struct firmware_update_info *firm_ctx; 796 797 firm_ctx = calloc(1, sizeof(struct firmware_update_info)); 798 if (!firm_ctx) { 799 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 800 "Memory allocation error."); 801 return; 802 } 803 firm_ctx->fw_image = NULL; 804 TAILQ_INIT(&firm_ctx->desc_head); 805 firm_ctx->request = request; 806 807 firm_ctx->req = calloc(1, sizeof(struct rpc_apply_firmware)); 808 if (!firm_ctx->req) { 809 snprintf(msg, sizeof(msg), "Memory allocation error."); 810 goto err; 811 } 812 813 if (spdk_json_decode_object(params, rpc_apply_firmware_decoders, 814 SPDK_COUNTOF(rpc_apply_firmware_decoders), firm_ctx->req)) { 815 snprintf(msg, sizeof(msg), "spdk_json_decode_object failed."); 816 goto err; 817 } 818 819 if ((bdev = spdk_bdev_get_by_name(firm_ctx->req->bdev_name)) == NULL) { 820 snprintf(msg, sizeof(msg), "bdev %s were not found", firm_ctx->req->bdev_name); 821 goto err; 822 } 823 824 if ((ctrlr = bdev_nvme_get_ctrlr(bdev)) == NULL) { 825 snprintf(msg, sizeof(msg), "Controller information for %s were not found.", 826 firm_ctx->req->bdev_name); 827 goto err; 828 } 829 firm_ctx->ctrlr = ctrlr; 830 831 for (bdev2 = spdk_bdev_first(); bdev2; bdev2 = spdk_bdev_next(bdev2)) { 832 833 if (bdev_nvme_get_ctrlr(bdev2) != ctrlr) { 834 continue; 835 } 836 837 if (!(opt = malloc(sizeof(struct open_descriptors)))) { 838 snprintf(msg, sizeof(msg), "Memory allocation error."); 839 goto err; 840 } 841 842 if (spdk_bdev_open_ext(spdk_bdev_get_name(bdev2), true, apply_firmware_open_cb, NULL, &desc) != 0) { 843 snprintf(msg, sizeof(msg), "Device %s is in use.", firm_ctx->req->bdev_name); 844 free(opt); 845 goto err; 846 } 847 848 /* Save the thread where the base device is opened */ 849 opt->thread = spdk_get_thread(); 850 851 opt->desc = desc; 852 opt->bdev = bdev; 853 TAILQ_INSERT_TAIL(&firm_ctx->desc_head, opt, tqlst); 854 } 855 856 /* 857 * find a descriptor associated with our bdev 858 */ 859 firm_ctx->desc = NULL; 860 TAILQ_FOREACH(opt, &firm_ctx->desc_head, tqlst) { 861 if (opt->bdev == bdev) { 862 firm_ctx->desc = opt->desc; 863 break; 864 } 865 } 866 867 if (!firm_ctx->desc) { 868 snprintf(msg, sizeof(msg), "No descriptor were found."); 869 goto err; 870 } 871 872 firm_ctx->ch = spdk_bdev_get_io_channel(firm_ctx->desc); 873 if (!firm_ctx->ch) { 874 snprintf(msg, sizeof(msg), "No channels were found."); 875 goto err; 876 } 877 878 fd = open(firm_ctx->req->filename, O_RDONLY); 879 if (fd < 0) { 880 snprintf(msg, sizeof(msg), "open file failed."); 881 goto err; 882 } 883 884 rc = fstat(fd, &fw_stat); 885 if (rc < 0) { 886 close(fd); 887 snprintf(msg, sizeof(msg), "fstat failed."); 888 goto err; 889 } 890 891 firm_ctx->size = fw_stat.st_size; 892 if (fw_stat.st_size % 4) { 893 close(fd); 894 snprintf(msg, sizeof(msg), "Firmware image size is not multiple of 4."); 895 goto err; 896 } 897 898 firm_ctx->fw_image = spdk_zmalloc(firm_ctx->size, 4096, NULL, 899 SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA); 900 if (!firm_ctx->fw_image) { 901 close(fd); 902 snprintf(msg, sizeof(msg), "Memory allocation error."); 903 goto err; 904 } 905 firm_ctx->p = firm_ctx->fw_image; 906 907 if (read(fd, firm_ctx->p, firm_ctx->size) != ((ssize_t)(firm_ctx->size))) { 908 close(fd); 909 snprintf(msg, sizeof(msg), "Read firmware image failed!"); 910 goto err; 911 } 912 close(fd); 913 914 firm_ctx->offset = 0; 915 firm_ctx->size_remaining = firm_ctx->size; 916 firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096); 917 918 cmd = malloc(sizeof(struct spdk_nvme_cmd)); 919 if (!cmd) { 920 snprintf(msg, sizeof(msg), "Memory allocation error."); 921 goto err; 922 } 923 memset(cmd, 0, sizeof(struct spdk_nvme_cmd)); 924 cmd->opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; 925 926 cmd->cdw10 = spdk_nvme_bytes_to_numd(firm_ctx->transfer); 927 cmd->cdw11 = firm_ctx->offset >> 2; 928 929 rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, cmd, firm_ctx->p, 930 firm_ctx->transfer, apply_firmware_complete, firm_ctx); 931 if (rc == 0) { 932 /* normal return here. */ 933 return; 934 } 935 936 free(cmd); 937 snprintf(msg, sizeof(msg), "Read firmware image failed!"); 938 err: 939 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg); 940 apply_firmware_cleanup(firm_ctx); 941 } 942 SPDK_RPC_REGISTER("bdev_nvme_apply_firmware", rpc_bdev_nvme_apply_firmware, SPDK_RPC_RUNTIME) 943 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(bdev_nvme_apply_firmware, apply_nvme_firmware) 944 945 struct rpc_bdev_nvme_transport_stat_ctx { 946 struct spdk_jsonrpc_request *request; 947 struct spdk_json_write_ctx *w; 948 }; 949 950 static void 951 rpc_bdev_nvme_rdma_stats(struct spdk_json_write_ctx *w, 952 struct spdk_nvme_transport_poll_group_stat *stat) 953 { 954 struct spdk_nvme_rdma_device_stat *device_stats; 955 uint32_t i; 956 957 spdk_json_write_named_array_begin(w, "devices"); 958 959 for (i = 0; i < stat->rdma.num_devices; i++) { 960 device_stats = &stat->rdma.device_stats[i]; 961 spdk_json_write_object_begin(w); 962 spdk_json_write_named_string(w, "dev_name", device_stats->name); 963 spdk_json_write_named_uint64(w, "polls", device_stats->polls); 964 spdk_json_write_named_uint64(w, "idle_polls", device_stats->idle_polls); 965 spdk_json_write_named_uint64(w, "completions", device_stats->completions); 966 spdk_json_write_named_uint64(w, "queued_requests", device_stats->queued_requests); 967 spdk_json_write_named_uint64(w, "total_send_wrs", device_stats->total_send_wrs); 968 spdk_json_write_named_uint64(w, "send_doorbell_updates", device_stats->send_doorbell_updates); 969 spdk_json_write_named_uint64(w, "total_recv_wrs", device_stats->total_recv_wrs); 970 spdk_json_write_named_uint64(w, "recv_doorbell_updates", device_stats->recv_doorbell_updates); 971 spdk_json_write_object_end(w); 972 } 973 spdk_json_write_array_end(w); 974 } 975 976 static void 977 rpc_bdev_nvme_pcie_stats(struct spdk_json_write_ctx *w, 978 struct spdk_nvme_transport_poll_group_stat *stat) 979 { 980 spdk_json_write_named_uint64(w, "polls", stat->pcie.polls); 981 spdk_json_write_named_uint64(w, "idle_polls", stat->pcie.idle_polls); 982 spdk_json_write_named_uint64(w, "completions", stat->pcie.completions); 983 spdk_json_write_named_uint64(w, "cq_doorbell_updates", stat->pcie.cq_doorbell_updates); 984 spdk_json_write_named_uint64(w, "queued_requests", stat->pcie.queued_requests); 985 spdk_json_write_named_uint64(w, "submitted_requests", stat->pcie.submitted_requests); 986 spdk_json_write_named_uint64(w, "sq_doobell_updates", stat->pcie.sq_doobell_updates); 987 } 988 989 static void 990 rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i) 991 { 992 struct rpc_bdev_nvme_transport_stat_ctx *ctx; 993 struct spdk_io_channel *ch; 994 struct nvme_bdev_poll_group *bdev_group; 995 struct spdk_nvme_poll_group *group; 996 struct spdk_nvme_poll_group_stat *stat; 997 struct spdk_nvme_transport_poll_group_stat *tr_stat; 998 uint32_t j; 999 int rc; 1000 1001 ctx = spdk_io_channel_iter_get_ctx(i); 1002 ch = spdk_io_channel_iter_get_channel(i); 1003 bdev_group = spdk_io_channel_get_ctx(ch); 1004 group = bdev_group->group; 1005 1006 rc = spdk_nvme_poll_group_get_stats(group, &stat); 1007 if (rc) { 1008 spdk_for_each_channel_continue(i, rc); 1009 return; 1010 } 1011 1012 spdk_json_write_object_begin(ctx->w); 1013 spdk_json_write_named_string(ctx->w, "thread", spdk_thread_get_name(spdk_get_thread())); 1014 spdk_json_write_named_array_begin(ctx->w, "transports"); 1015 1016 for (j = 0; j < stat->num_transports; j++) { 1017 tr_stat = stat->transport_stat[j]; 1018 spdk_json_write_object_begin(ctx->w); 1019 spdk_json_write_named_string(ctx->w, "trname", spdk_nvme_transport_id_trtype_str(tr_stat->trtype)); 1020 1021 switch (stat->transport_stat[j]->trtype) { 1022 case SPDK_NVME_TRANSPORT_RDMA: 1023 rpc_bdev_nvme_rdma_stats(ctx->w, tr_stat); 1024 break; 1025 case SPDK_NVME_TRANSPORT_PCIE: 1026 rpc_bdev_nvme_pcie_stats(ctx->w, tr_stat); 1027 break; 1028 default: 1029 SPDK_WARNLOG("Can't handle trtype %d %s\n", tr_stat->trtype, 1030 spdk_nvme_transport_id_trtype_str(tr_stat->trtype)); 1031 } 1032 spdk_json_write_object_end(ctx->w); 1033 } 1034 /* transports array */ 1035 spdk_json_write_array_end(ctx->w); 1036 spdk_json_write_object_end(ctx->w); 1037 1038 spdk_nvme_poll_group_free_stats(group, stat); 1039 spdk_for_each_channel_continue(i, 0); 1040 } 1041 1042 static void 1043 rpc_bdev_nvme_stats_done(struct spdk_io_channel_iter *i, int status) 1044 { 1045 struct rpc_bdev_nvme_transport_stat_ctx *ctx = spdk_io_channel_iter_get_ctx(i); 1046 1047 spdk_json_write_array_end(ctx->w); 1048 spdk_json_write_object_end(ctx->w); 1049 spdk_jsonrpc_end_result(ctx->request, ctx->w); 1050 free(ctx); 1051 } 1052 1053 static void 1054 rpc_bdev_nvme_get_transport_statistics(struct spdk_jsonrpc_request *request, 1055 const struct spdk_json_val *params) 1056 { 1057 struct rpc_bdev_nvme_transport_stat_ctx *ctx; 1058 1059 if (params) { 1060 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 1061 "'bdev_nvme_get_transport_statistics' requires no arguments"); 1062 return; 1063 } 1064 1065 ctx = calloc(1, sizeof(*ctx)); 1066 if (!ctx) { 1067 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 1068 "Memory allocation error"); 1069 return; 1070 } 1071 ctx->request = request; 1072 ctx->w = spdk_jsonrpc_begin_result(ctx->request); 1073 spdk_json_write_object_begin(ctx->w); 1074 spdk_json_write_named_array_begin(ctx->w, "poll_groups"); 1075 1076 spdk_for_each_channel(&g_nvme_bdev_ctrlrs, 1077 rpc_bdev_nvme_stats_per_channel, 1078 ctx, 1079 rpc_bdev_nvme_stats_done); 1080 } 1081 SPDK_RPC_REGISTER("bdev_nvme_get_transport_statistics", rpc_bdev_nvme_get_transport_statistics, 1082 SPDK_RPC_RUNTIME) 1083