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