Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -242,14 +242,37 @@ struct nvme_completion *); struct nvme_feature_obj { - uint32_t cdw11; + void *data; nvme_feature_cb set; nvme_feature_cb get; bool namespace_specific; }; +#define NVME_NUM_OF_TEMP_SENSOR 9 + +struct nvme_feature_temperature_threshold_data { + uint16_t temp_thres[NVME_NUM_OF_TEMP_SENSOR][2]; +} temp_thres_data; + #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) + struct pci_nvme_aer { STAILQ_ENTRY(pci_nvme_aer) link; uint16_t cid; /* Command ID of the submitted AER */ @@ -351,6 +374,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 *, @@ -614,11 +645,25 @@ static void pci_nvme_init_features(struct pci_nvme_softc *sc) { + uint8_t i; sc->feat[0].set = nvme_feature_invalid_cb; 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; + + temp_thres_data.temp_thres[0][0] = sc->ctrldata.wctemp; + temp_thres_data.temp_thres[0][1] = sc->ctrldata.wctemp - 100; + for (i = 1; i < NVME_NUM_OF_TEMP_SENSOR; i++) { + temp_thres_data.temp_thres[i][0] = 0xFFFF; + temp_thres_data.temp_thres[i][1] = 0x0; + } + sc->feat[NVME_FEAT_TEMPERATURE_THRESHOLD].data = &temp_thres_data; + 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 +1371,77 @@ } +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; + struct nvme_feature_temperature_threshold_data *data = + (struct nvme_feature_temperature_threshold_data *)feat->data; + + 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++ ) + data->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; + struct nvme_feature_temperature_threshold_data *data = + (struct nvme_feature_temperature_threshold_data *)feat->data; + + 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; + }; + + compl->cdw0 = data->temp_thres[tmpsel][thsel]; +} + static void nvme_feature_num_queues(struct pci_nvme_softc *sc, struct nvme_feature_obj *feat, @@ -1406,9 +1522,6 @@ if (feat->set) feat->set(sc, feat, command, compl); - if (compl->status == NVME_SC_SUCCESS) - feat->cdw11 = command->cdw11; - return (0); } @@ -1435,10 +1548,6 @@ feat->get(sc, feat, command, compl); } - if (compl->status == NVME_SC_SUCCESS) { - compl->cdw0 = feat->cdw11; - } - return (0); }