diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 20c4a246e..e5572a44d 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -5466,6 +5466,94 @@ Example response: } ~~~ +# OPAL + +## bdev_opal_create {#rpc_bdev_opal_create} + +This is used to create an OPAL virtual bdev. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +nvme_ctrlr_name | Required | string | name of nvme ctrlr that supports OPAL +nsid | Required | number | namespace ID +locking_range_id | Required | number | OPAL locking range ID +range_start | Required | number | locking range start LBA +range_length | Required | number | locking range length +password | Required | string | admin password of OPAL + +### Response + +The response is the name of created OPAL virtual bdev. + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "method": "bdev_opal_create", + "id": 1, + "params": { + "nvme_ctrlr_name": "nvme0", + "nsid": 1, + "locking_range_id": 1, + "range_start": 0, + "range_length": 4096, + "password": "*****" + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": "nvme0n1r1" +} +~~~ + +## bdev_opal_delete {#rpc_bdev_opal_delete} + +This is used to delete OPAL vbdev. + +### Parameters + +Name | Optional | Type | Description +----------------------- | -------- | ----------- | ----------- +bdev_name | Required | string | name of OPAL vbdev +password | Required | string | admin password + +### Example + +Example request: + +~~~ +{ + "jsonrpc": "2.0", + "method": "bdev_opal_delete", + "id": 1, + "params": { + "bdev_name": "nvme0n1r1", + "password": "*****" + } +} +~~~ + +Example response: + +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + # Notifications ## notify_get_types {#rpc_notify_get_types} diff --git a/module/bdev/nvme/Makefile b/module/bdev/nvme/Makefile index e66dee58a..536af9c1b 100644 --- a/module/bdev/nvme/Makefile +++ b/module/bdev/nvme/Makefile @@ -36,7 +36,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk C_SRCS = bdev_nvme.c bdev_nvme_rpc.c nvme_rpc.c common.c ifeq ($(OS),Linux) -C_SRCS += bdev_ftl.c bdev_ftl_rpc.c vbdev_opal.c +C_SRCS += bdev_ftl.c bdev_ftl_rpc.c vbdev_opal.c vbdev_opal_rpc.c endif LIBNAME = bdev_nvme diff --git a/module/bdev/nvme/vbdev_opal_rpc.c b/module/bdev/nvme/vbdev_opal_rpc.c new file mode 100644 index 000000000..842773cd7 --- /dev/null +++ b/module/bdev/nvme/vbdev_opal_rpc.c @@ -0,0 +1,149 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/rpc.h" +#include "spdk/util.h" +#include "spdk/string.h" +#include "spdk_internal/log.h" + +#include "vbdev_opal.h" + +struct rpc_bdev_opal_create { + char *nvme_ctrlr_name; + uint32_t nsid; + uint16_t locking_range_id; + uint64_t range_start; + uint64_t range_length; + char *password; +}; + +static void +free_rpc_bdev_opal_create(struct rpc_bdev_opal_create *req) +{ + free(req->nvme_ctrlr_name); + free(req->password); +} + +static const struct spdk_json_object_decoder rpc_bdev_opal_create_decoders[] = { + {"nvme_ctrlr_name", offsetof(struct rpc_bdev_opal_create, nvme_ctrlr_name), spdk_json_decode_string}, + {"nsid", offsetof(struct rpc_bdev_opal_create, nsid), spdk_json_decode_uint32}, + {"locking_range_id", offsetof(struct rpc_bdev_opal_create, locking_range_id), spdk_json_decode_uint16}, + {"range_start", offsetof(struct rpc_bdev_opal_create, range_start), spdk_json_decode_uint64}, + {"range_length", offsetof(struct rpc_bdev_opal_create, range_length), spdk_json_decode_uint64}, + {"password", offsetof(struct rpc_bdev_opal_create, password), spdk_json_decode_string}, +}; + +static void +spdk_rpc_bdev_opal_create(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_bdev_opal_create req = {}; + struct spdk_json_write_ctx *w; + char *opal_bdev_name; + int rc; + + if (spdk_json_decode_object(params, rpc_bdev_opal_create_decoders, + SPDK_COUNTOF(rpc_bdev_opal_create_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + goto out; + } + + rc = spdk_vbdev_opal_create(req.nvme_ctrlr_name, req.nsid, req.locking_range_id, req.range_start, + req.range_length, req.password); + if (rc != 0) { + spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Failed to create opal vbdev from '%s': %s", + req.nvme_ctrlr_name, spdk_strerror(-rc)); + goto out; + } + + w = spdk_jsonrpc_begin_result(request); + opal_bdev_name = spdk_sprintf_alloc("%sn%dr%d", req.nvme_ctrlr_name, req.nsid, + req.locking_range_id); + spdk_json_write_string(w, opal_bdev_name); + spdk_jsonrpc_end_result(request, w); + free(opal_bdev_name); + +out: + free_rpc_bdev_opal_create(&req); +} +SPDK_RPC_REGISTER("bdev_opal_create", spdk_rpc_bdev_opal_create, SPDK_RPC_RUNTIME) + +struct rpc_bdev_opal_delete { + char *bdev_name; + char *password; +}; + +static void +free_rpc_bdev_opal_delete(struct rpc_bdev_opal_delete *req) +{ + free(req->bdev_name); + free(req->password); +} + +static const struct spdk_json_object_decoder rpc_bdev_opal_delete_decoders[] = { + {"bdev_name", offsetof(struct rpc_bdev_opal_delete, bdev_name), spdk_json_decode_string}, + {"password", offsetof(struct rpc_bdev_opal_delete, password), spdk_json_decode_string}, +}; + +static void +spdk_rpc_bdev_opal_delete(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_bdev_opal_delete req = {}; + struct spdk_json_write_ctx *w; + int rc; + + if (spdk_json_decode_object(params, rpc_bdev_opal_delete_decoders, + SPDK_COUNTOF(rpc_bdev_opal_delete_decoders), + &req)) { + SPDK_ERRLOG("spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + goto out; + } + + rc = spdk_vbdev_opal_destruct(req.bdev_name, req.password); + if (rc < 0) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, spdk_strerror(-rc)); + goto out; + } + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_bool(w, true); + spdk_jsonrpc_end_result(request, w); +out: + free_rpc_bdev_opal_delete(&req); +} +SPDK_RPC_REGISTER("bdev_opal_delete", spdk_rpc_bdev_opal_delete, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index 3bcf2fc8d..2ea417b6a 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2013,6 +2013,35 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse domain:bus:device.function format or domain.bus.device.function format""") p.set_defaults(func=ioat_scan_copy_engine) + # opal + def bdev_opal_create(args): + print_json(rpc.bdev.bdev_opal_create(args.client, + nvme_ctrlr_name=args.nvme_ctrlr_name, + nsid=args.nsid, + locking_range_id=args.locking_range_id, + range_start=args.range_start, + range_length=args.range_length, + password=args.password)) + + p = subparsers.add_parser('bdev_opal_create', help="""Create opal bdev on specified NVMe controller""") + p.add_argument('-b', '--nvme-ctrlr-name', help='nvme ctrlr name', required=True) + p.add_argument('-n', '--nsid', help='namespace ID (only support nsid=1 for now)', type=int, required=True) + p.add_argument('-i', '--locking-range-id', help='locking range id', type=int, required=True) + p.add_argument('-s', '--range-start', help='locking range start LBA', type=int, required=True) + p.add_argument('-l', '--range-length', help='locking range length (in blocks)', type=int, required=True) + p.add_argument('-p', '--password', help='admin password', required=True) + p.set_defaults(func=bdev_opal_create) + + def bdev_opal_delete(args): + rpc.bdev.bdev_opal_delete(args.client, + bdev_name=args.bdev_name, + password=args.password) + + p = subparsers.add_parser('bdev_opal_delete', help="""delete a virtual opal bdev""") + p.add_argument('-b', '--bdev-name', help='opal virtual bdev', required=True) + p.add_argument('-p', '--password', help='admin password', required=True) + p.set_defaults(func=bdev_opal_delete) + # bdev_nvme_send_cmd def bdev_nvme_send_cmd(args): print_dict(rpc.nvme.bdev_nvme_send_cmd(args.client, diff --git a/scripts/rpc/bdev.py b/scripts/rpc/bdev.py index a60d3dead..4d2c8da46 100644 --- a/scripts/rpc/bdev.py +++ b/scripts/rpc/bdev.py @@ -663,6 +663,47 @@ def bdev_passthru_delete(client, name): return client.call('bdev_passthru_delete', params) +def bdev_opal_create(client, nvme_ctrlr_name, nsid, locking_range_id, range_start, range_length, password): + """Create opal virtual block devices from a base nvme bdev. + + Args: + nvme_ctrlr_name: name of the nvme ctrlr + nsid: namespace ID of nvme ctrlr + locking_range_id: locking range ID corresponding to this virtual bdev + range_start: start address of this locking range + range_length: length of this locking range + password: admin password of base nvme bdev + + Returns: + Name of the new created block devices. + """ + params = { + 'nvme_ctrlr_name': nvme_ctrlr_name, + 'nsid': nsid, + 'locking_range_id': locking_range_id, + 'range_start': range_start, + 'range_length': range_length, + 'password': password, + } + + return client.call('bdev_opal_create', params) + + +def bdev_opal_delete(client, bdev_name, password): + """Delete opal virtual bdev from the system. + + Args: + bdev_name: name of opal vbdev to delete + password: admin password of base nvme bdev + """ + params = { + 'bdev_name': bdev_name, + 'password': password, + } + + return client.call('bdev_opal_delete', params) + + @deprecated_alias('construct_split_vbdev') def bdev_split_create(client, base_bdev, split_count, split_size_mb=None): """Create split block devices from a base bdev.