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