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