2016-06-07 17:34:03 +00:00
|
|
|
/*-
|
|
|
|
* BSD LICENSE
|
|
|
|
*
|
|
|
|
* Copyright (c) Intel Corporation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <rte_config.h>
|
|
|
|
#include <rte_malloc.h>
|
|
|
|
#include <rte_mempool.h>
|
|
|
|
#include <rte_lcore.h>
|
|
|
|
|
|
|
|
#include "spdk_cunit.h"
|
|
|
|
|
|
|
|
#include "spdk/string.h"
|
|
|
|
|
|
|
|
#include "nvmf/controller.c"
|
2016-06-08 16:04:45 +00:00
|
|
|
#include "nvmf/nvmf.c"
|
2016-06-07 17:34:03 +00:00
|
|
|
#include "nvmf/nvmf_admin_cmd.c"
|
|
|
|
#include "nvmf/nvmf_io_cmd.c"
|
|
|
|
#include "nvmf/session.c"
|
|
|
|
#include "nvmf/subsystem_grp.c"
|
|
|
|
|
|
|
|
|
|
|
|
#define NS_PER_CTRLR 8
|
|
|
|
struct spdk_nvme_ctrlr;
|
|
|
|
|
|
|
|
struct spdk_nvme_ns {
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
|
|
|
int id;
|
|
|
|
int a;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct spdk_nvme_qpair {
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct spdk_nvme_ctrlr {
|
|
|
|
int a;
|
|
|
|
int attached;
|
|
|
|
uint32_t num_ns;
|
|
|
|
struct spdk_nvme_ctrlr_data data;
|
|
|
|
struct spdk_nvme_ns ns[NS_PER_CTRLR];
|
|
|
|
struct spdk_nvme_ns_data ns_data[NS_PER_CTRLR];
|
|
|
|
struct spdk_nvme_qpair ioq;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* expected cntlid for single session with single connection */
|
|
|
|
#define SS_SC_CNTLID ((1 << NVMF_CNTLID_SUBS_SHIFT) + 1)
|
|
|
|
|
|
|
|
static int controller_checked[20];
|
|
|
|
|
|
|
|
struct rte_mempool *request_mempool;
|
|
|
|
|
|
|
|
int spdk_nvmf_parse_conf(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nvmf_rdma_init(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int spdk_initialize_nvmf_conns(int max_connections)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-08 23:00:39 +00:00
|
|
|
void spdk_nvmf_host_destroy_all(void)
|
2016-06-07 17:34:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvmf_port *spdk_nvmf_port_find_by_tag(int tag)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void spdk_nvmf_port_destroy_all(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-06-08 23:00:39 +00:00
|
|
|
struct spdk_nvmf_host *spdk_nvmf_host_find_by_tag(int tag)
|
2016-06-07 17:34:03 +00:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-21 23:11:37 +00:00
|
|
|
void
|
|
|
|
spdk_nvmf_request_complete(struct nvmf_request *req)
|
2016-06-07 17:34:03 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_probe(void *cb_ctx, spdk_nvme_probe_cb probe_cb, spdk_nvme_attach_cb attach_cb)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
spdk_nvme_ctrlr_register_aer_callback(struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
spdk_nvme_aer_cb aer_cb,
|
|
|
|
void *aer_cb_arg)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool spdk_nvme_ns_is_active(struct spdk_nvme_ns *ns)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
spdk_nvme_ctrlr_get_num_ns(struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
|
|
|
return ctrlr->num_ns;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct spdk_nvme_ctrlr_data *
|
|
|
|
spdk_nvme_ctrlr_get_data(struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
|
|
|
memset(&ctrlr->data, 0, sizeof(struct spdk_nvme_ctrlr_data));
|
|
|
|
strcpy(ctrlr->data.sn, "NVMeB000D001F002");
|
|
|
|
ctrlr->data.nn = NS_PER_CTRLR;
|
|
|
|
return &ctrlr->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvme_ns *
|
|
|
|
spdk_nvme_ctrlr_get_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t ns_id)
|
|
|
|
{
|
|
|
|
if (!ctrlr)
|
|
|
|
return NULL;
|
|
|
|
if (ns_id < 1 || ns_id > ctrlr->num_ns) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return &ctrlr->ns[ns_id - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_ns_cmd_read(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload,
|
|
|
|
uint64_t lba, uint32_t lba_count,
|
|
|
|
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_cpl cpe;
|
|
|
|
//nlb is 0 based
|
|
|
|
CU_ASSERT_EQUAL(lba_count, 17);
|
|
|
|
strcpy(payload, "hello");
|
|
|
|
// change cdw0 and verify it in the nvmf call back.
|
|
|
|
cpe.status.sc = SPDK_NVME_SC_SUCCESS;
|
|
|
|
cpe.cdw0 = 0xff;
|
|
|
|
/* read complete, call nvme call back. */
|
|
|
|
/* nvme call back will call nvmf call back */
|
|
|
|
/* nvme call back = nvmf_complete_cmd */
|
|
|
|
/* nvmf call back = my_nvmf_cmd_complete */
|
|
|
|
cb_fn(cb_arg, &cpe);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_ctrlr_cmd_io_raw(struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
struct spdk_nvme_qpair *qpair,
|
|
|
|
struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, uint32_t len,
|
|
|
|
spdk_nvme_cmd_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_cpl cpe;
|
|
|
|
CU_ASSERT_EQUAL(len, 64);
|
|
|
|
CU_ASSERT_STRING_EQUAL(buf, "hello");
|
|
|
|
cpe.cdw0 = 0xff;
|
|
|
|
cpe.status.sc = SPDK_NVME_SC_SUCCESS;
|
|
|
|
/* read complete, call nvme call back. */
|
|
|
|
/* nvme call back will call nvmf call back */
|
|
|
|
/* nvme call back = nvmf_complete_cmd */
|
|
|
|
/* nvmf call back = my_nvmf_cmd_complete */
|
|
|
|
cb_fn(cb_arg, &cpe);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct spdk_nvme_ns_data *
|
|
|
|
spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_ns_data *nsdata;
|
|
|
|
|
|
|
|
nsdata = &ns->ctrlr->ns_data[ns->id - 1];
|
|
|
|
nsdata->nsze = 100; //we could check it
|
|
|
|
return nsdata;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
spdk_nvme_request_size(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_detach(struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
|
|
|
ctrlr->attached = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_ns_cmd_write(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair, void *payload,
|
|
|
|
uint64_t lba, uint32_t lba_count,
|
|
|
|
spdk_nvme_cmd_cb cb_fn, void *cb_arg, uint32_t io_flags)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_cpl cpe;
|
|
|
|
|
|
|
|
//nlb is 0 based
|
|
|
|
CU_ASSERT_EQUAL(lba_count, 17);
|
|
|
|
CU_ASSERT_STRING_EQUAL(payload, "hello");
|
|
|
|
cpe.cdw0 = 0xff;
|
|
|
|
cpe.status.sc = SPDK_NVME_SC_SUCCESS;
|
|
|
|
cb_fn(cb_arg, &cpe);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_ctrlr_cmd_admin_raw(struct spdk_nvme_ctrlr *ctrlr,
|
|
|
|
struct spdk_nvme_cmd *cmd,
|
|
|
|
void *buf, uint32_t len,
|
|
|
|
spdk_nvme_cmd_cb cb_fn, void *cb_arg)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t
|
|
|
|
spdk_nvme_ctrlr_process_admin_completions(struct spdk_nvme_ctrlr *ctrlr)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while (controller_checked[i] != -1)
|
|
|
|
i++;
|
|
|
|
controller_checked[i] = ctrlr->a;
|
|
|
|
controller_checked[i + 1] = -1;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t
|
|
|
|
spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while (controller_checked[i] != -1)
|
|
|
|
i++;
|
|
|
|
|
|
|
|
controller_checked[i] = qpair->ctrlr->a;
|
|
|
|
controller_checked[i + 1] = -1;
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct spdk_nvme_qpair *
|
|
|
|
spdk_nvme_ctrlr_alloc_io_qpair(struct spdk_nvme_ctrlr *ctrlr, enum spdk_nvme_qprio qprio)
|
|
|
|
{
|
|
|
|
if (ctrlr == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctrlr->ioq.ctrlr = ctrlr;
|
|
|
|
return &ctrlr->ioq;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
spdk_nvme_ctrlr_free_io_qpair(struct spdk_nvme_qpair *qpair)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
help_response_check(struct spdk_nvmf_fabric_connect_rsp *actual,
|
|
|
|
struct spdk_nvmf_fabric_connect_rsp *expect)
|
|
|
|
{
|
|
|
|
CU_ASSERT_EQUAL(actual->status_code_specific.success.cntlid,
|
|
|
|
expect->status_code_specific.success.cntlid);
|
|
|
|
CU_ASSERT_EQUAL(actual->status_code_specific.success.authreq,
|
|
|
|
expect->status_code_specific.success.authreq);
|
|
|
|
CU_ASSERT_EQUAL(actual->status.sc, expect->status.sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_init(void)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
struct spdk_nvme_ctrlr *ctrlr;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
request_mempool = NULL;
|
|
|
|
/* test that NVMf library will trap if mempool not created */
|
|
|
|
rc = nvmf_initialize();
|
|
|
|
CU_ASSERT(rc < 0);
|
|
|
|
request_mempool = malloc(sizeof(struct rte_mempool));
|
|
|
|
rc = nvmf_initialize();
|
|
|
|
CU_ASSERT(rc == 0);
|
|
|
|
free(request_mempool);
|
|
|
|
/* create faked controller */
|
|
|
|
ctrlr = malloc(sizeof(struct spdk_nvme_ctrlr));
|
|
|
|
SPDK_CU_ASSERT_FATAL(ctrlr != NULL);
|
|
|
|
ctrlr->num_ns = NS_PER_CTRLR;
|
|
|
|
for (i = 0; i < ctrlr->num_ns; i++) {
|
|
|
|
ctrlr->ns[i].ctrlr = ctrlr;
|
|
|
|
ctrlr->ns[i].id = i + 1;
|
|
|
|
}
|
|
|
|
ctrlr->attached = 1;
|
|
|
|
spdk_nvmf_ctrlr_create("Nvme0", 0, 0, 1, 2, ctrlr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_create_subsystem(void)
|
|
|
|
{
|
|
|
|
char correct_name[] = "subsystem1";
|
|
|
|
char wrong_name[512];
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
struct spdk_nvmf_ctrlr *nvmf_ctrlr;
|
|
|
|
subsystem = nvmf_create_subsystem(1, correct_name);
|
|
|
|
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num, 1);
|
|
|
|
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, correct_name);
|
|
|
|
nvmf_ctrlr = spdk_nvmf_ctrlr_claim("Nvme0");
|
|
|
|
SPDK_CU_ASSERT_FATAL(nvmf_ctrlr != NULL);
|
|
|
|
nvmf_subsystem_add_ns(subsystem, nvmf_ctrlr->ctrlr);
|
|
|
|
|
|
|
|
/* test long name */
|
|
|
|
memset(wrong_name, 'a', 512);
|
|
|
|
subsystem = nvmf_create_subsystem(2, wrong_name);
|
|
|
|
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num, 2);
|
|
|
|
CU_ASSERT_STRING_NOT_EQUAL(subsystem->subnqn, wrong_name);
|
|
|
|
CU_ASSERT_EQUAL(strlen(subsystem->subnqn) + 1, MAX_NQN_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_find_subsystem(void)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
//char long_name[MAX_NQN_SIZE];
|
|
|
|
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_find_subsystem(NULL));
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num, 1);
|
|
|
|
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, "subsystem1");
|
|
|
|
/* check long name */
|
|
|
|
/* segment fault. Comment it */
|
|
|
|
/*
|
|
|
|
memset(long_name, 'a', MAX_NQN_SIZE);
|
|
|
|
subsystem = nvmf_find_subsystem(long_name);
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num, 2);
|
|
|
|
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, long_name);
|
|
|
|
*/
|
|
|
|
/* check none-exist subsystem */
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_find_subsystem("fake"));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_create_session(void)
|
|
|
|
{
|
|
|
|
int fake_session_count = 5;
|
|
|
|
int i;
|
|
|
|
struct nvmf_session *session;
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
|
|
|
|
/* create session in non-exist subsystem */
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_create_session("subsystem2"));
|
|
|
|
/* create session and check init values */
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
session = nvmf_create_session("subsystem1");
|
|
|
|
SPDK_CU_ASSERT_FATAL(session != NULL);
|
|
|
|
CU_ASSERT_EQUAL(session->cntlid, SS_SC_CNTLID);
|
|
|
|
CU_ASSERT_TRUE(session->is_valid);
|
|
|
|
CU_ASSERT_EQUAL(session->num_connections, 0);
|
|
|
|
CU_ASSERT_EQUAL(session->active_queues, 0);
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num_sessions, 1);
|
|
|
|
/* add multi-sessions to one subsystem
|
|
|
|
* if multi-sessions is not suported in the future
|
|
|
|
* we need to change the check condition. */
|
|
|
|
for (i = 0; i != fake_session_count; i++) {
|
|
|
|
nvmf_create_session("subsystem1");
|
|
|
|
}
|
|
|
|
CU_ASSERT_EQUAL(session->subsys->num_sessions, fake_session_count + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_find_session_by_id(void)
|
|
|
|
{
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
CU_ASSERT_EQUAL(sess->cntlid, SS_SC_CNTLID);
|
|
|
|
/* test non-exist conditions */
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_find_session_by_id("fake", 9));
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_find_session_by_id("subsystem1", 90));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_delete_session(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int fake_session_count = 5;
|
|
|
|
struct nvmf_session *session;
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
for (i = 0; i != fake_session_count + 1; i++) {
|
|
|
|
session = nvmf_find_session_by_id("subsystem1",
|
|
|
|
(subsystem->num << NVMF_CNTLID_SUBS_SHIFT) + (i + 1));
|
|
|
|
SPDK_CU_ASSERT_FATAL(session != NULL);
|
|
|
|
nvmf_delete_session(session);
|
|
|
|
}
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num_sessions, 0);
|
|
|
|
CU_ASSERT_PTR_NULL(subsystem->sessions.tqh_first);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_connect(void)
|
|
|
|
{
|
|
|
|
uint64_t fabric_conn = 0;
|
|
|
|
uint64_t fabric_conn_admin = 1;
|
|
|
|
uint64_t fabric_conn_IO = 2;
|
|
|
|
struct nvmf_session *sess, *io_sess;
|
|
|
|
struct spdk_nvmf_fabric_connect_cmd connect = {};
|
|
|
|
struct spdk_nvmf_fabric_connect_data connect_data = {};
|
|
|
|
struct spdk_nvmf_fabric_connect_rsp response = {};
|
|
|
|
struct spdk_nvmf_fabric_connect_rsp expect_rsp = {};
|
|
|
|
|
|
|
|
|
|
|
|
connect.opcode = 0x7f;
|
|
|
|
connect.cid = 0x01;
|
|
|
|
connect.fctype = 0x01;
|
|
|
|
connect_data.cntlid = 0xffff;
|
|
|
|
connect.qid = 0;
|
|
|
|
connect.sqsize = 64;
|
|
|
|
|
|
|
|
/* change cmd field to do failure test first */
|
|
|
|
/* invalid subnqn and qid = 0*/
|
|
|
|
strcpy((char *)connect_data.subnqn, "fake");
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_connect((void *)fabric_conn, &connect, &connect_data, &response));
|
|
|
|
CU_ASSERT_NOT_EQUAL(response.status.sc, 0);
|
|
|
|
/* valid subnqn and qid = 0 and cntlid != 0xfffff */
|
|
|
|
strcpy((char *)connect_data.subnqn, "subsystem1");
|
|
|
|
connect_data.cntlid = 0x000f;
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_connect((void *)fabric_conn, &connect, &connect_data, &response));
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_INVALID_PARAM);
|
|
|
|
/* invalid subnqn and qid = 1 */
|
|
|
|
strcpy((char *)connect_data.subnqn, "fake");
|
|
|
|
connect.qid = 1;
|
|
|
|
connect_data.cntlid = 0;
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_connect((void *)fabric_conn, &connect, &connect_data, &response));
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY);
|
|
|
|
/* valid subnqn but session is not created. */
|
|
|
|
strcpy((char *)connect_data.subnqn, "subsystem1");
|
|
|
|
connect_data.cntlid = 0;
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_connect((void *)fabric_conn, &connect, &connect_data, &response));
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY);
|
|
|
|
/* create admin connection */
|
|
|
|
connect.qid = 0;
|
|
|
|
connect_data.cntlid = 0xffff;
|
|
|
|
sess = nvmf_connect((void *)fabric_conn_admin, &connect, &connect_data, &response);
|
|
|
|
SPDK_CU_ASSERT_FATAL(sess != NULL);
|
|
|
|
nvmf_init_session_properties(sess, 64);
|
|
|
|
sess->max_connections_allowed = 2;
|
|
|
|
CU_ASSERT_EQUAL(sess->num_connections, 1);
|
|
|
|
CU_ASSERT_PTR_EQUAL(sess->connections.tqh_first->fabric_conn, fabric_conn_admin);
|
|
|
|
expect_rsp.status_code_specific.success.cntlid = SS_SC_CNTLID;
|
|
|
|
expect_rsp.status.sc = 0;
|
|
|
|
help_response_check(&response, &expect_rsp);
|
|
|
|
/* create IO connection */
|
|
|
|
connect.cid = 0x02;
|
|
|
|
connect.qid = 1;
|
|
|
|
connect_data.cntlid = SS_SC_CNTLID;
|
|
|
|
io_sess = nvmf_connect((void *)fabric_conn_IO, &connect, &connect_data, &response);
|
|
|
|
SPDK_CU_ASSERT_FATAL(io_sess != NULL);
|
|
|
|
CU_ASSERT_EQUAL(io_sess->num_connections, 2);
|
|
|
|
/* check admin and io connection are in same session. */
|
|
|
|
CU_ASSERT_PTR_EQUAL(io_sess, sess);
|
|
|
|
expect_rsp.status_code_specific.success.cntlid = SS_SC_CNTLID;
|
|
|
|
expect_rsp.status.sc = 0;
|
|
|
|
help_response_check(&response, &expect_rsp);
|
|
|
|
/* right subnqn, session is created, but wrong cntlid */
|
|
|
|
connect_data.cntlid = 1;
|
|
|
|
connect.qid = 2;
|
|
|
|
CU_ASSERT_PTR_NULL(nvmf_connect((void *)&fabric_conn, &connect, &connect_data, &response));
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_RESTART_DISCOVERY);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_process_io_cmd(void)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_cmd nvmf_cmd = {};
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct nvmf_request nvmf_req = {};
|
|
|
|
struct nvme_read_cdw12 *cdw12;
|
|
|
|
struct spdk_nvmf_subsystem *tmp;
|
|
|
|
uint8_t *buf;
|
|
|
|
nvmf_cmd.opc = SPDK_NVME_OPC_READ;
|
|
|
|
nvmf_cmd.nsid = 2;
|
|
|
|
nvmf_cmd.cid = 3;
|
2016-06-20 22:12:28 +00:00
|
|
|
nvmf_req.cmd = (union nvmf_h2c_msg *)&nvmf_cmd;
|
2016-06-07 17:34:03 +00:00
|
|
|
nvmf_req.rsp = malloc(sizeof(union nvmf_c2h_msg));
|
|
|
|
nvmf_req.cid = nvmf_cmd.cid;
|
|
|
|
cdw12 = (struct nvme_read_cdw12 *)&nvmf_cmd.cdw12;
|
|
|
|
cdw12->nlb = 16; //read 16 lb, check in nvme read
|
2016-06-20 22:12:28 +00:00
|
|
|
nvmf_req.length = 64;
|
|
|
|
buf = malloc(nvmf_req.length);
|
2016-06-07 17:34:03 +00:00
|
|
|
SPDK_CU_ASSERT_FATAL(buf != NULL);
|
2016-06-20 22:12:28 +00:00
|
|
|
nvmf_req.data = buf;
|
2016-06-07 17:34:03 +00:00
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
2016-06-20 22:12:28 +00:00
|
|
|
nvmf_req.session = sess;
|
2016-06-07 17:34:03 +00:00
|
|
|
sess->vcprop.csts.bits.rdy = 1;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), 0);
|
2016-06-07 17:34:03 +00:00
|
|
|
CU_ASSERT_STRING_EQUAL(buf, "hello");
|
|
|
|
nvmf_cmd.cid = 4;
|
|
|
|
nvmf_cmd.opc = SPDK_NVME_OPC_WRITE;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), 0);
|
2016-06-07 17:34:03 +00:00
|
|
|
nvmf_cmd.opc = 0xff;
|
|
|
|
nvmf_cmd.cid = 5;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), 0);
|
2016-06-07 17:34:03 +00:00
|
|
|
sess->vcprop.csts.bits.rdy = 0;
|
|
|
|
nvmf_cmd.cid = 6;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), -1);
|
2016-06-07 17:34:03 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_NAMESPACE_NOT_READY);
|
|
|
|
sess->vcprop.csts.bits.rdy = 1;
|
|
|
|
/* nsid = 0 */
|
|
|
|
nvmf_cmd.nsid = 0;
|
|
|
|
nvmf_cmd.cid = 7;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), -1);
|
2016-06-07 17:34:03 +00:00
|
|
|
CU_ASSERT_NOT_EQUAL(nvmf_req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS);
|
|
|
|
/* set sess->subsys to NULL */
|
|
|
|
tmp = sess->subsys;
|
|
|
|
sess->subsys = NULL;
|
|
|
|
nvmf_cmd.nsid = 1;
|
|
|
|
nvmf_cmd.cid = 8;
|
2016-06-20 22:12:28 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_io_cmd(&nvmf_req), -1);
|
2016-06-07 17:34:03 +00:00
|
|
|
CU_ASSERT_NOT_EQUAL(nvmf_req.rsp->nvme_cpl.status.sc, SPDK_NVME_SC_SUCCESS);
|
|
|
|
sess->subsys = tmp;
|
|
|
|
free(buf);
|
|
|
|
free(nvmf_req.rsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_process_admin_cmd(void)
|
|
|
|
{
|
|
|
|
struct spdk_nvme_cmd nvmf_cmd = {};
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct nvmf_request nvmf_req = {};
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
int buf_len = sizeof(struct spdk_nvme_ns_data);
|
|
|
|
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
2016-06-21 15:39:49 +00:00
|
|
|
nvmf_req.session = sess;
|
|
|
|
nvmf_req.cmd = (union nvmf_h2c_msg *)&nvmf_cmd;
|
2016-06-07 17:34:03 +00:00
|
|
|
nvmf_req.rsp = malloc(sizeof(union nvmf_c2h_msg));
|
|
|
|
#define BUILD_CMD(cmd_opc, cmd_nsid, cmd_cid, cmd_cdw10) \
|
|
|
|
do { \
|
|
|
|
nvmf_cmd.opc = cmd_opc; \
|
|
|
|
nvmf_cmd.nsid = cmd_nsid; \
|
|
|
|
nvmf_cmd.cid = cmd_cid; \
|
|
|
|
nvmf_cmd.cdw10 = cmd_cdw10; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define RUN_AND_CHECK_PROPERT_GET_RESULT(expect_ret, cmd_cid, sts) \
|
|
|
|
do { \
|
2016-06-21 15:39:49 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_process_admin_cmd(&nvmf_req), expect_ret); \
|
2016-06-07 17:34:03 +00:00
|
|
|
CU_ASSERT_EQUAL(nvmf_req.rsp->nvme_cpl.cid, cmd_cid); \
|
|
|
|
CU_ASSERT_EQUAL(nvmf_req.rsp->nvme_cpl.status.sc, sts); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
/* check subsys=NULL condition */
|
2016-06-21 15:39:49 +00:00
|
|
|
nvmf_req.data = malloc(buf_len);
|
2016-06-07 17:34:03 +00:00
|
|
|
subsystem = sess->subsys;
|
|
|
|
sess->subsys = NULL;
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, 2, 100, 0);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 100, SPDK_NVME_SC_INTERNAL_DEVICE_ERROR);
|
|
|
|
sess->subsys = subsystem;
|
|
|
|
/* identify namespace, namespace id = MAX_PER_SUBSYSTEM_NAMESPACES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, MAX_PER_SUBSYSTEM_NAMESPACES, 101, 0);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 101, SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT);
|
|
|
|
/* namespace id > MAX_PER_SUBSYSTEM_NAMESPACES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, MAX_PER_SUBSYSTEM_NAMESPACES + 1, 102, 0);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 102, SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT);
|
|
|
|
/* namespace id = 0 */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, 0, 103, 0);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 103, SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT);
|
|
|
|
/* identify namespace */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, 2, 8, 0);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(0, 8, SPDK_NVME_SC_SUCCESS);
|
2016-06-21 15:39:49 +00:00
|
|
|
free(nvmf_req.data);
|
2016-06-07 17:34:03 +00:00
|
|
|
/* identify controller */
|
|
|
|
buf_len = sizeof(struct spdk_nvme_ctrlr_data);
|
2016-06-21 15:39:49 +00:00
|
|
|
nvmf_req.data = malloc(buf_len);
|
2016-06-07 17:34:03 +00:00
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, 2, 9, 1);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(0, 9, SPDK_NVME_SC_SUCCESS);
|
2016-06-21 15:39:49 +00:00
|
|
|
free(nvmf_req.data);
|
2016-06-07 17:34:03 +00:00
|
|
|
/* identify controller with invalid cdw10=2 */
|
|
|
|
buf_len = sizeof(struct spdk_nvme_ctrlr_data);
|
2016-06-21 15:39:49 +00:00
|
|
|
nvmf_req.data = malloc(buf_len);
|
2016-06-07 17:34:03 +00:00
|
|
|
BUILD_CMD(SPDK_NVME_OPC_IDENTIFY, 2, 9, 2);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 9, SPDK_NVME_SC_INVALID_OPCODE);
|
|
|
|
/* create IO SQ whose qid > MAX_SESSION_IO_QUEUES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_SQ, 2, 110, 0xff00ff);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 110, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* create IO SQ */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_SQ, 2, 10, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 10, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* create same IO SQ again*/
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_SQ, 2, 101, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 101, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* create CO SQ whose qid > MAX_SESSION_IO_QUEUES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_CQ, 2, 112, 0xff00ff);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 112, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* create IO CQ */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_CQ, 2, 11, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 11, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 1);
|
|
|
|
/* create same IO CQ again*/
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_CREATE_IO_SQ, 2, 103, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 103, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 1);
|
|
|
|
/* del IO SQ whose id > MAX_SESSION_IO_QUEUES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_SQ, 2, 105, 0xff0fff);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 105, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 1);
|
|
|
|
/* del IO SQ who is not active */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_SQ, 2, 106, 0xff0002);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 106, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 1);
|
|
|
|
/* del IO SQ */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_SQ, 2, 12, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 12, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* del IO CQ whose id > MAX_SESSION_IO_QUEUES */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_CQ, 2, 107, 0xff0fff);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 107, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
/* del IO SQ who is not active */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_CQ, 2, 108, 0xff0002);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 108, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
/* del IO CQ */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_CQ, 2, 13, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 13, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(sess->active_queues, 0);
|
|
|
|
/* del same IO SQ again, should fail */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_SQ, 2, 15, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 15, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
/* del same CQ again, should fail */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_DELETE_IO_CQ, 2, 16, 0xff0001);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(-1, 16, SPDK_NVME_SC_INVALID_FIELD);
|
|
|
|
/* get max io queue number */
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_GET_FEATURES, 2, 17, SPDK_NVME_FEAT_NUMBER_OF_QUEUES);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 17, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(nvmf_req.rsp->nvme_cpl.cdw0 & 0xffff, 63);
|
|
|
|
/* set max io queue number failed due to active queue */
|
|
|
|
sess->active_queues = 1;
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_SET_FEATURES, 2, 18, SPDK_NVME_FEAT_NUMBER_OF_QUEUES);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 18, SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR);
|
|
|
|
sess->active_queues = 0;
|
|
|
|
/* set max io queue number, these are not completed*/
|
|
|
|
BUILD_CMD(SPDK_NVME_OPC_SET_FEATURES, 2, 19, SPDK_NVME_FEAT_NUMBER_OF_QUEUES);
|
|
|
|
RUN_AND_CHECK_PROPERT_GET_RESULT(1, 19, SPDK_NVME_SC_SUCCESS);
|
|
|
|
CU_ASSERT_EQUAL(nvmf_req.rsp->nvme_cpl.cdw0 & 0xffff, 63);
|
2016-06-21 15:39:49 +00:00
|
|
|
free(nvmf_req.data);
|
|
|
|
nvmf_req.data = NULL;
|
2016-06-07 17:34:03 +00:00
|
|
|
}
|
|
|
|
/* for property get and set only */
|
|
|
|
#define BUILD_PROPERTY_CMD(property_name, cmd_attr, cmd_cid) \
|
|
|
|
do { \
|
|
|
|
cmd.ofst = offsetof(struct spdk_nvmf_ctrlr_properties, property_name); \
|
|
|
|
cmd.attrib = cmd_attr; \
|
|
|
|
cmd.cid = cmd_cid; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
#define RUN_AND_CHECK_PROPERTY_RESULT(fsts, cmd_cid) \
|
|
|
|
do { \
|
|
|
|
nvmf_property_get(sess, &cmd, &response); \
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, fsts); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_property_get(void)
|
|
|
|
{
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct spdk_nvmf_fabric_prop_get_cmd cmd;
|
|
|
|
struct spdk_nvmf_fabric_prop_get_rsp response;
|
|
|
|
union spdk_nvme_cap_lo_register *cap_lo;
|
|
|
|
union spdk_nvme_cap_hi_register *cap_hi;
|
|
|
|
union spdk_nvme_csts_register *csts;
|
|
|
|
union spdk_nvme_aqa_register *aqa;
|
|
|
|
union spdk_nvmf_property_size *propsz;
|
|
|
|
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
nvmf_init_session_properties(sess, 64);
|
|
|
|
sess->vcprop.csts.bits.rdy = 1;
|
|
|
|
/* vs */
|
|
|
|
BUILD_PROPERTY_CMD(vs, 0, 17);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 17);
|
|
|
|
CU_ASSERT_EQUAL(response.value.u32.low, 0x10000);
|
|
|
|
/* cap_lo */
|
|
|
|
BUILD_PROPERTY_CMD(cap_lo, 1, 18);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 18);
|
|
|
|
cap_lo = (union spdk_nvme_cap_lo_register *)&response.value.u32.low;
|
|
|
|
cap_hi = (union spdk_nvme_cap_hi_register *)&response.value.u32.high;
|
|
|
|
CU_ASSERT_EQUAL(cap_lo->bits.to, 1);
|
|
|
|
CU_ASSERT_EQUAL(cap_hi->bits.css_nvm, 1);
|
|
|
|
/* cc */
|
|
|
|
BUILD_PROPERTY_CMD(cc, 0, 19);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 19);
|
|
|
|
CU_ASSERT_EQUAL(response.value.u32.low, 0);
|
|
|
|
/* csts */
|
|
|
|
BUILD_PROPERTY_CMD(csts, 0, 20);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 20);
|
|
|
|
csts = (union spdk_nvme_csts_register *)&response.value.u32.low;
|
|
|
|
CU_ASSERT_EQUAL(csts->bits.rdy, 1);
|
|
|
|
/* aqa */
|
|
|
|
BUILD_PROPERTY_CMD(aqa, 0, 21);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 21);
|
|
|
|
aqa = (union spdk_nvme_aqa_register *)&response.value.u32.low;
|
|
|
|
CU_ASSERT_EQUAL(aqa->bits.asqs, 64);
|
|
|
|
CU_ASSERT_EQUAL(aqa->bits.acqs, 64);
|
|
|
|
/* propsz */
|
|
|
|
BUILD_PROPERTY_CMD(propsz, 0, 22);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 22);
|
|
|
|
propsz = (union spdk_nvmf_property_size *)&response.value.u32.low;
|
|
|
|
CU_ASSERT_EQUAL(propsz->bits.size, sizeof(struct spdk_nvmf_ctrlr_properties) / 64);
|
|
|
|
/* cap_hi */
|
|
|
|
BUILD_PROPERTY_CMD(cap_hi, 0, 23);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 23);
|
|
|
|
cap_hi = (union spdk_nvme_cap_hi_register *)&response.value.u32.low;
|
|
|
|
CU_ASSERT_EQUAL(cap_hi->bits.css_nvm, 1);
|
|
|
|
/* intms */
|
|
|
|
BUILD_PROPERTY_CMD(intms, 0, 24);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(SPDK_NVMF_FABRIC_SC_INVALID_PARAM, 24);
|
|
|
|
/* intmc */
|
|
|
|
BUILD_PROPERTY_CMD(intmc, 0, 25);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(SPDK_NVMF_FABRIC_SC_INVALID_PARAM, 25);
|
|
|
|
/* nssr */
|
|
|
|
BUILD_PROPERTY_CMD(nssr, 0, 26);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(0, 26);
|
|
|
|
/* asq */
|
|
|
|
BUILD_PROPERTY_CMD(asq, 0, 27);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(SPDK_NVMF_FABRIC_SC_INVALID_PARAM, 27);
|
|
|
|
/* acq */
|
|
|
|
BUILD_PROPERTY_CMD(acq, 0, 28);
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(SPDK_NVMF_FABRIC_SC_INVALID_PARAM, 28);
|
|
|
|
/* begin to check error condition */
|
|
|
|
#define TEST_SIZE_NOT_RIGHT(prop_name, attr, c_id) \
|
|
|
|
do { \
|
|
|
|
BUILD_PROPERTY_CMD(prop_name, attr, c_id); \
|
|
|
|
RUN_AND_CHECK_PROPERTY_RESULT(SPDK_NVMF_FABRIC_SC_INVALID_PARAM, c_id); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
TEST_SIZE_NOT_RIGHT(cc, 1, 22);
|
|
|
|
TEST_SIZE_NOT_RIGHT(csts, 1, 23);
|
|
|
|
TEST_SIZE_NOT_RIGHT(aqa, 1, 24);
|
|
|
|
TEST_SIZE_NOT_RIGHT(propsz, 1, 25);
|
|
|
|
TEST_SIZE_NOT_RIGHT(vs, 1, 26);
|
|
|
|
TEST_SIZE_NOT_RIGHT(nssr, 1, 27);
|
|
|
|
TEST_SIZE_NOT_RIGHT(capattr_hi, 1, 28);
|
|
|
|
/* invalid offset */
|
|
|
|
cmd.ofst = 0xffff;
|
|
|
|
cmd.attrib = 0;
|
|
|
|
cmd.cid = 29;
|
|
|
|
nvmf_property_get(sess, &cmd, &response);
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_INVALID_PARAM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_property_set(void)
|
|
|
|
{
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct spdk_nvmf_fabric_prop_set_cmd cmd;
|
|
|
|
struct spdk_nvmf_fabric_prop_set_rsp response;
|
|
|
|
union spdk_nvme_cc_register *cc;
|
|
|
|
union spdk_nvme_csts_register *csts;
|
|
|
|
union spdk_nvme_aqa_register *aqa;
|
|
|
|
uint32_t nssr;
|
|
|
|
bool shutdown;
|
|
|
|
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
|
|
|
|
#define TEST_PROPERTY_SET(property_name, attr, c_id, union_name, bits_attr, val) \
|
|
|
|
do {\
|
|
|
|
BUILD_PROPERTY_CMD(property_name, attr, c_id); \
|
|
|
|
property_name = (union union_name *)&cmd.value.u32.low; \
|
|
|
|
property_name->bits.bits_attr = val; \
|
|
|
|
nvmf_property_set(sess, &cmd, &response, &shutdown); \
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, 0); \
|
|
|
|
CU_ASSERT_EQUAL(sess->vcprop.property_name.bits.bits_attr, val); \
|
|
|
|
} while (0)
|
|
|
|
TEST_PROPERTY_SET(cc, 0, 31, spdk_nvme_cc_register, en, 1);
|
|
|
|
TEST_PROPERTY_SET(csts, 0, 32, spdk_nvme_csts_register, rdy, 1);
|
|
|
|
TEST_PROPERTY_SET(aqa, 0, 33, spdk_nvme_aqa_register, asqs, 0xf);
|
|
|
|
nssr = 1;
|
|
|
|
cmd.ofst = offsetof(struct spdk_nvmf_ctrlr_properties, nssr);
|
|
|
|
cmd.attrib = 0;
|
|
|
|
cmd.cid = 34;
|
|
|
|
cmd.value.u32.low = nssr;
|
|
|
|
nvmf_property_set(sess, &cmd, &response, &shutdown);
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, 0);
|
|
|
|
CU_ASSERT_EQUAL(sess->vcprop.nssr, nssr);
|
|
|
|
|
|
|
|
/* error conditions */
|
|
|
|
#define TEST_PROPERTY_SET_ERROR(property_name, attr, c_id, union_name, bits_attr, val) \
|
|
|
|
do {\
|
|
|
|
BUILD_PROPERTY_CMD(property_name, attr, c_id); \
|
|
|
|
property_name = (union union_name *)&cmd.value.u32.low; \
|
|
|
|
property_name->bits.bits_attr = val; \
|
|
|
|
nvmf_property_set(sess, &cmd, &response, &shutdown); \
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_INVALID_PARAM); \
|
|
|
|
CU_ASSERT_NOT_EQUAL(sess->vcprop.property_name.bits.bits_attr, val); \
|
|
|
|
} while (0)
|
|
|
|
TEST_PROPERTY_SET_ERROR(cc, 1, 31, spdk_nvme_cc_register, en, 0);
|
|
|
|
TEST_PROPERTY_SET_ERROR(csts, 1, 32, spdk_nvme_csts_register, rdy, 0);
|
|
|
|
TEST_PROPERTY_SET_ERROR(aqa, 1, 33, spdk_nvme_aqa_register, asqs, 0xe);
|
|
|
|
/* nssr attr = 1 */
|
|
|
|
nssr = 1;
|
|
|
|
cmd.ofst = offsetof(struct spdk_nvmf_ctrlr_properties, nssr);
|
|
|
|
cmd.attrib = 1;
|
|
|
|
cmd.cid = 37;
|
|
|
|
cmd.value.u32.low = nssr;
|
|
|
|
nvmf_property_set(sess, &cmd, &response, &shutdown);
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_INVALID_PARAM);
|
|
|
|
|
|
|
|
cmd.ofst = 0xffff;
|
|
|
|
cmd.attrib = 0;
|
|
|
|
cmd.value.u32.low = 20;
|
|
|
|
cmd.cid = 35;
|
|
|
|
nvmf_property_set(sess, &cmd, &response, &shutdown);
|
|
|
|
CU_ASSERT_EQUAL(response.status.sc, SPDK_NVMF_FABRIC_SC_INVALID_PARAM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_check_admin_completions(void)
|
|
|
|
{
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
struct spdk_nvme_ctrlr ctrlr1, ctrlr2;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ctrlr1.a = 1;
|
|
|
|
ctrlr2.a = 2;
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
/* preload ns_list_map */
|
|
|
|
#define PRELOAD_NS_LIST(index, nvme_ctrlr, ns_id) \
|
|
|
|
do { \
|
|
|
|
subsystem->ns_list_map[index].ctrlr = nvme_ctrlr; \
|
|
|
|
subsystem->ns_list_map[index].ns = NULL; \
|
|
|
|
subsystem->ns_list_map[index].nvme_ns_id = ns_id; \
|
|
|
|
\
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
|
|
|
PRELOAD_NS_LIST(i, NULL, 0);
|
|
|
|
}
|
|
|
|
PRELOAD_NS_LIST(0, &ctrlr1, 1);
|
|
|
|
PRELOAD_NS_LIST(1, &ctrlr1, 2);
|
|
|
|
PRELOAD_NS_LIST(2, &ctrlr1, 3);
|
|
|
|
PRELOAD_NS_LIST(3, NULL, 1);
|
|
|
|
PRELOAD_NS_LIST(4, &ctrlr1, 4);
|
|
|
|
PRELOAD_NS_LIST(5, &ctrlr2, 1);
|
|
|
|
PRELOAD_NS_LIST(6, &ctrlr2, 2);
|
|
|
|
PRELOAD_NS_LIST(7, NULL, 2);
|
|
|
|
PRELOAD_NS_LIST(8, NULL, 3);
|
|
|
|
PRELOAD_NS_LIST(9, &ctrlr1, 5);
|
|
|
|
#undef PRELOAD_NS_LIST
|
|
|
|
/* make sure the check completion is done by
|
|
|
|
* ctrlr1,ctrlr2,ctrlr1
|
|
|
|
*/
|
|
|
|
controller_checked[0] = -1;
|
|
|
|
nvmf_check_admin_completions(sess);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[0], 1);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[1], 2);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[2], 1);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[3], -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_check_io_completions(void)
|
|
|
|
{
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
struct spdk_nvme_ctrlr ctrlr1, ctrlr2;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ctrlr1.a = 1;
|
|
|
|
ctrlr2.a = 2;
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
/* preload ns_list_map */
|
|
|
|
#define PRELOAD_NS_LIST(index, nvme_ctrlr, ns_id) \
|
|
|
|
do { \
|
|
|
|
subsystem->ns_list_map[index].ctrlr = nvme_ctrlr; \
|
|
|
|
subsystem->ns_list_map[index].qpair = spdk_nvme_ctrlr_alloc_io_qpair(nvme_ctrlr, 0); \
|
|
|
|
subsystem->ns_list_map[index].ns = NULL; \
|
|
|
|
subsystem->ns_list_map[index].nvme_ns_id = ns_id; \
|
|
|
|
\
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
|
|
|
|
PRELOAD_NS_LIST(i, NULL, 0);
|
|
|
|
}
|
|
|
|
PRELOAD_NS_LIST(0, &ctrlr1, 4);
|
|
|
|
PRELOAD_NS_LIST(1, &ctrlr1, 1);
|
|
|
|
PRELOAD_NS_LIST(2, &ctrlr2, 2);
|
|
|
|
PRELOAD_NS_LIST(3, NULL, 1);
|
|
|
|
PRELOAD_NS_LIST(4, &ctrlr1, 3);
|
|
|
|
PRELOAD_NS_LIST(5, &ctrlr1, 1);
|
|
|
|
PRELOAD_NS_LIST(6, &ctrlr1, 2);
|
|
|
|
PRELOAD_NS_LIST(7, NULL, 2);
|
|
|
|
PRELOAD_NS_LIST(8, NULL, 3);
|
|
|
|
PRELOAD_NS_LIST(9, &ctrlr2, 4);
|
|
|
|
#undef PRELOAD_NS_LIST
|
|
|
|
/* make sure the check completion is done by
|
|
|
|
* ctrlr1,ctrlr2,ctrlr1,ctrlr2
|
|
|
|
*/
|
|
|
|
controller_checked[0] = -1;
|
|
|
|
nvmf_check_io_completions(sess);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[0], 1);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[1], 2);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[2], 1);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[3], 2);
|
|
|
|
CU_ASSERT_EQUAL(controller_checked[4], -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_disconnect(void)
|
|
|
|
{
|
|
|
|
uint64_t fabric_conn_admin = 1;
|
|
|
|
uint64_t fabric_conn_IO = 2;
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
|
|
|
|
sess = nvmf_find_session_by_id("subsystem1", SS_SC_CNTLID);
|
|
|
|
/* delete non-exist connection */
|
|
|
|
nvmf_disconnect((void *)6, sess);
|
|
|
|
/* we have two connections admin and io */
|
|
|
|
CU_ASSERT_EQUAL(sess->num_connections, 2);
|
|
|
|
/* delete IO connection */
|
|
|
|
nvmf_disconnect((void *)fabric_conn_IO, sess);
|
|
|
|
CU_ASSERT_EQUAL(sess->num_connections, 1);
|
|
|
|
/* delete admin connection */
|
|
|
|
nvmf_disconnect((void *)fabric_conn_admin, sess);
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
CU_ASSERT_EQUAL(subsystem->num_sessions, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_delete_subsystem(void)
|
|
|
|
{
|
|
|
|
struct spdk_nvmf_subsystem *subsystem;
|
|
|
|
struct nvmf_session *sess;
|
|
|
|
|
|
|
|
sess = nvmf_create_session("subsystem1");
|
|
|
|
SPDK_CU_ASSERT_FATAL(sess != NULL);
|
|
|
|
subsystem = nvmf_find_subsystem("subsystem1");
|
|
|
|
CU_ASSERT_EQUAL(nvmf_delete_subsystem(subsystem), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nvmf_test_shutdown(void)
|
|
|
|
{
|
|
|
|
nvmf_shutdown();
|
|
|
|
CU_ASSERT_EQUAL(g_ctrlrs.tqh_first, NULL);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
CU_pSuite suite = NULL;
|
|
|
|
unsigned int num_failures;
|
|
|
|
|
|
|
|
if (CU_initialize_registry() != CUE_SUCCESS) {
|
|
|
|
return CU_get_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
suite = CU_add_suite("nvmf", NULL, NULL);
|
|
|
|
if (suite == NULL) {
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return CU_get_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
CU_add_test(suite, "nvmf_test_init", nvmf_test_init) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_create_subsystem", nvmf_test_create_subsystem) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_find_subsystem", nvmf_test_find_subsystem) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_create_session", nvmf_test_create_session) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_find_session_by_id", nvmf_test_find_session_by_id) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_delete_session", nvmf_test_delete_session) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_connect", nvmf_test_connect) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_process_io_cmd", nvmf_test_process_io_cmd) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_process_admin_cmd", nvmf_test_process_admin_cmd) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_property_get", nvmf_test_property_get) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_property_set", nvmf_test_property_set) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_check_admin_completions",
|
|
|
|
nvmf_test_check_admin_completions) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_check_io_completions", nvmf_test_check_io_completions) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_disconnect", nvmf_test_disconnect) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_delete_subsystem", nvmf_test_delete_subsystem) == NULL ||
|
|
|
|
CU_add_test(suite, "nvmf_test_shutdown", nvmf_test_shutdown) == NULL) {
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return CU_get_error();
|
|
|
|
}
|
|
|
|
|
|
|
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
|
|
|
CU_basic_run_tests();
|
|
|
|
num_failures = CU_get_number_of_failures();
|
|
|
|
CU_cleanup_registry();
|
|
|
|
return num_failures;
|
|
|
|
}
|
|
|
|
|