1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/bdev.h" 8 #include "spdk/env.h" 9 #include "spdk/thread.h" 10 #include "spdk/json.h" 11 #include "spdk/string.h" 12 #include "spdk/likely.h" 13 #include "spdk/util.h" 14 #include "spdk/string.h" 15 #include "spdk/ftl.h" 16 #include "spdk/log.h" 17 18 #include "bdev_ftl.h" 19 20 struct ftl_bdev { 21 struct spdk_bdev bdev; 22 23 struct spdk_ftl_dev *dev; 24 25 ftl_bdev_init_fn init_cb; 26 27 void *init_arg; 28 }; 29 30 struct ftl_deferred_init { 31 struct ftl_bdev_init_opts opts; 32 33 LIST_ENTRY(ftl_deferred_init) entry; 34 }; 35 36 static LIST_HEAD(, ftl_deferred_init) g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init); 37 38 static int bdev_ftl_initialize(void); 39 static void bdev_ftl_finish(void); 40 static void bdev_ftl_examine(struct spdk_bdev *bdev); 41 42 static struct spdk_bdev_module g_ftl_if = { 43 .name = "ftl", 44 .module_init = bdev_ftl_initialize, 45 .module_fini = bdev_ftl_finish, 46 .examine_disk = bdev_ftl_examine, 47 }; 48 49 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if) 50 51 static void 52 bdev_ftl_free_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 53 { 54 struct ftl_bdev *ftl_bdev = ctx; 55 56 spdk_bdev_destruct_done(&ftl_bdev->bdev, status); 57 free(ftl_bdev->bdev.name); 58 free(ftl_bdev); 59 } 60 61 static int 62 bdev_ftl_destruct(void *ctx) 63 { 64 struct ftl_bdev *ftl_bdev = ctx; 65 spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_free_cb, ftl_bdev); 66 67 /* return 1 to indicate that the destruction is asynchronous */ 68 return 1; 69 } 70 71 static void 72 bdev_ftl_cb(void *arg, int rc) 73 { 74 struct spdk_bdev_io *bdev_io = arg; 75 enum spdk_bdev_io_status status; 76 77 switch (rc) { 78 case 0: 79 status = SPDK_BDEV_IO_STATUS_SUCCESS; 80 break; 81 case -ENOMEM: 82 status = SPDK_BDEV_IO_STATUS_NOMEM; 83 break; 84 default: 85 status = SPDK_BDEV_IO_STATUS_FAILED; 86 break; 87 } 88 89 spdk_bdev_io_complete(bdev_io, status); 90 } 91 92 static void 93 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 94 bool success) 95 { 96 struct ftl_bdev *ftl_bdev; 97 int rc; 98 99 ftl_bdev = bdev_io->bdev->ctxt; 100 101 if (!success) { 102 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 103 return; 104 } 105 106 rc = spdk_ftl_read(ftl_bdev->dev, 107 ch, 108 bdev_io->u.bdev.offset_blocks, 109 bdev_io->u.bdev.num_blocks, 110 bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 111 112 if (spdk_unlikely(rc != 0)) { 113 spdk_bdev_io_complete(bdev_io, rc); 114 } 115 } 116 117 static int 118 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 119 { 120 struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt; 121 122 switch (bdev_io->type) { 123 case SPDK_BDEV_IO_TYPE_READ: 124 spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb, 125 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 126 return 0; 127 128 case SPDK_BDEV_IO_TYPE_WRITE: 129 return spdk_ftl_write(ftl_bdev->dev, ch, bdev_io->u.bdev.offset_blocks, 130 bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs, 131 bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 132 133 case SPDK_BDEV_IO_TYPE_FLUSH: 134 return spdk_ftl_flush(ftl_bdev->dev, bdev_ftl_cb, bdev_io); 135 136 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 137 case SPDK_BDEV_IO_TYPE_RESET: 138 case SPDK_BDEV_IO_TYPE_UNMAP: 139 default: 140 return -ENOTSUP; 141 break; 142 } 143 } 144 145 static void 146 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 147 { 148 int rc = _bdev_ftl_submit_request(ch, bdev_io); 149 150 if (spdk_unlikely(rc != 0)) { 151 spdk_bdev_io_complete(bdev_io, rc); 152 } 153 } 154 155 static bool 156 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 157 { 158 switch (io_type) { 159 case SPDK_BDEV_IO_TYPE_READ: 160 case SPDK_BDEV_IO_TYPE_WRITE: 161 case SPDK_BDEV_IO_TYPE_FLUSH: 162 return true; 163 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES: 164 case SPDK_BDEV_IO_TYPE_RESET: 165 case SPDK_BDEV_IO_TYPE_UNMAP: 166 default: 167 return false; 168 } 169 } 170 171 static struct spdk_io_channel * 172 bdev_ftl_get_io_channel(void *ctx) 173 { 174 struct ftl_bdev *ftl_bdev = ctx; 175 176 return spdk_get_io_channel(ftl_bdev->dev); 177 } 178 179 static void 180 _bdev_ftl_write_config_info(struct ftl_bdev *ftl_bdev, struct spdk_json_write_ctx *w) 181 { 182 struct spdk_ftl_attrs attrs = {}; 183 184 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs); 185 186 spdk_json_write_named_string(w, "base_bdev", attrs.base_bdev); 187 188 if (attrs.cache_bdev) { 189 spdk_json_write_named_string(w, "cache", attrs.cache_bdev); 190 } 191 } 192 193 static void 194 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 195 { 196 struct ftl_bdev *ftl_bdev = bdev->ctxt; 197 struct spdk_ftl_attrs attrs; 198 struct spdk_ftl_conf *conf = &attrs.conf; 199 char uuid[SPDK_UUID_STRING_LEN]; 200 201 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs); 202 203 spdk_json_write_object_begin(w); 204 205 spdk_json_write_named_string(w, "method", "bdev_ftl_create"); 206 207 spdk_json_write_named_object_begin(w, "params"); 208 spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name); 209 210 spdk_json_write_named_bool(w, "allow_open_bands", conf->allow_open_bands); 211 spdk_json_write_named_uint64(w, "overprovisioning", conf->lba_rsvd); 212 spdk_json_write_named_uint64(w, "limit_crit", conf->limits[SPDK_FTL_LIMIT_CRIT].limit); 213 spdk_json_write_named_uint64(w, "limit_crit_threshold", conf->limits[SPDK_FTL_LIMIT_CRIT].thld); 214 spdk_json_write_named_uint64(w, "limit_high", conf->limits[SPDK_FTL_LIMIT_HIGH].limit); 215 spdk_json_write_named_uint64(w, "limit_high_threshold", conf->limits[SPDK_FTL_LIMIT_HIGH].thld); 216 spdk_json_write_named_uint64(w, "limit_low", conf->limits[SPDK_FTL_LIMIT_LOW].limit); 217 spdk_json_write_named_uint64(w, "limit_low_threshold", conf->limits[SPDK_FTL_LIMIT_LOW].thld); 218 spdk_json_write_named_uint64(w, "limit_start", conf->limits[SPDK_FTL_LIMIT_START].limit); 219 spdk_json_write_named_uint64(w, "limit_start_threshold", conf->limits[SPDK_FTL_LIMIT_START].thld); 220 if (conf->l2p_path) { 221 spdk_json_write_named_string(w, "l2p_path", conf->l2p_path); 222 } 223 224 spdk_uuid_fmt_lower(uuid, sizeof(uuid), &attrs.uuid); 225 spdk_json_write_named_string(w, "uuid", uuid); 226 227 _bdev_ftl_write_config_info(ftl_bdev, w); 228 229 spdk_json_write_object_end(w); 230 spdk_json_write_object_end(w); 231 } 232 233 static int 234 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 235 { 236 struct ftl_bdev *ftl_bdev = ctx; 237 struct spdk_ftl_attrs attrs; 238 239 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs); 240 241 spdk_json_write_named_object_begin(w, "ftl"); 242 243 _bdev_ftl_write_config_info(ftl_bdev, w); 244 spdk_json_write_named_string_fmt(w, "num_zones", "%zu", attrs.num_zones); 245 spdk_json_write_named_string_fmt(w, "zone_size", "%zu", attrs.zone_size); 246 247 /* ftl */ 248 spdk_json_write_object_end(w); 249 250 return 0; 251 } 252 253 static const struct spdk_bdev_fn_table ftl_fn_table = { 254 .destruct = bdev_ftl_destruct, 255 .submit_request = bdev_ftl_submit_request, 256 .io_type_supported = bdev_ftl_io_type_supported, 257 .get_io_channel = bdev_ftl_get_io_channel, 258 .write_config_json = bdev_ftl_write_config_json, 259 .dump_info_json = bdev_ftl_dump_info_json, 260 }; 261 262 static void 263 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 264 { 265 struct ftl_bdev *ftl_bdev = ctx; 266 struct ftl_bdev_info info = {}; 267 struct spdk_ftl_attrs attrs; 268 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 269 void *init_arg = ftl_bdev->init_arg; 270 int rc = -ENODEV; 271 272 if (status) { 273 SPDK_ERRLOG("Failed to create FTL device (%d)\n", status); 274 rc = status; 275 goto error; 276 } 277 278 spdk_ftl_dev_get_attrs(dev, &attrs); 279 280 ftl_bdev->dev = dev; 281 ftl_bdev->bdev.product_name = "FTL disk"; 282 ftl_bdev->bdev.write_cache = 0; 283 ftl_bdev->bdev.blocklen = attrs.block_size; 284 ftl_bdev->bdev.blockcnt = attrs.num_blocks; 285 ftl_bdev->bdev.uuid = attrs.uuid; 286 287 SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name); 288 SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size); 289 SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks); 290 291 ftl_bdev->bdev.ctxt = ftl_bdev; 292 ftl_bdev->bdev.fn_table = &ftl_fn_table; 293 ftl_bdev->bdev.module = &g_ftl_if; 294 295 if (spdk_bdev_register(&ftl_bdev->bdev)) { 296 goto error; 297 } 298 299 info.name = ftl_bdev->bdev.name; 300 info.uuid = ftl_bdev->bdev.uuid; 301 302 init_cb(&info, init_arg, 0); 303 return; 304 305 error: 306 free(ftl_bdev->bdev.name); 307 free(ftl_bdev); 308 309 init_cb(NULL, init_arg, rc); 310 } 311 312 static void 313 bdev_ftl_defer_free(struct ftl_deferred_init *init) 314 { 315 free((char *)init->opts.name); 316 free((char *)init->opts.base_bdev); 317 free((char *)init->opts.cache_bdev); 318 free(init); 319 } 320 321 static int 322 bdev_ftl_defer_init(const struct ftl_bdev_init_opts *opts) 323 { 324 struct ftl_deferred_init *init; 325 326 init = calloc(1, sizeof(*init)); 327 if (!init) { 328 return -ENOMEM; 329 } 330 331 init->opts.mode = opts->mode; 332 init->opts.uuid = opts->uuid; 333 init->opts.ftl_conf = opts->ftl_conf; 334 335 init->opts.name = strdup(opts->name); 336 if (!init->opts.name) { 337 SPDK_ERRLOG("Could not allocate bdev name\n"); 338 goto error; 339 } 340 341 init->opts.base_bdev = strdup(opts->base_bdev); 342 if (!init->opts.base_bdev) { 343 SPDK_ERRLOG("Could not allocate base bdev name\n"); 344 goto error; 345 } 346 347 if (opts->cache_bdev) { 348 init->opts.cache_bdev = strdup(opts->cache_bdev); 349 if (!init->opts.cache_bdev) { 350 SPDK_ERRLOG("Could not allocate cache bdev name\n"); 351 goto error; 352 } 353 } 354 355 LIST_INSERT_HEAD(&g_deferred_init, init, entry); 356 357 return 0; 358 359 error: 360 bdev_ftl_defer_free(init); 361 return -ENOMEM; 362 } 363 364 int 365 bdev_ftl_create_bdev(const struct ftl_bdev_init_opts *bdev_opts, 366 ftl_bdev_init_fn cb, void *cb_arg) 367 { 368 struct ftl_bdev *ftl_bdev = NULL; 369 struct spdk_ftl_dev_init_opts opts = {}; 370 int rc; 371 372 ftl_bdev = calloc(1, sizeof(*ftl_bdev)); 373 if (!ftl_bdev) { 374 SPDK_ERRLOG("Could not allocate ftl_bdev\n"); 375 return -ENOMEM; 376 } 377 378 ftl_bdev->bdev.name = strdup(bdev_opts->name); 379 if (!ftl_bdev->bdev.name) { 380 rc = -ENOMEM; 381 goto error_bdev; 382 } 383 384 if (spdk_bdev_get_by_name(bdev_opts->base_bdev) == NULL || 385 (bdev_opts->cache_bdev && spdk_bdev_get_by_name(bdev_opts->cache_bdev) == NULL)) { 386 rc = bdev_ftl_defer_init(bdev_opts); 387 if (rc == 0) { 388 rc = -ENODEV; 389 } 390 goto error_name; 391 } 392 393 ftl_bdev->init_cb = cb; 394 ftl_bdev->init_arg = cb_arg; 395 396 opts.mode = bdev_opts->mode; 397 opts.uuid = bdev_opts->uuid; 398 opts.name = ftl_bdev->bdev.name; 399 opts.base_bdev = bdev_opts->base_bdev; 400 opts.cache_bdev = bdev_opts->cache_bdev; 401 opts.conf = &bdev_opts->ftl_conf; 402 403 /* TODO: set threads based on config */ 404 opts.core_thread = spdk_get_thread(); 405 406 rc = spdk_ftl_dev_init(&opts, bdev_ftl_create_cb, ftl_bdev); 407 if (rc) { 408 SPDK_ERRLOG("Could not create FTL device\n"); 409 goto error_name; 410 } 411 412 return 0; 413 414 error_name: 415 free(ftl_bdev->bdev.name); 416 error_bdev: 417 free(ftl_bdev); 418 return rc; 419 } 420 421 static int 422 bdev_ftl_initialize(void) 423 { 424 return 0; 425 } 426 427 void 428 bdev_ftl_delete_bdev(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg) 429 { 430 int rc; 431 432 rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg); 433 if (rc != 0) { 434 cb_fn(cb_arg, rc); 435 } 436 } 437 438 static void 439 bdev_ftl_finish(void) 440 { 441 } 442 443 static void 444 bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status) 445 { 446 struct ftl_deferred_init *opts = ctx; 447 448 if (status) { 449 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name); 450 } 451 452 bdev_ftl_defer_free(opts); 453 454 spdk_bdev_module_examine_done(&g_ftl_if); 455 } 456 457 static void 458 bdev_ftl_examine(struct spdk_bdev *bdev) 459 { 460 struct ftl_deferred_init *opts; 461 462 LIST_FOREACH(opts, &g_deferred_init, entry) { 463 if (spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) { 464 continue; 465 } 466 467 if (opts->opts.cache_bdev && spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) { 468 continue; 469 } 470 471 LIST_REMOVE(opts, entry); 472 473 /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */ 474 if (bdev_ftl_create_bdev(&opts->opts, bdev_ftl_create_deferred_cb, opts)) { 475 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name); 476 bdev_ftl_defer_free(opts); 477 break; 478 } 479 return; 480 } 481 482 spdk_bdev_module_examine_done(&g_ftl_if); 483 } 484 485 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl) 486