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