Page MenuHomeFreeBSD

D35453.id106833.diff
No OneTemporary

D35453.id106833.diff

Index: usr.sbin/bhyve/pci_nvme.c
===================================================================
--- usr.sbin/bhyve/pci_nvme.c
+++ usr.sbin/bhyve/pci_nvme.c
@@ -398,6 +398,7 @@
((sts) >> NVME_CSTS_REG_RDY_SHIFT & NVME_CSTS_REG_RDY_MASK)
#define NVME_CSTS_RDY (1 << NVME_CSTS_REG_RDY_SHIFT)
+#define NVME_CSTS_CFS (1 << NVME_CSTS_REG_CFS_SHIFT)
/* Completion Queue status word utils */
#define NVME_STATUS_P (1 << NVME_STATUS_P_SHIFT)
@@ -1081,30 +1082,61 @@
pthread_mutex_unlock(&sc->mtx);
}
-static void
+static int
pci_nvme_init_controller(struct vmctx *ctx, struct pci_nvme_softc *sc)
{
uint16_t acqs, asqs;
DPRINTF("%s", __func__);
- asqs = (sc->regs.aqa & NVME_AQA_REG_ASQS_MASK) + 1;
+ /*
+ * NVMe 2.0 states that "enabling a controller while this field is
+ * cleared to 0h produces undefined results" for both ACQS and
+ * ASQS. If zero, set CFS and do not become ready.
+ */
+ asqs = ONE_BASED(sc->regs.aqa & NVME_AQA_REG_ASQS_MASK);
+ if (asqs < 2) {
+ EPRINTLN("%s: illegal ASQS value %#x (aqa=%#x)", __func__,
+ asqs - 1, sc->regs.aqa);
+ sc->regs.csts |= NVME_CSTS_CFS;
+ return (-1);
+ }
sc->submit_queues[0].size = asqs;
sc->submit_queues[0].qbase = vm_map_gpa(ctx, sc->regs.asq,
sizeof(struct nvme_command) * asqs);
+ if (sc->submit_queues[0].qbase == NULL) {
+ EPRINTLN("%s: ASQ vm_map_gpa(%lx) failed", __func__,
+ sc->regs.asq);
+ sc->regs.csts |= NVME_CSTS_CFS;
+ return (-1);
+ }
DPRINTF("%s mapping Admin-SQ guest 0x%lx, host: %p",
__func__, sc->regs.asq, sc->submit_queues[0].qbase);
- acqs = ((sc->regs.aqa >> NVME_AQA_REG_ACQS_SHIFT) &
- NVME_AQA_REG_ACQS_MASK) + 1;
+ acqs = ONE_BASED((sc->regs.aqa >> NVME_AQA_REG_ACQS_SHIFT) &
+ NVME_AQA_REG_ACQS_MASK);
+ if (acqs < 2) {
+ EPRINTLN("%s: illegal ACQS value %#x (aqa=%#x)", __func__,
+ acqs - 1, sc->regs.aqa);
+ sc->regs.csts |= NVME_CSTS_CFS;
+ return (-1);
+ }
sc->compl_queues[0].size = acqs;
sc->compl_queues[0].qbase = vm_map_gpa(ctx, sc->regs.acq,
sizeof(struct nvme_completion) * acqs);
+ if (sc->compl_queues[0].qbase == NULL) {
+ EPRINTLN("%s: ACQ vm_map_gpa(%lx) failed", __func__,
+ sc->regs.acq);
+ sc->regs.csts |= NVME_CSTS_CFS;
+ return (-1);
+ }
sc->compl_queues[0].intr_en = NVME_CQ_INTEN;
DPRINTF("%s mapping Admin-CQ guest 0x%lx, host: %p",
__func__, sc->regs.acq, sc->compl_queues[0].qbase);
+
+ return (0);
}
static int
@@ -2867,6 +2899,12 @@
uint64_t idx = belloffset / 8; /* door bell size = 2*int */
int is_sq = (belloffset % 8) < 4;
+ if ((sc->regs.csts & NVME_CSTS_RDY) == 0) {
+ WPRINTF("doorbell write prior to RDY (offset=%#lx)\n",
+ offset);
+ return;
+ }
+
if (belloffset > ((sc->max_queues+1) * 8 - 4)) {
WPRINTF("guest attempted an overflow write offset "
"0x%lx, val 0x%lx in %s",
@@ -2874,6 +2912,12 @@
return;
}
+ if (is_sq) {
+ if (sc->submit_queues[idx].qbase == NULL)
+ return;
+ } else if (sc->compl_queues[idx].qbase == NULL)
+ return;
+
pci_nvme_handle_doorbell(ctx, sc, idx, is_sq, value);
return;
}
@@ -2940,7 +2984,8 @@
sc->regs.cc &= ~NVME_CC_NEN_WRITE_MASK;
sc->regs.cc |= ccreg & NVME_CC_NEN_WRITE_MASK;
sc->regs.csts &= ~NVME_CSTS_RDY;
- } else if (sc->pending_ios == 0) {
+ } else if ((sc->pending_ios == 0) &&
+ !(sc->regs.csts & NVME_CSTS_CFS)) {
sc->regs.csts |= NVME_CSTS_RDY;
}
break;

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 22, 4:42 AM (14 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35347664
Default Alt Text
D35453.id106833.diff (3 KB)

Event Timeline