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 "spdk/stdinc.h" 35 36 #include "nvmf_internal.h" 37 #include "ctrlr.h" 38 #include "subsystem.h" 39 #include "transport.h" 40 41 #include "spdk/likely.h" 42 #include "spdk/string.h" 43 #include "spdk/trace.h" 44 #include "spdk/nvmf_spec.h" 45 46 #include "spdk_internal/bdev.h" 47 #include "spdk_internal/log.h" 48 49 struct spdk_nvmf_subsystem * 50 spdk_nvmf_find_subsystem_with_cntlid(uint16_t cntlid) 51 { 52 struct spdk_nvmf_subsystem *subsystem; 53 struct spdk_nvmf_ctrlr *ctrlr; 54 55 TAILQ_FOREACH(subsystem, &g_nvmf_tgt.subsystems, entries) { 56 TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) { 57 if (ctrlr->cntlid == cntlid) { 58 return subsystem; 59 } 60 } 61 } 62 63 return NULL; 64 } 65 66 int 67 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem) 68 { 69 return spdk_nvmf_subsystem_bdev_attach(subsystem); 70 } 71 72 static bool 73 nvmf_subsystem_removable(struct spdk_nvmf_subsystem *subsystem) 74 { 75 struct spdk_nvmf_ctrlr *ctrlr; 76 struct spdk_nvmf_qpair *qpair; 77 78 if (subsystem->is_removed) { 79 TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) { 80 TAILQ_FOREACH(qpair, &ctrlr->qpairs, link) { 81 if (!spdk_nvmf_transport_qpair_is_idle(qpair)) { 82 return false; 83 } 84 } 85 } 86 return true; 87 } 88 return false; 89 } 90 91 void 92 spdk_nvmf_subsystem_poll(struct spdk_nvmf_subsystem *subsystem) 93 { 94 struct spdk_nvmf_ctrlr *ctrlr; 95 96 TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) { 97 /* For each connection in the ctrlr, check for completions */ 98 spdk_nvmf_ctrlr_poll(ctrlr); 99 } 100 101 if (nvmf_subsystem_removable(subsystem)) { 102 spdk_nvmf_subsystem_bdev_detach(subsystem); 103 } 104 } 105 106 static bool 107 spdk_nvmf_valid_nqn(const char *nqn) 108 { 109 size_t len; 110 111 len = strlen(nqn); 112 if (len > SPDK_NVMF_NQN_MAX_LEN) { 113 SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN); 114 return false; 115 } 116 117 if (strncmp(nqn, "nqn.", 4) != 0) { 118 SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn); 119 return false; 120 } 121 122 /* yyyy-mm. */ 123 if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) && 124 nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) { 125 SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn); 126 return false; 127 } 128 129 return true; 130 } 131 132 struct spdk_nvmf_subsystem * 133 spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt, 134 const char *nqn, 135 enum spdk_nvmf_subtype type, 136 uint32_t num_ns, 137 void *cb_ctx, 138 spdk_nvmf_subsystem_connect_fn connect_cb, 139 spdk_nvmf_subsystem_disconnect_fn disconnect_cb) 140 { 141 struct spdk_nvmf_subsystem *subsystem; 142 143 if (!spdk_nvmf_valid_nqn(nqn)) { 144 return NULL; 145 } 146 147 if (type == SPDK_NVMF_SUBTYPE_DISCOVERY && num_ns != 0) { 148 SPDK_ERRLOG("Discovery subsystem cannot have namespaces.\n"); 149 return NULL; 150 } 151 152 subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem)); 153 if (subsystem == NULL) { 154 return NULL; 155 } 156 157 subsystem->tgt = tgt; 158 159 tgt->current_subsystem_id++; 160 161 subsystem->id = tgt->current_subsystem_id; 162 subsystem->subtype = type; 163 subsystem->max_nsid = num_ns; 164 subsystem->num_allocated_nsid = 0; 165 subsystem->cb_ctx = cb_ctx; 166 subsystem->connect_cb = connect_cb; 167 subsystem->disconnect_cb = disconnect_cb; 168 snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn); 169 TAILQ_INIT(&subsystem->listeners); 170 TAILQ_INIT(&subsystem->hosts); 171 TAILQ_INIT(&subsystem->ctrlrs); 172 173 if (num_ns != 0) { 174 subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns)); 175 if (subsystem->ns == NULL) { 176 SPDK_ERRLOG("Namespace memory allocation failed\n"); 177 free(subsystem); 178 return NULL; 179 } 180 } 181 182 TAILQ_INSERT_TAIL(&tgt->subsystems, subsystem, entries); 183 tgt->discovery_genctr++; 184 185 return subsystem; 186 } 187 188 void 189 spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem) 190 { 191 struct spdk_nvmf_listener *listener, *listener_tmp; 192 struct spdk_nvmf_host *host, *host_tmp; 193 struct spdk_nvmf_ctrlr *ctrlr, *ctrlr_tmp; 194 195 if (!subsystem) { 196 return; 197 } 198 199 SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "subsystem is %p\n", subsystem); 200 201 TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) { 202 TAILQ_REMOVE(&subsystem->listeners, listener, link); 203 free(listener); 204 } 205 206 TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) { 207 TAILQ_REMOVE(&subsystem->hosts, host, link); 208 free(host->nqn); 209 free(host); 210 } 211 212 TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) { 213 spdk_nvmf_ctrlr_destruct(ctrlr); 214 } 215 216 spdk_nvmf_subsystem_bdev_detach(subsystem); 217 218 free(subsystem->ns); 219 220 TAILQ_REMOVE(&subsystem->tgt->subsystems, subsystem, entries); 221 subsystem->tgt->discovery_genctr++; 222 223 free(subsystem); 224 } 225 226 227 int 228 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn) 229 { 230 struct spdk_nvmf_host *host; 231 232 if (!spdk_nvmf_valid_nqn(hostnqn)) { 233 return -1; 234 } 235 236 host = calloc(1, sizeof(*host)); 237 if (!host) { 238 return -1; 239 } 240 host->nqn = strdup(hostnqn); 241 if (!host->nqn) { 242 free(host); 243 return -1; 244 } 245 246 TAILQ_INSERT_HEAD(&subsystem->hosts, host, link); 247 subsystem->tgt->discovery_genctr++; 248 249 return 0; 250 } 251 252 bool 253 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn) 254 { 255 struct spdk_nvmf_host *host; 256 257 if (!hostnqn) { 258 return false; 259 } 260 261 if (TAILQ_EMPTY(&subsystem->hosts)) { 262 /* No hosts means any host can connect */ 263 return true; 264 } 265 266 TAILQ_FOREACH(host, &subsystem->hosts, link) { 267 if (strcmp(hostnqn, host->nqn) == 0) { 268 return true; 269 } 270 } 271 272 return false; 273 } 274 275 struct spdk_nvmf_host * 276 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem) 277 { 278 return TAILQ_FIRST(&subsystem->hosts); 279 } 280 281 282 struct spdk_nvmf_host * 283 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem, 284 struct spdk_nvmf_host *prev_host) 285 { 286 return TAILQ_NEXT(prev_host, link); 287 } 288 289 const char * 290 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host) 291 { 292 return host->nqn; 293 } 294 295 int 296 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem, 297 struct spdk_nvmf_listen_addr *listen_addr) 298 { 299 struct spdk_nvmf_listener *listener; 300 301 listener = calloc(1, sizeof(*listener)); 302 if (!listener) { 303 return -1; 304 } 305 306 listener->listen_addr = listen_addr; 307 308 TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link); 309 310 return 0; 311 } 312 313 /* 314 * TODO: this is the whitelist and will be called during connection setup 315 */ 316 bool 317 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem, 318 struct spdk_nvmf_listen_addr *listen_addr) 319 { 320 struct spdk_nvmf_listener *listener; 321 322 if (TAILQ_EMPTY(&subsystem->listeners)) { 323 return true; 324 } 325 326 TAILQ_FOREACH(listener, &subsystem->listeners, link) { 327 if (listener->listen_addr == listen_addr) { 328 return true; 329 } 330 } 331 332 return false; 333 } 334 335 struct spdk_nvmf_listener * 336 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem) 337 { 338 return TAILQ_FIRST(&subsystem->listeners); 339 } 340 341 struct spdk_nvmf_listener * 342 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem, 343 struct spdk_nvmf_listener *prev_listener) 344 { 345 return TAILQ_NEXT(prev_listener, link); 346 } 347 348 349 const struct spdk_nvme_transport_id * 350 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener) 351 { 352 return &listener->listen_addr->trid; 353 } 354 355 static void spdk_nvmf_ctrlr_hot_remove(void *remove_ctx) 356 { 357 struct spdk_nvmf_subsystem *subsystem = (struct spdk_nvmf_subsystem *)remove_ctx; 358 359 subsystem->is_removed = true; 360 } 361 362 uint32_t 363 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev, 364 uint32_t nsid) 365 { 366 struct spdk_nvmf_ns *ns; 367 uint32_t i; 368 int rc; 369 370 if (nsid > subsystem->max_nsid || 371 (nsid == 0 && subsystem->num_allocated_nsid == subsystem->max_nsid)) { 372 struct spdk_nvmf_ns *new_ns_array; 373 uint32_t new_max_nsid; 374 375 if (nsid > subsystem->max_nsid) { 376 new_max_nsid = nsid; 377 } else { 378 new_max_nsid = subsystem->max_nsid + 1; 379 } 380 381 if (!TAILQ_EMPTY(&subsystem->ctrlrs)) { 382 SPDK_ERRLOG("Can't extend NSID range with active connections\n"); 383 return 0; 384 } 385 386 new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns) * new_max_nsid); 387 if (new_ns_array == NULL) { 388 SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n"); 389 return 0; 390 } 391 392 memset(new_ns_array + subsystem->max_nsid, 0, 393 sizeof(struct spdk_nvmf_ns) * (new_max_nsid - subsystem->max_nsid)); 394 subsystem->ns = new_ns_array; 395 subsystem->max_nsid = new_max_nsid; 396 } 397 398 if (nsid == 0) { 399 /* NSID not specified - find a free index */ 400 for (i = 0; i < subsystem->max_nsid; i++) { 401 if (_spdk_nvmf_subsystem_get_ns(subsystem, i + 1) == NULL) { 402 nsid = i + 1; 403 break; 404 } 405 } 406 if (nsid == 0) { 407 SPDK_ERRLOG("All available NSIDs in use\n"); 408 return 0; 409 } 410 } else { 411 /* Specific NSID requested */ 412 if (_spdk_nvmf_subsystem_get_ns(subsystem, nsid)) { 413 SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", nsid); 414 return 0; 415 } 416 } 417 418 ns = &subsystem->ns[nsid - 1]; 419 memset(ns, 0, sizeof(*ns)); 420 ns->bdev = bdev; 421 ns->id = nsid; 422 rc = spdk_bdev_open(bdev, true, spdk_nvmf_ctrlr_hot_remove, subsystem, &ns->desc); 423 if (rc != 0) { 424 SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n", 425 subsystem->subnqn, spdk_bdev_get_name(bdev), rc); 426 return 0; 427 } 428 ns->allocated = true; 429 430 SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n", 431 spdk_nvmf_subsystem_get_nqn(subsystem), 432 spdk_bdev_get_name(bdev), 433 nsid); 434 435 subsystem->max_nsid = spdk_max(subsystem->max_nsid, nsid); 436 subsystem->num_allocated_nsid++; 437 return nsid; 438 } 439 440 static uint32_t 441 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem, 442 uint32_t prev_nsid) 443 { 444 uint32_t nsid; 445 446 if (prev_nsid >= subsystem->max_nsid) { 447 return 0; 448 } 449 450 for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) { 451 if (subsystem->ns[nsid - 1].allocated) { 452 return nsid; 453 } 454 } 455 456 return 0; 457 } 458 459 struct spdk_nvmf_ns * 460 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem) 461 { 462 uint32_t first_nsid; 463 464 first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0); 465 return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid); 466 } 467 468 struct spdk_nvmf_ns * 469 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem, 470 struct spdk_nvmf_ns *prev_ns) 471 { 472 uint32_t next_nsid; 473 474 next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->id); 475 return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid); 476 } 477 478 struct spdk_nvmf_ns * 479 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid) 480 { 481 return _spdk_nvmf_subsystem_get_ns(subsystem, nsid); 482 } 483 484 uint32_t 485 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns) 486 { 487 return ns->id; 488 } 489 490 struct spdk_bdev * 491 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns) 492 { 493 return ns->bdev; 494 } 495 496 const char * 497 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem) 498 { 499 return subsystem->sn; 500 } 501 502 int 503 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn) 504 { 505 size_t len, max_len; 506 507 max_len = sizeof(subsystem->sn) - 1; 508 len = strlen(sn); 509 if (len > max_len) { 510 SPDK_DEBUGLOG(SPDK_TRACE_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n", 511 sn, len, max_len); 512 return -1; 513 } 514 515 snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn); 516 517 return 0; 518 } 519 520 const char * 521 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem) 522 { 523 return subsystem->subnqn; 524 } 525 526 /* Workaround for astyle formatting bug */ 527 typedef enum spdk_nvmf_subtype nvmf_subtype_t; 528 529 nvmf_subtype_t 530 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem) 531 { 532 return subsystem->subtype; 533 } 534