1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2018 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/stdinc.h"
7 #include "spdk/nvme.h"
8 #include "spdk/thread.h"
9 #include "spdk/string.h"
10 #include "spdk/likely.h"
11 #include "spdk/ftl.h"
12 #include "spdk/bdev_module.h"
13 #include "spdk/config.h"
14
15 #include "ftl_core.h"
16 #include "ftl_io.h"
17 #include "ftl_band.h"
18 #include "ftl_debug.h"
19 #include "ftl_nv_cache.h"
20 #include "ftl_writer.h"
21 #include "ftl_utils.h"
22 #include "mngt/ftl_mngt.h"
23
24 struct ftl_dev_init_ctx {
25 spdk_ftl_init_fn cb_fn;
26 /* Callback's argument */
27 void *cb_arg;
28 };
29
30 struct ftl_dev_free_ctx {
31 spdk_ftl_fn cb_fn;
32 /* Callback's argument */
33 void *cb_arg;
34 };
35
36 static int
init_core_thread(struct spdk_ftl_dev * dev)37 init_core_thread(struct spdk_ftl_dev *dev)
38 {
39 struct spdk_cpuset cpumask = {};
40
41 /*
42 * If core mask is provided create core thread on first cpu that match with the mask,
43 * otherwise use current user thread
44 */
45 if (dev->conf.core_mask) {
46 if (spdk_cpuset_parse(&cpumask, dev->conf.core_mask)) {
47 return -EINVAL;
48 }
49 dev->core_thread = spdk_thread_create("ftl_core_thread", &cpumask);
50 } else {
51 dev->core_thread = spdk_get_thread();
52 }
53
54 if (dev->core_thread == NULL) {
55 FTL_ERRLOG(dev, "Cannot create thread for mask %s\n", dev->conf.core_mask);
56 return -ENOMEM;
57 }
58
59 return 0;
60 }
61
62 static void
exit_thread(void * ctx)63 exit_thread(void *ctx)
64 {
65 struct spdk_thread *thread = ctx;
66
67 spdk_thread_exit(thread);
68 }
69
70 static void
deinit_core_thread(struct spdk_ftl_dev * dev)71 deinit_core_thread(struct spdk_ftl_dev *dev)
72 {
73 if (dev->core_thread && dev->conf.core_mask) {
74 spdk_thread_send_msg(dev->core_thread, exit_thread,
75 dev->core_thread);
76 dev->core_thread = NULL;
77 }
78 }
79
80 static void
free_dev(struct spdk_ftl_dev * dev)81 free_dev(struct spdk_ftl_dev *dev)
82 {
83 if (!dev) {
84 return;
85 }
86
87 deinit_core_thread(dev);
88 spdk_ftl_conf_deinit(&dev->conf);
89 ftl_properties_deinit(dev);
90 free(dev);
91 }
92
93 static struct spdk_ftl_dev *
allocate_dev(const struct spdk_ftl_conf * conf,int * error)94 allocate_dev(const struct spdk_ftl_conf *conf, int *error)
95 {
96 int rc;
97 struct spdk_ftl_dev *dev = calloc(1, sizeof(*dev));
98
99 if (!dev) {
100 FTL_ERRLOG(dev, "Cannot allocate FTL device\n");
101 *error = -ENOMEM;
102 return NULL;
103 }
104
105 rc = ftl_properties_init(dev);
106 if (rc) {
107 *error = rc;
108 goto error;
109 }
110
111 rc = ftl_conf_init_dev(dev, conf);
112 if (rc) {
113 *error = rc;
114 goto error;
115 }
116
117 rc = init_core_thread(dev);
118 if (rc) {
119 *error = rc;
120 goto error;
121 }
122
123 TAILQ_INIT(&dev->rd_sq);
124 TAILQ_INIT(&dev->wr_sq);
125 TAILQ_INIT(&dev->trim_sq);
126 TAILQ_INIT(&dev->ioch_queue);
127
128 ftl_writer_init(dev, &dev->writer_user, SPDK_FTL_LIMIT_HIGH, FTL_BAND_TYPE_COMPACTION);
129 ftl_writer_init(dev, &dev->writer_gc, SPDK_FTL_LIMIT_CRIT, FTL_BAND_TYPE_GC);
130
131 return dev;
132 error:
133 free_dev(dev);
134 return NULL;
135 }
136
137 static void
dev_init_cb(struct spdk_ftl_dev * dev,void * _ctx,int status)138 dev_init_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
139 {
140 struct ftl_dev_init_ctx *ctx = _ctx;
141 int rc;
142
143 if (status) {
144 if (dev->init_retry) {
145 FTL_NOTICELOG(dev, "Startup retry\n");
146 rc = spdk_ftl_dev_init(&dev->conf, ctx->cb_fn, ctx->cb_arg);
147 if (!rc) {
148 free_dev(dev);
149 free(ctx);
150 return;
151 }
152 FTL_NOTICELOG(dev, "Startup retry failed: %d\n", rc);
153 }
154
155 free_dev(dev);
156 dev = NULL;
157 }
158 ctx->cb_fn(dev, ctx->cb_arg, status);
159 free(ctx);
160 }
161
162 int
spdk_ftl_dev_init(const struct spdk_ftl_conf * conf,spdk_ftl_init_fn cb_fn,void * cb_arg)163 spdk_ftl_dev_init(const struct spdk_ftl_conf *conf, spdk_ftl_init_fn cb_fn, void *cb_arg)
164 {
165 int rc = -1;
166 struct ftl_dev_init_ctx *ctx;
167 struct spdk_ftl_dev *dev = NULL;
168
169 ctx = calloc(1, sizeof(*ctx));
170 if (!ctx) {
171 rc = -ENOMEM;
172 goto error;
173 }
174 ctx->cb_fn = cb_fn;
175 ctx->cb_arg = cb_arg;
176
177 dev = allocate_dev(conf, &rc);
178 if (!dev) {
179 goto error;
180 }
181
182 rc = ftl_mngt_call_dev_startup(dev, dev_init_cb, ctx);
183 if (rc) {
184 goto error;
185 }
186
187 return 0;
188
189 error:
190 free(ctx);
191 free_dev(dev);
192 return rc;
193 }
194
195 static void
dev_free_cb(struct spdk_ftl_dev * dev,void * _ctx,int status)196 dev_free_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
197 {
198 struct ftl_dev_free_ctx *ctx = _ctx;
199
200 if (!status) {
201 free_dev(dev);
202 }
203 ctx->cb_fn(ctx->cb_arg, status);
204 free(ctx);
205 }
206
207 int
spdk_ftl_dev_free(struct spdk_ftl_dev * dev,spdk_ftl_fn cb_fn,void * cb_arg)208 spdk_ftl_dev_free(struct spdk_ftl_dev *dev, spdk_ftl_fn cb_fn, void *cb_arg)
209 {
210 int rc = -1;
211 struct ftl_dev_free_ctx *ctx;
212
213 ctx = calloc(1, sizeof(*ctx));
214 if (!ctx) {
215 rc = -ENOMEM;
216 goto error;
217 }
218 ctx->cb_fn = cb_fn;
219 ctx->cb_arg = cb_arg;
220
221 rc = ftl_mngt_call_dev_shutdown(dev, dev_free_cb, ctx);
222 if (rc) {
223 goto error;
224 }
225
226 return 0;
227
228 error:
229 free(ctx);
230 return rc;
231 }
232
233 SPDK_LOG_REGISTER_COMPONENT(ftl_init)
234