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 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 63 exit_thread(void *ctx) 64 { 65 struct spdk_thread *thread = ctx; 66 67 spdk_thread_exit(thread); 68 } 69 70 static void 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 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 * 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->unmap_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 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 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 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 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