static int set_host_identifier(struct spdk_nvme_ctrlr *ctrlr) { int ret; uint64_t host_id; struct spdk_nvme_cmd cmd = {}; cmd.opc = SPDK_NVME_OPC_SET_FEATURES; cmd.cdw10 = SPDK_NVME_FEAT_HOST_IDENTIFIER; host_id = HOST_ID; outstanding_commands = 0; set_feature_result = -1; fprintf(stdout, "Set Feature: Host Identifier 0x%" PRIx64 "\n", host_id); ret = spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, &host_id, sizeof(host_id), set_feature_completion, &features[SPDK_NVME_FEAT_HOST_IDENTIFIER]); if (ret) { fprintf(stdout, "Set Feature: Failed\n"); return -1; } outstanding_commands++; while (outstanding_commands) { spdk_nvme_ctrlr_process_admin_completions(ctrlr); } if (set_feature_result) fprintf(stdout, "Set Feature: Host Identifier Failed\n"); return 0; }
static int get_temp_threshold(struct dev *dev) { struct spdk_nvme_cmd cmd = {}; cmd.opc = SPDK_NVME_OPC_GET_FEATURES; cmd.cdw10 = SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD; return spdk_nvme_ctrlr_cmd_admin_raw(dev->ctrlr, &cmd, NULL, 0, get_feature_completion, dev); }
static int get_host_identifier(struct spdk_nvme_ctrlr *ctrlr) { int ret; uint64_t *host_id; struct spdk_nvme_cmd cmd = {}; cmd.opc = SPDK_NVME_OPC_GET_FEATURES; cmd.cdw10 = SPDK_NVME_FEAT_HOST_IDENTIFIER; outstanding_commands = 0; host_id = rte_malloc(NULL, 8, 0); if (host_id == NULL) { fprintf(stderr, "host_id allocation failed\n"); return -1; } ret = spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, &cmd, host_id, 8, get_feature_completion, &features[SPDK_NVME_FEAT_HOST_IDENTIFIER]); if (ret) { fprintf(stdout, "Get Feature: Failed\n"); rte_free(host_id); return -1; } outstanding_commands++; while (outstanding_commands) { spdk_nvme_ctrlr_process_admin_completions(ctrlr); } if (features[SPDK_NVME_FEAT_HOST_IDENTIFIER].valid) { fprintf(stdout, "Get Feature: Host Identifier 0x%"PRIx64"\n", *host_id); } rte_free(host_id); return 0; }
static bool nvmf_process_admin_cmd(struct spdk_nvmf_request *req) { struct nvmf_session *session = req->conn->sess; struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; struct spdk_nvmf_subsystem *subsystem = session->subsys; struct spdk_nvme_ctrlr *ctrlr = NULL; uint32_t nsid = 0; int rc = 0; uint8_t feature; /* pre-set response details for this command */ response->status.sc = SPDK_NVME_SC_SUCCESS; response->cid = cmd->cid; /* verify subsystem */ if (subsystem == NULL) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Subsystem Not Initialized!\n"); response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; return true; } if (cmd->nsid == 0) { /* may be valid for the requested command. but need to at least map to a known valid controller. Note: Issue when in multi-controller subsystem mode, commands that do not provide ns_id can not be mapped to valid HW ctrlr! This is where definition of a virtual controller is required */ ctrlr = subsystem->ns_list_map[0].ctrlr; nsid = 0; } else { /* verify namespace id */ if (cmd->nsid > MAX_PER_SUBSYSTEM_NAMESPACES) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Invalid NS_ID %u\n", cmd->nsid); response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT; return true; } ctrlr = subsystem->ns_list_map[cmd->nsid - 1].ctrlr; nsid = subsystem->ns_list_map[cmd->nsid - 1].nvme_ns_id; } SPDK_TRACELOG(SPDK_TRACE_NVMF, "ctrlr %p nvme ns_id %u\n", ctrlr, nsid); switch (cmd->opc) { case SPDK_NVME_OPC_IDENTIFY: if (req->data == NULL) { SPDK_ERRLOG("identify command with no buffer\n"); response->status.sc = SPDK_NVME_SC_INVALID_FIELD; return true; } if (cmd->cdw10 == 0) { /* identify namespace */ struct spdk_nvme_ns *ns; const struct spdk_nvme_ns_data *nsdata; SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Namespace\n"); if (nsid == 0) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Invalid NS_ID = 0\n"); response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT; return true; } ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid); if (ns == NULL) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Unsuccessful query for Namespace reference\n"); response->status.sc = SPDK_NVME_SC_INVALID_FIELD; return true; } nsdata = spdk_nvme_ns_get_data(ns); memcpy(req->data, (char *)nsdata, sizeof(struct spdk_nvme_ns_data)); return true; } else if (cmd->cdw10 == 1) { /* identify controller */ SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n"); /* pull from virtual controller context */ memcpy(req->data, (char *)&session->vcdata, sizeof(struct spdk_nvme_ctrlr_data)); return true; } else { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Namespace List\n"); response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; return true; } break; case SPDK_NVME_OPC_GET_FEATURES: feature = cmd->cdw10 & 0xff; /* mask out the FID value */ switch (feature) { case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - Number of Queues\n"); response->cdw0 = ((session->max_io_queues - 1) << 16) | (session->max_io_queues - 1); return true; case SPDK_NVME_FEAT_LBA_RANGE_TYPE: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Get Features - LBA Range Type\n"); cmd->nsid = nsid; goto passthrough; default: goto passthrough; } break; case SPDK_NVME_OPC_SET_FEATURES: feature = cmd->cdw10 & 0xff; /* mask out the FID value */ switch (feature) { case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Set Features - Number of Queues, cdw11 0x%x\n", cmd->cdw11); /* verify that the contoller is ready to process commands */ if (session->active_queues != 0) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Queue pairs already active!\n"); response->status.sc = SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR; } else { response->cdw0 = ((session->max_io_queues - 1) << 16) | (session->max_io_queues - 1); } return true; default: goto passthrough; } break; case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Async Event Request\n"); /* Trap request here and save in the session context until NVMe library indicates some event. */ if (session->aer_req == NULL) { session->aer_req = req; return false; } else { /* AER already recorded, send error response */ SPDK_TRACELOG(SPDK_TRACE_NVMF, "AER already active!\n"); response->status.sc = SPDK_NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED; return true; } break; case SPDK_NVME_OPC_KEEP_ALIVE: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Keep Alive\n"); /* To handle keep alive just clear or reset the session based keep alive duration counter. When added, a separate timer based process will monitor if the time since last recorded keep alive has exceeded the max duration and take appropriate action. */ //session->keep_alive_timestamp = ; return true; case SPDK_NVME_OPC_CREATE_IO_SQ: case SPDK_NVME_OPC_CREATE_IO_CQ: case SPDK_NVME_OPC_DELETE_IO_SQ: case SPDK_NVME_OPC_DELETE_IO_CQ: SPDK_ERRLOG("Admin opc 0x%02X not allowed in NVMf\n", cmd->opc); response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; return true; default: passthrough: SPDK_TRACELOG(SPDK_TRACE_NVMF, "admin_cmd passthrough: opc 0x%02x\n", cmd->opc); cmd->nsid = nsid; rc = spdk_nvme_ctrlr_cmd_admin_raw(ctrlr, cmd, req->data, req->length, nvmf_complete_cmd, req); if (rc) { SPDK_ERRLOG("Error submitting admin opc 0x%02x\n", cmd->opc); response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; return true; } return false; } }
static int nvmf_direct_ctrlr_process_admin_cmd(struct spdk_nvmf_request *req) { struct spdk_nvmf_session *session = req->conn->sess; struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd; struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl; struct spdk_nvmf_subsystem *subsystem = session->subsys; union spdk_nvme_vs_register vs; int rc = 0; uint8_t feature; /* pre-set response details for this command */ response->status.sc = SPDK_NVME_SC_SUCCESS; switch (cmd->opc) { case SPDK_NVME_OPC_IDENTIFY: if (req->data == NULL || req->length < 4096) { SPDK_ERRLOG("identify command with invalid buffer\n"); response->status.sc = SPDK_NVME_SC_INVALID_FIELD; return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_CTRLR) { SPDK_TRACELOG(SPDK_TRACE_NVMF, "Identify Controller\n"); /* pull from virtual controller context */ memcpy(req->data, &session->vcdata, sizeof(struct spdk_nvme_ctrlr_data)); return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } else if ((cmd->cdw10 & 0xFF) == SPDK_NVME_IDENTIFY_ACTIVE_NS_LIST) { vs = spdk_nvme_ctrlr_get_regs_vs(subsystem->dev.direct.ctrlr); if (vs.raw < SPDK_NVME_VERSION(1, 1, 0)) { /* fill in identify ns list with virtual controller information */ rc = nvmf_direct_ctrlr_admin_identify_nslist(subsystem->dev.direct.ctrlr, req); if (rc < 0) { SPDK_ERRLOG("Invalid Namespace or Format\n"); response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT; } return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } } goto passthrough; case SPDK_NVME_OPC_GET_FEATURES: feature = cmd->cdw10 & 0xff; /* mask out the FID value */ switch (feature) { case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: return spdk_nvmf_session_get_features_number_of_queues(req); case SPDK_NVME_FEAT_HOST_IDENTIFIER: return spdk_nvmf_session_get_features_host_identifier(req); case SPDK_NVME_FEAT_KEEP_ALIVE_TIMER: return spdk_nvmf_session_get_features_keep_alive_timer(req); default: goto passthrough; } break; case SPDK_NVME_OPC_SET_FEATURES: feature = cmd->cdw10 & 0xff; /* mask out the FID value */ switch (feature) { case SPDK_NVME_FEAT_NUMBER_OF_QUEUES: return spdk_nvmf_session_set_features_number_of_queues(req); case SPDK_NVME_FEAT_HOST_IDENTIFIER: return spdk_nvmf_session_set_features_host_identifier(req); case SPDK_NVME_FEAT_KEEP_ALIVE_TIMER: return spdk_nvmf_session_set_features_keep_alive_timer(req); default: goto passthrough; } break; case SPDK_NVME_OPC_ASYNC_EVENT_REQUEST: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Async Event Request\n"); /* TODO: Just release the request as consumed. AER events will never * be triggered. */ return SPDK_NVMF_REQUEST_EXEC_STATUS_RELEASE; case SPDK_NVME_OPC_KEEP_ALIVE: SPDK_TRACELOG(SPDK_TRACE_NVMF, "Keep Alive\n"); /* To handle keep alive just clear or reset the session based keep alive duration counter. When added, a separate timer based process will monitor if the time since last recorded keep alive has exceeded the max duration and take appropriate action. */ //session->keep_alive_timestamp = ; return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; case SPDK_NVME_OPC_CREATE_IO_SQ: case SPDK_NVME_OPC_CREATE_IO_CQ: case SPDK_NVME_OPC_DELETE_IO_SQ: case SPDK_NVME_OPC_DELETE_IO_CQ: SPDK_ERRLOG("Admin opc 0x%02X not allowed in NVMf\n", cmd->opc); response->status.sc = SPDK_NVME_SC_INVALID_OPCODE; return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; default: passthrough: SPDK_TRACELOG(SPDK_TRACE_NVMF, "admin_cmd passthrough: opc 0x%02x\n", cmd->opc); rc = spdk_nvme_ctrlr_cmd_admin_raw(subsystem->dev.direct.ctrlr, cmd, req->data, req->length, nvmf_direct_ctrlr_complete_cmd, req); if (rc) { SPDK_ERRLOG("Error submitting admin opc 0x%02x\n", cmd->opc); response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR; return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE; } return SPDK_NVMF_REQUEST_EXEC_STATUS_ASYNCHRONOUS; } }