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