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 bool nvmf_process_connect(struct spdk_nvmf_request *req) { 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_conn *conn = req->conn; struct nvmf_session *session; if (req->length < sizeof(struct spdk_nvmf_fabric_connect_data)) { SPDK_ERRLOG("Connect command data length 0x%x too small\n", req->length); req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_INVALID_FIELD; return true; } connect = &req->cmd->connect_cmd; connect_data = (struct spdk_nvmf_fabric_connect_data *)req->data; RTE_VERIFY(connect_data != NULL); SPDK_TRACELOG(SPDK_TRACE_NVMF, "Connect cmd: cid 0x%x recfmt 0x%x qid %u sqsize %u\n", connect->cid, connect->recfmt, connect->qid, connect->sqsize); SPDK_TRACELOG(SPDK_TRACE_NVMF, "Connect data:\n"); SPDK_TRACELOG(SPDK_TRACE_NVMF, " cntlid: 0x%04x\n", connect_data->cntlid); SPDK_TRACELOG(SPDK_TRACE_NVMF, " hostid: %08x-%04x-%04x-%02x%02x-%04x%08x ***\n", ntohl(*(uint32_t *)&connect_data->hostid[0]), ntohs(*(uint16_t *)&connect_data->hostid[4]), ntohs(*(uint16_t *)&connect_data->hostid[6]), connect_data->hostid[8], connect_data->hostid[9], ntohs(*(uint16_t *)&connect_data->hostid[10]), ntohl(*(uint32_t *)&connect_data->hostid[12])); SPDK_TRACELOG(SPDK_TRACE_NVMF, " subnqn: \"%s\"\n", (char *)&connect_data->subnqn[0]); SPDK_TRACELOG(SPDK_TRACE_NVMF, " hostnqn: \"%s\"\n", (char *)&connect_data->hostnqn[0]); response = &req->rsp->connect_rsp; session = nvmf_connect((void *)conn, connect, connect_data, response); if (session != NULL) { conn->sess = session; conn->qid = connect->qid; if (connect->qid > 0) { conn->type = CONN_TYPE_IOQ; /* I/O Connection */ } else { /* When session first created, set some attributes */ nvmf_init_conn_properites(conn, session, response); } } /* Allocate RDMA reqs according to the queue depth and conn type*/ if (spdk_nvmf_rdma_alloc_reqs(conn)) { SPDK_ERRLOG("Unable to allocate sufficient RDMA work requests\n"); req->rsp->nvme_cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; return true; } SPDK_TRACELOG(SPDK_TRACE_NVMF, "connect capsule response: cntlid = 0x%04x\n", response->status_code_specific.success.cntlid); return true; }
static void nvmf_connect_continue(struct spdk_nvmf_conn *conn, struct nvme_qp_tx_desc *tx_desc) { struct nvme_qp_rx_desc *rx_desc; struct nvmf_request *req; struct spdk_nvmf_fabric_connect_cmd *connect; struct spdk_nvmf_fabric_connect_data *connect_data; struct spdk_nvmf_fabric_connect_rsp *response; struct nvmf_session *session; int ret; if (tx_desc == NULL) { SPDK_TRACELOG(SPDK_TRACE_DEBUG, " tx_desc does not exist!\n"); return; } rx_desc = tx_desc->rx_desc; if (rx_desc == NULL) { SPDK_TRACELOG(SPDK_TRACE_DEBUG, " rx_desc does not exist!\n"); return; } connect = (struct spdk_nvmf_fabric_connect_cmd *)&rx_desc->msg_buf; connect_data = (struct spdk_nvmf_fabric_connect_data *)rx_desc->bb; req = &tx_desc->req_state; /* clear the SGL details for any RDMA previously performed */ req->length = 0; SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** Connect Capsule Data *** %p\n", connect_data); SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** cntlid = %x ***\n", connect_data->cntlid); SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** hostid = %04x%04x-%04x-%04x-%04x-%04x%04x%04x ***\n", htons(*(unsigned short *) &connect_data->hostid[0]), htons(*(unsigned short *) &connect_data->hostid[2]), htons(*(unsigned short *) &connect_data->hostid[4]), htons(*(unsigned short *) &connect_data->hostid[6]), htons(*(unsigned short *) &connect_data->hostid[8]), htons(*(unsigned short *) &connect_data->hostid[10]), htons(*(unsigned short *) &connect_data->hostid[12]), htons(*(unsigned short *) &connect_data->hostid[14])); SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** subsiqn = %s ***\n", (char *)&connect_data->subnqn[0]); SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** hostiqn = %s ***\n", (char *)&connect_data->hostnqn[0]); response = &req->rsp->connect_rsp; session = nvmf_connect((void *)conn, connect, connect_data, response); if (session != NULL) { conn->sess = session; conn->qid = connect->qid; if (connect->qid > 0) { conn->type = CONN_TYPE_IOQ; /* I/O Connection */ } else { /* When session first created, set some attributes */ nvmf_init_conn_properites(conn, session, response); } } /* synchronous call, nvmf library expected to init response status. */ SPDK_TRACELOG(SPDK_TRACE_NVMF, "send connect capsule response\n"); SPDK_TRACELOG(SPDK_TRACE_NVMF, " *** cntlid = %x ***\n", response->status_code_specific.success.cntlid); ret = spdk_nvmf_send_response(conn, req); if (ret) { SPDK_ERRLOG("Unable to send aq qp tx descriptor\n"); goto connect_error; } return; connect_error: /* recover the tx_desc */ if (tx_desc != NULL) { tx_desc->rx_desc = NULL; nvmf_deactive_tx_desc(tx_desc); } }