xref: /spdk/test/unit/lib/nvmf/fc_ls.c/fc_ls_ut.c (revision 307b8c112ffd90a26d53dd15fad67bd9038ef526)
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