2019-04-22 09:28:02 +00:00
|
|
|
/*
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018-2019 Broadcom. All Rights Reserved.
|
|
|
|
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* NVMF FC LS Command Processor Unit Test */
|
|
|
|
|
|
|
|
#include "spdk/env.h"
|
|
|
|
#include "spdk_cunit.h"
|
|
|
|
#include "spdk/nvmf.h"
|
|
|
|
#include "spdk/endian.h"
|
|
|
|
#include "spdk/trace.h"
|
2020-10-06 16:16:26 +00:00
|
|
|
#include "spdk/log.h"
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
#include "ut_multithread.c"
|
|
|
|
|
|
|
|
#include "transport.h"
|
|
|
|
#include "nvmf_internal.h"
|
|
|
|
#include "nvmf_fc.h"
|
|
|
|
|
|
|
|
#include "fc_ls.c"
|
|
|
|
|
|
|
|
#define LAST_RSLT_STOP_TEST 999
|
|
|
|
|
|
|
|
void spdk_set_thread(struct spdk_thread *thread);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SPDK Stuff
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEFINE_STUB(spdk_nvmf_request_complete, int, (struct spdk_nvmf_request *req), -ENOSPC);
|
|
|
|
DEFINE_STUB(spdk_nvmf_subsystem_host_allowed, bool,
|
|
|
|
(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn), true);
|
2020-01-21 05:50:38 +00:00
|
|
|
DEFINE_STUB_V(spdk_nvme_trid_populate_transport, (struct spdk_nvme_transport_id *trid,
|
|
|
|
enum spdk_nvme_transport_type trtype));
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
static const char *fc_ut_subsystem_nqn =
|
|
|
|
"nqn.2017-11.io.spdk:sn.390c0dc7c87011e786b300a0989adc53:subsystem.good";
|
|
|
|
static struct spdk_nvmf_host fc_ut_initiator = {
|
|
|
|
.nqn = "nqn.2017-11.fc_host",
|
|
|
|
};
|
|
|
|
static struct spdk_nvmf_host *fc_ut_host = &fc_ut_initiator;
|
|
|
|
static struct spdk_nvmf_tgt g_nvmf_tgt;
|
|
|
|
static struct spdk_nvmf_transport_opts g_nvmf_transport_opts = {
|
|
|
|
.max_queue_depth = 128,
|
|
|
|
.max_qpairs_per_ctrlr = 4,
|
|
|
|
.max_aq_depth = 32,
|
|
|
|
};
|
|
|
|
static uint32_t g_hw_queue_depth = 1024;
|
|
|
|
static struct spdk_nvmf_subsystem g_nvmf_subsystem;
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
void nvmf_fc_request_abort(struct spdk_nvmf_fc_request *fc_req, bool send_abts,
|
|
|
|
spdk_nvmf_fc_caller_cb cb, void *cb_args);
|
2019-04-22 09:28:02 +00:00
|
|
|
void spdk_bdev_io_abort(struct spdk_bdev_io *bdev_io, void *ctx);
|
2020-05-15 01:14:26 +00:00
|
|
|
void nvmf_fc_request_abort_complete(void *arg1);
|
|
|
|
bool nvmf_fc_req_in_xfer(struct spdk_nvmf_fc_request *fc_req);
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
struct spdk_nvmf_subsystem *
|
|
|
|
spdk_nvmf_tgt_find_subsystem(struct spdk_nvmf_tgt *tgt, const char *subnqn)
|
|
|
|
{
|
|
|
|
if (!strcmp(subnqn, g_nvmf_subsystem.subnqn)) {
|
|
|
|
return &g_nvmf_subsystem;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvmf_poll_group_add(struct spdk_nvmf_poll_group *group,
|
|
|
|
struct spdk_nvmf_qpair *qpair)
|
|
|
|
{
|
|
|
|
qpair->state = SPDK_NVMF_QPAIR_ACTIVE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct spdk_nvmf_transport_ops spdk_nvmf_transport_fc = {
|
|
|
|
.type = (enum spdk_nvme_transport_type) SPDK_NVMF_TRTYPE_FC,
|
|
|
|
.create = NULL,
|
|
|
|
.destroy = NULL,
|
|
|
|
|
|
|
|
.listen = NULL,
|
|
|
|
.stop_listen = NULL,
|
|
|
|
.accept = NULL,
|
|
|
|
|
|
|
|
.listener_discover = NULL,
|
|
|
|
|
|
|
|
.poll_group_create = NULL,
|
|
|
|
.poll_group_destroy = NULL,
|
|
|
|
.poll_group_add = NULL,
|
|
|
|
.poll_group_poll = NULL,
|
|
|
|
|
|
|
|
.req_complete = NULL,
|
|
|
|
|
|
|
|
.qpair_fini = NULL,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
struct spdk_nvmf_transport g_nvmf_transport = {
|
|
|
|
.ops = &spdk_nvmf_transport_fc,
|
|
|
|
.tgt = &g_nvmf_tgt,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct spdk_nvmf_transport *
|
2020-01-07 17:36:40 +00:00
|
|
|
spdk_nvmf_tgt_get_transport(struct spdk_nvmf_tgt *tgt, const char *transport_name)
|
2019-04-22 09:28:02 +00:00
|
|
|
{
|
|
|
|
return &g_nvmf_transport;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvmf_qpair_disconnect(struct spdk_nvmf_qpair *qpair, nvmf_qpair_disconnect_cb cb_fn, void *ctx)
|
|
|
|
{
|
|
|
|
cb_fn(ctx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-06-08 21:57:25 +00:00
|
|
|
void
|
|
|
|
spdk_nvmf_tgt_new_qpair(struct spdk_nvmf_tgt *tgt, struct spdk_nvmf_qpair *qpair)
|
2019-04-22 09:28:02 +00:00
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
struct spdk_nvmf_fc_conn *fc_conn;
|
|
|
|
struct spdk_nvmf_fc_hwqp *hwqp = NULL, *sel_hwqp = NULL;
|
|
|
|
struct spdk_nvmf_fc_ls_add_conn_api_data *api_data = NULL;
|
|
|
|
struct spdk_nvmf_fc_port *fc_port;
|
|
|
|
|
|
|
|
fc_conn = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_fc_conn, qpair);
|
|
|
|
api_data = &fc_conn->create_opd->u.add_conn;
|
|
|
|
|
|
|
|
/* Pick a hwqp with least load */
|
|
|
|
fc_port = fc_conn->fc_assoc->tgtport->fc_port;
|
|
|
|
for (i = 0; i < fc_port->num_io_queues; i ++) {
|
|
|
|
hwqp = &fc_port->io_queues[i];
|
|
|
|
if (!sel_hwqp || (hwqp->rq_size > sel_hwqp->rq_size)) {
|
|
|
|
sel_hwqp = hwqp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nvmf_fc_assign_conn_to_hwqp(sel_hwqp,
|
|
|
|
&fc_conn->conn_id,
|
|
|
|
fc_conn->max_queue_depth)) {
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fc_conn->hwqp = sel_hwqp;
|
|
|
|
|
|
|
|
/* If this is for ADMIN connection, then update assoc ID. */
|
|
|
|
if (fc_conn->qpair.qid == 0) {
|
|
|
|
fc_conn->fc_assoc->assoc_id = fc_conn->conn_id;
|
|
|
|
}
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_poller_api_func(sel_hwqp, SPDK_NVMF_FC_POLLER_API_ADD_CONNECTION, &api_data->args);
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
err:
|
|
|
|
nvmf_fc_ls_add_conn_failure(api_data->assoc, api_data->ls_rqst,
|
|
|
|
api_data->args.fc_conn, api_data->aq_conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvmf_fc_conn *
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_hwqp_find_fc_conn(struct spdk_nvmf_fc_hwqp *hwqp, uint64_t conn_id)
|
2019-04-22 09:28:02 +00:00
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_conn *fc_conn;
|
|
|
|
|
|
|
|
TAILQ_FOREACH(fc_conn, &hwqp->connection_list, link) {
|
|
|
|
if (fc_conn->conn_id == conn_id) {
|
|
|
|
return fc_conn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* LLD functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline uint64_t
|
|
|
|
nvmf_fc_gen_conn_id(uint32_t qnum, struct spdk_nvmf_fc_hwqp *hwqp)
|
|
|
|
{
|
|
|
|
static uint16_t conn_cnt = 0;
|
|
|
|
return ((uint64_t) qnum | (conn_cnt++ << 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
nvmf_fc_assign_conn_to_hwqp(struct spdk_nvmf_fc_hwqp *hwqp,
|
|
|
|
uint64_t *conn_id, uint32_t sq_size)
|
|
|
|
{
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_DEBUGLOG(nvmf_fc_ls, "Assign connection to HWQP\n");
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (hwqp->rq_size < sq_size) {
|
|
|
|
return false; /* queue has no space for this connection */
|
|
|
|
}
|
|
|
|
|
|
|
|
hwqp->rq_size -= sq_size;
|
|
|
|
hwqp->num_conns++;
|
|
|
|
|
|
|
|
/* create connection ID */
|
|
|
|
*conn_id = nvmf_fc_gen_conn_id(hwqp->hwqp_id, hwqp);
|
|
|
|
|
2020-09-04 11:27:29 +00:00
|
|
|
SPDK_DEBUGLOG(nvmf_fc_ls,
|
2019-04-22 09:28:02 +00:00
|
|
|
"New connection assigned to HWQP%d (free %d), conn_id 0x%lx\n",
|
|
|
|
hwqp->hwqp_id, hwqp->rq_size, *conn_id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvmf_fc_hwqp *
|
|
|
|
nvmf_fc_get_hwqp_from_conn_id(struct spdk_nvmf_fc_hwqp *queues,
|
|
|
|
uint32_t num_queues, uint64_t conn_id)
|
|
|
|
{
|
|
|
|
return &queues[(conn_id & 0xff) % num_queues];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nvmf_fc_release_conn(struct spdk_nvmf_fc_hwqp *hwqp, uint64_t conn_id,
|
|
|
|
uint32_t sq_size)
|
|
|
|
{
|
|
|
|
hwqp->rq_size += sq_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvmf_fc_srsr_bufs *
|
|
|
|
nvmf_fc_alloc_srsr_bufs(size_t rqst_len, size_t rsp_len)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_srsr_bufs *srsr_bufs;
|
|
|
|
|
|
|
|
srsr_bufs = calloc(1, sizeof(struct spdk_nvmf_fc_srsr_bufs));
|
|
|
|
if (!srsr_bufs) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
srsr_bufs->rqst = calloc(1, rqst_len + rsp_len);
|
|
|
|
if (srsr_bufs->rqst) {
|
|
|
|
srsr_bufs->rqst_len = rqst_len;
|
|
|
|
srsr_bufs->rsp = srsr_bufs->rqst + rqst_len;
|
|
|
|
srsr_bufs->rsp_len = rsp_len;
|
|
|
|
} else {
|
|
|
|
free(srsr_bufs);
|
|
|
|
srsr_bufs = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return srsr_bufs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nvmf_fc_free_srsr_bufs(struct spdk_nvmf_fc_srsr_bufs *srsr_bufs)
|
|
|
|
{
|
|
|
|
if (srsr_bufs) {
|
|
|
|
free(srsr_bufs->rqst);
|
|
|
|
free(srsr_bufs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The Tests
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum _test_run_type {
|
|
|
|
TEST_RUN_TYPE_CREATE_ASSOC = 1,
|
|
|
|
TEST_RUN_TYPE_CREATE_CONN,
|
|
|
|
TEST_RUN_TYPE_DISCONNECT,
|
|
|
|
TEST_RUN_TYPE_CONN_BAD_ASSOC,
|
|
|
|
TEST_RUN_TYPE_FAIL_LS_RSP,
|
|
|
|
TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC,
|
|
|
|
TEST_RUN_TYPE_CREATE_MAX_ASSOC,
|
|
|
|
};
|
|
|
|
|
|
|
|
static uint32_t g_test_run_type = 0;
|
|
|
|
static uint64_t g_curr_assoc_id = 0;
|
|
|
|
static uint16_t g_create_conn_test_cnt = 0;
|
|
|
|
static uint16_t g_max_assoc_conn_test = 0;
|
|
|
|
static int g_last_rslt = 0;
|
|
|
|
static bool g_spdk_nvmf_fc_xmt_srsr_req = false;
|
|
|
|
static struct spdk_nvmf_fc_remote_port_info g_rem_port;
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_create_assoc_test(const char *subnqn,
|
|
|
|
struct spdk_nvmf_host *host,
|
|
|
|
struct spdk_nvmf_fc_nport *tgt_port)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_rqst ls_rqst;
|
|
|
|
struct spdk_nvmf_fc_ls_cr_assoc_rqst ca_rqst;
|
|
|
|
uint8_t respbuf[128];
|
|
|
|
|
|
|
|
memset(&ca_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst));
|
|
|
|
|
|
|
|
ca_rqst.w0.ls_cmd = FCNVME_LS_CREATE_ASSOCIATION;
|
|
|
|
to_be32(&ca_rqst.desc_list_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
to_be32(&ca_rqst.assoc_cmd.desc_tag, FCNVME_LSDESC_CREATE_ASSOC_CMD);
|
|
|
|
to_be32(&ca_rqst.assoc_cmd.desc_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
to_be16(&ca_rqst.assoc_cmd.ersp_ratio, (g_nvmf_transport.opts.max_aq_depth / 2));
|
|
|
|
to_be16(&ca_rqst.assoc_cmd.sqsize, g_nvmf_transport.opts.max_aq_depth - 1);
|
|
|
|
snprintf(&ca_rqst.assoc_cmd.subnqn[0], strlen(subnqn) + 1, "%s", subnqn);
|
|
|
|
snprintf(&ca_rqst.assoc_cmd.hostnqn[0], strlen(host->nqn) + 1, "%s", host->nqn);
|
|
|
|
ls_rqst.rqstbuf.virt = &ca_rqst;
|
|
|
|
ls_rqst.rspbuf.virt = respbuf;
|
|
|
|
ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_cr_assoc_rqst);
|
|
|
|
ls_rqst.rsp_len = 0;
|
|
|
|
ls_rqst.rpi = 5000;
|
|
|
|
ls_rqst.private_data = NULL;
|
|
|
|
ls_rqst.s_id = 0;
|
|
|
|
ls_rqst.nport = tgt_port;
|
|
|
|
ls_rqst.rport = &g_rem_port;
|
|
|
|
ls_rqst.nvmf_tgt = &g_nvmf_tgt;
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_handle_ls_rqst(&ls_rqst);
|
2019-04-22 09:28:02 +00:00
|
|
|
poll_thread(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_create_conn_test(struct spdk_nvmf_host *host,
|
|
|
|
struct spdk_nvmf_fc_nport *tgt_port,
|
|
|
|
uint64_t assoc_id,
|
|
|
|
uint16_t qid)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_rqst ls_rqst;
|
|
|
|
struct spdk_nvmf_fc_ls_cr_conn_rqst cc_rqst;
|
|
|
|
uint8_t respbuf[128];
|
|
|
|
|
|
|
|
memset(&cc_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst));
|
|
|
|
|
|
|
|
/* fill in request descriptor */
|
|
|
|
cc_rqst.w0.ls_cmd = FCNVME_LS_CREATE_CONNECTION;
|
|
|
|
to_be32(&cc_rqst.desc_list_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
|
|
|
|
/* fill in connect command descriptor */
|
|
|
|
to_be32(&cc_rqst.connect_cmd.desc_tag, FCNVME_LSDESC_CREATE_CONN_CMD);
|
|
|
|
to_be32(&cc_rqst.connect_cmd.desc_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_cr_conn_cmd) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
|
|
|
|
to_be16(&cc_rqst.connect_cmd.ersp_ratio, (g_nvmf_transport.opts.max_queue_depth / 2));
|
|
|
|
to_be16(&cc_rqst.connect_cmd.sqsize, g_nvmf_transport.opts.max_queue_depth - 1);
|
|
|
|
to_be16(&cc_rqst.connect_cmd.qid, qid);
|
|
|
|
|
|
|
|
/* fill in association id descriptor */
|
|
|
|
to_be32(&cc_rqst.assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID),
|
|
|
|
to_be32(&cc_rqst.assoc_id.desc_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
cc_rqst.assoc_id.association_id = assoc_id; /* alreday be64 */
|
|
|
|
|
|
|
|
ls_rqst.rqstbuf.virt = &cc_rqst;
|
|
|
|
ls_rqst.rspbuf.virt = respbuf;
|
|
|
|
ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst);
|
|
|
|
ls_rqst.rsp_len = 0;
|
|
|
|
ls_rqst.rpi = 5000;
|
|
|
|
ls_rqst.private_data = NULL;
|
|
|
|
ls_rqst.s_id = 0;
|
|
|
|
ls_rqst.nport = tgt_port;
|
|
|
|
ls_rqst.rport = &g_rem_port;
|
|
|
|
ls_rqst.nvmf_tgt = &g_nvmf_tgt;
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_handle_ls_rqst(&ls_rqst);
|
2019-04-22 09:28:02 +00:00
|
|
|
poll_thread(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_disconn_test(struct spdk_nvmf_fc_nport *tgt_port,
|
|
|
|
uint64_t assoc_id)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_rqst ls_rqst;
|
|
|
|
struct spdk_nvmf_fc_ls_disconnect_rqst dc_rqst;
|
|
|
|
uint8_t respbuf[128];
|
|
|
|
|
|
|
|
memset(&dc_rqst, 0, sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst));
|
|
|
|
|
|
|
|
/* fill in request descriptor */
|
|
|
|
dc_rqst.w0.ls_cmd = FCNVME_LS_DISCONNECT;
|
|
|
|
to_be32(&dc_rqst.desc_list_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
|
|
|
|
/* fill in disconnect command descriptor */
|
|
|
|
to_be32(&dc_rqst.disconn_cmd.desc_tag, FCNVME_LSDESC_DISCONN_CMD);
|
|
|
|
to_be32(&dc_rqst.disconn_cmd.desc_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_disconn_cmd) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
|
|
|
|
/* fill in association id descriptor */
|
|
|
|
to_be32(&dc_rqst.assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID),
|
|
|
|
to_be32(&dc_rqst.assoc_id.desc_len,
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
dc_rqst.assoc_id.association_id = assoc_id; /* alreday be64 */
|
|
|
|
|
|
|
|
ls_rqst.rqstbuf.virt = &dc_rqst;
|
|
|
|
ls_rqst.rspbuf.virt = respbuf;
|
|
|
|
ls_rqst.rqst_len = sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst);
|
|
|
|
ls_rqst.rsp_len = 0;
|
|
|
|
ls_rqst.rpi = 5000;
|
|
|
|
ls_rqst.private_data = NULL;
|
|
|
|
ls_rqst.s_id = 0;
|
|
|
|
ls_rqst.nport = tgt_port;
|
|
|
|
ls_rqst.rport = &g_rem_port;
|
|
|
|
ls_rqst.nvmf_tgt = &g_nvmf_tgt;
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_handle_ls_rqst(&ls_rqst);
|
2019-04-22 09:28:02 +00:00
|
|
|
poll_thread(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
disconnect_assoc_cb(void *cb_data, uint32_t err)
|
|
|
|
{
|
|
|
|
CU_ASSERT(err == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
handle_ca_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst, bool max_assoc_test)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
|
|
|
|
(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
|
|
|
|
if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_ASSOCIATION) {
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
|
|
|
|
struct spdk_nvmf_fc_ls_cr_assoc_acc *acc =
|
|
|
|
(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_cr_assoc_acc) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RQST);
|
|
|
|
CU_ASSERT(from_be32(&acc->assoc_id.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_ASSOC_ID);
|
|
|
|
CU_ASSERT(from_be32(&acc->assoc_id.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc->conn_id.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_CONN_ID);
|
|
|
|
CU_ASSERT(from_be32(&acc->conn_id.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_conn_id) - 8);
|
|
|
|
|
|
|
|
g_curr_assoc_id = acc->assoc_id.association_id;
|
|
|
|
g_create_conn_test_cnt++;
|
|
|
|
return 0;
|
|
|
|
} else if (max_assoc_test) {
|
|
|
|
/* reject reason code should be insufficient resources */
|
|
|
|
struct spdk_nvmf_fc_ls_rjt *rjt =
|
|
|
|
(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
|
|
|
|
if (rjt->rjt.reason_code == FCNVME_RJT_RC_INSUFF_RES) {
|
|
|
|
return LAST_RSLT_STOP_TEST;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CU_FAIL("Unexpected reject response for create association");
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Response not for create association");
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
handle_cc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
|
|
|
|
(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_CONNECTION) {
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
|
|
|
|
struct spdk_nvmf_fc_ls_cr_conn_acc *acc =
|
|
|
|
(struct spdk_nvmf_fc_ls_cr_conn_acc *)ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_cr_conn_acc) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RQST);
|
|
|
|
CU_ASSERT(from_be32(&acc->conn_id.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_CONN_ID);
|
|
|
|
CU_ASSERT(from_be32(&acc->conn_id.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_conn_id) - 8);
|
|
|
|
g_create_conn_test_cnt++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
|
|
|
|
struct spdk_nvmf_fc_ls_rjt *rjt =
|
|
|
|
(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
|
|
|
|
if (g_create_conn_test_cnt == g_nvmf_transport.opts.max_qpairs_per_ctrlr) {
|
|
|
|
/* expected to get reject for too many connections */
|
|
|
|
CU_ASSERT(rjt->rjt.reason_code ==
|
|
|
|
FCNVME_RJT_RC_INV_PARAM);
|
|
|
|
CU_ASSERT(rjt->rjt.reason_explanation ==
|
|
|
|
FCNVME_RJT_EXP_INV_Q_ID);
|
|
|
|
} else if (!g_max_assoc_conn_test) {
|
|
|
|
CU_FAIL("Unexpected reject response create connection");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Unexpected response code for create connection");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Response not for create connection");
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
handle_disconn_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
|
|
|
|
(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_DISCONNECT) {
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_ACC) {
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_disconnect_acc) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_rqst) - 8);
|
|
|
|
CU_ASSERT(from_be32(&acc_hdr->rqst.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RQST);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Unexpected reject response for disconnect");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Response not for create connection");
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
handle_conn_bad_assoc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
|
|
|
|
(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_CREATE_CONNECTION) {
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
|
|
|
|
struct spdk_nvmf_fc_ls_rjt *rjt =
|
|
|
|
(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
CU_ASSERT(from_be32(&rjt->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_rjt) - 8);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rqst.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RQST);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rjt.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_rjt) - 8);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rjt.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RJT);
|
|
|
|
CU_ASSERT(rjt->rjt.reason_code ==
|
|
|
|
FCNVME_RJT_RC_INV_ASSOC);
|
|
|
|
CU_ASSERT(rjt->rjt.reason_explanation ==
|
|
|
|
FCNVME_RJT_EXP_NONE);
|
|
|
|
/* make sure reserved fields are 0 */
|
|
|
|
CU_ASSERT(rjt->rjt.rsvd8 == 0);
|
|
|
|
CU_ASSERT(rjt->rjt.rsvd12 == 0);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Unexpected accept response for create conn. on bad assoc_id");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Response not for create connection on bad assoc_id");
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
handle_disconn_bad_assoc_rsp(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr =
|
|
|
|
(struct spdk_nvmf_fc_ls_acc_hdr *) ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
if (acc_hdr->rqst.w0.ls_cmd == FCNVME_LS_DISCONNECT) {
|
|
|
|
if (acc_hdr->w0.ls_cmd == FCNVME_LS_RJT) {
|
|
|
|
struct spdk_nvmf_fc_ls_rjt *rjt =
|
|
|
|
(struct spdk_nvmf_fc_ls_rjt *)ls_rqst->rspbuf.virt;
|
|
|
|
|
|
|
|
CU_ASSERT(from_be32(&rjt->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_rjt) - 8);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rqst.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RQST);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rjt.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_rjt) - 8);
|
|
|
|
CU_ASSERT(from_be32(&rjt->rjt.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_RJT);
|
|
|
|
CU_ASSERT(rjt->rjt.reason_code ==
|
|
|
|
FCNVME_RJT_RC_INV_ASSOC);
|
|
|
|
CU_ASSERT(rjt->rjt.reason_explanation ==
|
|
|
|
FCNVME_RJT_EXP_NONE);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Unexpected accept response for disconnect on bad assoc_id");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
CU_FAIL("Response not for dsconnect on bad assoc_id");
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static struct spdk_nvmf_fc_port g_fc_port = {
|
|
|
|
.num_io_queues = 16,
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct spdk_nvmf_fc_nport g_tgt_port;
|
|
|
|
|
|
|
|
static uint64_t assoc_id[1024];
|
|
|
|
|
|
|
|
#define FC_LS_UT_MAX_IO_QUEUES 16
|
|
|
|
struct spdk_nvmf_fc_hwqp g_fc_hwqp[FC_LS_UT_MAX_IO_QUEUES];
|
2019-08-29 23:38:44 +00:00
|
|
|
struct spdk_nvmf_fc_poll_group g_fgroup[FC_LS_UT_MAX_IO_QUEUES];
|
2019-04-22 09:28:02 +00:00
|
|
|
struct spdk_nvmf_poll_group g_poll_group[FC_LS_UT_MAX_IO_QUEUES];
|
|
|
|
static bool threads_allocated = false;
|
|
|
|
|
|
|
|
static void
|
|
|
|
ls_assign_hwqp_threads(void)
|
|
|
|
{
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < g_fc_port.num_io_queues; i++) {
|
|
|
|
struct spdk_nvmf_fc_hwqp *hwqp = &g_fc_port.io_queues[i];
|
|
|
|
if (hwqp->thread == NULL) {
|
|
|
|
hwqp->thread = spdk_get_thread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ls_prepare_threads(void)
|
|
|
|
{
|
|
|
|
if (threads_allocated == false) {
|
|
|
|
allocate_threads(8);
|
|
|
|
set_thread(0);
|
|
|
|
}
|
|
|
|
threads_allocated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_polling_threads(void)
|
|
|
|
{
|
|
|
|
ls_prepare_threads();
|
|
|
|
set_thread(0);
|
|
|
|
ls_assign_hwqp_threads();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ls_tests_init(void)
|
|
|
|
{
|
|
|
|
uint16_t i;
|
|
|
|
|
|
|
|
bzero(&g_nvmf_tgt, sizeof(g_nvmf_tgt));
|
|
|
|
|
|
|
|
g_nvmf_transport.opts = g_nvmf_transport_opts;
|
|
|
|
|
|
|
|
snprintf(g_nvmf_subsystem.subnqn, sizeof(g_nvmf_subsystem.subnqn), "%s", fc_ut_subsystem_nqn);
|
|
|
|
g_fc_port.hw_port_status = SPDK_FC_PORT_ONLINE;
|
|
|
|
g_fc_port.io_queues = g_fc_hwqp;
|
|
|
|
for (i = 0; i < g_fc_port.num_io_queues; i++) {
|
|
|
|
struct spdk_nvmf_fc_hwqp *hwqp = &g_fc_port.io_queues[i];
|
|
|
|
hwqp->lcore_id = i;
|
|
|
|
hwqp->hwqp_id = i;
|
|
|
|
hwqp->thread = NULL;
|
|
|
|
hwqp->fc_port = &g_fc_port;
|
|
|
|
hwqp->num_conns = 0;
|
|
|
|
hwqp->rq_size = g_hw_queue_depth;
|
|
|
|
TAILQ_INIT(&hwqp->connection_list);
|
|
|
|
TAILQ_INIT(&hwqp->in_use_reqs);
|
|
|
|
|
|
|
|
bzero(&g_poll_group[i], sizeof(struct spdk_nvmf_poll_group));
|
2019-08-29 23:38:44 +00:00
|
|
|
bzero(&g_fgroup[i], sizeof(struct spdk_nvmf_fc_poll_group));
|
2019-04-22 09:28:02 +00:00
|
|
|
TAILQ_INIT(&g_poll_group[i].tgroups);
|
|
|
|
TAILQ_INIT(&g_poll_group[i].qpairs);
|
2019-09-02 05:04:36 +00:00
|
|
|
g_fgroup[i].group.transport = &g_nvmf_transport;
|
|
|
|
g_fgroup[i].group.group = &g_poll_group[i];
|
2019-08-29 23:38:44 +00:00
|
|
|
hwqp->fgroup = &g_fgroup[i];
|
2019-04-22 09:28:02 +00:00
|
|
|
}
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_ls_init(&g_fc_port);
|
2019-04-22 09:28:02 +00:00
|
|
|
bzero(&g_tgt_port, sizeof(struct spdk_nvmf_fc_nport));
|
|
|
|
g_tgt_port.fc_port = &g_fc_port;
|
|
|
|
TAILQ_INIT(&g_tgt_port.rem_port_list);
|
|
|
|
TAILQ_INIT(&g_tgt_port.fc_associations);
|
|
|
|
|
|
|
|
bzero(&g_rem_port, sizeof(struct spdk_nvmf_fc_remote_port_info));
|
|
|
|
TAILQ_INSERT_TAIL(&g_tgt_port.rem_port_list, &g_rem_port, link);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ls_tests_fini(void)
|
|
|
|
{
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_ls_fini(&g_fc_port);
|
2019-04-22 09:28:02 +00:00
|
|
|
free_threads();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_single_assoc_test(void)
|
|
|
|
{
|
|
|
|
setup_polling_threads();
|
|
|
|
/* main test driver */
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CREATE_ASSOC;
|
|
|
|
run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
|
|
|
|
|
|
|
|
if (g_last_rslt == 0) {
|
|
|
|
/* disconnect the association */
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_DISCONNECT;
|
|
|
|
run_disconn_test(&g_tgt_port, g_curr_assoc_id);
|
|
|
|
g_create_conn_test_cnt = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_max_conns_test(void)
|
|
|
|
{
|
|
|
|
uint16_t qid = 1;
|
|
|
|
|
|
|
|
setup_polling_threads();
|
|
|
|
/* main test driver */
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CREATE_ASSOC;
|
|
|
|
run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
|
|
|
|
|
|
|
|
if (g_last_rslt == 0) {
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CREATE_CONN;
|
|
|
|
/* create connections until we get too many connections error */
|
|
|
|
while (g_last_rslt == 0) {
|
|
|
|
if (g_create_conn_test_cnt > g_nvmf_transport.opts.max_qpairs_per_ctrlr) {
|
|
|
|
CU_FAIL("Did not get CIOC failure for too many connections");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, qid++);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* disconnect the association */
|
|
|
|
g_last_rslt = 0;
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_DISCONNECT;
|
|
|
|
run_disconn_test(&g_tgt_port, g_curr_assoc_id);
|
|
|
|
g_create_conn_test_cnt = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
invalid_connection_test(void)
|
|
|
|
{
|
|
|
|
setup_polling_threads();
|
|
|
|
/* run test to create connection to invalid association */
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CONN_BAD_ASSOC;
|
|
|
|
run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
create_max_aq_conns_test(void)
|
|
|
|
{
|
|
|
|
/* run test to create max. associations with max. connections */
|
|
|
|
uint32_t i, j;
|
|
|
|
uint32_t create_assoc_test_cnt = 0;
|
|
|
|
|
|
|
|
setup_polling_threads();
|
|
|
|
g_max_assoc_conn_test = 1;
|
|
|
|
g_last_rslt = 0;
|
|
|
|
while (1) {
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CREATE_MAX_ASSOC;
|
|
|
|
run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
|
|
|
|
if (g_last_rslt == 0) {
|
|
|
|
assoc_id[create_assoc_test_cnt++] = g_curr_assoc_id;
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_CREATE_CONN;
|
|
|
|
for (j = 1; j < g_nvmf_transport.opts.max_qpairs_per_ctrlr; j++) {
|
|
|
|
if (g_last_rslt == 0) {
|
|
|
|
run_create_conn_test(fc_ut_host, &g_tgt_port, g_curr_assoc_id, (uint16_t) j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_last_rslt == LAST_RSLT_STOP_TEST) {
|
|
|
|
uint32_t ma = (((g_hw_queue_depth / g_nvmf_transport.opts.max_queue_depth) *
|
|
|
|
(g_fc_port.num_io_queues - 1))) /
|
|
|
|
(g_nvmf_transport.opts.max_qpairs_per_ctrlr - 1);
|
|
|
|
if (create_assoc_test_cnt < ma) {
|
|
|
|
printf("(%d assocs - should be %d) ", create_assoc_test_cnt, ma);
|
|
|
|
CU_FAIL("Didn't create max. associations");
|
|
|
|
} else {
|
|
|
|
printf("(%d assocs.) ", create_assoc_test_cnt);
|
|
|
|
}
|
|
|
|
g_last_rslt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < create_assoc_test_cnt; i++) {
|
|
|
|
int ret;
|
|
|
|
g_spdk_nvmf_fc_xmt_srsr_req = false;
|
2020-05-15 01:14:26 +00:00
|
|
|
ret = nvmf_fc_delete_association(&g_tgt_port, from_be64(&assoc_id[i]), true, false,
|
|
|
|
disconnect_assoc_cb, 0);
|
2019-04-22 09:28:02 +00:00
|
|
|
CU_ASSERT(ret == 0);
|
|
|
|
poll_thread(0);
|
|
|
|
|
|
|
|
#if (NVMF_FC_LS_SEND_LS_DISCONNECT == 1)
|
|
|
|
if (ret == 0) {
|
|
|
|
/* check that LS disconnect was sent */
|
|
|
|
CU_ASSERT(g_spdk_nvmf_fc_xmt_srsr_req);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
g_max_assoc_conn_test = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xmt_ls_rsp_failure_test(void)
|
|
|
|
{
|
|
|
|
setup_polling_threads();
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_FAIL_LS_RSP;
|
|
|
|
run_create_assoc_test(fc_ut_subsystem_nqn, fc_ut_host, &g_tgt_port);
|
|
|
|
if (g_last_rslt == 0) {
|
|
|
|
/* check target port for associations */
|
|
|
|
CU_ASSERT(g_tgt_port.assoc_count == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
disconnect_bad_assoc_test(void)
|
|
|
|
{
|
|
|
|
setup_polling_threads();
|
|
|
|
g_test_run_type = TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC;
|
|
|
|
run_disconn_test(&g_tgt_port, 0xffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* SPDK functions that are called by LS processing
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_xmt_ls_rsp(struct spdk_nvmf_fc_nport *g_tgt_port,
|
|
|
|
struct spdk_nvmf_fc_ls_rqst *ls_rqst)
|
2019-04-22 09:28:02 +00:00
|
|
|
{
|
|
|
|
switch (g_test_run_type) {
|
|
|
|
case TEST_RUN_TYPE_CREATE_ASSOC:
|
|
|
|
g_last_rslt = handle_ca_rsp(ls_rqst, false);
|
|
|
|
break;
|
|
|
|
case TEST_RUN_TYPE_CREATE_CONN:
|
|
|
|
g_last_rslt = handle_cc_rsp(ls_rqst);
|
|
|
|
break;
|
|
|
|
case TEST_RUN_TYPE_DISCONNECT:
|
|
|
|
g_last_rslt = handle_disconn_rsp(ls_rqst);
|
|
|
|
break;
|
|
|
|
case TEST_RUN_TYPE_CONN_BAD_ASSOC:
|
|
|
|
g_last_rslt = handle_conn_bad_assoc_rsp(ls_rqst);
|
|
|
|
break;
|
|
|
|
case TEST_RUN_TYPE_FAIL_LS_RSP:
|
|
|
|
g_last_rslt = handle_ca_rsp(ls_rqst, false);
|
|
|
|
return 1;
|
|
|
|
case TEST_RUN_TYPE_DISCONNECT_BAD_ASSOC:
|
|
|
|
g_last_rslt = handle_disconn_bad_assoc_rsp(ls_rqst);
|
|
|
|
break;
|
|
|
|
case TEST_RUN_TYPE_CREATE_MAX_ASSOC:
|
|
|
|
g_last_rslt = handle_ca_rsp(ls_rqst, true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
CU_FAIL("LS Response for Invalid Test Type");
|
|
|
|
g_last_rslt = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2020-05-15 01:14:26 +00:00
|
|
|
nvmf_fc_xmt_srsr_req(struct spdk_nvmf_fc_hwqp *hwqp,
|
|
|
|
struct spdk_nvmf_fc_srsr_bufs *srsr_bufs,
|
|
|
|
spdk_nvmf_fc_caller_cb cb, void *cb_args)
|
2019-04-22 09:28:02 +00:00
|
|
|
{
|
|
|
|
struct spdk_nvmf_fc_ls_disconnect_rqst *dc_rqst =
|
|
|
|
(struct spdk_nvmf_fc_ls_disconnect_rqst *)
|
|
|
|
srsr_bufs->rqst;
|
|
|
|
|
|
|
|
CU_ASSERT(dc_rqst->w0.ls_cmd == FCNVME_LS_DISCONNECT);
|
|
|
|
CU_ASSERT(from_be32(&dc_rqst->desc_list_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
CU_ASSERT(from_be32(&dc_rqst->assoc_id.desc_tag) ==
|
|
|
|
FCNVME_LSDESC_ASSOC_ID);
|
|
|
|
CU_ASSERT(from_be32(&dc_rqst->assoc_id.desc_len) ==
|
|
|
|
sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
|
|
|
|
(2 * sizeof(uint32_t)));
|
|
|
|
|
|
|
|
g_spdk_nvmf_fc_xmt_srsr_req = true;
|
|
|
|
|
|
|
|
if (cb) {
|
|
|
|
cb(hwqp, 0, cb_args);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-15 01:14:26 +00:00
|
|
|
DEFINE_STUB_V(nvmf_fc_request_abort, (struct spdk_nvmf_fc_request *fc_req,
|
|
|
|
bool send_abts, spdk_nvmf_fc_caller_cb cb, void *cb_args));
|
2019-04-22 09:28:02 +00:00
|
|
|
DEFINE_STUB_V(spdk_bdev_io_abort, (struct spdk_bdev_io *bdev_io, void *ctx));
|
2020-05-15 01:14:26 +00:00
|
|
|
DEFINE_STUB_V(nvmf_fc_request_abort_complete, (void *arg1));
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
usage(const char *program_name)
|
|
|
|
{
|
|
|
|
printf("%s [options]\n", program_name);
|
|
|
|
printf("options:\n");
|
|
|
|
spdk_log_usage(stdout, "-t");
|
|
|
|
printf(" -i value - Number of IO Queues (default: %u)\n",
|
|
|
|
g_fc_port.num_io_queues);
|
|
|
|
printf(" -d value - HW queue depth (default: %u)\n",
|
|
|
|
g_hw_queue_depth);
|
|
|
|
printf(" -q value - SQ size (default: %u)\n",
|
|
|
|
g_nvmf_transport_opts.max_queue_depth);
|
|
|
|
printf(" -c value - Connection count (default: %u)\n",
|
|
|
|
g_nvmf_transport_opts.max_qpairs_per_ctrlr);
|
|
|
|
printf(" -u test# - Unit test# to run\n");
|
|
|
|
printf(" 0 : Run all tests (default)\n");
|
|
|
|
printf(" 1 : CASS/DISC create single assoc test\n");
|
|
|
|
printf(" 2 : Max. conns. test\n");
|
|
|
|
printf(" 3 : CIOC to invalid assoc_id connection test\n");
|
|
|
|
printf(" 4 : Create/delete max assoc conns test\n");
|
|
|
|
printf(" 5 : LS response failure test\n");
|
|
|
|
printf(" 6 : Disconnect bad assoc_id test\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
unsigned int num_failures = 0;
|
|
|
|
CU_pSuite suite = NULL;
|
|
|
|
int test = 0;
|
|
|
|
long int val;
|
|
|
|
int op;
|
|
|
|
|
|
|
|
while ((op = getopt(argc, argv, "a:q:c:t:u:d:i:")) != -1) {
|
|
|
|
switch (op) {
|
|
|
|
case 'q':
|
|
|
|
val = spdk_strtol(optarg, 10);
|
|
|
|
if (val < 16) {
|
|
|
|
fprintf(stderr, "SQ size must be at least 16\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
g_nvmf_transport_opts.max_queue_depth = (uint16_t)val;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
val = spdk_strtol(optarg, 10);
|
|
|
|
if (val < 2) {
|
|
|
|
fprintf(stderr, "Connection count must be at least 2\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
g_nvmf_transport_opts.max_qpairs_per_ctrlr = (uint16_t)val;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
if (spdk_log_set_flag(optarg) < 0) {
|
|
|
|
fprintf(stderr, "Unknown trace flag '%s'\n", optarg);
|
|
|
|
usage(argv[0]);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
test = (int)spdk_strtol(optarg, 10);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
val = spdk_strtol(optarg, 10);
|
|
|
|
if (val < 16) {
|
|
|
|
fprintf(stderr, "HW queue depth must be at least 16\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
g_hw_queue_depth = (uint32_t)val;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
val = spdk_strtol(optarg, 10);
|
|
|
|
if (val < 2) {
|
|
|
|
fprintf(stderr, "Number of io queues must be at least 2\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (val > FC_LS_UT_MAX_IO_QUEUES) {
|
|
|
|
fprintf(stderr, "Number of io queues can't be greater than %d\n",
|
|
|
|
FC_LS_UT_MAX_IO_QUEUES);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
g_fc_port.num_io_queues = (uint32_t)val;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-11 17:59:24 +00:00
|
|
|
CU_set_error_action(CUEA_ABORT);
|
|
|
|
CU_initialize_registry();
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
suite = CU_add_suite("FC-NVMe LS", ls_tests_init, ls_tests_fini);
|
|
|
|
|
|
|
|
if (test == 0) {
|
|
|
|
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_single_assoc_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_max_conns_test);
|
|
|
|
CU_ADD_TEST(suite, invalid_connection_test);
|
|
|
|
CU_ADD_TEST(suite, disconnect_bad_assoc_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_max_aq_conns_test);
|
|
|
|
CU_ADD_TEST(suite, xmt_ls_rsp_failure_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
switch (test) {
|
|
|
|
case 1:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_single_assoc_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_max_conns_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, invalid_connection_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, create_max_aq_conns_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, xmt_ls_rsp_failure_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
case 6:
|
2020-03-11 19:15:39 +00:00
|
|
|
CU_ADD_TEST(suite, disconnect_bad_assoc_test);
|
2019-04-22 09:28:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "Invalid test number\n");
|
|
|
|
usage(argv[0]);
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
|
|
CU_basic_run_tests();
|
|
|
|
num_failures = CU_get_number_of_failures();
|
|
|
|
CU_cleanup_registry();
|
|
|
|
|
|
|
|
return num_failures;
|
|
|
|
}
|