diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 7051ba168..3a93198db 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -1033,6 +1033,54 @@ Example response: } ~~~ +## get_nvme_controllers {#rpc_get_nvme_controllers} + +Get information about NVMe controllers. + +### Parameters + +The user may specify no parameters in order to list all NVMe controllers, or one NVMe controller may be +specified by name. + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Optional | string | NVMe controller name + +### Response + +The response is an array of objects containing information about the requested NVMe controllers. + +### Example + +Example request: +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "method": "get_nvme_controllers", + "params": { + "name": "Nvme0" + } +} +~~~ + +Example response: +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "name": "Nvme0", + "trid": { + "trtype": "PCIe", + "traddr": "0000:05:00.0" + } + } + ] +} +~~~ + ## delete_nvme_controller {#rpc_delete_nvme_controller} Delete NVMe controller. diff --git a/lib/bdev/nvme/bdev_nvme.c b/lib/bdev/nvme/bdev_nvme.c index 2eb8705de..07c3b6ced 100644 --- a/lib/bdev/nvme/bdev_nvme.c +++ b/lib/bdev/nvme/bdev_nvme.c @@ -156,6 +156,18 @@ spdk_bdev_nvme_lookup_ctrlr(const char *ctrlr_name) return NULL; } +struct nvme_ctrlr * +spdk_bdev_nvme_first_ctrlr(void) +{ + return TAILQ_FIRST(&g_nvme_ctrlrs); +} + +struct nvme_ctrlr * +spdk_bdev_nvme_next_ctrlr(struct nvme_ctrlr *prev) +{ + return TAILQ_NEXT(prev, tailq); +} + static int bdev_nvme_get_ctx_size(void) { diff --git a/lib/bdev/nvme/bdev_nvme.h b/lib/bdev/nvme/bdev_nvme.h index 025d1e591..b8c458e88 100644 --- a/lib/bdev/nvme/bdev_nvme.h +++ b/lib/bdev/nvme/bdev_nvme.h @@ -88,6 +88,8 @@ void spdk_bdev_nvme_dump_trid_json(struct spdk_nvme_transport_id *trid, struct spdk_nvme_qpair *spdk_bdev_nvme_get_io_qpair(struct spdk_io_channel *ctrlr_io_ch); struct nvme_ctrlr *spdk_bdev_nvme_lookup_ctrlr(const char *ctrlr_name); +struct nvme_ctrlr *spdk_bdev_nvme_first_ctrlr(void); +struct nvme_ctrlr *spdk_bdev_nvme_next_ctrlr(struct nvme_ctrlr *prev); void spdk_bdev_nvme_get_opts(struct spdk_bdev_nvme_opts *opts); int spdk_bdev_nvme_set_opts(const struct spdk_bdev_nvme_opts *opts); int spdk_bdev_nvme_set_hotplug(bool enabled, uint64_t period_us, spdk_thread_fn cb, void *cb_ctx); diff --git a/lib/bdev/nvme/bdev_nvme_rpc.c b/lib/bdev/nvme/bdev_nvme_rpc.c index a9154d4e5..0312a7562 100644 --- a/lib/bdev/nvme/bdev_nvme_rpc.c +++ b/lib/bdev/nvme/bdev_nvme_rpc.c @@ -268,6 +268,90 @@ invalid: } SPDK_RPC_REGISTER("construct_nvme_bdev", spdk_rpc_construct_nvme_bdev, SPDK_RPC_RUNTIME) +static void +spdk_rpc_dump_nvme_controller_info(struct spdk_json_write_ctx *w, + struct nvme_ctrlr *nvme_ctrlr) +{ + struct spdk_nvme_transport_id *trid; + + trid = &nvme_ctrlr->trid; + + spdk_json_write_object_begin(w); + spdk_json_write_named_string(w, "name", nvme_ctrlr->name); + + spdk_json_write_named_object_begin(w, "trid"); + spdk_bdev_nvme_dump_trid_json(trid, w); + spdk_json_write_object_end(w); + + spdk_json_write_object_end(w); +} + +struct rpc_get_nvme_controllers { + char *name; +}; + +static void +free_rpc_get_nvme_controllers(struct rpc_get_nvme_controllers *r) +{ + free(r->name); +} + +static const struct spdk_json_object_decoder rpc_get_nvme_controllers_decoders[] = { + {"name", offsetof(struct rpc_get_nvme_controllers, name), spdk_json_decode_string, true}, +}; + +static void +spdk_rpc_get_nvme_controllers(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_get_nvme_controllers req = {}; + struct spdk_json_write_ctx *w; + struct nvme_ctrlr *ctrlr = NULL; + + if (params && spdk_json_decode_object(params, rpc_get_nvme_controllers_decoders, + SPDK_COUNTOF(rpc_get_nvme_controllers_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + goto invalid; + } + + if (req.name) { + ctrlr = spdk_bdev_nvme_lookup_ctrlr(req.name); + if (ctrlr == NULL) { + SPDK_ERRLOG("ctrlr '%s' does not exist\n", req.name); + goto invalid; + } + } + + free_rpc_get_nvme_controllers(&req); + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_array_begin(w); + + if (ctrlr != NULL) { + spdk_rpc_dump_nvme_controller_info(w, ctrlr); + } else { + for (ctrlr = spdk_bdev_nvme_first_ctrlr(); ctrlr; ctrlr = spdk_bdev_nvme_next_ctrlr(ctrlr)) { + spdk_rpc_dump_nvme_controller_info(w, ctrlr); + } + } + + spdk_json_write_array_end(w); + + spdk_jsonrpc_end_result(request, w); + + return; + +invalid: + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + + free_rpc_get_nvme_controllers(&req); +} +SPDK_RPC_REGISTER("get_nvme_controllers", spdk_rpc_get_nvme_controllers, SPDK_RPC_RUNTIME) + struct rpc_delete_nvme { char *name; }; diff --git a/scripts/rpc.py b/scripts/rpc.py index 90e6604ba..d6ff9d264 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -291,6 +291,16 @@ if __name__ == "__main__": p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn') p.set_defaults(func=construct_nvme_bdev) + @call_cmd + def get_nvme_controllers(args): + print_dict(rpc.nvme.get_nvme_controllers(args.client, + name=args.name)) + + p = subparsers.add_parser( + 'get_nvme_controllers', help='Display current NVMe controllers list or required NVMe controller') + p.add_argument('-n', '--name', help="Name of the NVMe controller. Example: Nvme0", required=False) + p.set_defaults(func=get_nvme_controllers) + @call_cmd def delete_nvme_controller(args): rpc.bdev.delete_nvme_controller(args.client, diff --git a/scripts/rpc/nvme.py b/scripts/rpc/nvme.py index fed8740e2..a889474bc 100644 --- a/scripts/rpc/nvme.py +++ b/scripts/rpc/nvme.py @@ -37,3 +37,18 @@ def send_nvme_cmd(client, name, cmd_type, data_direction, cmdbuf, params['timeout_ms'] = timeout_ms return client.call('send_nvme_cmd', params) + + +def get_nvme_controllers(client, name=None): + """Get information about NVMe controllers. + + Args: + name: NVMe controller name to query (optional; if omitted, query all NVMe controllers) + + Returns: + List of NVMe controller information objects. + """ + params = {} + if name: + params['name'] = name + return client.call('get_nvme_controllers', params)