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