1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * All rights reserved. 4 * Copyright 2023 Solidigm All Rights Reserved 5 */ 6 7 #include "spdk/stdinc.h" 8 #include "spdk/bdev.h" 9 #include "spdk/env.h" 10 #include "spdk/thread.h" 11 #include "spdk/json.h" 12 #include "spdk/string.h" 13 #include "spdk/likely.h" 14 #include "spdk/util.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 struct spdk_ftl_dev *dev; 23 ftl_bdev_init_fn init_cb; 24 void *init_arg; 25 int rc; 26 struct spdk_bdev_desc *base_bdev_desc; 27 struct spdk_bdev_desc *cache_bdev_desc; 28 }; 29 30 struct bdev_ftl_action { 31 struct spdk_bdev_desc *ftl_bdev_desc; 32 struct ftl_bdev *ftl_bdev_dev; 33 spdk_ftl_fn cb_fn; 34 void *cb_arg; 35 int rc; 36 size_t ctx_size; 37 char ctx[0]; 38 }; 39 40 struct ftl_deferred_init { 41 struct spdk_ftl_conf conf; 42 43 LIST_ENTRY(ftl_deferred_init) entry; 44 }; 45 46 static LIST_HEAD(, ftl_deferred_init) g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init); 47 48 static int bdev_ftl_initialize(void); 49 static void bdev_ftl_finish(void); 50 static void bdev_ftl_examine(struct spdk_bdev *bdev); 51 52 static void bdev_ftl_action_finish_cb(void *cb_arg, int status); 53 static struct bdev_ftl_action *bdev_ftl_action_start(const char *bdev_name, 54 size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg); 55 static void bdev_ftl_action_finish(struct bdev_ftl_action *action); 56 static void *bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size); 57 58 static int 59 bdev_ftl_get_ctx_size(void) 60 { 61 return spdk_ftl_io_size(); 62 } 63 64 static struct spdk_bdev_module g_ftl_if = { 65 .name = "ftl", 66 .module_init = bdev_ftl_initialize, 67 .module_fini = bdev_ftl_finish, 68 .examine_disk = bdev_ftl_examine, 69 .get_ctx_size = bdev_ftl_get_ctx_size, 70 }; 71 72 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if) 73 74 static void 75 bdev_ftl_free(struct ftl_bdev *ftl_bdev) 76 { 77 spdk_bdev_close(ftl_bdev->base_bdev_desc); 78 spdk_bdev_close(ftl_bdev->cache_bdev_desc); 79 free(ftl_bdev->bdev.name); 80 free(ftl_bdev); 81 } 82 83 static void 84 bdev_ftl_dev_free_cb(void *ctx, int status) 85 { 86 struct ftl_bdev *ftl_bdev = ctx; 87 88 spdk_bdev_destruct_done(&ftl_bdev->bdev, status); 89 bdev_ftl_free(ftl_bdev); 90 } 91 92 static int 93 bdev_ftl_destruct(void *ctx) 94 { 95 struct ftl_bdev *ftl_bdev = ctx; 96 97 spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_dev_free_cb, ftl_bdev); 98 99 /* return 1 to indicate that the destruction is asynchronous */ 100 return 1; 101 } 102 103 static void 104 bdev_ftl_cb(void *arg, int rc) 105 { 106 struct spdk_bdev_io *bdev_io = arg; 107 enum spdk_bdev_io_status status; 108 109 switch (rc) { 110 case 0: 111 status = SPDK_BDEV_IO_STATUS_SUCCESS; 112 break; 113 case -EAGAIN: 114 case -ENOMEM: 115 status = SPDK_BDEV_IO_STATUS_NOMEM; 116 break; 117 default: 118 status = SPDK_BDEV_IO_STATUS_FAILED; 119 break; 120 } 121 122 spdk_bdev_io_complete(bdev_io, status); 123 } 124 125 static void 126 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 127 bool success) 128 { 129 struct ftl_bdev *ftl_bdev; 130 int rc; 131 132 ftl_bdev = bdev_io->bdev->ctxt; 133 134 if (!success) { 135 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 136 return; 137 } 138 139 rc = spdk_ftl_readv(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 140 ch, 141 bdev_io->u.bdev.offset_blocks, 142 bdev_io->u.bdev.num_blocks, 143 bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 144 145 if (spdk_unlikely(rc != 0)) { 146 bdev_ftl_cb(bdev_io, rc); 147 } 148 } 149 150 static int 151 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 152 { 153 struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt; 154 155 switch (bdev_io->type) { 156 case SPDK_BDEV_IO_TYPE_READ: 157 spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb, 158 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 159 return 0; 160 161 case SPDK_BDEV_IO_TYPE_WRITE: 162 return spdk_ftl_writev(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 163 ch, bdev_io->u.bdev.offset_blocks, 164 bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs, 165 bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 166 167 case SPDK_BDEV_IO_TYPE_UNMAP: 168 return spdk_ftl_unmap(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 169 ch, bdev_io->u.bdev.offset_blocks, 170 bdev_io->u.bdev.num_blocks, bdev_ftl_cb, bdev_io); 171 case SPDK_BDEV_IO_TYPE_FLUSH: 172 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 173 return 0; 174 default: 175 return -ENOTSUP; 176 } 177 } 178 179 static void 180 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 181 { 182 int rc = _bdev_ftl_submit_request(ch, bdev_io); 183 184 if (spdk_unlikely(rc != 0)) { 185 bdev_ftl_cb(bdev_io, rc); 186 } 187 } 188 189 static bool 190 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 191 { 192 switch (io_type) { 193 case SPDK_BDEV_IO_TYPE_READ: 194 case SPDK_BDEV_IO_TYPE_WRITE: 195 case SPDK_BDEV_IO_TYPE_FLUSH: 196 case SPDK_BDEV_IO_TYPE_UNMAP: 197 return true; 198 default: 199 return false; 200 } 201 } 202 203 static struct spdk_io_channel * 204 bdev_ftl_get_io_channel(void *ctx) 205 { 206 struct ftl_bdev *ftl_bdev = ctx; 207 208 return spdk_ftl_get_io_channel(ftl_bdev->dev); 209 } 210 211 static void 212 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 213 { 214 struct ftl_bdev *ftl_bdev = bdev->ctxt; 215 struct spdk_ftl_conf conf; 216 217 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf)); 218 219 spdk_json_write_object_begin(w); 220 221 spdk_json_write_named_string(w, "method", "bdev_ftl_create"); 222 223 spdk_json_write_named_object_begin(w, "params"); 224 spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name); 225 226 spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning); 227 spdk_json_write_named_uint64(w, "l2p_dram_limit", conf.l2p_dram_limit); 228 229 if (conf.core_mask) { 230 spdk_json_write_named_string(w, "core_mask", conf.core_mask); 231 } 232 233 spdk_json_write_named_uuid(w, "uuid", &conf.uuid); 234 235 spdk_json_write_named_bool(w, "fast_shutdown", conf.fast_shutdown); 236 237 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 238 239 if (conf.cache_bdev) { 240 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 241 } 242 243 spdk_json_write_object_end(w); 244 spdk_json_write_object_end(w); 245 } 246 247 static int 248 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 249 { 250 struct ftl_bdev *ftl_bdev = ctx; 251 struct spdk_ftl_attrs attrs; 252 struct spdk_ftl_conf conf; 253 254 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs, sizeof(attrs)); 255 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf)); 256 257 spdk_json_write_named_object_begin(w, "ftl"); 258 259 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 260 261 if (conf.cache_bdev) { 262 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 263 } 264 265 /* ftl */ 266 spdk_json_write_object_end(w); 267 268 return 0; 269 } 270 271 static const struct spdk_bdev_fn_table ftl_fn_table = { 272 .destruct = bdev_ftl_destruct, 273 .submit_request = bdev_ftl_submit_request, 274 .io_type_supported = bdev_ftl_io_type_supported, 275 .get_io_channel = bdev_ftl_get_io_channel, 276 .write_config_json = bdev_ftl_write_config_json, 277 .dump_info_json = bdev_ftl_dump_info_json, 278 }; 279 280 static void 281 bdev_ftl_create_err_complete(struct ftl_bdev *ftl_bdev) 282 { 283 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 284 void *init_arg = ftl_bdev->init_arg; 285 int rc = ftl_bdev->rc; 286 287 bdev_ftl_free(ftl_bdev); 288 289 assert(rc); 290 init_cb(NULL, init_arg, rc); 291 } 292 293 static void 294 bdev_ftl_create_err_cleanup_cb(void *ctx, int status) 295 { 296 struct ftl_bdev *ftl_bdev = ctx; 297 298 if (status) { 299 SPDK_ERRLOG("Fatal ERROR of FTL cleanup, name %s\n", ftl_bdev->bdev.name); 300 } 301 302 bdev_ftl_create_err_complete(ftl_bdev); 303 } 304 305 static void 306 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 307 { 308 struct ftl_bdev *ftl_bdev = ctx; 309 struct ftl_bdev_info info = {}; 310 struct spdk_ftl_attrs attrs; 311 struct spdk_ftl_conf conf; 312 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 313 void *init_arg = ftl_bdev->init_arg; 314 315 if (status) { 316 SPDK_ERRLOG("Failed to create FTL device (%d)\n", status); 317 ftl_bdev->rc = status; 318 goto error; 319 } 320 321 spdk_ftl_dev_get_attrs(dev, &attrs, sizeof(attrs)); 322 spdk_ftl_dev_get_conf(dev, &conf, sizeof(conf)); 323 324 ftl_bdev->dev = dev; 325 ftl_bdev->bdev.product_name = "FTL disk"; 326 ftl_bdev->bdev.write_cache = 0; 327 ftl_bdev->bdev.blocklen = attrs.block_size; 328 ftl_bdev->bdev.blockcnt = attrs.num_blocks; 329 ftl_bdev->bdev.uuid = conf.uuid; 330 ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size; 331 ftl_bdev->bdev.split_on_optimal_io_boundary = true; 332 333 SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name); 334 SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size); 335 SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks); 336 337 ftl_bdev->bdev.ctxt = ftl_bdev; 338 ftl_bdev->bdev.fn_table = &ftl_fn_table; 339 ftl_bdev->bdev.module = &g_ftl_if; 340 341 status = spdk_bdev_register(&ftl_bdev->bdev); 342 if (status) { 343 ftl_bdev->rc = status; 344 goto error; 345 } 346 347 info.name = ftl_bdev->bdev.name; 348 info.uuid = ftl_bdev->bdev.uuid; 349 350 init_cb(&info, init_arg, 0); 351 return; 352 353 error: 354 if (ftl_bdev->dev) { 355 /* Cleanup all FTL */ 356 spdk_ftl_dev_set_fast_shutdown(ftl_bdev->dev, false); 357 358 /* FTL was created, but we have got an error, so we need to delete it */ 359 spdk_ftl_dev_free(dev, bdev_ftl_create_err_cleanup_cb, ftl_bdev); 360 } else { 361 bdev_ftl_create_err_complete(ftl_bdev); 362 } 363 } 364 365 static void 366 bdev_ftl_defer_free(struct ftl_deferred_init *init) 367 { 368 spdk_ftl_conf_deinit(&init->conf); 369 free(init); 370 } 371 372 int 373 bdev_ftl_defer_init(const struct spdk_ftl_conf *conf) 374 { 375 struct ftl_deferred_init *init; 376 int rc; 377 378 init = calloc(1, sizeof(*init)); 379 if (!init) { 380 return -ENOMEM; 381 } 382 383 rc = spdk_ftl_conf_copy(&init->conf, conf); 384 if (rc) { 385 free(init); 386 return -ENOMEM; 387 } 388 389 LIST_INSERT_HEAD(&g_deferred_init, init, entry); 390 391 return 0; 392 } 393 394 static void 395 bdev_ftl_create_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 396 { 397 } 398 399 int 400 bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void *cb_arg) 401 { 402 struct ftl_bdev *ftl_bdev; 403 struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc; 404 int rc; 405 406 rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 407 &base_bdev_desc); 408 if (rc) { 409 return rc; 410 } 411 rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 412 &cache_bdev_desc); 413 if (rc) { 414 spdk_bdev_close(base_bdev_desc); 415 return rc; 416 } 417 418 ftl_bdev = calloc(1, sizeof(*ftl_bdev)); 419 if (!ftl_bdev) { 420 SPDK_ERRLOG("Could not allocate ftl_bdev\n"); 421 spdk_bdev_close(base_bdev_desc); 422 spdk_bdev_close(cache_bdev_desc); 423 return -ENOMEM; 424 } 425 426 ftl_bdev->base_bdev_desc = base_bdev_desc; 427 ftl_bdev->cache_bdev_desc = cache_bdev_desc; 428 429 ftl_bdev->bdev.name = strdup(conf->name); 430 if (!ftl_bdev->bdev.name) { 431 rc = -ENOMEM; 432 goto error; 433 } 434 435 ftl_bdev->init_cb = cb; 436 ftl_bdev->init_arg = cb_arg; 437 438 rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev); 439 if (rc) { 440 SPDK_ERRLOG("Could not create FTL device\n"); 441 goto error; 442 } 443 444 return 0; 445 446 error: 447 bdev_ftl_free(ftl_bdev); 448 return rc; 449 } 450 451 static int 452 bdev_ftl_initialize(void) 453 { 454 return spdk_ftl_init(); 455 } 456 457 static void 458 bdev_ftl_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 459 { 460 } 461 462 void 463 bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn, 464 void *cb_arg) 465 { 466 struct spdk_bdev_desc *ftl_bdev_desc; 467 struct spdk_bdev *bdev; 468 struct ftl_bdev *ftl; 469 int rc; 470 471 rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc); 472 473 if (rc) { 474 goto not_found; 475 } 476 477 bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc); 478 479 if (bdev->module != &g_ftl_if) { 480 goto bdev_opened; 481 } 482 483 ftl = bdev->ctxt; 484 assert(ftl); 485 spdk_ftl_dev_set_fast_shutdown(ftl->dev, fast_shutdown); 486 spdk_bdev_close(ftl_bdev_desc); 487 488 rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg); 489 if (rc) { 490 cb_fn(cb_arg, rc); 491 } 492 493 return; 494 bdev_opened: 495 spdk_bdev_close(ftl_bdev_desc); 496 not_found: 497 cb_fn(cb_arg, -ENODEV); 498 } 499 500 void 501 bdev_ftl_unmap(const char *name, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb_fn, 502 void *cb_arg) 503 { 504 struct bdev_ftl_action *action; 505 506 action = bdev_ftl_action_start(name, 0, cb_fn, cb_arg); 507 if (!action) { 508 return; 509 } 510 511 /* It's ok to pass NULL as IO channel - FTL will detect this and use it's internal IO channel for management operations */ 512 action->rc = spdk_ftl_unmap(action->ftl_bdev_dev->dev, NULL, NULL, lba, num_blocks, 513 bdev_ftl_action_finish_cb, action); 514 if (action->rc) { 515 bdev_ftl_action_finish(action); 516 } 517 } 518 519 static void 520 bdev_ftl_get_stats_cb(struct ftl_stats *stats, void *cb_arg) 521 { 522 struct bdev_ftl_action *action = cb_arg; 523 524 bdev_ftl_action_finish(action); 525 } 526 527 void 528 bdev_ftl_get_stats(const char *name, spdk_ftl_fn cb, struct rpc_ftl_stats_ctx *ftl_stats_ctx) 529 { 530 struct bdev_ftl_action *action; 531 532 action = bdev_ftl_action_start(name, 0, cb, ftl_stats_ctx); 533 if (!action) { 534 return; 535 } 536 ftl_stats_ctx->ftl_bdev_desc = action->ftl_bdev_desc; 537 action->rc = spdk_ftl_get_stats(action->ftl_bdev_dev->dev, &ftl_stats_ctx->ftl_stats, 538 bdev_ftl_get_stats_cb, action); 539 if (action->rc) { 540 bdev_ftl_action_finish(action); 541 } 542 } 543 544 void 545 bdev_ftl_get_properties(const char *name, spdk_ftl_fn cb_fn, struct spdk_jsonrpc_request *request) 546 { 547 struct bdev_ftl_action *action; 548 549 action = bdev_ftl_action_start(name, 0, cb_fn, request); 550 if (!action) { 551 return; 552 } 553 554 action->rc = spdk_ftl_get_properties(action->ftl_bdev_dev->dev, request, 555 bdev_ftl_action_finish_cb, action); 556 if (action->rc) { 557 bdev_ftl_action_finish(action); 558 } 559 } 560 561 struct bdev_ftl_set_property_args { 562 char *property; 563 char *value; 564 }; 565 566 static void 567 bdev_ftl_set_property_cb(void *cb_arg, int status) 568 { 569 struct bdev_ftl_action *action = cb_arg; 570 struct bdev_ftl_set_property_args *args = bdev_ftl_action_ctx(action, sizeof(*args)); 571 572 free(args->property); 573 free(args->value); 574 args->property = NULL; 575 args->value = NULL; 576 bdev_ftl_action_finish_cb(cb_arg, status); 577 } 578 579 void 580 bdev_ftl_set_property(const char *name, const char *property, const char *value, 581 spdk_ftl_fn cb_fn, void *cb_arg) 582 { 583 struct bdev_ftl_action *action; 584 struct bdev_ftl_set_property_args *args; 585 586 action = bdev_ftl_action_start(name, sizeof(*args), cb_fn, cb_arg); 587 if (!action) { 588 return; 589 } 590 591 args = bdev_ftl_action_ctx(action, sizeof(*args)); 592 args->property = strdup(property); 593 args->value = strdup(value); 594 595 if (!args->property || !args->value) { 596 free(args->property); 597 free(args->value); 598 action->rc = -ENOMEM; 599 bdev_ftl_action_finish(action); 600 return; 601 } 602 603 action->rc = spdk_ftl_set_property(action->ftl_bdev_dev->dev, 604 args->property, args->value, strlen(args->value) + 1, 605 bdev_ftl_set_property_cb, action); 606 if (action->rc) { 607 bdev_ftl_action_finish(action); 608 } 609 } 610 611 static void 612 bdev_ftl_finish(void) 613 { 614 spdk_ftl_fini(); 615 } 616 617 static void 618 bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status) 619 { 620 struct ftl_deferred_init *opts = ctx; 621 622 if (status) { 623 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->conf.name); 624 } 625 626 bdev_ftl_defer_free(opts); 627 628 spdk_bdev_module_examine_done(&g_ftl_if); 629 } 630 631 static void 632 bdev_ftl_examine(struct spdk_bdev *bdev) 633 { 634 struct ftl_deferred_init *opts; 635 int rc; 636 637 LIST_FOREACH(opts, &g_deferred_init, entry) { 638 /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */ 639 rc = bdev_ftl_create_bdev(&opts->conf, bdev_ftl_create_deferred_cb, opts); 640 if (rc == -ENODEV) { 641 continue; 642 } 643 644 LIST_REMOVE(opts, entry); 645 646 if (rc) { 647 bdev_ftl_create_deferred_cb(NULL, opts, rc); 648 } 649 return; 650 } 651 652 spdk_bdev_module_examine_done(&g_ftl_if); 653 } 654 655 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl) 656 657 /* 658 * Generic function to execute an action on the FTL bdev 659 */ 660 static void 661 bdev_ftl_action_finish(struct bdev_ftl_action *action) 662 { 663 action->cb_fn(action->cb_arg, action->rc); 664 if (action->ftl_bdev_desc) { 665 spdk_bdev_close(action->ftl_bdev_desc); 666 } 667 free(action); 668 } 669 670 static struct bdev_ftl_action * 671 bdev_ftl_action_start(const char *bdev_name, size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg) 672 { 673 struct spdk_bdev *bdev; 674 struct bdev_ftl_action *action = calloc(1, sizeof(*action) + ctx_size); 675 676 if (NULL == action) { 677 cb_fn(cb_arg, -ENOMEM); 678 return NULL; 679 } 680 action->cb_arg = cb_arg; 681 action->cb_fn = cb_fn; 682 action->ctx_size = ctx_size; 683 684 action->rc = spdk_bdev_open_ext(bdev_name, false, bdev_ftl_event_cb, NULL, &action->ftl_bdev_desc); 685 if (action->rc) { 686 goto error; 687 } 688 689 bdev = spdk_bdev_desc_get_bdev(action->ftl_bdev_desc); 690 if (bdev->module != &g_ftl_if) { 691 action->rc = -ENODEV; 692 goto error; 693 } 694 695 action->ftl_bdev_dev = bdev->ctxt; 696 assert(action->ftl_bdev_dev); 697 698 return action; 699 error: 700 bdev_ftl_action_finish(action); 701 return NULL; 702 } 703 704 static void 705 bdev_ftl_action_finish_cb(void *cb_arg, int status) 706 { 707 struct bdev_ftl_action *action = cb_arg; 708 709 action->rc = status; 710 bdev_ftl_action_finish(action); 711 } 712 713 static void * 714 bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size) 715 { 716 assert(action->ctx_size); 717 assert(size == action->ctx_size); 718 return action->ctx; 719 } 720