Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -116,6 +116,8 @@ #define NVME_NO_STATUS 0xffff #define NVME_COMPLETION_VALID(c) ((c).status != NVME_NO_STATUS) +#define NVME_GET_CNTID(cdw10) (cdw10 >> 16) + /* helpers */ /* Convert a zero-based value into a one-based value */ @@ -469,14 +471,15 @@ cd->ver = 0x00010300; - cd->oacs = 1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT; + cd->oacs = (1 << NVME_CTRLR_DATA_OACS_FORMAT_SHIFT) | + (1 << NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT);; cd->acl = 2; cd->aerl = 4; /* Advertise 1, Read-only firmware slot */ cd->frmw = NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK | (1 << NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT); - cd->lpa = 0; /* TODO: support some simple things like SMART */ + cd->lpa = (1 << NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT); cd->elpe = 0; /* max error log page entries */ cd->npss = 1; /* number of power states support */ @@ -1143,7 +1146,7 @@ nvme_opc_identify(struct pci_nvme_softc* sc, struct nvme_command* command, struct nvme_completion* compl) { - void *dest; + uint8_t buff[4096]; uint16_t status; DPRINTF("%s identify 0x%x nsid 0x%x", __func__, @@ -1164,11 +1167,17 @@ NVME_COPY_TO_PRP); break; case 0x02: /* list of 1024 active NSIDs > CDW1.NSID */ - dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, - sizeof(uint32_t) * 1024); + if (command->nsid >= 1) { + pci_nvme_status_genc(&status, + NVME_SC_INVALID_NAMESPACE_OR_FORMAT); + break; + } /* All unused entries shall be zero */ - bzero(dest, sizeof(uint32_t) * 1024); - ((uint32_t *)dest)[0] = 1; + bzero(buff, sizeof(buff)); + ((uint32_t *)buff)[0] = 1; + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, buff, sizeof(buff), + NVME_COPY_TO_PRP); break; case 0x03: /* list of NSID structures in CDW1.NSID, 4096 bytes */ if (command->nsid != 1) { @@ -1176,16 +1185,70 @@ NVME_SC_INVALID_NAMESPACE_OR_FORMAT); break; } - dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, - sizeof(uint32_t) * 1024); /* All bytes after the descriptor shall be zero */ - bzero(dest, sizeof(uint32_t) * 1024); + bzero(buff, sizeof(buff)); /* Return NIDT=1 (i.e. EUI64) descriptor */ - ((uint8_t *)dest)[0] = 1; - ((uint8_t *)dest)[1] = sizeof(uint64_t); - bcopy(sc->nsdata.eui64, ((uint8_t *)dest) + 4, sizeof(uint64_t)); - break; + ((uint8_t *)buff)[0] = 1; + ((uint8_t *)buff)[1] = sizeof(uint64_t); + bcopy(sc->nsdata.eui64, buff + 4, sizeof(uint64_t)); + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, buff, sizeof(buff), + NVME_COPY_TO_PRP); + break; + case 0x10: /* list of 1024 allocated NSIDs > CDW1.NSID */ + if (command->nsid == 0xFFFFFFFE || + command->nsid == 0xFFFFFFFF) { + pci_nvme_status_genc(&status, + NVME_SC_INVALID_NAMESPACE_OR_FORMAT); + break; + } + /* All unused entries shall be zero */ + bzero(buff, sizeof(buff)); + if (command->nsid == 0) + ((uint32_t *)buff)[0] = 1; + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, buff, sizeof(buff), + NVME_COPY_TO_PRP); + break; + case 0x11: /* return Identify Namespace data structure */ + if (command->nsid != 1) { + pci_nvme_status_genc(&status, + NVME_SC_INVALID_NAMESPACE_OR_FORMAT); + break; + } + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, (uint8_t *)&sc->nsdata, + sizeof(sc->nsdata), NVME_COPY_TO_PRP); + break; + case 0x12: /* list of up to 2047 controller identifiers >= CDW10.CNTID + which attached to CDW1.NSID */ + if (command->nsid != 1) { + pci_nvme_status_genc(&status, + NVME_SC_INVALID_NAMESPACE_OR_FORMAT); + break; + } + /* All unused entries shall be zero */ + bzero(buff, sizeof(buff)); + if (NVME_GET_CNTID(command->cdw10) <= 1) { + ((uint16_t *)buff)[0] = 1; + ((uint16_t *)buff)[1] = 1; + } + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, buff, sizeof(buff), + NVME_COPY_TO_PRP); + break; + case 0x13: /* list of up to 2047 controller identifiers >= CDW10.CNTID */ + /* All unused entries shall be zero */ + bzero(buff, sizeof(buff)); + if (NVME_GET_CNTID(command->cdw10) <= 1) { + ((uint16_t *)buff)[0] = 1; + ((uint16_t *)buff)[1] = 1; + } + nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, + command->prp2, buff, sizeof(buff), + NVME_COPY_TO_PRP); + break; default: DPRINTF("%s unsupported identify command requested 0x%x", __func__, command->cdw10 & 0xFF);