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