diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ad7a6891..fbd66bcb68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,6 +92,8 @@ The default value is `false`. New APIs, `spdk_nvme_ctrlr_reset_async` and `spdk_nvme_ctrlr_reset_poll_async`, have been added to reset a controller asynchronously. +New RPC `bdev_nvme_reset_controller` was added, to reset an NVMe controller. + ### rpc New RPC `bdev_rbd_register_cluster` and `bdev_rbd_unregister_cluster` was added, it allows to create diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index e9096bb2c4..dc66e54c0e 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -3006,6 +3006,43 @@ Example response: } ~~~ +## bdev_nvme_reset_controller {#rpc_bdev_nvme_reset_controller} + +Reset NVMe controller. + +Returns true if the controller reset was successful, false otherwise. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +name | Required | string | NVMe controller name + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "method": "bdev_nvme_reset_controller", + "params": { + "name": "Nvme0" + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ## bdev_nvme_cuse_register {#rpc_bdev_nvme_cuse_register} Register CUSE device on NVMe controller. diff --git a/module/bdev/nvme/bdev_nvme.c b/module/bdev/nvme/bdev_nvme.c index 6740720b65..8c62777853 100644 --- a/module/bdev/nvme/bdev_nvme.c +++ b/module/bdev/nvme/bdev_nvme.c @@ -660,6 +660,19 @@ bdev_nvme_reset(struct nvme_ctrlr *nvme_ctrlr) return 0; } +int +bdev_nvme_reset_rpc(struct nvme_ctrlr *nvme_ctrlr, bdev_nvme_reset_cb cb_fn, void *cb_arg) +{ + int rc; + + rc = bdev_nvme_reset(nvme_ctrlr); + if (rc == 0) { + nvme_ctrlr->reset_cb_fn = cb_fn; + nvme_ctrlr->reset_cb_arg = cb_arg; + } + return rc; +} + static void bdev_nvme_reset_io_complete(void *cb_arg, int rc) { diff --git a/module/bdev/nvme/bdev_nvme.h b/module/bdev/nvme/bdev_nvme.h index 9b2e5d735f..dc76684b83 100644 --- a/module/bdev/nvme/bdev_nvme.h +++ b/module/bdev/nvme/bdev_nvme.h @@ -92,4 +92,16 @@ struct spdk_nvme_ctrlr *bdev_nvme_get_ctrlr(struct spdk_bdev *bdev); */ int bdev_nvme_delete(const char *name, const struct spdk_nvme_transport_id *trid); +/** + * Reset NVMe controller. + * + * \param nvme_ctrlr The specified NVMe controller to reset + * \param cb_fn Function to be called back after reset completes + * \param cb_arg Argument for callback function + * \return zero on success. Negated errno on the following error conditions: + * -EBUSY: controller is being destroyed. + * -EAGAIN: controller is already being reset. + */ +int bdev_nvme_reset_rpc(struct nvme_ctrlr *nvme_ctrlr, bdev_nvme_reset_cb cb_fn, void *cb_arg); + #endif /* SPDK_BDEV_NVME_H */ diff --git a/module/bdev/nvme/bdev_nvme_rpc.c b/module/bdev/nvme/bdev_nvme_rpc.c index 4c0ddde09e..d333e5bbdf 100644 --- a/module/bdev/nvme/bdev_nvme_rpc.c +++ b/module/bdev/nvme/bdev_nvme_rpc.c @@ -1089,3 +1089,59 @@ rpc_bdev_nvme_get_transport_statistics(struct spdk_jsonrpc_request *request, } SPDK_RPC_REGISTER("bdev_nvme_get_transport_statistics", rpc_bdev_nvme_get_transport_statistics, SPDK_RPC_RUNTIME) + +struct rpc_bdev_nvme_reset_controller_req { + char *name; +}; + +static void +free_rpc_bdev_nvme_reset_controller_req(struct rpc_bdev_nvme_reset_controller_req *r) +{ + free(r->name); +} + +static const struct spdk_json_object_decoder rpc_bdev_nvme_reset_controller_req_decoders[] = { + {"name", offsetof(struct rpc_bdev_nvme_reset_controller_req, name), spdk_json_decode_string}, +}; + +static void +_rpc_bdev_nvme_reset_controller_cb(void *cb_arg, int rc) +{ + struct spdk_jsonrpc_request *request = cb_arg; + + spdk_jsonrpc_send_bool_response(request, rc == 0); +} + +static void +rpc_bdev_nvme_reset_controller(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_bdev_nvme_reset_controller_req req = {NULL}; + struct nvme_ctrlr *nvme_ctrlr; + int rc; + + if (spdk_json_decode_object(params, rpc_bdev_nvme_reset_controller_req_decoders, + SPDK_COUNTOF(rpc_bdev_nvme_reset_controller_req_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(EINVAL)); + goto cleanup; + } + + nvme_ctrlr = nvme_ctrlr_get_by_name(req.name); + if (nvme_ctrlr == NULL) { + SPDK_ERRLOG("Failed at device lookup\n"); + spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV)); + goto cleanup; + } + + rc = bdev_nvme_reset_rpc(nvme_ctrlr, _rpc_bdev_nvme_reset_controller_cb, request); + if (rc != 0) { + SPDK_NOTICELOG("Failed at bdev_nvme_reset_rpc\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(-rc)); + } + +cleanup: + free_rpc_bdev_nvme_reset_controller_req(&req); +} +SPDK_RPC_REGISTER("bdev_nvme_reset_controller", rpc_bdev_nvme_reset_controller, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index 496480dec9..8b4940b753 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -589,6 +589,14 @@ if __name__ == "__main__": p.add_argument('-n', '--subnqn', help='NVMe-oF target subnqn') p.set_defaults(func=bdev_nvme_detach_controller) + def bdev_nvme_reset_controller(args): + rpc.bdev.bdev_nvme_reset_controller(args.client, name=args.name) + + p = subparsers.add_parser('bdev_nvme_reset_controller', + help='Reset an NVMe controller') + p.add_argument('name', help="Name of the NVMe controller") + p.set_defaults(func=bdev_nvme_reset_controller) + def bdev_nvme_cuse_register(args): rpc.bdev.bdev_nvme_cuse_register(args.client, name=args.name) diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index 66c751f1d5..cf40b951cc 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -611,6 +611,18 @@ def bdev_nvme_detach_controller(client, name, trtype=None, traddr=None, return client.call('bdev_nvme_detach_controller', params) +def bdev_nvme_reset_controller(client, name): + """Reset NVMe controller. + + Args: + name: controller name + """ + + params = {'name': name} + + return client.call('bdev_nvme_reset_controller', params) + + def bdev_nvme_cuse_register(client, name): """Register CUSE devices on NVMe controller.