xref: /spdk/test/unit/lib/nvmf/fc_ls.c/fc_ls_ut.c (revision 7961de43413e7f818f7499bf8518909beb59c82f)
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright (c) 2018-2019 Broadcom.  All Rights Reserved.
5  *   The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
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 /* NVMF FC LS Command Processor Unit Test */
35 
36 #include "spdk/env.h"
37 #include "spdk_cunit.h"
38 #include "spdk/nvmf.h"
39 #include "spdk_internal/event.h"
40 #include "spdk/endian.h"
41 #include "spdk/trace.h"
42 #include "spdk_internal/log.h"
43 
44 #include "ut_multithread.c"
45 
46 #include "transport.h"
47 #include "nvmf_internal.h"
48 #include "nvmf_fc.h"
49 
50 #include "fc_ls.c"
51 
52 #define LAST_RSLT_STOP_TEST 999
53 
54 void spdk_set_thread(struct spdk_thread *thread);
55 
56 /*
57  * SPDK Stuff
58  */
59 
60 DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), -ENOSPC);
61 DEFINE_STUB(spdk_nvmf_subsystem_host_allowed, bool,
62 	    (struct spdk_nvmf_subsystem *subsystem, const char *hostnqn), true);
63 
64 static const char *fc_ut_subsystem_nqn =
65 	"nqn.2017-11.io.spdk:sn.390c0dc7c87011e786b300a0989adc53:subsystem.good";
66 static struct spdk_nvmf_host fc_ut_initiator = {
67 	.nqn = "nqn.2017-11.fc_host",
68 };
69 static struct spdk_nvmf_host *fc_ut_host = &fc_ut_initiator;
70 static struct spdk_nvmf_tgt g_nvmf_tgt;
71 static struct spdk_nvmf_transport_opts g_nvmf_transport_opts = {
72 	.max_queue_depth = 128,
73 	.max_qpairs_per_ctrlr = 4,
74 	.max_aq_depth = 32,
75 };
76 static uint32_t g_hw_queue_depth = 1024;
77 static struct spdk_nvmf_subsystem g_nvmf_subsystem;
78 
79 
80 int spdk_nvmf_fc_xmt_ls_rsp(struct spdk_nvmf_fc_nport *g_tgt_port,
81 			    struct spdk_nvmf_fc_ls_rqst *ls_rqst);
82 void spdk_nvmf_fc_request_abort(struct spdk_nvmf_fc_request *fc_req, bool send_abts,
83 				spdk_nvmf_fc_caller_cb cb, void *cb_args);
84 void spdk_bdev_io_abort(struct spdk_bdev_io *bdev_io, void *ctx);
85 void spdk_nvmf_fc_request_abort_complete(void *arg1);
86 bool spdk_nvmf_fc_req_in_xfer(struct spdk_nvmf_fc_request *fc_req);
87 
88 struct spdk_nvmf_subsystem *
89 spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
90 {
91 	if (!strcmp(subnqn, g_nvmf_subsystem.subnqn)) {
92 		return &g_nvmf_subsystem;
93 	}
94 	return NULL;
95 }
96 
97 int
98 spdk_nvmf_poll_group_add(struct spdk_nvmf_poll_group *group,
99 			 struct spdk_nvmf_qpair *qpair)
100 {
101 	qpair->state = SPDK_NVMF_QPAIR_ACTIVE;
102 	return 0;
103 }
104 
105 const struct spdk_nvmf_transport_ops spdk_nvmf_transport_fc = {
106 	.type = (enum spdk_nvme_transport_type) SPDK_NVMF_TRTYPE_FC,
107 	.create = NULL,
108 	.destroy = NULL,
109 
110 	.listen = NULL,
111 	.stop_listen = NULL,
112 	.accept = NULL,
113 
114 	.listener_discover = NULL,
115 
116 	.poll_group_create = NULL,
117 	.poll_group_destroy = NULL,
118 	.poll_group_add = NULL,
119 	.poll_group_poll = NULL,
120 
121 	.req_complete = NULL,
122 
123 	.qpair_fini = NULL,
124 
125 };
126 
127 struct spdk_nvmf_transport g_nvmf_transport = {
128 	.ops = &spdk_nvmf_transport_fc,
129 	.tgt = &g_nvmf_tgt,
130 };
131 
132 struct spdk_nvmf_transport *
133 spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, enum spdk_nvme_transport_type type)
134 {
135 	return &g_nvmf_transport;
136 }
137 
138 int
139 spdk_nvmf_qpair_disconnect(struct spdk_nvmf_qpair *qpair, nvmf_qpair_disconnect_cb cb_fn, void *ctx)
140 {
141 	cb_fn(ctx);
142 	return 0;
143 }
144 
145 static void
146 new_qpair(struct spdk_nvmf_qpair *qpair, void *cb_arg)
147 {
148 	uint32_t i;
149 	struct spdk_nvmf_fc_conn *fc_conn;
150 	struct spdk_nvmf_fc_hwqp *hwqp = NULL, *sel_hwqp = NULL;
151 	struct spdk_nvmf_fc_ls_add_conn_api_data *api_data = NULL;
152 	struct spdk_nvmf_fc_port *fc_port;
153 
154 	fc_conn = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_fc_conn, qpair);
155 	api_data = &fc_conn->create_opd->u.add_conn;
156 
157 	/* Pick a hwqp with least load */
158 	fc_port = fc_conn->fc_assoc->tgtport->fc_port;
159 	for (i = 0; i < fc_port->num_io_queues; i ++) {
160 		hwqp = &fc_port->io_queues[i];
161 		if (!sel_hwqp || (hwqp->rq_size > sel_hwqp->rq_size)) {
162 			sel_hwqp = hwqp;
163 		}
164 	}
165 
166 	if (!nvmf_fc_assign_conn_to_hwqp(sel_hwqp,
167 					 &fc_conn->conn_id,
168 					 fc_conn->max_queue_depth)) {
169 		goto err;
170 	}
171 
172 	fc_conn->hwqp = sel_hwqp;
173 
174 	/* If this is for ADMIN connection, then update assoc ID. */
175 	if (fc_conn->qpair.qid == 0) {
176 		fc_conn->fc_assoc->assoc_id = fc_conn->conn_id;
177 	}
178 
179 	spdk_nvmf_fc_poller_api_func(sel_hwqp, SPDK_NVMF_FC_POLLER_API_ADD_CONNECTION, &api_data->args);
180 
181 	return;
182 err:
183 	nvmf_fc_ls_add_conn_failure(api_data->assoc, api_data->ls_rqst,
184 				    api_data->args.fc_conn, api_data->aq_conn);
185 }
186 
187 struct spdk_nvmf_fc_conn *
188 spdk_nvmf_fc_hwqp_find_fc_conn(struct spdk_nvmf_fc_hwqp *hwqp, uint64_t conn_id)
189 {
190 	struct spdk_nvmf_fc_conn *fc_conn;
191 
192 	TAILQ_FOREACH(fc_conn, &hwqp->connection_list, link) {
193 		if (fc_conn->conn_id == conn_id) {
194 			return fc_conn;
195 		}
196 	}
197 
198 	return NULL;
199 }
200 
201 /*
202  * LLD functions
203  */
204 
205 static inline uint64_t
206 nvmf_fc_gen_conn_id(uint32_t qnum, struct spdk_nvmf_fc_hwqp *hwqp)
207 {
208 	static uint16_t conn_cnt = 0;
209 	return ((uint64_t) qnum | (conn_cnt++ << 8));
210 }
211 
212 bool
213 nvmf_fc_assign_conn_to_hwqp(struct spdk_nvmf_fc_hwqp *hwqp,
214 			    uint64_t *conn_id, uint32_t sq_size)
215 {
216 	SPDK_DEBUGLOG(SPDK_LOG_NVMF_FC_LS, "Assign connection to HWQP\n");
217 
218 
219 	if (hwqp->rq_size < sq_size) {
220 		return false; /* queue has no space for this connection */
221 	}
222 
223 	hwqp->rq_size -= sq_size;
224 	hwqp->num_conns++;
225 
226 	/* create connection ID */
227 	*conn_id = nvmf_fc_gen_conn_id(hwqp->hwqp_id, hwqp);
228 
229 	SPDK_DEBUGLOG(SPDK_LOG_NVMF_FC_LS,
230 		      "New connection assigned to HWQP%d (free %d), conn_id 0x%lx\n",
231 		      hwqp->hwqp_id, hwqp->rq_size, *conn_id);
232 	return true;
233 }
234 
235 struct spdk_nvmf_fc_hwqp *
236 nvmf_fc_get_hwqp_from_conn_id(struct spdk_nvmf_fc_hwqp *queues,
237 			      uint32_t num_queues, uint64_t conn_id)
238 {
239 	return &queues[(conn_id & 0xff) % num_queues];
240 }
241 
242 void
243 nvmf_fc_release_conn(struct spdk_nvmf_fc_hwqp *hwqp, uint64_t conn_id,
244 		     uint32_t sq_size)
245 {
246 	hwqp->rq_size += sq_size;
247 }
248 
249 struct spdk_nvmf_fc_srsr_bufs *
250 nvmf_fc_alloc_srsr_bufs(size_t rqst_len, size_t rsp_len)
251 {
252 	struct spdk_nvmf_fc_srsr_bufs *srsr_bufs;
253 
254 	srsr_bufs = calloc(1, sizeof(struct spdk_nvmf_fc_srsr_bufs));
255 	if (!srsr_bufs) {
256 		return NULL;
257 	}
258 
259 	srsr_bufs->rqst = calloc(1, rqst_len + rsp_len);
260 	if (srsr_bufs->rqst) {
261 		srsr_bufs->rqst_len = rqst_len;
262 		srsr_bufs->rsp = srsr_bufs->rqst + rqst_len;
263 		srsr_bufs->rsp_len = rsp_len;
264 	} else {
265 		free(srsr_bufs);
266 		srsr_bufs = NULL;
267 	}
268 
269 	return srsr_bufs;
270 }
271 
272 void
273 nvmf_fc_free_srsr_bufs(struct spdk_nvmf_fc_srsr_bufs *srsr_bufs)
274 {
275 	if (srsr_bufs) {
276 		free(srsr_bufs->rqst);
277 		free(srsr_bufs);
278 	}
279 }
280 
281 int
282 nvmf_fc_xmt_ls_rsp(struct spdk_nvmf_fc_nport *tgtport, struct spdk_nvmf_fc_ls_rqst *ls_rqst)
283 {
284 	return spdk_nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
285 }
286 
287 /*
288  *  The Tests
289  */
290 
291 enum _test_run_type {
292 	TEST_RUN_TYPE_CREATE_ASSOC = 1,
293 	TEST_RUN_TYPE_CREATE_CONN,
294 	TEST_RUN_TYPE_DISCONNECT,
295 	TEST_RUN_TYPE_CONN_BAD_ASSOC,
296 	TEST_RUN_TYPE_FAIL_LS_RSP,
297 	TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC,
298 	TEST_RUN_TYPE_CREATE_MAX_ASSOC,
299 };
300 
301 static uint32_t g_test_run_type = 0;
302 static uint64_t g_curr_assoc_id = 0;
303 static uint16_t g_create_conn_test_cnt = 0;
304 static uint16_t g_max_assoc_conn_test = 0;
305 static int g_last_rslt = 0;
306 static bool g_spdk_nvmf_fc_xmt_srsr_req = false;
307 static struct spdk_nvmf_fc_remote_port_info g_rem_port;
308 
309 static void
310 run_create_assoc_test(const char *subnqn,
311 		      struct spdk_nvmf_host *host,
312 		      struct spdk_nvmf_fc_nport *tgt_port)
313 {
314 	struct spdk_nvmf_fc_ls_rqst ls_rqst;
315 	struct spdk_nvmf_fc_ls_cr_assoc_rqst ca_rqst;
316 	uint8_t respbuf[128];
317 
318 	memset(&ca_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst));
319 
320 	ca_rqst.w0.ls_cmd = FCNVME_LS_CREATE_ASSOCIATION;
321 	to_be32(&ca_rqst.desc_list_len,
322 		sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst) -
323 		(2 * sizeof(uint32_t)));
324 	to_be32(&ca_rqst.assoc_cmd.desc_tag, FCNVME_LSDESC_CREATE_ASSOC_CMD);
325 	to_be32(&ca_rqst.assoc_cmd.desc_len,
326 		sizeof(struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd) -
327 		(2 * sizeof(uint32_t)));
328 	to_be16(&ca_rqst.assoc_cmd.ersp_ratio, (g_nvmf_transport.opts.max_aq_depth / 2));
329 	to_be16(&ca_rqst.assoc_cmd.sqsize,  g_nvmf_transport.opts.max_aq_depth - 1);
330 	snprintf(&ca_rqst.assoc_cmd.subnqn[0], strlen(subnqn) + 1, "%s", subnqn);
331 	snprintf(&ca_rqst.assoc_cmd.hostnqn[0], strlen(host->nqn) + 1, "%s", host->nqn);
332 	ls_rqst.rqstbuf.virt = &ca_rqst;
333 	ls_rqst.rspbuf.virt = respbuf;
334 	ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst);
335 	ls_rqst.rsp_len = 0;
336 	ls_rqst.rpi = 5000;
337 	ls_rqst.private_data = NULL;
338 	ls_rqst.s_id = 0;
339 	ls_rqst.nport = tgt_port;
340 	ls_rqst.rport = &g_rem_port;
341 	ls_rqst.nvmf_tgt = &g_nvmf_tgt;
342 
343 	spdk_nvmf_fc_handle_ls_rqst(&ls_rqst);
344 	poll_thread(0);
345 }
346 
347 static void
348 run_create_conn_test(struct spdk_nvmf_host *host,
349 		     struct spdk_nvmf_fc_nport *tgt_port,
350 		     uint64_t assoc_id,
351 		     uint16_t qid)
352 {
353 	struct spdk_nvmf_fc_ls_rqst ls_rqst;
354 	struct spdk_nvmf_fc_ls_cr_conn_rqst cc_rqst;
355 	uint8_t respbuf[128];
356 
357 	memset(&cc_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst));
358 
359 	/* fill in request descriptor */
360 	cc_rqst.w0.ls_cmd = FCNVME_LS_CREATE_CONNECTION;
361 	to_be32(&cc_rqst.desc_list_len,
362 		sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst) -
363 		(2 * sizeof(uint32_t)));
364 
365 	/* fill in connect command descriptor */
366 	to_be32(&cc_rqst.connect_cmd.desc_tag, FCNVME_LSDESC_CREATE_CONN_CMD);
367 	to_be32(&cc_rqst.connect_cmd.desc_len,
368 		sizeof(struct spdk_nvmf_fc_lsdesc_cr_conn_cmd) -
369 		(2 * sizeof(uint32_t)));
370 
371 	to_be16(&cc_rqst.connect_cmd.ersp_ratio, (g_nvmf_transport.opts.max_queue_depth / 2));
372 	to_be16(&cc_rqst.connect_cmd.sqsize, g_nvmf_transport.opts.max_queue_depth - 1);
373 	to_be16(&cc_rqst.connect_cmd.qid, qid);
374 
375 	/* fill in association id descriptor */
376 	to_be32(&cc_rqst.assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID),
377 		to_be32(&cc_rqst.assoc_id.desc_len,
378 			sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
379 			(2 * sizeof(uint32_t)));
380 	cc_rqst.assoc_id.association_id = assoc_id; /* alreday be64 */
381 
382 	ls_rqst.rqstbuf.virt = &cc_rqst;
383 	ls_rqst.rspbuf.virt = respbuf;
384 	ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst);
385 	ls_rqst.rsp_len = 0;
386 	ls_rqst.rpi = 5000;
387 	ls_rqst.private_data = NULL;
388 	ls_rqst.s_id = 0;
389 	ls_rqst.nport = tgt_port;
390 	ls_rqst.rport = &g_rem_port;
391 	ls_rqst.nvmf_tgt = &g_nvmf_tgt;
392 
393 	spdk_nvmf_fc_handle_ls_rqst(&ls_rqst);
394 	poll_thread(0);
395 }
396 
397 static void
398 run_disconn_test(struct spdk_nvmf_fc_nport *tgt_port,
399 		 uint64_t assoc_id)
400 {
401 	struct spdk_nvmf_fc_ls_rqst ls_rqst;
402 	struct spdk_nvmf_fc_ls_disconnect_rqst dc_rqst;
403 	uint8_t respbuf[128];
404 
405 	memset(&dc_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst));
406 
407 	/* fill in request descriptor */
408 	dc_rqst.w0.ls_cmd = FCNVME_LS_DISCONNECT;
409 	to_be32(&dc_rqst.desc_list_len,
410 		sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) -
411 		(2 * sizeof(uint32_t)));
412 
413 	/* fill in disconnect command descriptor */
414 	to_be32(&dc_rqst.disconn_cmd.desc_tag, FCNVME_LSDESC_DISCONN_CMD);
415 	to_be32(&dc_rqst.disconn_cmd.desc_len,
416 		sizeof(struct spdk_nvmf_fc_lsdesc_disconn_cmd) -
417 		(2 * sizeof(uint32_t)));
418 
419 	/* fill in association id descriptor */
420 	to_be32(&dc_rqst.assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID),
421 		to_be32(&dc_rqst.assoc_id.desc_len,
422 			sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
423 			(2 * sizeof(uint32_t)));
424 	dc_rqst.assoc_id.association_id = assoc_id; /* alreday be64 */
425 
426 	ls_rqst.rqstbuf.virt = &dc_rqst;
427 	ls_rqst.rspbuf.virt = respbuf;
428 	ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst);
429 	ls_rqst.rsp_len = 0;
430 	ls_rqst.rpi = 5000;
431 	ls_rqst.private_data = NULL;
432 	ls_rqst.s_id = 0;
433 	ls_rqst.nport = tgt_port;
434 	ls_rqst.rport = &g_rem_port;
435 	ls_rqst.nvmf_tgt = &g_nvmf_tgt;
436 
437 	spdk_nvmf_fc_handle_ls_rqst(&ls_rqst);
438 	poll_thread(0);
439 }
440 
441 static void
442 disconnect_assoc_cb(void *cb_data, uint32_t err)
443 {
444 	CU_ASSERT(err == 0);
445 }
446 
447 static int
448 handle_ca_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst, bool max_assoc_test)
449 {
450 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
451 		(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
452 
453 
454 	if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_ASSOCIATION) {
455 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
456 			struct spdk_nvmf_fc_ls_cr_assoc_acc *acc =
457 				(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
458 
459 			CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
460 				  sizeof(struct spdk_nvmf_fc_ls_cr_assoc_acc) - 8);
461 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
462 				  sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
463 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
464 				  FCNVME_LSDESC_RQST);
465 			CU_ASSERT(from_be32(&acc->assoc_id.desc_tag) ==
466 				  FCNVME_LSDESC_ASSOC_ID);
467 			CU_ASSERT(from_be32(&acc->assoc_id.desc_len) ==
468 				  sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) - 8);
469 			CU_ASSERT(from_be32(&acc->conn_id.desc_tag) ==
470 				  FCNVME_LSDESC_CONN_ID);
471 			CU_ASSERT(from_be32(&acc->conn_id.desc_len) ==
472 				  sizeof(struct spdk_nvmf_fc_lsdesc_conn_id) - 8);
473 
474 			g_curr_assoc_id = acc->assoc_id.association_id;
475 			g_create_conn_test_cnt++;
476 			return 0;
477 		} else if (max_assoc_test) {
478 			/* reject reason code should be insufficient resources */
479 			struct spdk_nvmf_fc_ls_rjt *rjt =
480 				(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
481 			if (rjt->rjt.reason_code == FCNVME_RJT_RC_INSUFF_RES) {
482 				return LAST_RSLT_STOP_TEST;
483 			}
484 		}
485 		CU_FAIL("Unexpected reject response for create association");
486 	} else {
487 		CU_FAIL("Response not for create association");
488 	}
489 
490 	return -EINVAL;
491 }
492 
493 static int
494 handle_cc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
495 {
496 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
497 		(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
498 
499 	if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_CONNECTION) {
500 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
501 			struct spdk_nvmf_fc_ls_cr_conn_acc *acc =
502 				(struct spdk_nvmf_fc_ls_cr_conn_acc *)ls_rqst->rspbuf.virt;
503 
504 			CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
505 				  sizeof(struct spdk_nvmf_fc_ls_cr_conn_acc) - 8);
506 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
507 				  sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
508 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
509 				  FCNVME_LSDESC_RQST);
510 			CU_ASSERT(from_be32(&acc->conn_id.desc_tag) ==
511 				  FCNVME_LSDESC_CONN_ID);
512 			CU_ASSERT(from_be32(&acc->conn_id.desc_len) ==
513 				  sizeof(struct spdk_nvmf_fc_lsdesc_conn_id) - 8);
514 			g_create_conn_test_cnt++;
515 			return 0;
516 		}
517 
518 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
519 			struct spdk_nvmf_fc_ls_rjt *rjt =
520 				(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
521 			if (g_create_conn_test_cnt == g_nvmf_transport.opts.max_qpairs_per_ctrlr) {
522 				/* expected to get reject for too many connections */
523 				CU_ASSERT(rjt->rjt.reason_code ==
524 					  FCNVME_RJT_RC_INV_PARAM);
525 				CU_ASSERT(rjt->rjt.reason_explanation ==
526 					  FCNVME_RJT_EXP_INV_Q_ID);
527 			} else if (!g_max_assoc_conn_test) {
528 				CU_FAIL("Unexpected reject response create connection");
529 			}
530 		} else {
531 			CU_FAIL("Unexpected response code for create connection");
532 		}
533 	} else {
534 		CU_FAIL("Response not for create connection");
535 	}
536 
537 	return -EINVAL;
538 }
539 
540 static int
541 handle_disconn_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
542 {
543 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
544 		(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
545 
546 	if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_DISCONNECT) {
547 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
548 			CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
549 				  sizeof(struct spdk_nvmf_fc_ls_disconnect_acc) - 8);
550 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
551 				  sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
552 			CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
553 				  FCNVME_LSDESC_RQST);
554 			return 0;
555 		} else {
556 			CU_FAIL("Unexpected reject response for disconnect");
557 		}
558 	} else {
559 		CU_FAIL("Response not for create connection");
560 	}
561 
562 	return -EINVAL;
563 }
564 
565 static int
566 handle_conn_bad_assoc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
567 {
568 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
569 		(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
570 
571 	if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_CONNECTION) {
572 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
573 			struct spdk_nvmf_fc_ls_rjt *rjt =
574 				(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
575 
576 			CU_ASSERT(from_be32(&rjt->desc_list_len) ==
577 				  sizeof(struct spdk_nvmf_fc_ls_rjt) - 8);
578 			CU_ASSERT(from_be32(&rjt->rqst.desc_tag) ==
579 				  FCNVME_LSDESC_RQST);
580 			CU_ASSERT(from_be32(&rjt->rjt.desc_len) ==
581 				  sizeof(struct spdk_nvmf_fc_lsdesc_rjt) - 8);
582 			CU_ASSERT(from_be32(&rjt->rjt.desc_tag) ==
583 				  FCNVME_LSDESC_RJT);
584 			CU_ASSERT(rjt->rjt.reason_code ==
585 				  FCNVME_RJT_RC_INV_ASSOC);
586 			CU_ASSERT(rjt->rjt.reason_explanation ==
587 				  FCNVME_RJT_EXP_NONE);
588 			/* make sure reserved fields are 0 */
589 			CU_ASSERT(rjt->rjt.rsvd8 == 0);
590 			CU_ASSERT(rjt->rjt.rsvd12 == 0);
591 			return 0;
592 		} else {
593 			CU_FAIL("Unexpected accept response for create conn. on bad assoc_id");
594 		}
595 	} else {
596 		CU_FAIL("Response not for create connection on bad assoc_id");
597 	}
598 
599 	return -EINVAL;
600 }
601 
602 static int
603 handle_disconn_bad_assoc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
604 {
605 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
606 		(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
607 
608 	if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_DISCONNECT) {
609 		if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
610 			struct spdk_nvmf_fc_ls_rjt *rjt =
611 				(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
612 
613 			CU_ASSERT(from_be32(&rjt->desc_list_len) ==
614 				  sizeof(struct spdk_nvmf_fc_ls_rjt) - 8);
615 			CU_ASSERT(from_be32(&rjt->rqst.desc_tag) ==
616 				  FCNVME_LSDESC_RQST);
617 			CU_ASSERT(from_be32(&rjt->rjt.desc_len) ==
618 				  sizeof(struct spdk_nvmf_fc_lsdesc_rjt) - 8);
619 			CU_ASSERT(from_be32(&rjt->rjt.desc_tag) ==
620 				  FCNVME_LSDESC_RJT);
621 			CU_ASSERT(rjt->rjt.reason_code ==
622 				  FCNVME_RJT_RC_INV_ASSOC);
623 			CU_ASSERT(rjt->rjt.reason_explanation ==
624 				  FCNVME_RJT_EXP_NONE);
625 			return 0;
626 		} else {
627 			CU_FAIL("Unexpected accept response for disconnect on bad assoc_id");
628 		}
629 	} else {
630 		CU_FAIL("Response not for dsconnect on bad assoc_id");
631 	}
632 
633 	return -EINVAL;
634 }
635 
636 
637 static struct spdk_nvmf_fc_port g_fc_port = {
638 	.num_io_queues = 16,
639 	.new_qp_cb = new_qpair,
640 };
641 
642 static struct spdk_nvmf_fc_nport g_tgt_port;
643 
644 static uint64_t assoc_id[1024];
645 
646 #define FC_LS_UT_MAX_IO_QUEUES 16
647 struct spdk_nvmf_fc_hwqp g_fc_hwqp[FC_LS_UT_MAX_IO_QUEUES];
648 struct spdk_nvmf_fc_poll_group g_fgroup[FC_LS_UT_MAX_IO_QUEUES];
649 struct spdk_nvmf_poll_group g_poll_group[FC_LS_UT_MAX_IO_QUEUES];
650 static bool threads_allocated = false;
651 
652 static void
653 ls_assign_hwqp_threads(void)
654 {
655 	uint32_t i;
656 
657 	for (i = 0; i < g_fc_port.num_io_queues; i++) {
658 		struct spdk_nvmf_fc_hwqp *hwqp = &g_fc_port.io_queues[i];
659 		if (hwqp->thread == NULL) {
660 			hwqp->thread = spdk_get_thread();
661 		}
662 	}
663 }
664 
665 static void
666 ls_prepare_threads(void)
667 {
668 	if (threads_allocated == false) {
669 		allocate_threads(8);
670 		set_thread(0);
671 	}
672 	threads_allocated = true;
673 }
674 
675 static void
676 setup_polling_threads(void)
677 {
678 	ls_prepare_threads();
679 	set_thread(0);
680 	ls_assign_hwqp_threads();
681 }
682 
683 static int
684 ls_tests_init(void)
685 {
686 	uint16_t i;
687 
688 	bzero(&g_nvmf_tgt, sizeof(g_nvmf_tgt));
689 
690 	g_nvmf_transport.opts = g_nvmf_transport_opts;
691 
692 	snprintf(g_nvmf_subsystem.subnqn, sizeof(g_nvmf_subsystem.subnqn), "%s", fc_ut_subsystem_nqn);
693 	g_fc_port.hw_port_status = SPDK_FC_PORT_ONLINE;
694 	g_fc_port.io_queues = g_fc_hwqp;
695 	for (i = 0; i < g_fc_port.num_io_queues; i++) {
696 		struct spdk_nvmf_fc_hwqp *hwqp = &g_fc_port.io_queues[i];
697 		hwqp->lcore_id = i;
698 		hwqp->hwqp_id = i;
699 		hwqp->thread = NULL;
700 		hwqp->fc_port = &g_fc_port;
701 		hwqp->num_conns = 0;
702 		hwqp->rq_size = g_hw_queue_depth;
703 		TAILQ_INIT(&hwqp->connection_list);
704 		TAILQ_INIT(&hwqp->in_use_reqs);
705 
706 		bzero(&g_poll_group[i], sizeof(struct spdk_nvmf_poll_group));
707 		bzero(&g_fgroup[i], sizeof(struct spdk_nvmf_fc_poll_group));
708 		TAILQ_INIT(&g_poll_group[i].tgroups);
709 		TAILQ_INIT(&g_poll_group[i].qpairs);
710 		g_fgroup[i].group.transport = &g_nvmf_transport;
711 		g_fgroup[i].group.group = &g_poll_group[i];
712 		hwqp->fgroup = &g_fgroup[i];
713 	}
714 
715 	spdk_nvmf_fc_ls_init(&g_fc_port);
716 	bzero(&g_tgt_port, sizeof(struct spdk_nvmf_fc_nport));
717 	g_tgt_port.fc_port = &g_fc_port;
718 	TAILQ_INIT(&g_tgt_port.rem_port_list);
719 	TAILQ_INIT(&g_tgt_port.fc_associations);
720 
721 	bzero(&g_rem_port, sizeof(struct spdk_nvmf_fc_remote_port_info));
722 	TAILQ_INSERT_TAIL(&g_tgt_port.rem_port_list, &g_rem_port, link);
723 
724 	return 0;
725 }
726 
727 static int
728 ls_tests_fini(void)
729 {
730 	spdk_nvmf_fc_ls_fini(&g_fc_port);
731 	free_threads();
732 	return 0;
733 }
734 
735 static void
736 create_single_assoc_test(void)
737 {
738 	setup_polling_threads();
739 	/* main test driver */
740 	g_test_run_type = TEST_RUN_TYPE_CREATE_ASSOC;
741 	run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
742 
743 	if (g_last_rslt == 0) {
744 		/* disconnect the association */
745 		g_test_run_type = TEST_RUN_TYPE_DISCONNECT;
746 		run_disconn_test(&g_tgt_port, g_curr_assoc_id);
747 		g_create_conn_test_cnt = 0;
748 	}
749 }
750 
751 static void
752 create_max_conns_test(void)
753 {
754 	uint16_t qid = 1;
755 
756 	setup_polling_threads();
757 	/* main test driver */
758 	g_test_run_type = TEST_RUN_TYPE_CREATE_ASSOC;
759 	run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
760 
761 	if (g_last_rslt == 0) {
762 		g_test_run_type = TEST_RUN_TYPE_CREATE_CONN;
763 		/* create connections until we get too many connections error */
764 		while (g_last_rslt == 0) {
765 			if (g_create_conn_test_cnt > g_nvmf_transport.opts.max_qpairs_per_ctrlr) {
766 				CU_FAIL("Did not get CIOC failure for too many connections");
767 				break;
768 			}
769 			run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, qid++);
770 		}
771 
772 		/* disconnect the association */
773 		g_last_rslt = 0;
774 		g_test_run_type = TEST_RUN_TYPE_DISCONNECT;
775 		run_disconn_test(&g_tgt_port, g_curr_assoc_id);
776 		g_create_conn_test_cnt = 0;
777 	}
778 }
779 
780 static void
781 invalid_connection_test(void)
782 {
783 	setup_polling_threads();
784 	/* run test to create connection to invalid association */
785 	g_test_run_type = TEST_RUN_TYPE_CONN_BAD_ASSOC;
786 	run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, 1);
787 }
788 
789 static void
790 create_max_aq_conns_test(void)
791 {
792 	/* run test to create max. associations with max. connections */
793 	uint32_t i, j;
794 	uint32_t create_assoc_test_cnt = 0;
795 
796 	setup_polling_threads();
797 	g_max_assoc_conn_test = 1;
798 	g_last_rslt = 0;
799 	while (1) {
800 		g_test_run_type = TEST_RUN_TYPE_CREATE_MAX_ASSOC;
801 		run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
802 		if (g_last_rslt == 0) {
803 			assoc_id[create_assoc_test_cnt++] = g_curr_assoc_id;
804 			g_test_run_type = TEST_RUN_TYPE_CREATE_CONN;
805 			for (j = 1; j < g_nvmf_transport.opts.max_qpairs_per_ctrlr; j++) {
806 				if (g_last_rslt == 0) {
807 					run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, (uint16_t) j);
808 				}
809 			}
810 		} else {
811 			break;
812 		}
813 	}
814 
815 	if (g_last_rslt == LAST_RSLT_STOP_TEST) {
816 		uint32_t ma = (((g_hw_queue_depth / g_nvmf_transport.opts.max_queue_depth) *
817 				(g_fc_port.num_io_queues - 1))) /
818 			      (g_nvmf_transport.opts.max_qpairs_per_ctrlr - 1);
819 		if (create_assoc_test_cnt < ma) {
820 			printf("(%d assocs - should be %d) ", create_assoc_test_cnt, ma);
821 			CU_FAIL("Didn't create max. associations");
822 		} else {
823 			printf("(%d assocs.) ", create_assoc_test_cnt);
824 		}
825 		g_last_rslt = 0;
826 	}
827 
828 	for (i = 0; i < create_assoc_test_cnt; i++) {
829 		int ret;
830 		g_spdk_nvmf_fc_xmt_srsr_req = false;
831 		ret = spdk_nvmf_fc_delete_association(&g_tgt_port, from_be64(&assoc_id[i]), true, false,
832 						      disconnect_assoc_cb, 0);
833 		CU_ASSERT(ret == 0);
834 		poll_thread(0);
835 
836 #if (NVMF_FC_LS_SEND_LS_DISCONNECT == 1)
837 		if (ret == 0) {
838 			/* check that LS disconnect was sent */
839 			CU_ASSERT(g_spdk_nvmf_fc_xmt_srsr_req);
840 		}
841 #endif
842 	}
843 	g_max_assoc_conn_test = 0;
844 }
845 
846 static void
847 xmt_ls_rsp_failure_test(void)
848 {
849 	setup_polling_threads();
850 	g_test_run_type = TEST_RUN_TYPE_FAIL_LS_RSP;
851 	run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
852 	if (g_last_rslt == 0) {
853 		/* check target port for associations */
854 		CU_ASSERT(g_tgt_port.assoc_count == 0);
855 	}
856 }
857 
858 static void
859 disconnect_bad_assoc_test(void)
860 {
861 	setup_polling_threads();
862 	g_test_run_type = TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC;
863 	run_disconn_test(&g_tgt_port, 0xffff);
864 }
865 
866 /*
867  * SPDK functions that are called by LS processing
868  */
869 
870 int
871 spdk_nvmf_fc_xmt_ls_rsp(struct spdk_nvmf_fc_nport *g_tgt_port,
872 			struct spdk_nvmf_fc_ls_rqst *ls_rqst)
873 {
874 	switch (g_test_run_type) {
875 	case TEST_RUN_TYPE_CREATE_ASSOC:
876 		g_last_rslt = handle_ca_rsp(ls_rqst, false);
877 		break;
878 	case TEST_RUN_TYPE_CREATE_CONN:
879 		g_last_rslt = handle_cc_rsp(ls_rqst);
880 		break;
881 	case TEST_RUN_TYPE_DISCONNECT:
882 		g_last_rslt = handle_disconn_rsp(ls_rqst);
883 		break;
884 	case TEST_RUN_TYPE_CONN_BAD_ASSOC:
885 		g_last_rslt = handle_conn_bad_assoc_rsp(ls_rqst);
886 		break;
887 	case TEST_RUN_TYPE_FAIL_LS_RSP:
888 		g_last_rslt = handle_ca_rsp(ls_rqst, false);
889 		return 1;
890 	case TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC:
891 		g_last_rslt = handle_disconn_bad_assoc_rsp(ls_rqst);
892 		break;
893 	case TEST_RUN_TYPE_CREATE_MAX_ASSOC:
894 		g_last_rslt = handle_ca_rsp(ls_rqst, true);
895 		break;
896 
897 	default:
898 		CU_FAIL("LS Response for Invalid Test Type");
899 		g_last_rslt = 1;
900 	}
901 
902 	return 0;
903 }
904 
905 int
906 spdk_nvmf_fc_xmt_srsr_req(struct spdk_nvmf_fc_hwqp *hwqp,
907 			  struct spdk_nvmf_fc_srsr_bufs *srsr_bufs,
908 			  spdk_nvmf_fc_caller_cb cb, void *cb_args)
909 {
910 	struct spdk_nvmf_fc_ls_disconnect_rqst *dc_rqst =
911 		(struct spdk_nvmf_fc_ls_disconnect_rqst *)
912 		srsr_bufs->rqst;
913 
914 	CU_ASSERT(dc_rqst->w0.ls_cmd == FCNVME_LS_DISCONNECT);
915 	CU_ASSERT(from_be32(&dc_rqst->desc_list_len) ==
916 		  sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) -
917 		  (2 * sizeof(uint32_t)));
918 	CU_ASSERT(from_be32(&dc_rqst->assoc_id.desc_tag) ==
919 		  FCNVME_LSDESC_ASSOC_ID);
920 	CU_ASSERT(from_be32(&dc_rqst->assoc_id.desc_len) ==
921 		  sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
922 		  (2 * sizeof(uint32_t)));
923 
924 	g_spdk_nvmf_fc_xmt_srsr_req = true;
925 
926 	if (cb) {
927 		cb(hwqp, 0, cb_args);
928 	}
929 
930 	return 0;
931 }
932 
933 DEFINE_STUB_V(spdk_nvmf_fc_request_abort, (struct spdk_nvmf_fc_request *fc_req,
934 		bool send_abts, spdk_nvmf_fc_caller_cb cb, void *cb_args));
935 DEFINE_STUB_V(spdk_bdev_io_abort, (struct spdk_bdev_io *bdev_io, void *ctx));
936 DEFINE_STUB_V(spdk_nvmf_fc_request_abort_complete, (void *arg1));
937 
938 static void
939 usage(const char *program_name)
940 {
941 	printf("%s [options]\n", program_name);
942 	printf("options:\n");
943 	spdk_log_usage(stdout, "-t");
944 	printf(" -i value - Number of IO Queues (default: %u)\n",
945 	       g_fc_port.num_io_queues);
946 	printf(" -d value - HW queue depth (default: %u)\n",
947 	       g_hw_queue_depth);
948 	printf(" -q value - SQ size (default: %u)\n",
949 	       g_nvmf_transport_opts.max_queue_depth);
950 	printf(" -c value - Connection count (default: %u)\n",
951 	       g_nvmf_transport_opts.max_qpairs_per_ctrlr);
952 	printf(" -u test# - Unit test# to run\n");
953 	printf("            0 : Run all tests (default)\n");
954 	printf("            1 : CASS/DISC create single assoc test\n");
955 	printf("            2 : Max. conns. test\n");
956 	printf("            3 : CIOC to invalid assoc_id connection test\n");
957 	printf("            4 : Create/delete max assoc conns test\n");
958 	printf("            5 : LS response failure test\n");
959 	printf("            6 : Disconnect bad assoc_id test\n");
960 }
961 
962 int main(int argc, char **argv)
963 {
964 	unsigned int num_failures = 0;
965 	CU_pSuite suite = NULL;
966 	int test = 0;
967 	long int val;
968 	int op;
969 
970 	while ((op = getopt(argc, argv, "a:q:c:t:u:d:i:")) != -1) {
971 		switch (op) {
972 		case 'q':
973 			val = spdk_strtol(optarg, 10);
974 			if (val < 16) {
975 				fprintf(stderr, "SQ size must be at least 16\n");
976 				return -EINVAL;
977 			}
978 			g_nvmf_transport_opts.max_queue_depth = (uint16_t)val;
979 			break;
980 		case 'c':
981 			val = spdk_strtol(optarg, 10);
982 			if (val < 2) {
983 				fprintf(stderr, "Connection count must be at least 2\n");
984 				return -EINVAL;
985 			}
986 			g_nvmf_transport_opts.max_qpairs_per_ctrlr = (uint16_t)val;
987 			break;
988 		case 't':
989 			if (spdk_log_set_flag(optarg) < 0) {
990 				fprintf(stderr, "Unknown trace flag '%s'\n", optarg);
991 				usage(argv[0]);
992 				return -EINVAL;
993 			}
994 			break;
995 		case 'u':
996 			test = (int)spdk_strtol(optarg, 10);
997 			break;
998 		case 'd':
999 			val = spdk_strtol(optarg, 10);
1000 			if (val < 16) {
1001 				fprintf(stderr, "HW queue depth must be at least 16\n");
1002 				return -EINVAL;
1003 			}
1004 			g_hw_queue_depth = (uint32_t)val;
1005 			break;
1006 		case 'i':
1007 			val = spdk_strtol(optarg, 10);
1008 			if (val < 2) {
1009 				fprintf(stderr, "Number of io queues must be at least 2\n");
1010 				return -EINVAL;
1011 			}
1012 			if (val > FC_LS_UT_MAX_IO_QUEUES) {
1013 				fprintf(stderr, "Number of io queues can't be greater than %d\n",
1014 					FC_LS_UT_MAX_IO_QUEUES);
1015 				return -EINVAL;
1016 			}
1017 			g_fc_port.num_io_queues = (uint32_t)val;
1018 			break;
1019 
1020 
1021 		default:
1022 			usage(argv[0]);
1023 			return -EINVAL;
1024 		}
1025 	}
1026 
1027 	if (CU_initialize_registry() != CUE_SUCCESS) {
1028 		return CU_get_error();
1029 	}
1030 
1031 	suite = CU_add_suite("FC-NVMe LS", ls_tests_init, ls_tests_fini);
1032 	if (suite == NULL) {
1033 		CU_cleanup_registry();
1034 		return CU_get_error();
1035 	}
1036 
1037 	if (test == 0) {
1038 
1039 		if (CU_add_test(suite, "CASS/DISC", create_single_assoc_test) == NULL) {
1040 			CU_cleanup_registry();
1041 			return CU_get_error();
1042 		}
1043 
1044 		if (CU_add_test(suite, "Max. Connections", create_max_conns_test) == NULL) {
1045 			CU_cleanup_registry();
1046 			return CU_get_error();
1047 		}
1048 
1049 		if (CU_add_test(suite, "CIOC to bad assoc_id", invalid_connection_test) == NULL) {
1050 			CU_cleanup_registry();
1051 			return CU_get_error();
1052 		}
1053 
1054 		if (CU_add_test(suite, "DISC bad assoc_id", disconnect_bad_assoc_test) == NULL) {
1055 			CU_cleanup_registry();
1056 			return CU_get_error();
1057 		}
1058 
1059 		if (CU_add_test(suite, "Create/delete max. assocs/conns", create_max_aq_conns_test) == NULL) {
1060 			CU_cleanup_registry();
1061 			return CU_get_error();
1062 		}
1063 
1064 		if (CU_add_test(suite, "Xmt LS RSP ERR Cleanup", xmt_ls_rsp_failure_test) == NULL) {
1065 			CU_cleanup_registry();
1066 			return CU_get_error();
1067 		}
1068 
1069 	} else {
1070 
1071 		switch (test) {
1072 		case 1:
1073 			if (CU_add_test(suite, "CASS/DISC", create_single_assoc_test) == NULL) {
1074 				CU_cleanup_registry();
1075 				return CU_get_error();
1076 			}
1077 			break;
1078 		case 2:
1079 			if (CU_add_test(suite, "Max. Connections", create_max_conns_test) == NULL) {
1080 				CU_cleanup_registry();
1081 				return CU_get_error();
1082 			}
1083 			break;
1084 		case 3:
1085 			if (CU_add_test(suite, "CIOC to bad assoc_id", invalid_connection_test) == NULL) {
1086 				CU_cleanup_registry();
1087 				return CU_get_error();
1088 			}
1089 			break;
1090 		case 4:
1091 			if (CU_add_test(suite, "Create/delete max. assocs/conns",
1092 					create_max_aq_conns_test) == NULL) {
1093 				CU_cleanup_registry();
1094 				return CU_get_error();
1095 			}
1096 			break;
1097 		case 5:
1098 			if (CU_add_test(suite, "Xmt LS RSP ERR Cleanup", xmt_ls_rsp_failure_test) == NULL) {
1099 				CU_cleanup_registry();
1100 				return CU_get_error();
1101 			}
1102 			break;
1103 		case 6:
1104 			if (CU_add_test(suite, "DISC bad assoc_id", disconnect_bad_assoc_test) == NULL) {
1105 				CU_cleanup_registry();
1106 				return CU_get_error();
1107 			}
1108 			break;
1109 
1110 		default:
1111 			fprintf(stderr, "Invalid test number\n");
1112 			usage(argv[0]);
1113 			CU_cleanup_registry();
1114 			return -EINVAL;
1115 		}
1116 	}
1117 
1118 	CU_basic_set_mode(CU_BRM_VERBOSE);
1119 	CU_basic_run_tests();
1120 	num_failures = CU_get_number_of_failures();
1121 	CU_cleanup_registry();
1122 
1123 	return num_failures;
1124 }
1125