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 * 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 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 * 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 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 153 nvmf_fc_free_conn_reqpool(struct spdk_nvmf_fc_conn *fc_conn) 154 { 155 } 156 157 int 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 600 setup_polling_threads(void) 601 { 602 ls_prepare_threads(); 603 set_thread(0); 604 ls_assign_hwqp_threads(); 605 } 606 607 static int 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 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 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 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 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 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 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 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 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 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 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