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