1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/thread.h" 7 8 #include "ftl_core.h" 9 #include "ftl_mngt.h" 10 #include "ftl_mngt_steps.h" 11 12 struct ftl_io_channel_ctx { 13 struct ftl_io_channel *ioch; 14 }; 15 16 struct ftl_io_channel * 17 ftl_io_channel_get_ctx(struct spdk_io_channel *ioch) 18 { 19 struct ftl_io_channel_ctx *ctx = spdk_io_channel_get_ctx(ioch); 20 return ctx->ioch; 21 } 22 23 static void 24 ftl_dev_register_channel(void *ctx) 25 { 26 struct ftl_io_channel *ioch = ctx; 27 struct spdk_ftl_dev *dev = ioch->dev; 28 29 /* This only runs on the core thread, so it's safe to do this lockless */ 30 TAILQ_INSERT_TAIL(&dev->ioch_queue, ioch, entry); 31 } 32 33 static void 34 io_channel_unregister(void *ctx) 35 { 36 struct ftl_io_channel *ioch = ctx; 37 struct spdk_ftl_dev *dev = ioch->dev; 38 39 TAILQ_REMOVE(&dev->ioch_queue, ioch, entry); 40 41 spdk_ring_free(ioch->cq); 42 spdk_ring_free(ioch->sq); 43 ftl_mempool_destroy(ioch->map_pool); 44 free(ioch); 45 } 46 47 static int 48 io_channel_create_cb(void *io_device, void *ctx) 49 { 50 struct spdk_ftl_dev *dev = io_device; 51 struct ftl_io_channel_ctx *_ioch = ctx; 52 struct ftl_io_channel *ioch; 53 char mempool_name[32]; 54 int rc; 55 56 FTL_NOTICELOG(dev, "FTL IO channel created on %s\n", 57 spdk_thread_get_name(spdk_get_thread())); 58 59 /* This gets unregistered asynchronously with the device - 60 * we can't just use the ctx buffer passed by the thread library 61 */ 62 ioch = calloc(1, sizeof(*ioch)); 63 if (ioch == NULL) { 64 FTL_ERRLOG(dev, "Failed to allocate IO channel\n"); 65 return -1; 66 } 67 68 rc = snprintf(mempool_name, sizeof(mempool_name), "ftl_io_%p", ioch); 69 if (rc < 0 || rc >= (int)sizeof(mempool_name)) { 70 FTL_ERRLOG(dev, "Failed to create IO channel pool name\n"); 71 free(ioch); 72 return -1; 73 } 74 75 ioch->dev = dev; 76 77 ioch->map_pool = ftl_mempool_create( 78 dev->conf.user_io_pool_size, 79 sizeof(ftl_addr) * dev->xfer_size, 80 64, 81 SPDK_ENV_SOCKET_ID_ANY); 82 if (!ioch->map_pool) { 83 FTL_ERRLOG(dev, "Failed to create IO channel's map IO pool\n"); 84 goto fail_io_pool; 85 } 86 87 ioch->cq = spdk_ring_create(SPDK_RING_TYPE_SP_SC, spdk_align64pow2(dev->conf.user_io_pool_size + 1), 88 SPDK_ENV_SOCKET_ID_ANY); 89 if (!ioch->cq) { 90 FTL_ERRLOG(dev, "Failed to create IO channel completion queue\n"); 91 goto fail_io_pool; 92 } 93 94 ioch->sq = spdk_ring_create(SPDK_RING_TYPE_SP_SC, spdk_align64pow2(dev->conf.user_io_pool_size + 1), 95 SPDK_ENV_SOCKET_ID_ANY); 96 if (!ioch->sq) { 97 FTL_ERRLOG(dev, "Failed to create IO channel submission queue\n"); 98 goto fail_cq; 99 } 100 101 ioch->poller = SPDK_POLLER_REGISTER(ftl_io_channel_poll, ioch, 0); 102 if (!ioch->poller) { 103 FTL_ERRLOG(dev, "Failed to register IO channel poller\n"); 104 goto fail_sq; 105 } 106 107 if (spdk_thread_send_msg(dev->core_thread, ftl_dev_register_channel, ioch)) { 108 FTL_ERRLOG(dev, "Failed to register IO channel\n"); 109 goto fail_poller; 110 } 111 112 _ioch->ioch = ioch; 113 return 0; 114 115 fail_poller: 116 spdk_poller_unregister(&ioch->poller); 117 fail_cq: 118 spdk_ring_free(ioch->cq); 119 fail_sq: 120 spdk_ring_free(ioch->sq); 121 fail_io_pool: 122 ftl_mempool_destroy(ioch->map_pool); 123 free(ioch); 124 125 return -1; 126 } 127 128 static void 129 io_channel_destroy_cb(void *io_device, void *ctx) 130 { 131 struct ftl_io_channel_ctx *_ioch = ctx; 132 struct ftl_io_channel *ioch = _ioch->ioch; 133 struct spdk_ftl_dev *dev = ioch->dev; 134 135 FTL_NOTICELOG(dev, "FTL IO channel destroy on %s\n", 136 spdk_thread_get_name(spdk_get_thread())); 137 138 spdk_poller_unregister(&ioch->poller); 139 spdk_thread_send_msg(ftl_get_core_thread(dev), 140 io_channel_unregister, ioch); 141 } 142 143 void 144 ftl_mngt_register_io_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 145 { 146 dev->io_device_registered = true; 147 148 spdk_io_device_register(dev, io_channel_create_cb, 149 io_channel_destroy_cb, 150 sizeof(struct ftl_io_channel_ctx), 151 NULL); 152 153 ftl_mngt_next_step(mngt); 154 } 155 156 static void 157 unregister_cb(void *io_device) 158 { 159 struct spdk_ftl_dev *dev = io_device; 160 struct ftl_mngt_process *mngt = dev->unregister_process; 161 162 dev->io_device_registered = false; 163 dev->unregister_process = NULL; 164 165 ftl_mngt_next_step(mngt); 166 } 167 168 void 169 ftl_mngt_unregister_io_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 170 { 171 if (dev->io_device_registered) { 172 dev->unregister_process = mngt; 173 spdk_io_device_unregister(dev, unregister_cb); 174 } else { 175 ftl_mngt_skip_step(mngt); 176 } 177 } 178 179 void 180 ftl_mngt_init_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 181 { 182 dev->ioch = spdk_get_io_channel(dev); 183 if (!dev->ioch) { 184 FTL_ERRLOG(dev, "Unable to get IO channel for core thread"); 185 ftl_mngt_fail_step(mngt); 186 return; 187 } 188 189 ftl_mngt_next_step(mngt); 190 } 191 192 void 193 ftl_mngt_deinit_io_channel(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 194 { 195 if (dev->ioch) { 196 spdk_put_io_channel(dev->ioch); 197 dev->ioch = NULL; 198 } 199 200 ftl_mngt_next_step(mngt); 201 } 202