host = kzalloc(sizeof(*host) * 2, GFP_KERNEL); if (!host) goto out_complete_req;
ret = nvme_get_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
host, sizeof(*host), NULL); if (ret) goto out_free_host;
status = nvmet_copy_from_sgl(req, 0, &host[1], sizeof(*host)); if (status) goto out_free_host;
if (memcmp(&host[0], &host[1], sizeof(host[0]))) {
pr_warn("target host has requested different behaviour from the local host\n");
status = NVME_SC_INTERNAL;
}
u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req)
{ /* Reject any commands with non-sgl flags set (ie. fused commands) */ if (req->cmd->common.flags & ~NVME_CMD_SGL_ALL) return NVME_SC_INVALID_FIELD;
switch (req->cmd->common.opcode) { case nvme_cmd_resv_register: case nvme_cmd_resv_report: case nvme_cmd_resv_acquire: case nvme_cmd_resv_release: /* *Reservationscannotbesupportedproperlybecausethe *underlyingdevicehasnowayofdifferentiatingdifferent *hoststhatconnectviafabrics.Thiscouldpotentiallybe *emulatedinthefutureifregulartargetsgrowsupportfor *thisfeature.
*/ return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
}
return nvmet_setup_passthru_command(req);
}
/* *Onlyfeaturesthatareemulatedorspecificallyallowedinthelistare *passeddowntothecontroller.Thisfunctionimplementstheallowlistfor *bothgetandsetfeatures.
*/ static u16 nvmet_passthru_get_set_features(struct nvmet_req *req)
{ switch (le32_to_cpu(req->cmd->features.fid)) { case NVME_FEAT_ARBITRATION: case NVME_FEAT_POWER_MGMT: case NVME_FEAT_LBA_RANGE: case NVME_FEAT_TEMP_THRESH: case NVME_FEAT_ERR_RECOVERY: case NVME_FEAT_VOLATILE_WC: case NVME_FEAT_WRITE_ATOMIC: case NVME_FEAT_AUTO_PST: case NVME_FEAT_TIMESTAMP: case NVME_FEAT_HCTM: case NVME_FEAT_NOPSC: case NVME_FEAT_RRL: case NVME_FEAT_PLM_CONFIG: case NVME_FEAT_PLM_WINDOW: case NVME_FEAT_HOST_BEHAVIOR: case NVME_FEAT_SANITIZE: case NVME_FEAT_VENDOR_START ... NVME_FEAT_VENDOR_END: return nvmet_setup_passthru_command(req);
case NVME_FEAT_ASYNC_EVENT: /* There is no support for forwarding ASYNC events */ case NVME_FEAT_IRQ_COALESCE: case NVME_FEAT_IRQ_CONFIG: /* The IRQ settings will not apply to the target controller */ case NVME_FEAT_HOST_MEM_BUF: /* *AnyHMBthat'ssetwillnotbepassedthroughandwill *notworkasexpected
*/ case NVME_FEAT_SW_PROGRESS: /* *ThePre-BootSoftwareLoadCountdoesn'tmakemuch *senseforatargettoexport
*/ case NVME_FEAT_RESV_MASK: case NVME_FEAT_RESV_PERSIST: /* No reservations, see nvmet_parse_passthru_io_cmd() */ default: return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR;
}
}
u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
{ /* Reject any commands with non-sgl flags set (ie. fused commands) */ if (req->cmd->common.flags & ~NVME_CMD_SGL_ALL) return NVME_SC_INVALID_FIELD;
/* *Passthruallvendorspecificcommands
*/ if (req->cmd->common.opcode >= nvme_admin_vendor_start) return nvmet_setup_passthru_command(req);
switch (req->cmd->common.opcode) { case nvme_admin_async_event:
req->execute = nvmet_execute_async_event; return NVME_SC_SUCCESS; case nvme_admin_keep_alive: /* *MostPCIectrlsdon'tsupportkeepalivecmd,weroutekeep *alivetothenon-passthrumode.Infuturepleasechangethis *codewhenPCIectrlswithkeepalivesupportavailable.
*/
req->execute = nvmet_execute_keep_alive; return NVME_SC_SUCCESS; case nvme_admin_set_features: switch (le32_to_cpu(req->cmd->features.fid)) { case NVME_FEAT_ASYNC_EVENT: case NVME_FEAT_KATO: case NVME_FEAT_NUM_QUEUES: case NVME_FEAT_HOST_ID:
req->execute = nvmet_execute_set_features; return NVME_SC_SUCCESS; case NVME_FEAT_HOST_BEHAVIOR:
req->execute = nvmet_passthru_set_host_behaviour; return NVME_SC_SUCCESS; default: return nvmet_passthru_get_set_features(req);
} break; case nvme_admin_get_features: switch (le32_to_cpu(req->cmd->features.fid)) { case NVME_FEAT_ASYNC_EVENT: case NVME_FEAT_KATO: case NVME_FEAT_NUM_QUEUES: case NVME_FEAT_HOST_ID:
req->execute = nvmet_execute_get_features; return NVME_SC_SUCCESS; case NVME_FEAT_FDP: return nvmet_setup_passthru_command(req); default: return nvmet_passthru_get_set_features(req);
} break; case nvme_admin_identify: switch (req->cmd->identify.cns) { case NVME_ID_CNS_CS_CTRL: switch (req->cmd->identify.csi) { case NVME_CSI_ZNS:
req->execute = nvmet_passthru_execute_cmd;
req->p.use_workqueue = true; return NVME_SC_SUCCESS;
} return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; case NVME_ID_CNS_CTRL: case NVME_ID_CNS_NS: case NVME_ID_CNS_NS_DESC_LIST:
req->execute = nvmet_passthru_execute_cmd;
req->p.use_workqueue = true; return NVME_SC_SUCCESS; case NVME_ID_CNS_CS_NS: switch (req->cmd->identify.csi) { case NVME_CSI_ZNS:
req->execute = nvmet_passthru_execute_cmd;
req->p.use_workqueue = true; return NVME_SC_SUCCESS;
} return NVME_SC_INVALID_OPCODE | NVME_STATUS_DNR; default: return nvmet_setup_passthru_command(req);
} case nvme_admin_get_log_page: return nvmet_setup_passthru_command(req); default: /* Reject commands not in the allowlist above */ return nvmet_report_invalid_opcode(req);
}
}
int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys)
{ struct nvme_ctrl *ctrl; struct file *file; int ret = -EINVAL; void *old;
mutex_lock(&subsys->lock); if (!subsys->passthru_ctrl_path) goto out_unlock; if (subsys->passthru_ctrl) goto out_unlock;
if (subsys->nr_namespaces) {
pr_info("cannot enable both passthru and regular namespaces for a single subsystem"); goto out_unlock;
}
file = filp_open(subsys->passthru_ctrl_path, O_RDWR, 0); if (IS_ERR(file)) {
ret = PTR_ERR(file); goto out_unlock;
}
ctrl = nvme_ctrl_from_file(file); if (!ctrl) {
pr_err("failed to open nvme controller %s\n",
subsys->passthru_ctrl_path);
goto out_put_file;
}
old = xa_cmpxchg(&passthru_subsystems, ctrl->instance, NULL,
subsys, GFP_KERNEL); if (xa_is_err(old)) {
ret = xa_err(old); goto out_put_file;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.