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