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 rc = bdev_ftl_create_bdev(&conf, rpc_bdev_ftl_create_cb, request); 103 if (rc == -ENODEV) { 104 rc = bdev_ftl_defer_init(&conf); 105 if (rc == 0) { 106 w = spdk_jsonrpc_begin_result(request); 107 spdk_json_write_string_fmt(w, "FTL bdev: %s creation deferred", conf.name); 108 spdk_jsonrpc_end_result(request, w); 109 } 110 } 111 112 if (rc) { 113 spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, 114 "Failed to create FTL bdev: %s", 115 spdk_strerror(-rc)); 116 } 117 out: 118 spdk_ftl_conf_deinit(&conf); 119 } 120 SPDK_RPC_REGISTER("bdev_ftl_create", rpc_bdev_ftl_create, SPDK_RPC_RUNTIME) 121 122 static void 123 rpc_bdev_ftl_load(struct spdk_jsonrpc_request *request, 124 const struct spdk_json_val *params) 125 { 126 rpc_bdev_ftl_create(request, params); 127 } 128 SPDK_RPC_REGISTER("bdev_ftl_load", rpc_bdev_ftl_load, SPDK_RPC_RUNTIME) 129 130 struct rpc_delete_ftl { 131 char *name; 132 bool fast_shutdown; 133 }; 134 135 static const struct spdk_json_object_decoder rpc_delete_ftl_decoders[] = { 136 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 137 { 138 "fast_shutdown", offsetof(struct rpc_delete_ftl, fast_shutdown), 139 spdk_json_decode_bool, true 140 }, 141 }; 142 143 static void 144 rpc_bdev_ftl_delete(struct spdk_jsonrpc_request *request, 145 const struct spdk_json_val *params) 146 { 147 struct rpc_delete_ftl attrs = {}; 148 149 if (spdk_json_decode_object(params, rpc_delete_ftl_decoders, 150 SPDK_COUNTOF(rpc_delete_ftl_decoders), 151 &attrs)) { 152 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, 153 "Invalid parameters"); 154 goto invalid; 155 } 156 157 bdev_ftl_delete_bdev(attrs.name, attrs.fast_shutdown, rpc_bdev_ftl_basic_cb, request); 158 invalid: 159 free(attrs.name); 160 } 161 SPDK_RPC_REGISTER("bdev_ftl_delete", rpc_bdev_ftl_delete, SPDK_RPC_RUNTIME) 162 163 static void 164 rpc_bdev_ftl_unload(struct spdk_jsonrpc_request *request, 165 const struct spdk_json_val *params) 166 { 167 rpc_bdev_ftl_delete(request, params); 168 } 169 SPDK_RPC_REGISTER("bdev_ftl_unload", rpc_bdev_ftl_unload, SPDK_RPC_RUNTIME) 170 171 struct rpc_ftl_unmap { 172 char *name; 173 uint64_t lba; 174 uint64_t num_blocks; 175 }; 176 177 static const struct spdk_json_object_decoder rpc_ftl_unmap_decoders[] = { 178 {"name", offsetof(struct rpc_delete_ftl, name), spdk_json_decode_string}, 179 {"lba", offsetof(struct rpc_ftl_unmap, lba), spdk_json_decode_uint64, true}, 180 {"num_blocks", offsetof(struct rpc_ftl_unmap, num_blocks), spdk_json_decode_uint64, true}, 181 }; 182 183 184 static void 185 rpc_bdev_ftl_unmap(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) 186 { 187 struct rpc_ftl_unmap attrs = {}; 188 189 if (spdk_json_decode_object(params, rpc_ftl_unmap_decoders, SPDK_COUNTOF(rpc_ftl_unmap_decoders), 190 &attrs)) { 191 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 192 } else { 193 bdev_ftl_unmap(attrs.name, attrs.lba, attrs.num_blocks, rpc_bdev_ftl_basic_cb, request); 194 } 195 free(attrs.name); 196 } 197 198 SPDK_RPC_REGISTER("bdev_ftl_unmap", rpc_bdev_ftl_unmap, SPDK_RPC_RUNTIME) 199 200 static void 201 _rpc_bdev_ftl_get_stats(void *ctx, int rc) 202 { 203 struct rpc_ftl_stats_ctx *ftl_stats_ctx = ctx; 204 struct spdk_jsonrpc_request *request = ftl_stats_ctx->request; 205 struct ftl_stats *stats = &ftl_stats_ctx->ftl_stats; 206 struct spdk_json_write_ctx *w; 207 208 if (rc) { 209 free(ftl_stats_ctx); 210 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 211 return; 212 } 213 214 w = spdk_jsonrpc_begin_result(request); 215 spdk_json_write_object_begin(w); 216 spdk_json_write_named_string(w, "name", 217 spdk_bdev_desc_get_bdev(ftl_stats_ctx->ftl_bdev_desc)->name); 218 219 /* TODO: Instead of named objects, store them in an array with the name being an attribute */ 220 for (uint64_t i = 0; i < FTL_STATS_TYPE_MAX; i++) { 221 switch (i) { 222 case FTL_STATS_TYPE_USER: 223 spdk_json_write_named_object_begin(w, "user"); 224 break; 225 case FTL_STATS_TYPE_CMP: 226 spdk_json_write_named_object_begin(w, "cmp"); 227 break; 228 case FTL_STATS_TYPE_GC: 229 spdk_json_write_named_object_begin(w, "gc"); 230 break; 231 case FTL_STATS_TYPE_MD_BASE: 232 spdk_json_write_named_object_begin(w, "md_base"); 233 break; 234 case FTL_STATS_TYPE_MD_NV_CACHE: 235 spdk_json_write_named_object_begin(w, "md_nv_cache"); 236 break; 237 case FTL_STATS_TYPE_L2P: 238 spdk_json_write_named_object_begin(w, "l2p"); 239 break; 240 default: 241 assert(false); 242 continue; 243 } 244 245 spdk_json_write_named_object_begin(w, "read"); 246 spdk_json_write_named_uint64(w, "ios", stats->entries[i].read.ios); 247 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].read.blocks); 248 spdk_json_write_named_object_begin(w, "errors"); 249 spdk_json_write_named_uint64(w, "media", stats->entries[i].read.errors.media); 250 spdk_json_write_named_uint64(w, "crc", stats->entries[i].read.errors.crc); 251 spdk_json_write_named_uint64(w, "other", stats->entries[i].read.errors.other); 252 spdk_json_write_object_end(w); 253 spdk_json_write_object_end(w); 254 255 spdk_json_write_named_object_begin(w, "write"); 256 spdk_json_write_named_uint64(w, "ios", stats->entries[i].write.ios); 257 spdk_json_write_named_uint64(w, "blocks", stats->entries[i].write.blocks); 258 spdk_json_write_named_object_begin(w, "errors"); 259 spdk_json_write_named_uint64(w, "media", stats->entries[i].write.errors.media); 260 spdk_json_write_named_uint64(w, "other", stats->entries[i].write.errors.other); 261 spdk_json_write_object_end(w); 262 spdk_json_write_object_end(w); 263 264 spdk_json_write_object_end(w); 265 } 266 267 spdk_json_write_object_end(w); 268 spdk_jsonrpc_end_result(request, w); 269 free(ftl_stats_ctx); 270 } 271 272 static void 273 rpc_bdev_ftl_get_stats(struct spdk_jsonrpc_request *request, 274 const struct spdk_json_val *params) 275 { 276 struct rpc_ftl_basic_param attrs = {}; 277 struct rpc_ftl_stats_ctx *ctx = calloc(1, sizeof(*ctx)); 278 279 if (!ctx) { 280 spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(-ENOMEM)); 281 return; 282 } 283 284 if (spdk_json_decode_object(params, rpc_ftl_basic_decoders, SPDK_COUNTOF(rpc_ftl_basic_decoders), 285 &attrs)) { 286 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 287 free(ctx); 288 free(attrs.name); 289 return; 290 } 291 292 ctx->request = request; 293 bdev_ftl_get_stats(attrs.name, _rpc_bdev_ftl_get_stats, ctx); 294 free(attrs.name); 295 } 296 297 SPDK_RPC_REGISTER("bdev_ftl_get_stats", rpc_bdev_ftl_get_stats, SPDK_RPC_RUNTIME) 298 299 static void 300 rpc_bdev_ftl_get_properties_cb(void *ctx, int rc) 301 { 302 struct spdk_jsonrpc_request *request = ctx; 303 304 if (rc) { 305 spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); 306 } 307 } 308 309 static void 310 rpc_bdev_ftl_get_properties(struct spdk_jsonrpc_request *request, 311 const struct spdk_json_val *params) 312 { 313 struct rpc_ftl_basic_param attrs = {}; 314 315 if (spdk_json_decode_object(params, rpc_ftl_basic_decoders, SPDK_COUNTOF(rpc_ftl_basic_decoders), 316 &attrs)) { 317 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 318 free(attrs.name); 319 return; 320 } 321 322 bdev_ftl_get_properties(attrs.name, rpc_bdev_ftl_get_properties_cb, request); 323 free(attrs.name); 324 } 325 326 SPDK_RPC_REGISTER("bdev_ftl_get_properties", rpc_bdev_ftl_get_properties, SPDK_RPC_RUNTIME) 327 328 struct rpc_ftl_set_property_param { 329 char *name; 330 char *ftl_property; 331 char *value; 332 }; 333 334 static const struct spdk_json_object_decoder rpc_ftl_set_property_decoders[] = { 335 {"name", offsetof(struct rpc_ftl_set_property_param, name), spdk_json_decode_string}, 336 {"ftl_property", offsetof(struct rpc_ftl_set_property_param, ftl_property), spdk_json_decode_string}, 337 {"value", offsetof(struct rpc_ftl_set_property_param, value), spdk_json_decode_string}, 338 }; 339 340 static void 341 rpc_bdev_ftl_set_property(struct spdk_jsonrpc_request *request, 342 const struct spdk_json_val *params) 343 { 344 struct rpc_ftl_set_property_param attrs = {}; 345 346 if (spdk_json_decode_object(params, rpc_ftl_set_property_decoders, 347 SPDK_COUNTOF(rpc_ftl_set_property_decoders), 348 &attrs)) { 349 spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); 350 free(attrs.name); 351 free(attrs.ftl_property); 352 free(attrs.value); 353 return; 354 } 355 356 bdev_ftl_set_property(attrs.name, attrs.ftl_property, attrs.value, 357 rpc_bdev_ftl_basic_cb, request); 358 free(attrs.name); 359 free(attrs.ftl_property); 360 free(attrs.value); 361 } 362 363 SPDK_RPC_REGISTER("bdev_ftl_set_property", rpc_bdev_ftl_set_property, SPDK_RPC_RUNTIME) 364