xref: /spdk/lib/ftl/nvc/ftl_nvc_bdev_vss.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright 2023 Solidigm All Rights Reserved
3  */
4 
5 #include "ftl_nvc_dev.h"
6 #include "ftl_core.h"
7 #include "ftl_layout.h"
8 #include "utils/ftl_layout_tracker_bdev.h"
9 
10 static bool
11 is_bdev_compatible(struct spdk_ftl_dev *dev, struct spdk_bdev *bdev)
12 {
13 	if (!spdk_bdev_is_md_separate(bdev)) {
14 		/* It doesn't support separate metadata buffer IO */
15 		return false;
16 	}
17 
18 	if (spdk_bdev_get_md_size(bdev) != sizeof(union ftl_md_vss)) {
19 		/* Bdev's metadata is invalid size */
20 		return false;
21 	}
22 
23 	if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
24 		/* Unsupported DIF type used by bdev */
25 		return false;
26 	}
27 
28 	if (ftl_md_xfer_blocks(dev) * spdk_bdev_get_md_size(bdev) > FTL_ZERO_BUFFER_SIZE) {
29 		FTL_ERRLOG(dev, "Zero buffer too small for bdev %s metadata transfer\n",
30 			   spdk_bdev_get_name(bdev));
31 		return false;
32 	}
33 
34 	return true;
35 }
36 
37 static void
38 md_region_setup(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
39 		struct ftl_layout_region *region)
40 {
41 	assert(region);
42 	region->type = reg_type;
43 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
44 	region->name = ftl_md_region_name(reg_type);
45 
46 	region->bdev_desc = dev->nv_cache.bdev_desc;
47 	region->ioch = dev->nv_cache.cache_ioch;
48 	region->vss_blksz = dev->nv_cache.md_size;
49 }
50 
51 static int
52 md_region_create(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
53 		 uint32_t reg_version, size_t reg_blks)
54 {
55 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
56 
57 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
58 	reg_blks = ftl_md_region_align_blocks(dev, reg_blks);
59 
60 	reg_props = ftl_layout_tracker_bdev_add_region(dev->nvc_layout_tracker, reg_type, reg_version,
61 			reg_blks, 0);
62 	if (!reg_props) {
63 		return -1;
64 	}
65 	assert(reg_props->type == reg_type);
66 	assert(reg_props->ver == reg_version);
67 	assert(reg_props->blk_sz == reg_blks);
68 	assert(reg_props->blk_offs + reg_blks <= dev->layout.nvc.total_blocks);
69 	return 0;
70 }
71 
72 static int
73 md_region_open(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, uint32_t reg_version,
74 	       size_t entry_size, size_t entry_count, struct ftl_layout_region *region)
75 {
76 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
77 	uint64_t reg_blks = ftl_md_region_blocks(dev, entry_size * entry_count);
78 
79 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
80 
81 	while (true) {
82 		ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, reg_type, &reg_search_ctx);
83 		if (!reg_search_ctx || reg_search_ctx->ver == reg_version) {
84 			break;
85 		}
86 	}
87 
88 	if (!reg_search_ctx || reg_search_ctx->blk_sz < reg_blks) {
89 		/* Region not found or insufficient space */
90 		return -1;
91 	}
92 
93 	if (!region) {
94 		return 0;
95 	}
96 
97 	md_region_setup(dev, reg_type, region);
98 
99 	region->entry_size = entry_size / FTL_BLOCK_SIZE;
100 	region->num_entries = entry_count;
101 
102 	region->current.version = reg_version;
103 	region->current.offset = reg_search_ctx->blk_offs;
104 	region->current.blocks = reg_search_ctx->blk_sz;
105 
106 	return 0;
107 }
108 
109 struct ftl_nv_cache_device_desc nvc_bdev_vss = {
110 	.name = "bdev",
111 	.features = {
112 	},
113 	.ops = {
114 		.is_bdev_compatible = is_bdev_compatible,
115 
116 		.md_layout_ops = {
117 			.region_create = md_region_create,
118 			.region_open = md_region_open,
119 		},
120 	}
121 };
122 FTL_NV_CACHE_DEVICE_TYPE_REGISTER(nvc_bdev_vss)
123