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