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