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