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