Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -115,6 +115,18 @@ #define NVME_NO_STATUS 0xffff #define NVME_COMPLETION_VALID(c) ((c).status != NVME_NO_STATUS) +#define NVME_FEAT_SET_SV_SHIFT (31) +#define NVME_FEAT_SET_SV_MASK (0x1) +#define NVME_FEAT_SET_FID_SHIFT (0) +#define NVME_FEAT_SET_FID_MASK (0xFF) + +#define NVME_FEAT_SET_SV(x) \ + (((x) >> NVME_FEAT_SET_SV_SHIFT) & \ + NVME_FEAT_SET_SV_MASK) +#define NVME_FEAT_SET_FID(x) \ + (((x) >> NVME_FEAT_SET_FID_SHIFT) & \ + NVME_FEAT_SET_FID_MASK) + /* helpers */ /* Convert a zero-based value into a one-based value */ @@ -1382,7 +1394,8 @@ { struct nvme_feature_obj *feat; uint32_t nsid = command->nsid; - uint8_t fid = command->cdw10 & 0xFF; + uint8_t fid = NVME_FEAT_SET_FID(command->cdw10); + bool save = NVME_FEAT_SET_SV(command->cdw10); DPRINTF("%s: Feature ID 0x%x (%s)", __func__, fid, nvme_fid_to_name(fid)); @@ -1391,6 +1404,12 @@ pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); return (1); } + if (save) { + DPRINTF("%s feature is not saveable 0x%x", __func__, fid); + pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC, + NVME_SC_FEATURE_NOT_SAVEABLE); + return (1); + } feat = &sc->feat[fid]; if (!feat->namespace_specific &&