xref: /spdk/lib/nvmf/subsystem.c (revision eac02a4ace1a51fa675ea044cd054dc1d372e767)
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/event.h"
40 #include "spdk/likely.h"
41 #include "spdk/string.h"
42 #include "spdk/trace.h"
43 #include "spdk/nvmf_spec.h"
44 #include "spdk/uuid.h"
45 
46 #include "spdk_internal/bdev.h"
47 #include "spdk_internal/log.h"
48 #include "spdk_internal/utf.h"
49 
50 /*
51  * States for parsing valid domains in NQNs according to RFC 1034
52  */
53 enum spdk_nvmf_nqn_domain_states {
54 	/* First character of a domain must be a letter */
55 	SPDK_NVMF_DOMAIN_ACCEPT_LETTER = 0,
56 
57 	/* Subsequent characters can be any of letter, digit, or hyphen */
58 	SPDK_NVMF_DOMAIN_ACCEPT_LDH = 1,
59 
60 	/* A domain label must end with either a letter or digit */
61 	SPDK_NVMF_DOMAIN_ACCEPT_ANY = 2
62 };
63 
64 /* Returns true if is a valid ASCII string as defined by the NVMe spec */
65 static bool
66 spdk_nvmf_valid_ascii_string(const void *buf, size_t size)
67 {
68 	const uint8_t *str = buf;
69 	size_t i;
70 
71 	for (i = 0; i < size; i++) {
72 		if (str[i] < 0x20 || str[i] > 0x7E) {
73 			return false;
74 		}
75 	}
76 
77 	return true;
78 }
79 
80 static bool
81 spdk_nvmf_valid_nqn(const char *nqn)
82 {
83 	size_t len;
84 	struct spdk_uuid uuid_value;
85 	uint32_t i;
86 	int bytes_consumed;
87 	uint32_t domain_label_length;
88 	char *reverse_domain_end;
89 	uint32_t reverse_domain_end_index;
90 	enum spdk_nvmf_nqn_domain_states domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
91 
92 	/* Check for length requirements */
93 	len = strlen(nqn);
94 	if (len > SPDK_NVMF_NQN_MAX_LEN) {
95 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu > max %d\n", nqn, len, SPDK_NVMF_NQN_MAX_LEN);
96 		return false;
97 	}
98 
99 	/* The nqn must be at least as long as SPDK_NVMF_NQN_MIN_LEN to contain the necessary prefix. */
100 	if (len < SPDK_NVMF_NQN_MIN_LEN) {
101 		SPDK_ERRLOG("Invalid NQN \"%s\": length %zu < min %d\n", nqn, len, SPDK_NVMF_NQN_MIN_LEN);
102 		return false;
103 	}
104 
105 	/* Check for discovery controller nqn */
106 	if (!strcmp(nqn, SPDK_NVMF_DISCOVERY_NQN)) {
107 		return true;
108 	}
109 
110 	/* Check for equality with the generic nqn structure of the form "nqn.2014-08.org.nvmexpress:uuid:11111111-2222-3333-4444-555555555555" */
111 	if (!strncmp(nqn, SPDK_NVMF_NQN_UUID_PRE, SPDK_NVMF_NQN_UUID_PRE_LEN)) {
112 		if (len != SPDK_NVMF_NQN_UUID_PRE_LEN + SPDK_NVMF_UUID_STRING_LEN) {
113 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not the correct length\n", nqn);
114 			return false;
115 		}
116 
117 		if (spdk_uuid_parse(&uuid_value, &nqn[SPDK_NVMF_NQN_UUID_PRE_LEN])) {
118 			SPDK_ERRLOG("Invalid NQN \"%s\": uuid is not formatted correctly\n", nqn);
119 			return false;
120 		}
121 		return true;
122 	}
123 
124 	/* If the nqn does not match the uuid structure, the next several checks validate the form "nqn.yyyy-mm.reverse.domain:user-string" */
125 
126 	if (strncmp(nqn, "nqn.", 4) != 0) {
127 		SPDK_ERRLOG("Invalid NQN \"%s\": NQN must begin with \"nqn.\".\n", nqn);
128 		return false;
129 	}
130 
131 	/* Check for yyyy-mm. */
132 	if (!(isdigit(nqn[4]) && isdigit(nqn[5]) && isdigit(nqn[6]) && isdigit(nqn[7]) &&
133 	      nqn[8] == '-' && isdigit(nqn[9]) && isdigit(nqn[10]) && nqn[11] == '.')) {
134 		SPDK_ERRLOG("Invalid date code in NQN \"%s\"\n", nqn);
135 		return false;
136 	}
137 
138 	reverse_domain_end = strchr(nqn, ':');
139 	if (reverse_domain_end != NULL && (reverse_domain_end_index = reverse_domain_end - nqn) < len - 1) {
140 	} else {
141 		SPDK_ERRLOG("Invalid NQN \"%s\". NQN must contain user specified name with a ':' as a prefix.\n",
142 			    nqn);
143 		return false;
144 	}
145 
146 	/* Check for valid reverse domain */
147 	domain_label_length = 0;
148 	for (i = 12; i < reverse_domain_end_index; i++) {
149 		if (domain_label_length > SPDK_DOMAIN_LABEL_MAX_LEN) {
150 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". At least one Label is too long.\n", nqn);
151 			return false;
152 		}
153 
154 		switch (domain_state) {
155 
156 		case SPDK_NVMF_DOMAIN_ACCEPT_LETTER: {
157 			if (isalpha(nqn[i])) {
158 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
159 				domain_label_length++;
160 				break;
161 			} else {
162 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must start with a letter.\n", nqn);
163 				return false;
164 			}
165 		}
166 
167 		case SPDK_NVMF_DOMAIN_ACCEPT_LDH: {
168 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
169 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
170 				domain_label_length++;
171 				break;
172 			} else if (nqn[i] == '-') {
173 				if (i == reverse_domain_end_index - 1) {
174 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
175 						    nqn);
176 					return false;
177 				}
178 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
179 				domain_label_length++;
180 				break;
181 			} else if (nqn[i] == '.') {
182 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
183 					    nqn);
184 				return false;
185 			} else {
186 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
187 					    nqn);
188 				return false;
189 			}
190 		}
191 
192 		case SPDK_NVMF_DOMAIN_ACCEPT_ANY: {
193 			if (isalpha(nqn[i]) || isdigit(nqn[i])) {
194 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_ANY;
195 				domain_label_length++;
196 				break;
197 			} else if (nqn[i] == '-') {
198 				if (i == reverse_domain_end_index - 1) {
199 					SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must end with an alphanumeric symbol.\n",
200 						    nqn);
201 					return false;
202 				}
203 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LDH;
204 				domain_label_length++;
205 				break;
206 			} else if (nqn[i] == '.') {
207 				domain_state = SPDK_NVMF_DOMAIN_ACCEPT_LETTER;
208 				domain_label_length = 0;
209 				break;
210 			} else {
211 				SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only [a-z,A-Z,0-9,'-','.'].\n",
212 					    nqn);
213 				return false;
214 			}
215 		}
216 		}
217 	}
218 
219 	i = reverse_domain_end_index + 1;
220 	while (i < len) {
221 		bytes_consumed = utf8_valid(&nqn[i], &nqn[len]);
222 		if (bytes_consumed <= 0) {
223 			SPDK_ERRLOG("Invalid domain name in NQN \"%s\". Label names must contain only valid utf-8.\n", nqn);
224 			return false;
225 		}
226 
227 		i += bytes_consumed;
228 	}
229 	return true;
230 }
231 
232 struct spdk_nvmf_subsystem *
233 spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
234 			   const char *nqn,
235 			   enum spdk_nvmf_subtype type,
236 			   uint32_t num_ns)
237 {
238 	struct spdk_nvmf_subsystem	*subsystem;
239 	uint32_t			sid;
240 
241 	if (spdk_nvmf_tgt_find_subsystem(tgt, nqn)) {
242 		SPDK_ERRLOG("Subsystem NQN '%s' already exists\n", nqn);
243 		return NULL;
244 	}
245 
246 	if (!spdk_nvmf_valid_nqn(nqn)) {
247 		return NULL;
248 	}
249 
250 	if (type == SPDK_NVMF_SUBTYPE_DISCOVERY && num_ns != 0) {
251 		SPDK_ERRLOG("Discovery subsystem cannot have namespaces.\n");
252 		return NULL;
253 	}
254 
255 	/* Find a free subsystem id (sid) */
256 	for (sid = 0; sid < tgt->opts.max_subsystems; sid++) {
257 		if (tgt->subsystems[sid] == NULL) {
258 			break;
259 		}
260 	}
261 	if (sid >= tgt->opts.max_subsystems) {
262 		return NULL;
263 	}
264 
265 	subsystem = calloc(1, sizeof(struct spdk_nvmf_subsystem));
266 	if (subsystem == NULL) {
267 		return NULL;
268 	}
269 
270 	subsystem->thread = spdk_get_thread();
271 	subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
272 	subsystem->tgt = tgt;
273 	subsystem->id = sid;
274 	subsystem->subtype = type;
275 	subsystem->max_nsid = num_ns;
276 	/*
277 	 *  Initially max_nsid and max_allowed_nsid will be same. If max_allowed_nsid is zero nsid range can grow dynamically
278 	 *  but if it is more than 1 nsid range cannot be extended beyond max_allowed_nsid
279 	 */
280 	subsystem->max_allowed_nsid = num_ns;
281 	subsystem->num_allocated_nsid = 0;
282 	subsystem->next_cntlid = 0;
283 	snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn);
284 	TAILQ_INIT(&subsystem->listeners);
285 	TAILQ_INIT(&subsystem->hosts);
286 	TAILQ_INIT(&subsystem->ctrlrs);
287 
288 	if (num_ns != 0) {
289 		subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns *));
290 		if (subsystem->ns == NULL) {
291 			SPDK_ERRLOG("Namespace memory allocation failed\n");
292 			free(subsystem);
293 			return NULL;
294 		}
295 	}
296 
297 	tgt->subsystems[sid] = subsystem;
298 	tgt->discovery_genctr++;
299 
300 	return subsystem;
301 }
302 
303 static void
304 _spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_host *host)
305 {
306 	TAILQ_REMOVE(&subsystem->hosts, host, link);
307 	free(host->nqn);
308 	free(host);
309 }
310 
311 static int _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid);
312 
313 void
314 spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
315 {
316 	struct spdk_nvmf_listener	*listener, *listener_tmp;
317 	struct spdk_nvmf_host		*host, *host_tmp;
318 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
319 	struct spdk_nvmf_ns		*ns;
320 
321 	if (!subsystem) {
322 		return;
323 	}
324 
325 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
326 
327 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
328 
329 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
330 		TAILQ_REMOVE(&subsystem->listeners, listener, link);
331 		free(listener);
332 	}
333 
334 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
335 		_spdk_nvmf_subsystem_remove_host(subsystem, host);
336 	}
337 
338 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
339 		spdk_nvmf_ctrlr_destruct(ctrlr);
340 	}
341 
342 	ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
343 	while (ns != NULL) {
344 		struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
345 
346 		_spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
347 		ns = next_ns;
348 	}
349 
350 	free(subsystem->ns);
351 
352 	subsystem->tgt->subsystems[subsystem->id] = NULL;
353 	subsystem->tgt->discovery_genctr++;
354 
355 	free(subsystem);
356 }
357 
358 static int
359 spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
360 			      enum spdk_nvmf_subsystem_state state)
361 {
362 	enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
363 
364 	switch (state) {
365 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
366 		expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
367 		break;
368 	case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
369 		expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
370 		break;
371 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
372 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
373 		break;
374 	case SPDK_NVMF_SUBSYSTEM_PAUSING:
375 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
376 		break;
377 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
378 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
379 		break;
380 	case SPDK_NVMF_SUBSYSTEM_RESUMING:
381 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
382 		break;
383 	case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
384 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
385 		break;
386 	default:
387 		assert(false);
388 		return -1;
389 	}
390 
391 	actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
392 	if (actual_old_state != expected_old_state) {
393 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
394 		    state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
395 			expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
396 		}
397 		actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
398 	}
399 	assert(actual_old_state == expected_old_state);
400 	return actual_old_state - expected_old_state;
401 }
402 
403 struct subsystem_state_change_ctx {
404 	struct spdk_nvmf_subsystem *subsystem;
405 
406 	enum spdk_nvmf_subsystem_state requested_state;
407 
408 	spdk_nvmf_subsystem_state_change_done cb_fn;
409 	void *cb_arg;
410 };
411 
412 static void
413 subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
414 {
415 	struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
416 
417 	if (status == 0) {
418 		status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
419 		if (status) {
420 			status = -1;
421 		}
422 	}
423 
424 	if (ctx->cb_fn) {
425 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
426 	}
427 	free(ctx);
428 }
429 
430 static void
431 subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
432 {
433 	struct subsystem_state_change_ctx *ctx;
434 	struct spdk_io_channel *ch;
435 	struct spdk_nvmf_poll_group *group;
436 	int rc = -1;
437 
438 	ctx = spdk_io_channel_iter_get_ctx(i);
439 	ch = spdk_io_channel_iter_get_channel(i);
440 	group = spdk_io_channel_get_ctx(ch);
441 
442 	switch (ctx->requested_state) {
443 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
444 		rc = spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem);
445 		break;
446 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
447 		if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
448 			rc = spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem);
449 		} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
450 			rc = spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem);
451 		}
452 		break;
453 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
454 		rc = spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem);
455 		break;
456 	default:
457 		assert(false);
458 		break;
459 	}
460 
461 	spdk_for_each_channel_continue(i, rc);
462 }
463 
464 static int
465 spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
466 				 enum spdk_nvmf_subsystem_state requested_state,
467 				 spdk_nvmf_subsystem_state_change_done cb_fn,
468 				 void *cb_arg)
469 {
470 	struct subsystem_state_change_ctx *ctx;
471 	enum spdk_nvmf_subsystem_state intermediate_state;
472 	int rc;
473 
474 	switch (requested_state) {
475 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
476 		intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
477 		break;
478 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
479 		if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
480 			intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
481 		} else {
482 			intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
483 		}
484 		break;
485 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
486 		intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
487 		break;
488 	default:
489 		assert(false);
490 		return -EINVAL;
491 	}
492 
493 	ctx = calloc(1, sizeof(*ctx));
494 	if (!ctx) {
495 		return -ENOMEM;
496 	}
497 
498 	rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
499 	if (rc) {
500 		free(ctx);
501 		return rc;
502 	}
503 
504 	ctx->subsystem = subsystem;
505 	ctx->requested_state = requested_state;
506 	ctx->cb_fn = cb_fn;
507 	ctx->cb_arg = cb_arg;
508 
509 	spdk_for_each_channel(subsystem->tgt,
510 			      subsystem_state_change_on_pg,
511 			      ctx,
512 			      subsystem_state_change_done);
513 
514 	return 0;
515 }
516 
517 int
518 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
519 			  spdk_nvmf_subsystem_state_change_done cb_fn,
520 			  void *cb_arg)
521 {
522 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
523 }
524 
525 int
526 spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
527 			 spdk_nvmf_subsystem_state_change_done cb_fn,
528 			 void *cb_arg)
529 {
530 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
531 }
532 
533 int
534 spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
535 			  spdk_nvmf_subsystem_state_change_done cb_fn,
536 			  void *cb_arg)
537 {
538 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
539 }
540 
541 int
542 spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
543 			   spdk_nvmf_subsystem_state_change_done cb_fn,
544 			   void *cb_arg)
545 {
546 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
547 }
548 
549 struct spdk_nvmf_subsystem *
550 spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt)
551 {
552 	struct spdk_nvmf_subsystem	*subsystem;
553 	uint32_t sid;
554 
555 	for (sid = 0; sid < tgt->opts.max_subsystems; sid++) {
556 		subsystem = tgt->subsystems[sid];
557 		if (subsystem) {
558 			return subsystem;
559 		}
560 	}
561 
562 	return NULL;
563 }
564 
565 struct spdk_nvmf_subsystem *
566 spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem)
567 {
568 	uint32_t sid;
569 	struct spdk_nvmf_tgt *tgt;
570 
571 	if (!subsystem) {
572 		return NULL;
573 	}
574 
575 	tgt = subsystem->tgt;
576 
577 	for (sid = subsystem->id + 1; sid < tgt->opts.max_subsystems; sid++) {
578 		subsystem = tgt->subsystems[sid];
579 		if (subsystem) {
580 			return subsystem;
581 		}
582 	}
583 
584 	return NULL;
585 }
586 
587 static struct spdk_nvmf_host *
588 _spdk_nvmf_subsystem_find_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
589 {
590 	struct spdk_nvmf_host *host = NULL;
591 
592 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
593 		if (strcmp(hostnqn, host->nqn) == 0) {
594 			return host;
595 		}
596 	}
597 
598 	return NULL;
599 }
600 
601 int
602 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
603 {
604 	struct spdk_nvmf_host *host;
605 
606 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
607 		return -EINVAL;
608 	}
609 
610 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
611 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
612 		return -EAGAIN;
613 	}
614 
615 	if (_spdk_nvmf_subsystem_find_host(subsystem, hostnqn)) {
616 		/* This subsystem already allows the specified host. */
617 		return 0;
618 	}
619 
620 	host = calloc(1, sizeof(*host));
621 	if (!host) {
622 		return -ENOMEM;
623 	}
624 	host->nqn = strdup(hostnqn);
625 	if (!host->nqn) {
626 		free(host);
627 		return -ENOMEM;
628 	}
629 
630 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
631 	subsystem->tgt->discovery_genctr++;
632 
633 	return 0;
634 }
635 
636 int
637 spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
638 {
639 	struct spdk_nvmf_host *host;
640 
641 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
642 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
643 		return -EAGAIN;
644 	}
645 
646 	host = _spdk_nvmf_subsystem_find_host(subsystem, hostnqn);
647 	if (host == NULL) {
648 		return -ENOENT;
649 	}
650 
651 	_spdk_nvmf_subsystem_remove_host(subsystem, host);
652 	return 0;
653 }
654 
655 int
656 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
657 {
658 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
659 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
660 		return -EAGAIN;
661 	}
662 
663 	subsystem->allow_any_host = allow_any_host;
664 
665 	return 0;
666 }
667 
668 bool
669 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
670 {
671 	return subsystem->allow_any_host;
672 }
673 
674 bool
675 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
676 {
677 	if (!hostnqn) {
678 		return false;
679 	}
680 
681 	if (subsystem->allow_any_host) {
682 		return true;
683 	}
684 
685 	return _spdk_nvmf_subsystem_find_host(subsystem, hostnqn) != NULL;
686 }
687 
688 struct spdk_nvmf_host *
689 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
690 {
691 	return TAILQ_FIRST(&subsystem->hosts);
692 }
693 
694 
695 struct spdk_nvmf_host *
696 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
697 				  struct spdk_nvmf_host *prev_host)
698 {
699 	return TAILQ_NEXT(prev_host, link);
700 }
701 
702 const char *
703 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
704 {
705 	return host->nqn;
706 }
707 
708 static struct spdk_nvmf_listener *
709 _spdk_nvmf_subsystem_find_listener(struct spdk_nvmf_subsystem *subsystem,
710 				   const struct spdk_nvme_transport_id *trid)
711 {
712 	struct spdk_nvmf_listener *listener;
713 
714 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
715 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
716 			return listener;
717 		}
718 	}
719 
720 	return NULL;
721 }
722 
723 int
724 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
725 				 struct spdk_nvme_transport_id *trid)
726 {
727 	struct spdk_nvmf_transport *transport;
728 	struct spdk_nvmf_listener *listener;
729 
730 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
731 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
732 		return -EAGAIN;
733 	}
734 
735 	if (_spdk_nvmf_subsystem_find_listener(subsystem, trid)) {
736 		/* Listener already exists in this subsystem */
737 		return 0;
738 	}
739 
740 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
741 	if (transport == NULL) {
742 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
743 		return -EINVAL;
744 	}
745 
746 	listener = calloc(1, sizeof(*listener));
747 	if (!listener) {
748 		return -ENOMEM;
749 	}
750 
751 	listener->trid = *trid;
752 	listener->transport = transport;
753 
754 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
755 
756 	return 0;
757 }
758 
759 int
760 spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
761 				    const struct spdk_nvme_transport_id *trid)
762 {
763 	struct spdk_nvmf_listener *listener;
764 
765 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
766 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
767 		return -EAGAIN;
768 	}
769 
770 	listener = _spdk_nvmf_subsystem_find_listener(subsystem, trid);
771 	if (listener == NULL) {
772 		return -ENOENT;
773 	}
774 
775 	TAILQ_REMOVE(&subsystem->listeners, listener, link);
776 	free(listener);
777 
778 	return 0;
779 }
780 
781 /*
782  * TODO: this is the whitelist and will be called during connection setup
783  */
784 bool
785 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
786 				     struct spdk_nvme_transport_id *trid)
787 {
788 	struct spdk_nvmf_listener *listener;
789 
790 	if (TAILQ_EMPTY(&subsystem->listeners)) {
791 		return true;
792 	}
793 
794 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
795 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
796 			return true;
797 		}
798 	}
799 
800 	return false;
801 }
802 
803 struct spdk_nvmf_listener *
804 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
805 {
806 	return TAILQ_FIRST(&subsystem->listeners);
807 }
808 
809 struct spdk_nvmf_listener *
810 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
811 				      struct spdk_nvmf_listener *prev_listener)
812 {
813 	return TAILQ_NEXT(prev_listener, link);
814 }
815 
816 const struct spdk_nvme_transport_id *
817 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
818 {
819 	return &listener->trid;
820 }
821 
822 struct subsystem_update_ns_ctx {
823 	struct spdk_nvmf_subsystem *subsystem;
824 
825 	spdk_nvmf_subsystem_state_change_done cb_fn;
826 	void *cb_arg;
827 };
828 
829 static void
830 subsystem_update_ns_done(struct spdk_io_channel_iter *i, int status)
831 {
832 	struct subsystem_update_ns_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
833 
834 	if (ctx->cb_fn) {
835 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
836 	}
837 	free(ctx);
838 }
839 
840 static void
841 subsystem_update_ns_on_pg(struct spdk_io_channel_iter *i)
842 {
843 	int rc;
844 	struct subsystem_update_ns_ctx *ctx;
845 	struct spdk_nvmf_poll_group *group;
846 	struct spdk_nvmf_subsystem *subsystem;
847 
848 	ctx = spdk_io_channel_iter_get_ctx(i);
849 	group = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i));
850 	subsystem = ctx->subsystem;
851 
852 	rc = spdk_nvmf_poll_group_update_subsystem(group, subsystem);
853 	spdk_for_each_channel_continue(i, rc);
854 }
855 
856 static int
857 spdk_nvmf_subsystem_update_ns(struct spdk_nvmf_subsystem *subsystem, spdk_channel_for_each_cpl cpl,
858 			      void *ctx)
859 {
860 	spdk_for_each_channel(subsystem->tgt,
861 			      subsystem_update_ns_on_pg,
862 			      ctx,
863 			      cpl);
864 
865 	return 0;
866 }
867 
868 static void
869 spdk_nvmf_subsystem_ns_changed(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
870 {
871 	struct spdk_nvmf_ctrlr *ctrlr;
872 
873 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
874 		spdk_nvmf_ctrlr_ns_changed(ctrlr, nsid);
875 	}
876 }
877 
878 static int
879 _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
880 {
881 	struct spdk_nvmf_ns *ns;
882 
883 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED ||
884 	       subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
885 
886 	if (nsid == 0 || nsid > subsystem->max_nsid) {
887 		return -1;
888 	}
889 
890 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
891 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
892 		return -1;
893 	}
894 
895 	ns = subsystem->ns[nsid - 1];
896 	if (!ns) {
897 		return -1;
898 	}
899 
900 	subsystem->ns[nsid - 1] = NULL;
901 
902 	spdk_bdev_close(ns->desc);
903 	free(ns);
904 	subsystem->num_allocated_nsid--;
905 
906 	spdk_nvmf_subsystem_ns_changed(subsystem, nsid);
907 
908 	return 0;
909 }
910 
911 int
912 spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid,
913 			      spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg)
914 {
915 	int rc;
916 	struct subsystem_update_ns_ctx *ctx;
917 
918 	rc = _spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
919 	if (rc < 0) {
920 		return rc;
921 	}
922 
923 	ctx = calloc(1, sizeof(*ctx));
924 
925 	if (ctx == NULL) {
926 		return -ENOMEM;
927 	}
928 
929 	ctx->subsystem = subsystem;
930 	ctx->cb_fn = cb_fn;
931 	ctx->cb_arg = cb_arg;
932 
933 	spdk_nvmf_subsystem_update_ns(subsystem, subsystem_update_ns_done, ctx);
934 
935 	return 0;
936 }
937 
938 static void
939 _spdk_nvmf_ns_hot_remove_done(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status)
940 {
941 	if (status != 0) {
942 		SPDK_ERRLOG("Failed to make changes to NVMe-oF subsystem with id %u\n", subsystem->id);
943 	}
944 	spdk_nvmf_subsystem_resume(subsystem, NULL, NULL);
945 }
946 
947 static void
948 _spdk_nvmf_ns_hot_remove(struct spdk_nvmf_subsystem *subsystem,
949 			 void *cb_arg, int status)
950 {
951 	struct spdk_nvmf_ns *ns = cb_arg;
952 
953 	spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid, _spdk_nvmf_ns_hot_remove_done,
954 				      subsystem);
955 }
956 
957 static void
958 spdk_nvmf_ns_hot_remove(void *remove_ctx)
959 {
960 	struct spdk_nvmf_ns *ns = remove_ctx;
961 	int rc;
962 
963 	rc = spdk_nvmf_subsystem_pause(ns->subsystem, _spdk_nvmf_ns_hot_remove, ns);
964 	if (rc) {
965 		SPDK_ERRLOG("Unable to pause subsystem to process namespace removal!\n");
966 	}
967 }
968 
969 void
970 spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size)
971 {
972 	/* All current fields are set to 0 by default. */
973 	memset(opts, 0, opts_size);
974 }
975 
976 uint32_t
977 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
978 			   const struct spdk_nvmf_ns_opts *user_opts, size_t opts_size)
979 {
980 	struct spdk_nvmf_ns_opts opts;
981 	struct spdk_nvmf_ns *ns;
982 	uint32_t i;
983 	int rc;
984 
985 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
986 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
987 		return 0;
988 	}
989 
990 	spdk_nvmf_ns_opts_get_defaults(&opts, sizeof(opts));
991 	if (user_opts) {
992 		memcpy(&opts, user_opts, spdk_min(sizeof(opts), opts_size));
993 	}
994 
995 	if (spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) {
996 		opts.uuid = *spdk_bdev_get_uuid(bdev);
997 	}
998 
999 	if (opts.nsid == SPDK_NVME_GLOBAL_NS_TAG) {
1000 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", opts.nsid);
1001 		return 0;
1002 	}
1003 
1004 	if ((subsystem->max_allowed_nsid > 0) && (opts.nsid > subsystem->max_allowed_nsid)) {
1005 		SPDK_ERRLOG("Can't extend NSID range above MaxNamespaces\n");
1006 		return 0;
1007 	}
1008 
1009 	if (opts.nsid > subsystem->max_nsid ||
1010 	    (opts.nsid == 0 && subsystem->num_allocated_nsid == subsystem->max_nsid)) {
1011 		struct spdk_nvmf_ns **new_ns_array;
1012 		uint32_t new_max_nsid;
1013 
1014 		if (opts.nsid > subsystem->max_nsid) {
1015 			new_max_nsid = opts.nsid;
1016 		} else {
1017 			new_max_nsid = subsystem->max_nsid + 1;
1018 		}
1019 
1020 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns *) * new_max_nsid);
1021 		if (new_ns_array == NULL) {
1022 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
1023 			return 0;
1024 		}
1025 
1026 		memset(new_ns_array + subsystem->max_nsid, 0,
1027 		       sizeof(struct spdk_nvmf_ns *) * (new_max_nsid - subsystem->max_nsid));
1028 		subsystem->ns = new_ns_array;
1029 		subsystem->max_nsid = new_max_nsid;
1030 	}
1031 
1032 	if (opts.nsid == 0) {
1033 		/* NSID not specified - find a free index */
1034 		for (i = 0; i < subsystem->max_nsid; i++) {
1035 			if (_spdk_nvmf_subsystem_get_ns(subsystem, i + 1) == NULL) {
1036 				opts.nsid = i + 1;
1037 				break;
1038 			}
1039 		}
1040 		if (opts.nsid == 0) {
1041 			SPDK_ERRLOG("All available NSIDs in use\n");
1042 			return 0;
1043 		}
1044 	} else {
1045 		/* Specific NSID requested */
1046 		if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid)) {
1047 			SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", opts.nsid);
1048 			return 0;
1049 		}
1050 	}
1051 
1052 	ns = calloc(1, sizeof(*ns));
1053 	if (ns == NULL) {
1054 		SPDK_ERRLOG("Namespace allocation failed\n");
1055 		return 0;
1056 	}
1057 
1058 	ns->bdev = bdev;
1059 	ns->opts = opts;
1060 	ns->subsystem = subsystem;
1061 	rc = spdk_bdev_open(bdev, true, spdk_nvmf_ns_hot_remove, ns, &ns->desc);
1062 	if (rc != 0) {
1063 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
1064 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
1065 		free(ns);
1066 		return 0;
1067 	}
1068 	subsystem->ns[opts.nsid - 1] = ns;
1069 
1070 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
1071 		      spdk_nvmf_subsystem_get_nqn(subsystem),
1072 		      spdk_bdev_get_name(bdev),
1073 		      opts.nsid);
1074 
1075 	subsystem->max_nsid = spdk_max(subsystem->max_nsid, opts.nsid);
1076 	subsystem->num_allocated_nsid++;
1077 
1078 	spdk_nvmf_subsystem_ns_changed(subsystem, opts.nsid);
1079 
1080 	return opts.nsid;
1081 }
1082 
1083 static uint32_t
1084 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
1085 		uint32_t prev_nsid)
1086 {
1087 	uint32_t nsid;
1088 
1089 	if (prev_nsid >= subsystem->max_nsid) {
1090 		return 0;
1091 	}
1092 
1093 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
1094 		if (subsystem->ns[nsid - 1]) {
1095 			return nsid;
1096 		}
1097 	}
1098 
1099 	return 0;
1100 }
1101 
1102 struct spdk_nvmf_ns *
1103 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
1104 {
1105 	uint32_t first_nsid;
1106 
1107 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
1108 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
1109 }
1110 
1111 struct spdk_nvmf_ns *
1112 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
1113 				struct spdk_nvmf_ns *prev_ns)
1114 {
1115 	uint32_t next_nsid;
1116 
1117 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->opts.nsid);
1118 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
1119 }
1120 
1121 struct spdk_nvmf_ns *
1122 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
1123 {
1124 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
1125 }
1126 
1127 uint32_t
1128 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
1129 {
1130 	return ns->opts.nsid;
1131 }
1132 
1133 struct spdk_bdev *
1134 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
1135 {
1136 	return ns->bdev;
1137 }
1138 
1139 void
1140 spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
1141 		      size_t opts_size)
1142 {
1143 	memset(opts, 0, opts_size);
1144 	memcpy(opts, &ns->opts, spdk_min(sizeof(ns->opts), opts_size));
1145 }
1146 
1147 const char *
1148 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
1149 {
1150 	return subsystem->sn;
1151 }
1152 
1153 int
1154 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
1155 {
1156 	size_t len, max_len;
1157 
1158 	max_len = sizeof(subsystem->sn) - 1;
1159 	len = strlen(sn);
1160 	if (len > max_len) {
1161 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
1162 			      sn, len, max_len);
1163 		return -1;
1164 	}
1165 
1166 	if (!spdk_nvmf_valid_ascii_string(sn, len)) {
1167 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Non-ASCII sn\n");
1168 		SPDK_TRACEDUMP(SPDK_LOG_NVMF, "sn", sn, len);
1169 		return -1;
1170 	}
1171 
1172 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
1173 
1174 	return 0;
1175 }
1176 
1177 const char *
1178 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
1179 {
1180 	return subsystem->subnqn;
1181 }
1182 
1183 /* Workaround for astyle formatting bug */
1184 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
1185 
1186 nvmf_subtype_t
1187 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
1188 {
1189 	return subsystem->subtype;
1190 }
1191 
1192 static uint16_t
1193 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
1194 {
1195 	int count;
1196 
1197 	/*
1198 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
1199 	 * before we find one that is unused (or find that all values are in use).
1200 	 */
1201 	for (count = 0; count < 0xFFF0 - 1; count++) {
1202 		subsystem->next_cntlid++;
1203 		if (subsystem->next_cntlid >= 0xFFF0) {
1204 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
1205 			subsystem->next_cntlid = 1;
1206 		}
1207 
1208 		/* Check if a controller with this cntlid currently exists. */
1209 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
1210 			/* Found unused cntlid */
1211 			return subsystem->next_cntlid;
1212 		}
1213 	}
1214 
1215 	/* All valid cntlid values are in use. */
1216 	return 0xFFFF;
1217 }
1218 
1219 int
1220 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
1221 {
1222 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
1223 	if (ctrlr->cntlid == 0xFFFF) {
1224 		/* Unable to get a cntlid */
1225 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
1226 		return -EBUSY;
1227 	}
1228 
1229 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
1230 
1231 	return 0;
1232 }
1233 
1234 void
1235 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
1236 				 struct spdk_nvmf_ctrlr *ctrlr)
1237 {
1238 	assert(subsystem == ctrlr->subsys);
1239 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
1240 }
1241 
1242 struct spdk_nvmf_ctrlr *
1243 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
1244 {
1245 	struct spdk_nvmf_ctrlr *ctrlr;
1246 
1247 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
1248 		if (ctrlr->cntlid == cntlid) {
1249 			return ctrlr;
1250 		}
1251 	}
1252 
1253 	return NULL;
1254 }
1255