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