xref: /spdk/lib/nvmf/subsystem.c (revision 5977aad8f7486552c94c5cc93ea9bb110e1cb5d0)
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/bdev_module.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->max_subsystems; sid++) {
257 		if (tgt->subsystems[sid] == NULL) {
258 			break;
259 		}
260 	}
261 	if (sid >= tgt->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 	subsystem->max_allowed_nsid = num_ns;
277 	subsystem->next_cntlid = 0;
278 	snprintf(subsystem->subnqn, sizeof(subsystem->subnqn), "%s", nqn);
279 	TAILQ_INIT(&subsystem->listeners);
280 	TAILQ_INIT(&subsystem->hosts);
281 	TAILQ_INIT(&subsystem->ctrlrs);
282 
283 	if (num_ns != 0) {
284 		subsystem->ns = calloc(num_ns, sizeof(struct spdk_nvmf_ns *));
285 		if (subsystem->ns == NULL) {
286 			SPDK_ERRLOG("Namespace memory allocation failed\n");
287 			free(subsystem);
288 			return NULL;
289 		}
290 	}
291 
292 	memset(subsystem->sn, '0', sizeof(subsystem->sn) - 1);
293 	subsystem->sn[sizeof(subsystem->sn) - 1] = '\n';
294 
295 	tgt->subsystems[sid] = subsystem;
296 	tgt->discovery_genctr++;
297 
298 	return subsystem;
299 }
300 
301 static void
302 _spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_host *host)
303 {
304 	TAILQ_REMOVE(&subsystem->hosts, host, link);
305 	free(host->nqn);
306 	free(host);
307 }
308 
309 static int _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid);
310 
311 void
312 spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
313 {
314 	struct spdk_nvmf_listener	*listener, *listener_tmp;
315 	struct spdk_nvmf_host		*host, *host_tmp;
316 	struct spdk_nvmf_ctrlr		*ctrlr, *ctrlr_tmp;
317 	struct spdk_nvmf_ns		*ns;
318 
319 	if (!subsystem) {
320 		return;
321 	}
322 
323 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
324 
325 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
326 
327 	TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
328 		TAILQ_REMOVE(&subsystem->listeners, listener, link);
329 		free(listener);
330 	}
331 
332 	TAILQ_FOREACH_SAFE(host, &subsystem->hosts, link, host_tmp) {
333 		_spdk_nvmf_subsystem_remove_host(subsystem, host);
334 	}
335 
336 	TAILQ_FOREACH_SAFE(ctrlr, &subsystem->ctrlrs, link, ctrlr_tmp) {
337 		spdk_nvmf_ctrlr_destruct(ctrlr);
338 	}
339 
340 	ns = spdk_nvmf_subsystem_get_first_ns(subsystem);
341 	while (ns != NULL) {
342 		struct spdk_nvmf_ns *next_ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns);
343 
344 		_spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid);
345 		ns = next_ns;
346 	}
347 
348 	free(subsystem->ns);
349 
350 	subsystem->tgt->subsystems[subsystem->id] = NULL;
351 	subsystem->tgt->discovery_genctr++;
352 
353 	free(subsystem);
354 }
355 
356 static int
357 spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
358 			      enum spdk_nvmf_subsystem_state state)
359 {
360 	enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
361 
362 	switch (state) {
363 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
364 		expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
365 		break;
366 	case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
367 		expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
368 		break;
369 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
370 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
371 		break;
372 	case SPDK_NVMF_SUBSYSTEM_PAUSING:
373 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
374 		break;
375 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
376 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
377 		break;
378 	case SPDK_NVMF_SUBSYSTEM_RESUMING:
379 		expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
380 		break;
381 	case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
382 		expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
383 		break;
384 	default:
385 		assert(false);
386 		return -1;
387 	}
388 
389 	actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
390 	if (actual_old_state != expected_old_state) {
391 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
392 		    state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
393 			expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
394 		}
395 		/* This is for the case when activating the subsystem fails. */
396 		if (actual_old_state == SPDK_NVMF_SUBSYSTEM_ACTIVATING &&
397 		    state == SPDK_NVMF_SUBSYSTEM_DEACTIVATING) {
398 			expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
399 		}
400 		actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
401 	}
402 	assert(actual_old_state == expected_old_state);
403 	return actual_old_state - expected_old_state;
404 }
405 
406 struct subsystem_state_change_ctx {
407 	struct spdk_nvmf_subsystem *subsystem;
408 
409 	enum spdk_nvmf_subsystem_state requested_state;
410 
411 	spdk_nvmf_subsystem_state_change_done cb_fn;
412 	void *cb_arg;
413 };
414 
415 static void
416 subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
417 {
418 	struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
419 
420 	if (status == 0) {
421 		status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
422 		if (status) {
423 			status = -1;
424 		}
425 	}
426 
427 	if (ctx->cb_fn) {
428 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
429 	}
430 	free(ctx);
431 }
432 
433 static void
434 subsystem_state_change_continue(void *ctx, int status)
435 {
436 	struct spdk_io_channel_iter *i = ctx;
437 	spdk_for_each_channel_continue(i, status);
438 }
439 
440 static void
441 subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
442 {
443 	struct subsystem_state_change_ctx *ctx;
444 	struct spdk_io_channel *ch;
445 	struct spdk_nvmf_poll_group *group;
446 
447 	ctx = spdk_io_channel_iter_get_ctx(i);
448 	ch = spdk_io_channel_iter_get_channel(i);
449 	group = spdk_io_channel_get_ctx(ch);
450 
451 	switch (ctx->requested_state) {
452 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
453 		spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
454 		break;
455 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
456 		if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
457 			spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
458 		} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
459 			spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
460 		}
461 		break;
462 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
463 		spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem, subsystem_state_change_continue, i);
464 		break;
465 	default:
466 		assert(false);
467 		break;
468 	}
469 }
470 
471 static int
472 spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
473 				 enum spdk_nvmf_subsystem_state requested_state,
474 				 spdk_nvmf_subsystem_state_change_done cb_fn,
475 				 void *cb_arg)
476 {
477 	struct subsystem_state_change_ctx *ctx;
478 	enum spdk_nvmf_subsystem_state intermediate_state;
479 	int rc;
480 
481 	switch (requested_state) {
482 	case SPDK_NVMF_SUBSYSTEM_INACTIVE:
483 		intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
484 		break;
485 	case SPDK_NVMF_SUBSYSTEM_ACTIVE:
486 		if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
487 			intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
488 		} else {
489 			intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
490 		}
491 		break;
492 	case SPDK_NVMF_SUBSYSTEM_PAUSED:
493 		intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
494 		break;
495 	default:
496 		assert(false);
497 		return -EINVAL;
498 	}
499 
500 	ctx = calloc(1, sizeof(*ctx));
501 	if (!ctx) {
502 		return -ENOMEM;
503 	}
504 
505 	rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
506 	if (rc) {
507 		free(ctx);
508 		return rc;
509 	}
510 
511 	ctx->subsystem = subsystem;
512 	ctx->requested_state = requested_state;
513 	ctx->cb_fn = cb_fn;
514 	ctx->cb_arg = cb_arg;
515 
516 	spdk_for_each_channel(subsystem->tgt,
517 			      subsystem_state_change_on_pg,
518 			      ctx,
519 			      subsystem_state_change_done);
520 
521 	return 0;
522 }
523 
524 int
525 spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
526 			  spdk_nvmf_subsystem_state_change_done cb_fn,
527 			  void *cb_arg)
528 {
529 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
530 }
531 
532 int
533 spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
534 			 spdk_nvmf_subsystem_state_change_done cb_fn,
535 			 void *cb_arg)
536 {
537 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
538 }
539 
540 int
541 spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
542 			  spdk_nvmf_subsystem_state_change_done cb_fn,
543 			  void *cb_arg)
544 {
545 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
546 }
547 
548 int
549 spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
550 			   spdk_nvmf_subsystem_state_change_done cb_fn,
551 			   void *cb_arg)
552 {
553 	return spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
554 }
555 
556 struct spdk_nvmf_subsystem *
557 spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *tgt)
558 {
559 	struct spdk_nvmf_subsystem	*subsystem;
560 	uint32_t sid;
561 
562 	for (sid = 0; sid < tgt->max_subsystems; sid++) {
563 		subsystem = tgt->subsystems[sid];
564 		if (subsystem) {
565 			return subsystem;
566 		}
567 	}
568 
569 	return NULL;
570 }
571 
572 struct spdk_nvmf_subsystem *
573 spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem)
574 {
575 	uint32_t sid;
576 	struct spdk_nvmf_tgt *tgt;
577 
578 	if (!subsystem) {
579 		return NULL;
580 	}
581 
582 	tgt = subsystem->tgt;
583 
584 	for (sid = subsystem->id + 1; sid < tgt->max_subsystems; sid++) {
585 		subsystem = tgt->subsystems[sid];
586 		if (subsystem) {
587 			return subsystem;
588 		}
589 	}
590 
591 	return NULL;
592 }
593 
594 static struct spdk_nvmf_host *
595 _spdk_nvmf_subsystem_find_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
596 {
597 	struct spdk_nvmf_host *host = NULL;
598 
599 	TAILQ_FOREACH(host, &subsystem->hosts, link) {
600 		if (strcmp(hostnqn, host->nqn) == 0) {
601 			return host;
602 		}
603 	}
604 
605 	return NULL;
606 }
607 
608 int
609 spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
610 {
611 	struct spdk_nvmf_host *host;
612 
613 	if (!spdk_nvmf_valid_nqn(hostnqn)) {
614 		return -EINVAL;
615 	}
616 
617 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
618 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
619 		return -EAGAIN;
620 	}
621 
622 	if (_spdk_nvmf_subsystem_find_host(subsystem, hostnqn)) {
623 		/* This subsystem already allows the specified host. */
624 		return 0;
625 	}
626 
627 	host = calloc(1, sizeof(*host));
628 	if (!host) {
629 		return -ENOMEM;
630 	}
631 	host->nqn = strdup(hostnqn);
632 	if (!host->nqn) {
633 		free(host);
634 		return -ENOMEM;
635 	}
636 
637 	TAILQ_INSERT_HEAD(&subsystem->hosts, host, link);
638 	subsystem->tgt->discovery_genctr++;
639 
640 	return 0;
641 }
642 
643 int
644 spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
645 {
646 	struct spdk_nvmf_host *host;
647 
648 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
649 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
650 		return -EAGAIN;
651 	}
652 
653 	host = _spdk_nvmf_subsystem_find_host(subsystem, hostnqn);
654 	if (host == NULL) {
655 		return -ENOENT;
656 	}
657 
658 	_spdk_nvmf_subsystem_remove_host(subsystem, host);
659 	return 0;
660 }
661 
662 int
663 spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
664 {
665 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
666 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
667 		return -EAGAIN;
668 	}
669 
670 	subsystem->allow_any_host = allow_any_host;
671 
672 	return 0;
673 }
674 
675 bool
676 spdk_nvmf_subsystem_get_allow_any_host(const struct spdk_nvmf_subsystem *subsystem)
677 {
678 	return subsystem->allow_any_host;
679 }
680 
681 bool
682 spdk_nvmf_subsystem_host_allowed(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
683 {
684 	if (!hostnqn) {
685 		return false;
686 	}
687 
688 	if (subsystem->allow_any_host) {
689 		return true;
690 	}
691 
692 	return _spdk_nvmf_subsystem_find_host(subsystem, hostnqn) != NULL;
693 }
694 
695 struct spdk_nvmf_host *
696 spdk_nvmf_subsystem_get_first_host(struct spdk_nvmf_subsystem *subsystem)
697 {
698 	return TAILQ_FIRST(&subsystem->hosts);
699 }
700 
701 
702 struct spdk_nvmf_host *
703 spdk_nvmf_subsystem_get_next_host(struct spdk_nvmf_subsystem *subsystem,
704 				  struct spdk_nvmf_host *prev_host)
705 {
706 	return TAILQ_NEXT(prev_host, link);
707 }
708 
709 const char *
710 spdk_nvmf_host_get_nqn(struct spdk_nvmf_host *host)
711 {
712 	return host->nqn;
713 }
714 
715 static struct spdk_nvmf_listener *
716 _spdk_nvmf_subsystem_find_listener(struct spdk_nvmf_subsystem *subsystem,
717 				   const struct spdk_nvme_transport_id *trid)
718 {
719 	struct spdk_nvmf_listener *listener;
720 
721 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
722 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
723 			return listener;
724 		}
725 	}
726 
727 	return NULL;
728 }
729 
730 int
731 spdk_nvmf_subsystem_add_listener(struct spdk_nvmf_subsystem *subsystem,
732 				 struct spdk_nvme_transport_id *trid)
733 {
734 	struct spdk_nvmf_transport *transport;
735 	struct spdk_nvmf_listener *listener;
736 
737 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
738 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
739 		return -EAGAIN;
740 	}
741 
742 	if (_spdk_nvmf_subsystem_find_listener(subsystem, trid)) {
743 		/* Listener already exists in this subsystem */
744 		return 0;
745 	}
746 
747 	transport = spdk_nvmf_tgt_get_transport(subsystem->tgt, trid->trtype);
748 	if (transport == NULL) {
749 		SPDK_ERRLOG("Unknown transport type %d\n", trid->trtype);
750 		return -EINVAL;
751 	}
752 
753 	listener = calloc(1, sizeof(*listener));
754 	if (!listener) {
755 		return -ENOMEM;
756 	}
757 
758 	listener->trid = *trid;
759 	listener->transport = transport;
760 
761 	TAILQ_INSERT_HEAD(&subsystem->listeners, listener, link);
762 
763 	return 0;
764 }
765 
766 int
767 spdk_nvmf_subsystem_remove_listener(struct spdk_nvmf_subsystem *subsystem,
768 				    const struct spdk_nvme_transport_id *trid)
769 {
770 	struct spdk_nvmf_listener *listener;
771 
772 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
773 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
774 		return -EAGAIN;
775 	}
776 
777 	listener = _spdk_nvmf_subsystem_find_listener(subsystem, trid);
778 	if (listener == NULL) {
779 		return -ENOENT;
780 	}
781 
782 	TAILQ_REMOVE(&subsystem->listeners, listener, link);
783 	free(listener);
784 
785 	return 0;
786 }
787 
788 bool
789 spdk_nvmf_subsystem_listener_allowed(struct spdk_nvmf_subsystem *subsystem,
790 				     struct spdk_nvme_transport_id *trid)
791 {
792 	struct spdk_nvmf_listener *listener;
793 
794 	if (!strcmp(subsystem->subnqn, SPDK_NVMF_DISCOVERY_NQN)) {
795 		return true;
796 	}
797 
798 	TAILQ_FOREACH(listener, &subsystem->listeners, link) {
799 		if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
800 			return true;
801 		}
802 	}
803 
804 	return false;
805 }
806 
807 struct spdk_nvmf_listener *
808 spdk_nvmf_subsystem_get_first_listener(struct spdk_nvmf_subsystem *subsystem)
809 {
810 	return TAILQ_FIRST(&subsystem->listeners);
811 }
812 
813 struct spdk_nvmf_listener *
814 spdk_nvmf_subsystem_get_next_listener(struct spdk_nvmf_subsystem *subsystem,
815 				      struct spdk_nvmf_listener *prev_listener)
816 {
817 	return TAILQ_NEXT(prev_listener, link);
818 }
819 
820 const struct spdk_nvme_transport_id *
821 spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
822 {
823 	return &listener->trid;
824 }
825 
826 struct subsystem_update_ns_ctx {
827 	struct spdk_nvmf_subsystem *subsystem;
828 
829 	spdk_nvmf_subsystem_state_change_done cb_fn;
830 	void *cb_arg;
831 };
832 
833 static void
834 subsystem_update_ns_done(struct spdk_io_channel_iter *i, int status)
835 {
836 	struct subsystem_update_ns_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
837 
838 	if (ctx->cb_fn) {
839 		ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
840 	}
841 	free(ctx);
842 }
843 
844 static void
845 subsystem_update_ns_on_pg(struct spdk_io_channel_iter *i)
846 {
847 	int rc;
848 	struct subsystem_update_ns_ctx *ctx;
849 	struct spdk_nvmf_poll_group *group;
850 	struct spdk_nvmf_subsystem *subsystem;
851 
852 	ctx = spdk_io_channel_iter_get_ctx(i);
853 	group = spdk_io_channel_get_ctx(spdk_io_channel_iter_get_channel(i));
854 	subsystem = ctx->subsystem;
855 
856 	rc = spdk_nvmf_poll_group_update_subsystem(group, subsystem);
857 	spdk_for_each_channel_continue(i, rc);
858 }
859 
860 static int
861 spdk_nvmf_subsystem_update_ns(struct spdk_nvmf_subsystem *subsystem, spdk_channel_for_each_cpl cpl,
862 			      void *ctx)
863 {
864 	spdk_for_each_channel(subsystem->tgt,
865 			      subsystem_update_ns_on_pg,
866 			      ctx,
867 			      cpl);
868 
869 	return 0;
870 }
871 
872 static void
873 spdk_nvmf_subsystem_ns_changed(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
874 {
875 	struct spdk_nvmf_ctrlr *ctrlr;
876 
877 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
878 		spdk_nvmf_ctrlr_ns_changed(ctrlr, nsid);
879 	}
880 }
881 
882 static int
883 _spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
884 {
885 	struct spdk_nvmf_ns *ns;
886 
887 	assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED ||
888 	       subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
889 
890 	if (nsid == 0 || nsid > subsystem->max_nsid) {
891 		return -1;
892 	}
893 
894 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
895 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
896 		return -1;
897 	}
898 
899 	ns = subsystem->ns[nsid - 1];
900 	if (!ns) {
901 		return -1;
902 	}
903 
904 	subsystem->ns[nsid - 1] = NULL;
905 
906 	spdk_bdev_module_release_bdev(ns->bdev);
907 	spdk_bdev_close(ns->desc);
908 	free(ns);
909 
910 	spdk_nvmf_subsystem_ns_changed(subsystem, nsid);
911 
912 	return 0;
913 }
914 
915 int
916 spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid,
917 			      spdk_nvmf_subsystem_state_change_done cb_fn, void *cb_arg)
918 {
919 	int rc;
920 	struct subsystem_update_ns_ctx *ctx;
921 
922 	rc = _spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
923 	if (rc < 0) {
924 		return rc;
925 	}
926 
927 	ctx = calloc(1, sizeof(*ctx));
928 
929 	if (ctx == NULL) {
930 		return -ENOMEM;
931 	}
932 
933 	ctx->subsystem = subsystem;
934 	ctx->cb_fn = cb_fn;
935 	ctx->cb_arg = cb_arg;
936 
937 	spdk_nvmf_subsystem_update_ns(subsystem, subsystem_update_ns_done, ctx);
938 
939 	return 0;
940 }
941 
942 static void
943 _spdk_nvmf_ns_hot_remove_done(struct spdk_nvmf_subsystem *subsystem, void *cb_arg, int status)
944 {
945 	if (status != 0) {
946 		SPDK_ERRLOG("Failed to make changes to NVMe-oF subsystem with id %u\n", subsystem->id);
947 	}
948 	spdk_nvmf_subsystem_resume(subsystem, NULL, NULL);
949 }
950 
951 static void
952 _spdk_nvmf_ns_hot_remove(struct spdk_nvmf_subsystem *subsystem,
953 			 void *cb_arg, int status)
954 {
955 	struct spdk_nvmf_ns *ns = cb_arg;
956 
957 	spdk_nvmf_subsystem_remove_ns(subsystem, ns->opts.nsid, _spdk_nvmf_ns_hot_remove_done,
958 				      subsystem);
959 }
960 
961 static void
962 spdk_nvmf_ns_hot_remove(void *remove_ctx)
963 {
964 	struct spdk_nvmf_ns *ns = remove_ctx;
965 	int rc;
966 
967 	rc = spdk_nvmf_subsystem_pause(ns->subsystem, _spdk_nvmf_ns_hot_remove, ns);
968 	if (rc) {
969 		SPDK_ERRLOG("Unable to pause subsystem to process namespace removal!\n");
970 	}
971 }
972 
973 void
974 spdk_nvmf_ns_opts_get_defaults(struct spdk_nvmf_ns_opts *opts, size_t opts_size)
975 {
976 	/* All current fields are set to 0 by default. */
977 	memset(opts, 0, opts_size);
978 }
979 
980 /* Dummy bdev module used to to claim bdevs. */
981 static struct spdk_bdev_module ns_bdev_module = {
982 	.name	= "NVMe-oF Target",
983 };
984 
985 uint32_t
986 spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bdev *bdev,
987 			   const struct spdk_nvmf_ns_opts *user_opts, size_t opts_size)
988 {
989 	struct spdk_nvmf_ns_opts opts;
990 	struct spdk_nvmf_ns *ns;
991 	int rc;
992 
993 	if (!(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
994 	      subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED)) {
995 		return 0;
996 	}
997 
998 	if (spdk_bdev_get_block_size(bdev) % 512) {
999 		SPDK_ERRLOG("Block size %u for Bdev %s is not supported now\n",
1000 			    spdk_bdev_get_block_size(bdev), spdk_bdev_get_name(bdev));
1001 		return 0;
1002 	}
1003 
1004 	spdk_nvmf_ns_opts_get_defaults(&opts, sizeof(opts));
1005 	if (user_opts) {
1006 		memcpy(&opts, user_opts, spdk_min(sizeof(opts), opts_size));
1007 	}
1008 
1009 	if (spdk_mem_all_zero(&opts.uuid, sizeof(opts.uuid))) {
1010 		opts.uuid = *spdk_bdev_get_uuid(bdev);
1011 	}
1012 
1013 	if (opts.nsid == SPDK_NVME_GLOBAL_NS_TAG) {
1014 		SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", opts.nsid);
1015 		return 0;
1016 	}
1017 
1018 	if (opts.nsid == 0) {
1019 		/*
1020 		 * NSID not specified - find a free index.
1021 		 *
1022 		 * If no free slots are found, opts.nsid will be subsystem->max_nsid + 1, which will
1023 		 * expand max_nsid if possible.
1024 		 */
1025 		for (opts.nsid = 1; opts.nsid <= subsystem->max_nsid; opts.nsid++) {
1026 			if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid) == NULL) {
1027 				break;
1028 			}
1029 		}
1030 	}
1031 
1032 	if (_spdk_nvmf_subsystem_get_ns(subsystem, opts.nsid)) {
1033 		SPDK_ERRLOG("Requested NSID %" PRIu32 " already in use\n", opts.nsid);
1034 		return 0;
1035 	}
1036 
1037 	if (opts.nsid > subsystem->max_nsid) {
1038 		struct spdk_nvmf_ns **new_ns_array;
1039 
1040 		/* If MaxNamespaces was specified, we can't extend max_nsid beyond it. */
1041 		if (subsystem->max_allowed_nsid > 0 && opts.nsid > subsystem->max_allowed_nsid) {
1042 			SPDK_ERRLOG("Can't extend NSID range above MaxNamespaces\n");
1043 			return 0;
1044 		}
1045 
1046 		/* If a controller is connected, we can't change NN. */
1047 		if (!TAILQ_EMPTY(&subsystem->ctrlrs)) {
1048 			SPDK_ERRLOG("Can't extend NSID range while controllers are connected\n");
1049 			return 0;
1050 		}
1051 
1052 		new_ns_array = realloc(subsystem->ns, sizeof(struct spdk_nvmf_ns *) * opts.nsid);
1053 		if (new_ns_array == NULL) {
1054 			SPDK_ERRLOG("Memory allocation error while resizing namespace array.\n");
1055 			return 0;
1056 		}
1057 
1058 		memset(new_ns_array + subsystem->max_nsid, 0,
1059 		       sizeof(struct spdk_nvmf_ns *) * (opts.nsid - subsystem->max_nsid));
1060 		subsystem->ns = new_ns_array;
1061 		subsystem->max_nsid = opts.nsid;
1062 	}
1063 
1064 	ns = calloc(1, sizeof(*ns));
1065 	if (ns == NULL) {
1066 		SPDK_ERRLOG("Namespace allocation failed\n");
1067 		return 0;
1068 	}
1069 
1070 	ns->bdev = bdev;
1071 	ns->opts = opts;
1072 	ns->subsystem = subsystem;
1073 	rc = spdk_bdev_open(bdev, true, spdk_nvmf_ns_hot_remove, ns, &ns->desc);
1074 	if (rc != 0) {
1075 		SPDK_ERRLOG("Subsystem %s: bdev %s cannot be opened, error=%d\n",
1076 			    subsystem->subnqn, spdk_bdev_get_name(bdev), rc);
1077 		free(ns);
1078 		return 0;
1079 	}
1080 	rc = spdk_bdev_module_claim_bdev(bdev, ns->desc, &ns_bdev_module);
1081 	if (rc != 0) {
1082 		spdk_bdev_close(ns->desc);
1083 		free(ns);
1084 		return 0;
1085 	}
1086 	subsystem->ns[opts.nsid - 1] = ns;
1087 	ns->nsid = opts.nsid;
1088 
1089 	SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Subsystem %s: bdev %s assigned nsid %" PRIu32 "\n",
1090 		      spdk_nvmf_subsystem_get_nqn(subsystem),
1091 		      spdk_bdev_get_name(bdev),
1092 		      opts.nsid);
1093 
1094 	spdk_nvmf_subsystem_ns_changed(subsystem, opts.nsid);
1095 
1096 	return opts.nsid;
1097 }
1098 
1099 static uint32_t
1100 spdk_nvmf_subsystem_get_next_allocated_nsid(struct spdk_nvmf_subsystem *subsystem,
1101 		uint32_t prev_nsid)
1102 {
1103 	uint32_t nsid;
1104 
1105 	if (prev_nsid >= subsystem->max_nsid) {
1106 		return 0;
1107 	}
1108 
1109 	for (nsid = prev_nsid + 1; nsid <= subsystem->max_nsid; nsid++) {
1110 		if (subsystem->ns[nsid - 1]) {
1111 			return nsid;
1112 		}
1113 	}
1114 
1115 	return 0;
1116 }
1117 
1118 struct spdk_nvmf_ns *
1119 spdk_nvmf_subsystem_get_first_ns(struct spdk_nvmf_subsystem *subsystem)
1120 {
1121 	uint32_t first_nsid;
1122 
1123 	first_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, 0);
1124 	return _spdk_nvmf_subsystem_get_ns(subsystem, first_nsid);
1125 }
1126 
1127 struct spdk_nvmf_ns *
1128 spdk_nvmf_subsystem_get_next_ns(struct spdk_nvmf_subsystem *subsystem,
1129 				struct spdk_nvmf_ns *prev_ns)
1130 {
1131 	uint32_t next_nsid;
1132 
1133 	next_nsid = spdk_nvmf_subsystem_get_next_allocated_nsid(subsystem, prev_ns->opts.nsid);
1134 	return _spdk_nvmf_subsystem_get_ns(subsystem, next_nsid);
1135 }
1136 
1137 struct spdk_nvmf_ns *
1138 spdk_nvmf_subsystem_get_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
1139 {
1140 	return _spdk_nvmf_subsystem_get_ns(subsystem, nsid);
1141 }
1142 
1143 uint32_t
1144 spdk_nvmf_ns_get_id(const struct spdk_nvmf_ns *ns)
1145 {
1146 	return ns->opts.nsid;
1147 }
1148 
1149 struct spdk_bdev *
1150 spdk_nvmf_ns_get_bdev(struct spdk_nvmf_ns *ns)
1151 {
1152 	return ns->bdev;
1153 }
1154 
1155 void
1156 spdk_nvmf_ns_get_opts(const struct spdk_nvmf_ns *ns, struct spdk_nvmf_ns_opts *opts,
1157 		      size_t opts_size)
1158 {
1159 	memset(opts, 0, opts_size);
1160 	memcpy(opts, &ns->opts, spdk_min(sizeof(ns->opts), opts_size));
1161 }
1162 
1163 const char *
1164 spdk_nvmf_subsystem_get_sn(const struct spdk_nvmf_subsystem *subsystem)
1165 {
1166 	return subsystem->sn;
1167 }
1168 
1169 int
1170 spdk_nvmf_subsystem_set_sn(struct spdk_nvmf_subsystem *subsystem, const char *sn)
1171 {
1172 	size_t len, max_len;
1173 
1174 	max_len = sizeof(subsystem->sn) - 1;
1175 	len = strlen(sn);
1176 	if (len > max_len) {
1177 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Invalid sn \"%s\": length %zu > max %zu\n",
1178 			      sn, len, max_len);
1179 		return -1;
1180 	}
1181 
1182 	if (!spdk_nvmf_valid_ascii_string(sn, len)) {
1183 		SPDK_DEBUGLOG(SPDK_LOG_NVMF, "Non-ASCII sn\n");
1184 		SPDK_LOGDUMP(SPDK_LOG_NVMF, "sn", sn, len);
1185 		return -1;
1186 	}
1187 
1188 	snprintf(subsystem->sn, sizeof(subsystem->sn), "%s", sn);
1189 
1190 	return 0;
1191 }
1192 
1193 const char *
1194 spdk_nvmf_subsystem_get_nqn(struct spdk_nvmf_subsystem *subsystem)
1195 {
1196 	return subsystem->subnqn;
1197 }
1198 
1199 /* Workaround for astyle formatting bug */
1200 typedef enum spdk_nvmf_subtype nvmf_subtype_t;
1201 
1202 nvmf_subtype_t
1203 spdk_nvmf_subsystem_get_type(struct spdk_nvmf_subsystem *subsystem)
1204 {
1205 	return subsystem->subtype;
1206 }
1207 
1208 static uint16_t
1209 spdk_nvmf_subsystem_gen_cntlid(struct spdk_nvmf_subsystem *subsystem)
1210 {
1211 	int count;
1212 
1213 	/*
1214 	 * In the worst case, we might have to try all CNTLID values between 1 and 0xFFF0 - 1
1215 	 * before we find one that is unused (or find that all values are in use).
1216 	 */
1217 	for (count = 0; count < 0xFFF0 - 1; count++) {
1218 		subsystem->next_cntlid++;
1219 		if (subsystem->next_cntlid >= 0xFFF0) {
1220 			/* The spec reserves cntlid values in the range FFF0h to FFFFh. */
1221 			subsystem->next_cntlid = 1;
1222 		}
1223 
1224 		/* Check if a controller with this cntlid currently exists. */
1225 		if (spdk_nvmf_subsystem_get_ctrlr(subsystem, subsystem->next_cntlid) == NULL) {
1226 			/* Found unused cntlid */
1227 			return subsystem->next_cntlid;
1228 		}
1229 	}
1230 
1231 	/* All valid cntlid values are in use. */
1232 	return 0xFFFF;
1233 }
1234 
1235 int
1236 spdk_nvmf_subsystem_add_ctrlr(struct spdk_nvmf_subsystem *subsystem, struct spdk_nvmf_ctrlr *ctrlr)
1237 {
1238 	ctrlr->cntlid = spdk_nvmf_subsystem_gen_cntlid(subsystem);
1239 	if (ctrlr->cntlid == 0xFFFF) {
1240 		/* Unable to get a cntlid */
1241 		SPDK_ERRLOG("Reached max simultaneous ctrlrs\n");
1242 		return -EBUSY;
1243 	}
1244 
1245 	TAILQ_INSERT_TAIL(&subsystem->ctrlrs, ctrlr, link);
1246 
1247 	return 0;
1248 }
1249 
1250 void
1251 spdk_nvmf_subsystem_remove_ctrlr(struct spdk_nvmf_subsystem *subsystem,
1252 				 struct spdk_nvmf_ctrlr *ctrlr)
1253 {
1254 	assert(subsystem == ctrlr->subsys);
1255 	TAILQ_REMOVE(&subsystem->ctrlrs, ctrlr, link);
1256 }
1257 
1258 struct spdk_nvmf_ctrlr *
1259 spdk_nvmf_subsystem_get_ctrlr(struct spdk_nvmf_subsystem *subsystem, uint16_t cntlid)
1260 {
1261 	struct spdk_nvmf_ctrlr *ctrlr;
1262 
1263 	TAILQ_FOREACH(ctrlr, &subsystem->ctrlrs, link) {
1264 		if (ctrlr->cntlid == cntlid) {
1265 			return ctrlr;
1266 		}
1267 	}
1268 
1269 	return NULL;
1270 }
1271 
1272 uint32_t
1273 spdk_nvmf_subsystem_get_max_namespaces(const struct spdk_nvmf_subsystem *subsystem)
1274 {
1275 	return subsystem->max_allowed_nsid;
1276 }
1277