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