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