1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 4 * All rights reserved. 5 */ 6 7 #include "spdk/rpc.h" 8 #include "spdk/util.h" 9 #include "spdk/bdev_module.h" 10 #include "spdk/string.h" 11 #include "spdk/log.h" 12 13 #include "bdev_ftl.h" 14 15 static const struct spdk_json_object_decoder rpc_bdev_ftl_create_decoders[] = { 16 {"name", offsetof(struct spdk_ftl_conf, name), spdk_json_decode_string}, 17 {"base_bdev", offsetof(struct spdk_ftl_conf, base_bdev), spdk_json_decode_string}, 18 {"uuid", offsetof(struct spdk_ftl_conf, uuid), spdk_json_decode_uuid, true}, 19 {"cache", offsetof(struct spdk_ftl_conf, cache_bdev), spdk_json_decode_string}, 20 { 21 "overprovisioning", offsetof(struct spdk_ftl_conf, overprovisioning), 22 spdk_json_decode_uint64, true 23 }, 24 { 25 "l2p_dram_limit", offsetof(struct spdk_ftl_conf, l2p_dram_limit), 26 spdk_json_decode_uint64, true 27 }, 28 { 29 "core_mask", offsetof(struct spdk_ftl_conf, core_mask), 30 spdk_json_decode_string, true 31 }, 32 { 33 "fast_shutdown", offsetof(struct spdk_ftl_conf, fast_shutdown), 34 spdk_json_decode_bool, true 35 }, 36 }; 37 38 static void 39 rpc_bdev_ftl_create_cb(const struct ftl_bdev_info *bdev_info, void *ctx, int status) 40 { 41 struct spdk_jsonrpc_request *request = ctx; 42 struct spdk_json_write_ctx *w; 43 44 if (status) { 45 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 46 "Failed to create FTL bdev: %s", 47 spdk_strerror(-status)); 48 return; 49 } 50 51 w = spdk_jsonrpc_begin_result(request); 52 spdk_json_write_object_begin(w); 53 spdk_json_write_named_string(w, "name", bdev_info->name); 54 spdk_json_write_named_uuid(w, "uuid", &bdev_info->uuid); 55 spdk_json_write_object_end(w); 56 spdk_jsonrpc_end_result(request, w); 57 } 58 59 static void 60 rpc_bdev_ftl_create(struct spdk_jsonrpc_request *request, 61 const struct spdk_json_val *params) 62 { 63 struct spdk_ftl_conf conf = {}; 64 struct spdk_json_write_ctx *w; 65 int rc; 66 67 spdk_ftl_get_default_conf(&conf, sizeof(conf)); 68 69 if (spdk_json_decode_object(params, rpc_bdev_ftl_create_decoders, 70 SPDK_COUNTOF(rpc_bdev_ftl_create_decoders), 71 &conf)) { 72 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 73 "Invalid parameters"); 74 goto out; 75 } 76 77 if (spdk_uuid_is_null(&conf.uuid)) { 78 conf.mode |= SPDK_FTL_MODE_CREATE; 79 } 80 81 rc = bdev_ftl_create_bdev(&conf, rpc_bdev_ftl_create_cb, request); 82 if (rc == -ENODEV) { 83 rc = bdev_ftl_defer_init(&conf); 84 if (rc == 0) { 85 w = spdk_jsonrpc_begin_result(request); 86 spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", conf.name); 87 spdk_jsonrpc_end_result(request, w); 88 } 89 } 90 91 if (rc) { 92 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 93 "Failed to create FTL bdev: %s", 94 spdk_strerror(-rc)); 95 } 96 out: 97 spdk_ftl_conf_deinit(&conf); 98 } 99 SPDK_RPC_REGISTER("bdev_ftl_create", rpc_bdev_ftl_create, SPDK_RPC_RUNTIME) 100 101 static void 102 rpc_bdev_ftl_load(struct spdk_jsonrpc_request *request, 103 const struct spdk_json_val *params) 104 { 105 rpc_bdev_ftl_create(request, params); 106 } 107 SPDK_RPC_REGISTER("bdev_ftl_load", rpc_bdev_ftl_load, SPDK_RPC_RUNTIME) 108 109 struct rpc_delete_ftl { 110 char *name; 111 bool fast_shutdown; 112 }; 113 114 static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { 115 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 116 { 117 "fast_shutdown", offsetof(struct rpc_delete_ftl, fast_shutdown), 118 spdk_json_decode_bool, true 119 }, 120 }; 121 122 static void 123 rpc_bdev_ftl_delete_cb(void *cb_arg, int bdeverrno) 124 { 125 struct spdk_jsonrpc_request *request = cb_arg; 126 127 if (bdeverrno == 0) { 128 spdk_jsonrpc_send_bool_response(request, true); 129 } else { 130 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 131 } 132 } 133 134 static void 135 rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request, 136 const struct spdk_json_val *params) 137 { 138 struct rpc_delete_ftl attrs = {}; 139 140 if (spdk_json_decode_object(params, rpc_delete_ftl_decoders, 141 SPDK_COUNTOF(rpc_delete_ftl_decoders), 142 &attrs)) { 143 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 144 "Invalid parameters"); 145 goto invalid; 146 } 147 148 bdev_ftl_delete_bdev(attrs.name, attrs.fast_shutdown, rpc_bdev_ftl_delete_cb, request); 149 invalid: 150 free(attrs.name); 151 } 152 SPDK_RPC_REGISTER("bdev_ftl_delete", rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME) 153 154 static void 155 rpc_bdev_ftl_unload(struct spdk_jsonrpc_request *request, 156 const struct spdk_json_val *params) 157 { 158 rpc_bdev_ftl_delete(request, params); 159 } 160 SPDK_RPC_REGISTER("bdev_ftl_unload", rpc_bdev_ftl_unload, SPDK_RPC_RUNTIME) 161 162 struct rpc_ftl_unmap { 163 char *name; 164 uint64_t lba; 165 uint64_t num_blocks; 166 }; 167 168 static const struct spdk_json_object_decoder rpc_ftl_unmap_decoders[] = { 169 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 170 {"lba", offsetof(struct rpc_ftl_unmap, lba), spdk_json_decode_uint64, true}, 171 {"num_blocks", offsetof(struct rpc_ftl_unmap, num_blocks), spdk_json_decode_uint64, true}, 172 }; 173 174 static void 175 rpc_bdev_ftl_unmap_cb(void *cb_arg, int bdeverrno) 176 { 177 struct spdk_jsonrpc_request *request = cb_arg; 178 179 if (bdeverrno == 0) { 180 spdk_jsonrpc_send_bool_response(request, true); 181 } else { 182 spdk_jsonrpc_send_error_response(request, bdeverrno, spdk_strerror(-bdeverrno)); 183 } 184 } 185 186 static void 187 rpc_bdev_ftl_unmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 188 { 189 struct rpc_ftl_unmap attrs = {}; 190 191 if (spdk_json_decode_object(params, rpc_ftl_unmap_decoders, SPDK_COUNTOF(rpc_ftl_unmap_decoders), 192 &attrs)) { 193 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 194 goto invalid; 195 } 196 197 bdev_ftl_unmap(attrs.name, attrs.lba, attrs.num_blocks, rpc_bdev_ftl_unmap_cb, request); 198 invalid: 199 free(attrs.name); 200 } 201 202 SPDK_RPC_REGISTER("bdev_ftl_unmap", rpc_bdev_ftl_unmap, SPDK_RPC_RUNTIME) 203 204 struct rpc_ftl_stats { 205 char *name; 206 }; 207 208 static const struct spdk_json_object_decoder rpc_ftl_stats_decoders[] = { 209 {"name", offsetof(struct rpc_ftl_stats, name), spdk_json_decode_string}, 210 }; 211 212 static void 213 _rpc_bdev_ftl_get_stats(void *cntx) 214 { 215 struct rpc_ftl_stats_ctx *ftl_stats = cntx; 216 struct spdk_jsonrpc_request *request = ftl_stats->request; 217 struct ftl_stats *stats = ftl_stats->ftl_stats; 218 struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request); 219 220 spdk_json_write_object_begin(w); 221 spdk_json_write_named_string(w, "name", spdk_bdev_desc_get_bdev(ftl_stats->ftl_bdev_desc)->name); 222 223 /* TODO: Instead of named objects, store them in an array with the name being an attribute */ 224 for (uint64_t i = 0; i < FTL_STATS_TYPE_MAX; i++) { 225 switch (i) { 226 case FTL_STATS_TYPE_USER: 227 spdk_json_write_named_object_begin(w, "user"); 228 break; 229 case FTL_STATS_TYPE_CMP: 230 spdk_json_write_named_object_begin(w, "cmp"); 231 break; 232 case FTL_STATS_TYPE_GC: 233 spdk_json_write_named_object_begin(w, "gc"); 234 break; 235 case FTL_STATS_TYPE_MD_BASE: 236 spdk_json_write_named_object_begin(w, "md_base"); 237 break; 238 case FTL_STATS_TYPE_MD_NV_CACHE: 239 spdk_json_write_named_object_begin(w, "md_nv_cache"); 240 break; 241 case FTL_STATS_TYPE_L2P: 242 spdk_json_write_named_object_begin(w, "l2p"); 243 break; 244 default: 245 assert(false); 246 continue; 247 } 248 249 spdk_json_write_named_object_begin(w, "read"); 250 spdk_json_write_named_uint64(w, "ios", stats->entries[i].read.ios); 251 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].read.blocks); 252 spdk_json_write_named_object_begin(w, "errors"); 253 spdk_json_write_named_uint64(w, "media", stats->entries[i].read.errors.media); 254 spdk_json_write_named_uint64(w, "crc", stats->entries[i].read.errors.crc); 255 spdk_json_write_named_uint64(w, "other", stats->entries[i].read.errors.other); 256 spdk_json_write_object_end(w); 257 spdk_json_write_object_end(w); 258 259 spdk_json_write_named_object_begin(w, "write"); 260 spdk_json_write_named_uint64(w, "ios", stats->entries[i].write.ios); 261 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].write.blocks); 262 spdk_json_write_named_object_begin(w, "errors"); 263 spdk_json_write_named_uint64(w, "media", stats->entries[i].write.errors.media); 264 spdk_json_write_named_uint64(w, "other", stats->entries[i].write.errors.other); 265 spdk_json_write_object_end(w); 266 spdk_json_write_object_end(w); 267 268 spdk_json_write_object_end(w); 269 } 270 271 spdk_json_write_object_end(w); 272 spdk_jsonrpc_end_result(request, w); 273 274 free(stats); 275 } 276 277 static void 278 rpc_bdev_ftl_get_stats(struct spdk_jsonrpc_request *request, 279 const struct spdk_json_val *params) 280 { 281 struct ftl_stats *stats; 282 struct rpc_ftl_stats attrs = {}; 283 int rc; 284 285 if (spdk_json_decode_object(params, rpc_ftl_stats_decoders, SPDK_COUNTOF(rpc_ftl_stats_decoders), 286 &attrs)) { 287 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 288 goto invalid; 289 } 290 291 stats = calloc(1, sizeof(struct ftl_stats)); 292 if (!stats) { 293 spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM)); 294 goto invalid; 295 } 296 297 rc = bdev_ftl_get_stats(attrs.name, _rpc_bdev_ftl_get_stats, request, stats); 298 if (rc) { 299 free(stats); 300 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 301 goto invalid; 302 } 303 304 invalid: 305 free(attrs.name); 306 } 307 308 SPDK_RPC_REGISTER("bdev_ftl_get_stats", rpc_bdev_ftl_get_stats, SPDK_RPC_RUNTIME) 309