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->ioch_queue); 121 122 ftl_writer_init(dev, &dev->writer_user, SPDK_FTL_LIMIT_HIGH, FTL_BAND_TYPE_COMPACTION); 123 ftl_writer_init(dev, &dev->writer_gc, SPDK_FTL_LIMIT_CRIT, FTL_BAND_TYPE_GC); 124 125 return dev; 126 error: 127 free_dev(dev); 128 return NULL; 129 } 130 131 static void 132 dev_init_cb(struct spdk_ftl_dev *dev, void *_ctx, int status) 133 { 134 struct ftl_dev_init_ctx *ctx = _ctx; 135 int rc; 136 137 if (status) { 138 if (dev->init_retry) { 139 FTL_NOTICELOG(dev, "Startup retry\n"); 140 rc = spdk_ftl_dev_init(&dev->conf, ctx->cb_fn, ctx->cb_arg); 141 if (!rc) { 142 free_dev(dev); 143 free(ctx); 144 return; 145 } 146 FTL_NOTICELOG(dev, "Startup retry failed: %d\n", rc); 147 } 148 149 free_dev(dev); 150 dev = NULL; 151 } 152 ctx->cb_fn(dev, ctx->cb_arg, status); 153 free(ctx); 154 } 155 156 int 157 spdk_ftl_dev_init(const struct spdk_ftl_conf *conf, spdk_ftl_init_fn cb_fn, void *cb_arg) 158 { 159 int rc = -1; 160 struct ftl_dev_init_ctx *ctx; 161 struct spdk_ftl_dev *dev = NULL; 162 163 ctx = calloc(1, sizeof(*ctx)); 164 if (!ctx) { 165 rc = -ENOMEM; 166 goto error; 167 } 168 ctx->cb_fn = cb_fn; 169 ctx->cb_arg = cb_arg; 170 171 dev = allocate_dev(conf, &rc); 172 if (!dev) { 173 goto error; 174 } 175 176 rc = ftl_mngt_call_dev_startup(dev, dev_init_cb, ctx); 177 if (rc) { 178 goto error; 179 } 180 181 return 0; 182 183 error: 184 free(ctx); 185 free_dev(dev); 186 return rc; 187 } 188 189 static void 190 dev_free_cb(struct spdk_ftl_dev *dev, void *_ctx, int status) 191 { 192 struct ftl_dev_free_ctx *ctx = _ctx; 193 194 if (!status) { 195 free_dev(dev); 196 } 197 ctx->cb_fn(ctx->cb_arg, status); 198 free(ctx); 199 } 200 201 int 202 spdk_ftl_dev_free(struct spdk_ftl_dev *dev, spdk_ftl_fn cb_fn, void *cb_arg) 203 { 204 int rc = -1; 205 struct ftl_dev_free_ctx *ctx; 206 207 ctx = calloc(1, sizeof(*ctx)); 208 if (!ctx) { 209 rc = -ENOMEM; 210 goto error; 211 } 212 ctx->cb_fn = cb_fn; 213 ctx->cb_arg = cb_arg; 214 215 rc = ftl_mngt_call_dev_shutdown(dev, dev_free_cb, ctx); 216 if (rc) { 217 goto error; 218 } 219 220 return 0; 221 222 error: 223 free(ctx); 224 return rc; 225 } 226 227 SPDK_LOG_REGISTER_COMPONENT(ftl_init) 228