Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F111632844
D24887.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D24887.diff
View Options
Index: head/usr.sbin/bhyve/pci_nvme.c
===================================================================
--- head/usr.sbin/bhyve/pci_nvme.c
+++ head/usr.sbin/bhyve/pci_nvme.c
@@ -222,6 +222,23 @@
NVME_DATASET_MANAGEMENT_DISABLE,
};
+struct pci_nvme_softc;
+struct nvme_feature_obj;
+
+typedef void (*nvme_feature_cb)(struct pci_nvme_softc *,
+ struct nvme_feature_obj *,
+ struct nvme_command *,
+ struct nvme_completion *);
+
+struct nvme_feature_obj {
+ uint32_t cdw11;
+ nvme_feature_cb set;
+ nvme_feature_cb get;
+ bool namespace_specific;
+};
+
+#define NVME_FID_MAX (NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION + 1)
+
struct pci_nvme_softc {
struct pci_devinst *nsc_pi;
@@ -241,6 +258,7 @@
uint32_t max_queues; /* max number of IO SQ's or CQ's */
uint32_t num_cqueues;
uint32_t num_squeues;
+ bool num_q_is_set; /* Has host set Number of Queues */
struct pci_nvme_ioreq *ioreqs;
STAILQ_HEAD(, pci_nvme_ioreq) ioreqs_free; /* free list of ioreqs */
@@ -255,10 +273,7 @@
struct nvme_completion_queue *compl_queues;
struct nvme_submission_queue *submit_queues;
- /* controller features */
- uint32_t intr_coales_aggr_time; /* 0x08: uS to delay intr */
- uint32_t intr_coales_aggr_thresh; /* 0x08: compl-Q entries */
- uint32_t async_ev_config; /* 0x0B: async event config */
+ struct nvme_feature_obj feat[NVME_FID_MAX];
enum nvme_dsm_type dataset_management;
};
@@ -303,6 +318,15 @@
#define NVME_ONCS_DSM (NVME_CTRLR_DATA_ONCS_DSM_MASK << \
NVME_CTRLR_DATA_ONCS_DSM_SHIFT)
+static void nvme_feature_invalid_cb(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 *,
+ struct nvme_completion *);
+
static __inline void
cpywithpad(char *dst, size_t dst_size, const char *src, char pad)
{
@@ -542,6 +566,18 @@
}
static void
+pci_nvme_init_features(struct pci_nvme_softc *sc)
+{
+
+ 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_ERROR_RECOVERY].namespace_specific = true;
+ sc->feat[NVME_FEAT_NUMBER_OF_QUEUES].set = nvme_feature_num_queues;
+}
+
+static void
pci_nvme_reset_locked(struct pci_nvme_softc *sc)
{
uint32_t i;
@@ -577,6 +613,8 @@
sc->compl_queues[i].tail = 0;
sc->compl_queues[i].head = 0;
}
+
+ sc->num_q_is_set = false;
}
static void
@@ -982,24 +1020,144 @@
DPRINTF("%s unsupported identify command requested 0x%x",
__func__, command->cdw10 & 0xFF);
pci_nvme_status_genc(&status, NVME_SC_INVALID_FIELD);
- return (1);
+ break;
}
compl->status = status;
return (1);
}
-static int
-nvme_set_feature_queues(struct pci_nvme_softc* sc, struct nvme_command* command,
- struct nvme_completion* compl)
+static const char *
+nvme_fid_to_name(uint8_t fid)
{
+ const char *name;
+
+ switch (fid) {
+ case NVME_FEAT_ARBITRATION:
+ name = "Arbitration";
+ break;
+ case NVME_FEAT_POWER_MANAGEMENT:
+ name = "Power Management";
+ break;
+ case NVME_FEAT_LBA_RANGE_TYPE:
+ name = "LBA Range Type";
+ break;
+ case NVME_FEAT_TEMPERATURE_THRESHOLD:
+ name = "Temperature Threshold";
+ break;
+ case NVME_FEAT_ERROR_RECOVERY:
+ name = "Error Recovery";
+ break;
+ case NVME_FEAT_VOLATILE_WRITE_CACHE:
+ name = "Volatile Write Cache";
+ break;
+ case NVME_FEAT_NUMBER_OF_QUEUES:
+ name = "Number of Queues";
+ break;
+ case NVME_FEAT_INTERRUPT_COALESCING:
+ name = "Interrupt Coalescing";
+ break;
+ case NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION:
+ name = "Interrupt Vector Configuration";
+ break;
+ case NVME_FEAT_WRITE_ATOMICITY:
+ name = "Write Atomicity Normal";
+ break;
+ case NVME_FEAT_ASYNC_EVENT_CONFIGURATION:
+ name = "Asynchronous Event Configuration";
+ break;
+ case NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION:
+ name = "Autonomous Power State Transition";
+ break;
+ case NVME_FEAT_HOST_MEMORY_BUFFER:
+ name = "Host Memory Buffer";
+ break;
+ case NVME_FEAT_TIMESTAMP:
+ name = "Timestamp";
+ break;
+ case NVME_FEAT_KEEP_ALIVE_TIMER:
+ name = "Keep Alive Timer";
+ break;
+ case NVME_FEAT_HOST_CONTROLLED_THERMAL_MGMT:
+ name = "Host Controlled Thermal Management";
+ break;
+ case NVME_FEAT_NON_OP_POWER_STATE_CONFIG:
+ name = "Non-Operation Power State Config";
+ break;
+ case NVME_FEAT_READ_RECOVERY_LEVEL_CONFIG:
+ name = "Read Recovery Level Config";
+ break;
+ case NVME_FEAT_PREDICTABLE_LATENCY_MODE_CONFIG:
+ name = "Predictable Latency Mode Config";
+ break;
+ case NVME_FEAT_PREDICTABLE_LATENCY_MODE_WINDOW:
+ name = "Predictable Latency Mode Window";
+ break;
+ case NVME_FEAT_LBA_STATUS_INFORMATION_ATTRIBUTES:
+ name = "LBA Status Information Report Interval";
+ break;
+ case NVME_FEAT_HOST_BEHAVIOR_SUPPORT:
+ name = "Host Behavior Support";
+ break;
+ case NVME_FEAT_SANITIZE_CONFIG:
+ name = "Sanitize Config";
+ break;
+ case NVME_FEAT_ENDURANCE_GROUP_EVENT_CONFIGURATION:
+ name = "Endurance Group Event Configuration";
+ break;
+ case NVME_FEAT_SOFTWARE_PROGRESS_MARKER:
+ name = "Software Progress Marker";
+ break;
+ case NVME_FEAT_HOST_IDENTIFIER:
+ name = "Host Identifier";
+ break;
+ case NVME_FEAT_RESERVATION_NOTIFICATION_MASK:
+ name = "Reservation Notification Mask";
+ break;
+ case NVME_FEAT_RESERVATION_PERSISTENCE:
+ name = "Reservation Persistence";
+ break;
+ case NVME_FEAT_NAMESPACE_WRITE_PROTECTION_CONFIG:
+ name = "Namespace Write Protection Config";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ }
+
+ return (name);
+}
+
+static void
+nvme_feature_invalid_cb(struct pci_nvme_softc *sc,
+ struct nvme_feature_obj *feat,
+ struct nvme_command *command,
+ struct nvme_completion *compl)
+{
+
+ pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD);
+}
+
+static void
+nvme_feature_num_queues(struct pci_nvme_softc *sc,
+ struct nvme_feature_obj *feat,
+ struct nvme_command *command,
+ struct nvme_completion *compl)
+{
uint16_t nqr; /* Number of Queues Requested */
+ if (sc->num_q_is_set) {
+ WPRINTF("%s: Number of Queues already set", __func__);
+ pci_nvme_status_genc(&compl->status,
+ NVME_SC_COMMAND_SEQUENCE_ERROR);
+ return;
+ }
+
nqr = command->cdw11 & 0xFFFF;
if (nqr == 0xffff) {
WPRINTF("%s: Illegal NSQR value %#x", __func__, nqr);
pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD);
- return (-1);
+ return;
}
sc->num_squeues = ONE_BASED(nqr);
@@ -1013,7 +1171,7 @@
if (nqr == 0xffff) {
WPRINTF("%s: Illegal NCQR value %#x", __func__, nqr);
pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD);
- return (-1);
+ return;
}
sc->num_cqueues = ONE_BASED(nqr);
@@ -1023,173 +1181,77 @@
sc->num_cqueues = sc->max_queues;
}
+ /* Patch the command value which will be saved on callback's return */
+ command->cdw11 = NVME_FEATURE_NUM_QUEUES(sc);
compl->cdw0 = NVME_FEATURE_NUM_QUEUES(sc);
- return (0);
+ sc->num_q_is_set = true;
}
static int
-nvme_opc_set_features(struct pci_nvme_softc* sc, struct nvme_command* command,
- struct nvme_completion* compl)
+nvme_opc_set_features(struct pci_nvme_softc *sc, struct nvme_command *command,
+ struct nvme_completion *compl)
{
- int feature = command->cdw10 & 0xFF;
- uint32_t iv;
+ struct nvme_feature_obj *feat;
+ uint32_t nsid = command->nsid;
+ uint8_t fid = command->cdw10 & 0xFF;
- DPRINTF("%s feature 0x%x", __func__, feature);
- compl->cdw0 = 0;
+ DPRINTF("%s: Feature ID 0x%x (%s)", __func__, fid, nvme_fid_to_name(fid));
- switch (feature) {
- case NVME_FEAT_ARBITRATION:
- DPRINTF(" arbitration 0x%x", command->cdw11);
- break;
- case NVME_FEAT_POWER_MANAGEMENT:
- DPRINTF(" power management 0x%x", command->cdw11);
- break;
- case NVME_FEAT_LBA_RANGE_TYPE:
- DPRINTF(" lba range 0x%x", command->cdw11);
- break;
- case NVME_FEAT_TEMPERATURE_THRESHOLD:
- DPRINTF(" temperature threshold 0x%x", command->cdw11);
- break;
- case NVME_FEAT_ERROR_RECOVERY:
- DPRINTF(" error recovery 0x%x", command->cdw11);
- break;
- case NVME_FEAT_VOLATILE_WRITE_CACHE:
- DPRINTF(" volatile write cache 0x%x", command->cdw11);
- break;
- case NVME_FEAT_NUMBER_OF_QUEUES:
- nvme_set_feature_queues(sc, command, compl);
- break;
- case NVME_FEAT_INTERRUPT_COALESCING:
- DPRINTF(" interrupt coalescing 0x%x", command->cdw11);
-
- /* in uS */
- sc->intr_coales_aggr_time = ((command->cdw11 >> 8) & 0xFF)*100;
-
- sc->intr_coales_aggr_thresh = command->cdw11 & 0xFF;
- break;
- case NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION:
- iv = command->cdw11 & 0xFFFF;
-
- DPRINTF(" interrupt vector configuration 0x%x",
- command->cdw11);
-
- for (uint32_t i = 0; i < sc->num_cqueues + 1; i++) {
- if (sc->compl_queues[i].intr_vec == iv) {
- if (command->cdw11 & (1 << 16))
- sc->compl_queues[i].intr_en |=
- NVME_CQ_INTCOAL;
- else
- sc->compl_queues[i].intr_en &=
- ~NVME_CQ_INTCOAL;
- }
- }
- break;
- case NVME_FEAT_WRITE_ATOMICITY:
- DPRINTF(" write atomicity 0x%x", command->cdw11);
- break;
- case NVME_FEAT_ASYNC_EVENT_CONFIGURATION:
- DPRINTF(" async event configuration 0x%x",
- command->cdw11);
- sc->async_ev_config = command->cdw11;
- break;
- case NVME_FEAT_SOFTWARE_PROGRESS_MARKER:
- DPRINTF(" software progress marker 0x%x",
- command->cdw11);
- break;
- case 0x0C:
- DPRINTF(" autonomous power state transition 0x%x",
- command->cdw11);
- break;
- default:
- WPRINTF("%s invalid feature", __func__);
+ if (fid >= NVME_FID_MAX) {
+ DPRINTF("%s invalid feature 0x%x", __func__, fid);
pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD);
return (1);
}
+ feat = &sc->feat[fid];
+ if (!feat->namespace_specific &&
+ !((nsid == 0) || (nsid == NVME_GLOBAL_NAMESPACE_TAG))) {
+ pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC,
+ NVME_SC_FEATURE_NOT_NS_SPECIFIC);
+ return (1);
+ }
+
+ compl->cdw0 = 0;
pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS);
- return (1);
+
+ if (feat->set)
+ feat->set(sc, feat, command, compl);
+
+ if (compl->status == NVME_SC_SUCCESS)
+ feat->cdw11 = command->cdw11;
+
+ return (0);
}
static int
nvme_opc_get_features(struct pci_nvme_softc* sc, struct nvme_command* command,
struct nvme_completion* compl)
{
- int feature = command->cdw10 & 0xFF;
+ struct nvme_feature_obj *feat;
+ uint8_t fid = command->cdw10 & 0xFF;
- DPRINTF("%s feature 0x%x", __func__, feature);
+ DPRINTF("%s: Feature ID 0x%x (%s)", __func__, fid, nvme_fid_to_name(fid));
- compl->cdw0 = 0;
-
- switch (feature) {
- case NVME_FEAT_ARBITRATION:
- DPRINTF(" arbitration");
- break;
- case NVME_FEAT_POWER_MANAGEMENT:
- DPRINTF(" power management");
- break;
- case NVME_FEAT_LBA_RANGE_TYPE:
- DPRINTF(" lba range");
- break;
- case NVME_FEAT_TEMPERATURE_THRESHOLD:
- DPRINTF(" temperature threshold");
- switch ((command->cdw11 >> 20) & 0x3) {
- case 0:
- /* Over temp threshold */
- compl->cdw0 = 0xFFFF;
- break;
- case 1:
- /* Under temp threshold */
- compl->cdw0 = 0;
- break;
- default:
- WPRINTF(" invalid threshold type select");
- pci_nvme_status_genc(&compl->status,
- NVME_SC_INVALID_FIELD);
- return (1);
- }
- break;
- case NVME_FEAT_ERROR_RECOVERY:
- DPRINTF(" error recovery");
- break;
- case NVME_FEAT_VOLATILE_WRITE_CACHE:
- DPRINTF(" volatile write cache");
- break;
- case NVME_FEAT_NUMBER_OF_QUEUES:
- compl->cdw0 = NVME_FEATURE_NUM_QUEUES(sc);
-
- DPRINTF(" number of queues (submit %u, completion %u)",
- compl->cdw0 & 0xFFFF,
- (compl->cdw0 >> 16) & 0xFFFF);
-
- break;
- case NVME_FEAT_INTERRUPT_COALESCING:
- DPRINTF(" interrupt coalescing");
- break;
- case NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION:
- DPRINTF(" interrupt vector configuration");
- break;
- case NVME_FEAT_WRITE_ATOMICITY:
- DPRINTF(" write atomicity");
- break;
- case NVME_FEAT_ASYNC_EVENT_CONFIGURATION:
- DPRINTF(" async event configuration");
- sc->async_ev_config = command->cdw11;
- break;
- case NVME_FEAT_SOFTWARE_PROGRESS_MARKER:
- DPRINTF(" software progress marker");
- break;
- case 0x0C:
- DPRINTF(" autonomous power state transition");
- break;
- default:
- WPRINTF("%s invalid feature 0x%x", __func__, feature);
+ if (fid >= NVME_FID_MAX) {
+ DPRINTF("%s invalid feature 0x%x", __func__, fid);
pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD);
return (1);
}
+ compl->cdw0 = 0;
pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS);
- return (1);
+
+ feat = &sc->feat[fid];
+ if (feat->get) {
+ feat->get(sc, feat, command, compl);
+ }
+
+ if (compl->status == NVME_SC_SUCCESS) {
+ compl->cdw0 = feat->cdw11;
+ }
+
+ return (0);
}
static int
@@ -2312,7 +2374,6 @@
pthread_mutex_init(&sc->ioreqs[i].mtx, NULL);
pthread_cond_init(&sc->ioreqs[i].cv, NULL);
}
- sc->intr_coales_aggr_thresh = 1;
pci_set_cfgdata16(pi, PCIR_DEVICE, 0x0A0A);
pci_set_cfgdata16(pi, PCIR_VENDOR, 0xFB5D);
@@ -2363,6 +2424,7 @@
pci_nvme_init_nsdata(sc, &sc->nsdata, 1, &sc->nvstore);
pci_nvme_init_ctrldata(sc);
pci_nvme_init_logpages(sc);
+ pci_nvme_init_features(sc);
pci_nvme_reset(sc);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 7, 7:11 AM (18 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17027249
Default Alt Text
D24887.diff (13 KB)
Attached To
Mode
D24887: bhyve: add more compliant NVMe Get/Set Features
Attached
Detach File
Event Timeline
Log In to Comment