Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -250,6 +250,25 @@ #define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT (20) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK (0x3) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT (16) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK (0xF) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT (0) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK (0xFFFF) + +#define NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL_MASK) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK) +#define NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(x) \ + (((x) >> NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_SHIFT) & \ + NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH_MASK) + +#define NVME_NUM_OF_TEMP_SENSOR 9 + struct pci_nvme_aer { STAILQ_ENTRY(pci_nvme_aer) link; uint16_t cid; /* Command ID of the submitted AER */ @@ -291,6 +310,8 @@ struct nvme_feature_obj feat[NVME_FID_MAX]; + uint16_t temp_thres[NVME_NUM_OF_TEMP_SENSOR][2]; + enum nvme_dsm_type dataset_management; /* Accounting for SMART data */ @@ -351,6 +372,14 @@ struct nvme_feature_obj *, struct nvme_command *, struct nvme_completion *); +static void nvme_feature_temperature_threshold_set(struct pci_nvme_softc *, + struct nvme_feature_obj *, + struct nvme_command *, + struct nvme_completion *); +static void nvme_feature_temperature_threshold_get(struct pci_nvme_softc *, + struct nvme_feature_obj *, + struct nvme_command *, + struct nvme_completion *); static void nvme_feature_num_queues(struct pci_nvme_softc *, struct nvme_feature_obj *, struct nvme_command *, @@ -446,6 +475,7 @@ pci_nvme_init_ctrldata(struct pci_nvme_softc *sc) { struct nvme_controller_data *cd = &sc->ctrldata; + uint8_t i; cd->vid = 0xFB5D; cd->ssvid = 0x0000; @@ -480,6 +510,12 @@ /* Warning Composite Temperature Threshold */ cd->wctemp = 0x0157; + sc->temp_thres[0][0] = cd->wctemp; + sc->temp_thres[0][1] = cd->wctemp - 100; + for (i = 1; i < NVME_NUM_OF_TEMP_SENSOR; i++) { + sc->temp_thres[i][0] = 0xFFFF; + sc->temp_thres[i][1] = 0x0; + } cd->sqes = (6 << NVME_CTRLR_DATA_SQES_MAX_SHIFT) | (6 << NVME_CTRLR_DATA_SQES_MIN_SHIFT); @@ -619,6 +655,11 @@ sc->feat[0].get = nvme_feature_invalid_cb; sc->feat[NVME_FEAT_LBA_RANGE_TYPE].namespace_specific = true; + sc->feat[NVME_FEAT_TEMPERATURE_THRESHOLD].set = + nvme_feature_temperature_threshold_set; + sc->feat[NVME_FEAT_TEMPERATURE_THRESHOLD].get = + nvme_feature_temperature_threshold_get; + sc->feat[NVME_FEAT_ERROR_RECOVERY].namespace_specific = true; sc->feat[NVME_FEAT_NUMBER_OF_QUEUES].set = nvme_feature_num_queues; sc->feat[NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION].set = @@ -1326,6 +1367,73 @@ } +static void +nvme_feature_temperature_threshold_set(struct pci_nvme_softc *sc, + struct nvme_feature_obj *feat, + struct nvme_command *command, + struct nvme_completion *compl) +{ + uint8_t thsel; + uint8_t tmpsel; + uint16_t tmpth; + uint8_t s, e, i; + + DPRINTF("%s: CDW11 0x%x", __func__, command->cdw11); + + thsel = NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL(command->cdw11); + tmpsel = NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL(command->cdw11); + tmpth = NVME_FEAT_TEMPERATURE_THRESHOLD_TMPTH(command->cdw11); + + DPRINTF("%s: THSEL: 0x%x TMPSEL: 0x%x TMPTH 0x%x", __func__, thsel, tmpsel, tmpth); + + if (tmpsel > NVME_NUM_OF_TEMP_SENSOR - 1 && + tmpsel != NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK ) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return; + }; + + if (thsel > 1) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return; + }; + + s = e = tmpsel; + if (tmpsel == NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL_MASK) { + s = 0; + e = NVME_NUM_OF_TEMP_SENSOR - 1; + } + + for ( i = s; i <= e; i++ ) + sc->temp_thres[i][thsel] = tmpth; +} + +static void +nvme_feature_temperature_threshold_get(struct pci_nvme_softc *sc, + struct nvme_feature_obj *feat, + struct nvme_command *command, + struct nvme_completion *compl) +{ + uint8_t thsel; + uint8_t tmpsel; + + thsel = NVME_FEAT_TEMPERATURE_THRESHOLD_THSEL(command->cdw11); + tmpsel = NVME_FEAT_TEMPERATURE_THRESHOLD_TMPSEL(command->cdw11); + + DPRINTF("%s: THSEL: 0x%x TMPSEL: 0x%x", __func__, thsel, tmpsel); + + if (tmpsel > NVME_NUM_OF_TEMP_SENSOR - 1) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return; + }; + + if (thsel > 1) { + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + return; + }; + + feat->cdw11 = sc->temp_thres[tmpsel][thsel]; +} + static void nvme_feature_num_queues(struct pci_nvme_softc *sc, struct nvme_feature_obj *feat,