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