1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <ctype.h> 35 #include <assert.h> 36 37 #include "nvmf_internal.h" 38 #include "session.h" 39 #include "subsystem.h" 40 #include "transport.h" 41 42 #include "spdk/string.h" 43 #include "spdk/trace.h" 44 #include "spdk/nvmf_spec.h" 45 46 #include "spdk_internal/log.h" 47 48 static TAILQ_HEAD(, spdk_nvmf_subsystem) g_subsystems = TAILQ_HEAD_INITIALIZER(g_subsystems); 49 50 struct spdk_nvmf_subsystem * 51 nvmf_find_subsystem(const char *subnqn, const char *hostnqn) 52 { 53 struct spdk_nvmf_subsystem *subsystem; 54 struct spdk_nvmf_host *host; 55 56 if (!subnqn || !hostnqn) { 57 return NULL; 58 } 59 60 TAILQ_FOREACH(subsystem, &g_subsystems, entries) { 61 if (strcmp(subnqn, subsystem->subnqn) == 0) { 62 if (subsystem->num_hosts == 0) { 63 /* No hosts means any host can connect */ 64 return subsystem; 65 } 66 67 TAILQ_FOREACH(host, &subsystem->hosts, link) { 68 if (strcmp(hostnqn, host->nqn) == 0) { 69 return subsystem; 70 } 71 } 72 } 73 } 74 75 return NULL; 76 } 77 78 void 79 spdk_nvmf_subsystem_poll(struct spdk_nvmf_subsystem *subsystem) 80 { 81 struct spdk_nvmf_session *session; 82 83 TAILQ_FOREACH(session, &subsystem->sessions, link) { 84 /* For NVMe subsystems, check the backing physical device for completions. */ 85 if (subsystem->subtype == SPDK_NVMF_SUBTYPE_NVME) { 86 session->subsys->ops->poll_for_completions(session); 87 } 88 89 /* For each connection in the session, check for completions */ 90 spdk_nvmf_session_poll(session); 91 } 92 } 93 94 static bool 95 spdk_nvmf_valid_nqn(const char *nqn) 96 { 97 size_t len; 98 99 len = strlen(nqn); 100 if (len >= SPDK_NVMF_NQN_MAX_LEN) { 101 SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN - 1); 102 return false; 103 } 104 105 if (strncmp(nqn, "nqn.", 4) != 0) { 106 SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn); 107 return false; 108 } 109 110 /* yyyy-mm. */ 111 if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) && 112 nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) { 113 SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn); 114 return false; 115 } 116 117 return true; 118 } 119 120 struct spdk_nvmf_subsystem * 121 spdk_nvmf_create_subsystem(const char *nqn, 122 enum spdk_nvmf_subtype type, 123 enum spdk_nvmf_subsystem_mode mode, 124 void *cb_ctx, 125 spdk_nvmf_subsystem_connect_fn connect_cb, 126 spdk_nvmf_subsystem_disconnect_fn disconnect_cb) 127 { 128 struct spdk_nvmf_subsystem *subsystem; 129 130 if (!spdk_nvmf_valid_nqn(nqn)) { 131 return NULL; 132 } 133 134 subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem)); 135 if (subsystem == NULL) { 136 return NULL; 137 } 138 139 subsystem->subtype = type; 140 subsystem->mode = mode; 141 subsystem->cb_ctx = cb_ctx; 142 subsystem->connect_cb = connect_cb; 143 subsystem->disconnect_cb = disconnect_cb; 144 snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn); 145 TAILQ_INIT(&subsystem->listen_addrs); 146 TAILQ_INIT(&subsystem->hosts); 147 TAILQ_INIT(&subsystem->sessions); 148 149 if (mode == NVMF_SUBSYSTEM_MODE_DIRECT) { 150 subsystem->ops = &spdk_nvmf_direct_ctrlr_ops; 151 } else { 152 subsystem->ops = &spdk_nvmf_virtual_ctrlr_ops; 153 } 154 155 TAILQ_INSERT_HEAD(&g_subsystems, subsystem, entries); 156 157 return subsystem; 158 } 159 160 void 161 spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem) 162 { 163 struct spdk_nvmf_listen_addr *listen_addr, *listen_addr_tmp; 164 struct spdk_nvmf_host *host, *host_tmp; 165 struct spdk_nvmf_session *session, *session_tmp; 166 167 if (!subsystem) { 168 return; 169 } 170 171 SPDK_TRACELOG(SPDK_TRACE_NVMF, "subsystem is %p\n", subsystem); 172 173 TAILQ_FOREACH_SAFE(listen_addr, &subsystem->listen_addrs, link, listen_addr_tmp) { 174 TAILQ_REMOVE(&subsystem->listen_addrs, listen_addr, link); 175 free(listen_addr->traddr); 176 free(listen_addr->trsvcid); 177 free(listen_addr->trname); 178 free(listen_addr); 179 subsystem->num_listen_addrs--; 180 } 181 182 TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) { 183 TAILQ_REMOVE(&subsystem->hosts, host, link); 184 free(host->nqn); 185 free(host); 186 subsystem->num_hosts--; 187 } 188 189 TAILQ_FOREACH_SAFE(session, &subsystem->sessions, link, session_tmp) { 190 spdk_nvmf_session_destruct(session); 191 } 192 193 if (subsystem->ops->detach) { 194 subsystem->ops->detach(subsystem); 195 } 196 197 TAILQ_REMOVE(&g_subsystems, subsystem, entries); 198 199 free(subsystem); 200 } 201 202 int 203 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem, 204 char *trname, char *traddr, char *trsvcid) 205 { 206 struct spdk_nvmf_listen_addr *listen_addr; 207 const struct spdk_nvmf_transport *transport; 208 int rc; 209 210 transport = spdk_nvmf_transport_get(trname); 211 if (!transport) { 212 return -1; 213 } 214 215 listen_addr = calloc(1, sizeof(*listen_addr)); 216 if (!listen_addr) { 217 return -1; 218 } 219 220 listen_addr->traddr = strdup(traddr); 221 if (!listen_addr->traddr) { 222 free(listen_addr); 223 return -1; 224 } 225 226 listen_addr->trsvcid = strdup(trsvcid); 227 if (!listen_addr->trsvcid) { 228 free(listen_addr->traddr); 229 free(listen_addr); 230 return -1; 231 } 232 233 listen_addr->trname = strdup(trname); 234 if (!listen_addr->trname) { 235 free(listen_addr->traddr); 236 free(listen_addr->trsvcid); 237 free(listen_addr); 238 return -1; 239 } 240 241 TAILQ_INSERT_HEAD(&subsystem->listen_addrs, listen_addr, link); 242 subsystem->num_listen_addrs++; 243 244 rc = transport->listen_addr_add(listen_addr); 245 if (rc < 0) { 246 SPDK_ERRLOG("Unable to listen on address '%s'\n", traddr); 247 return -1; 248 } 249 250 return 0; 251 } 252 253 int 254 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, char *host_nqn) 255 { 256 struct spdk_nvmf_host *host; 257 258 host = calloc(1, sizeof(*host)); 259 if (!host) { 260 return -1; 261 } 262 host->nqn = strdup(host_nqn); 263 if (!host->nqn) { 264 free(host); 265 return -1; 266 } 267 268 TAILQ_INSERT_HEAD(&subsystem->hosts, host, link); 269 subsystem->num_hosts++; 270 271 return 0; 272 } 273 274 int 275 nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, 276 struct spdk_nvme_ctrlr *ctrlr, const struct spdk_pci_addr *pci_addr) 277 { 278 subsystem->dev.direct.ctrlr = ctrlr; 279 subsystem->dev.direct.pci_addr = *pci_addr; 280 /* Assume that all I/O will be handled on one thread for now */ 281 subsystem->dev.direct.io_qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, 0); 282 if (subsystem->dev.direct.io_qpair == NULL) { 283 SPDK_ERRLOG("spdk_nvme_ctrlr_alloc_io_qpair() failed\n"); 284 return -1; 285 } 286 return 0; 287 } 288 289 void 290 spdk_format_discovery_log(struct spdk_nvmf_discovery_log_page *disc_log, uint32_t length) 291 { 292 int numrec = 0; 293 struct spdk_nvmf_subsystem *subsystem; 294 struct spdk_nvmf_listen_addr *listen_addr; 295 struct spdk_nvmf_discovery_log_page_entry *entry; 296 const struct spdk_nvmf_transport *transport; 297 298 TAILQ_FOREACH(subsystem, &g_subsystems, entries) { 299 if (subsystem->subtype == SPDK_NVMF_SUBTYPE_DISCOVERY) { 300 continue; 301 } 302 303 TAILQ_FOREACH(listen_addr, &subsystem->listen_addrs, link) { 304 /* include the discovery log entry */ 305 if (length > sizeof(struct spdk_nvmf_discovery_log_page)) { 306 if (sizeof(struct spdk_nvmf_discovery_log_page) + (numrec + 1) * sizeof( 307 struct spdk_nvmf_discovery_log_page_entry) > length) { 308 break; 309 } 310 entry = &disc_log->entries[numrec]; 311 entry->portid = numrec; 312 entry->cntlid = 0xffff; 313 entry->asqsz = g_nvmf_tgt.max_queue_depth; 314 entry->subtype = subsystem->subtype; 315 snprintf(entry->subnqn, sizeof(entry->subnqn), "%s", subsystem->subnqn); 316 317 transport = spdk_nvmf_transport_get(listen_addr->trname); 318 assert(transport != NULL); 319 320 transport->listen_addr_discover(listen_addr, entry); 321 } 322 numrec++; 323 } 324 } 325 326 disc_log->numrec = numrec; 327 } 328 329 int 330 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev) 331 { 332 int i = 0; 333 334 assert(subsystem->mode == NVMF_SUBSYSTEM_MODE_VIRTUAL); 335 while (i < MAX_VIRTUAL_NAMESPACE && subsystem->dev.virt.ns_list[i]) { 336 i++; 337 } 338 if (i == MAX_VIRTUAL_NAMESPACE) { 339 SPDK_ERRLOG("spdk_nvmf_subsystem_add_ns() failed\n"); 340 return -1; 341 } 342 subsystem->dev.virt.ns_list[i] = bdev; 343 subsystem->dev.virt.ns_count++; 344 return 0; 345 } 346 347 int 348 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn) 349 { 350 if (subsystem->mode != NVMF_SUBSYSTEM_MODE_VIRTUAL) { 351 return -1; 352 } 353 354 snprintf(subsystem->dev.virt.sn, sizeof(subsystem->dev.virt.sn), "%s", sn); 355 356 return 0; 357 } 358 359 const char * 360 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem) 361 { 362 return subsystem->subnqn; 363 } 364 365 /* Workaround for astyle formatting bug */ 366 typedef enum spdk_nvmf_subtype nvmf_subtype_t; 367 368 nvmf_subtype_t 369 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem) 370 { 371 return subsystem->subtype; 372 } 373 374 /* Workaround for astyle formatting bug */ 375 typedef enum spdk_nvmf_subsystem_mode nvmf_mode_t; 376 377 nvmf_mode_t 378 spdk_nvmf_subsystem_get_mode(struct spdk_nvmf_subsystem *subsystem) 379 { 380 return subsystem->mode; 381 } 382