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