Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_nvme.c
Show First 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
/* Note the + 1 allows for the initial descriptor to not be page aligned */ | /* Note the + 1 allows for the initial descriptor to not be page aligned */ | ||||
#define NVME_MAX_IOVEC ((1 << NVME_MDTS) + 1) | #define NVME_MAX_IOVEC ((1 << NVME_MDTS) + 1) | ||||
#define NVME_MAX_DATA_SIZE ((1 << NVME_MDTS) * NVME_MPSMIN_BYTES) | #define NVME_MAX_DATA_SIZE ((1 << NVME_MDTS) * NVME_MPSMIN_BYTES) | ||||
/* This is a synthetic status code to indicate there is no status */ | /* This is a synthetic status code to indicate there is no status */ | ||||
#define NVME_NO_STATUS 0xffff | #define NVME_NO_STATUS 0xffff | ||||
#define NVME_COMPLETION_VALID(c) ((c).status != NVME_NO_STATUS) | #define NVME_COMPLETION_VALID(c) ((c).status != NVME_NO_STATUS) | ||||
#define NVME_GET_CNTID(cdw10) (cdw10 >> 16) | |||||
/* helpers */ | /* helpers */ | ||||
/* Convert a zero-based value into a one-based value */ | /* Convert a zero-based value into a one-based value */ | ||||
#define ONE_BASED(zero) ((zero) + 1) | #define ONE_BASED(zero) ((zero) + 1) | ||||
/* Convert a one-based value into a zero-based value */ | /* Convert a one-based value into a zero-based value */ | ||||
#define ZERO_BASED(one) ((one) - 1) | #define ZERO_BASED(one) ((one) - 1) | ||||
/* Encode number of SQ's and CQ's for Set/Get Features */ | /* Encode number of SQ's and CQ's for Set/Get Features */ | ||||
▲ Show 20 Lines • Show All 337 Lines • ▼ Show 20 Lines | pci_nvme_init_ctrldata(struct pci_nvme_softc *sc) | ||||
cd->ieee[2] = 0xfc; | cd->ieee[2] = 0xfc; | ||||
cd->mic = 0; | cd->mic = 0; | ||||
cd->mdts = NVME_MDTS; /* max data transfer size (2^mdts * CAP.MPSMIN) */ | cd->mdts = NVME_MDTS; /* max data transfer size (2^mdts * CAP.MPSMIN) */ | ||||
cd->ver = 0x00010300; | 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->acl = 2; | ||||
cd->aerl = 4; | cd->aerl = 4; | ||||
/* Advertise 1, Read-only firmware slot */ | /* Advertise 1, Read-only firmware slot */ | ||||
cd->frmw = NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK | | cd->frmw = NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK | | ||||
(1 << NVME_CTRLR_DATA_FRMW_NUM_SLOTS_SHIFT); | (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->elpe = 0; /* max error log page entries */ | ||||
cd->npss = 1; /* number of power states support */ | cd->npss = 1; /* number of power states support */ | ||||
/* Warning Composite Temperature Threshold */ | /* Warning Composite Temperature Threshold */ | ||||
cd->wctemp = 0x0157; | cd->wctemp = 0x0157; | ||||
cd->sqes = (6 << NVME_CTRLR_DATA_SQES_MAX_SHIFT) | | cd->sqes = (6 << NVME_CTRLR_DATA_SQES_MAX_SHIFT) | | ||||
(6 << NVME_CTRLR_DATA_SQES_MIN_SHIFT); | (6 << NVME_CTRLR_DATA_SQES_MIN_SHIFT); | ||||
▲ Show 20 Lines • Show All 650 Lines • ▼ Show 20 Lines | nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command, | ||||
return (1); | return (1); | ||||
} | } | ||||
static int | static int | ||||
nvme_opc_identify(struct pci_nvme_softc* sc, struct nvme_command* command, | nvme_opc_identify(struct pci_nvme_softc* sc, struct nvme_command* command, | ||||
struct nvme_completion* compl) | struct nvme_completion* compl) | ||||
{ | { | ||||
void *dest; | uint8_t buff[4096]; | ||||
uint16_t status; | uint16_t status; | ||||
DPRINTF("%s identify 0x%x nsid 0x%x", __func__, | DPRINTF("%s identify 0x%x nsid 0x%x", __func__, | ||||
command->cdw10 & 0xFF, command->nsid); | command->cdw10 & 0xFF, command->nsid); | ||||
pci_nvme_status_genc(&status, NVME_SC_SUCCESS); | pci_nvme_status_genc(&status, NVME_SC_SUCCESS); | ||||
switch (command->cdw10 & 0xFF) { | switch (command->cdw10 & 0xFF) { | ||||
case 0x00: /* return Identify Namespace data structure */ | case 0x00: /* return Identify Namespace data structure */ | ||||
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | ||||
command->prp2, (uint8_t *)&sc->nsdata, sizeof(sc->nsdata), | command->prp2, (uint8_t *)&sc->nsdata, sizeof(sc->nsdata), | ||||
NVME_COPY_TO_PRP); | NVME_COPY_TO_PRP); | ||||
break; | break; | ||||
case 0x01: /* return Identify Controller data structure */ | case 0x01: /* return Identify Controller data structure */ | ||||
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | ||||
command->prp2, (uint8_t *)&sc->ctrldata, | command->prp2, (uint8_t *)&sc->ctrldata, | ||||
sizeof(sc->ctrldata), | sizeof(sc->ctrldata), | ||||
NVME_COPY_TO_PRP); | NVME_COPY_TO_PRP); | ||||
break; | break; | ||||
case 0x02: /* list of 1024 active NSIDs > CDW1.NSID */ | case 0x02: /* list of 1024 active NSIDs > CDW1.NSID */ | ||||
dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, | if (command->nsid >= 1) { | ||||
sizeof(uint32_t) * 1024); | pci_nvme_status_genc(&status, | ||||
NVME_SC_INVALID_NAMESPACE_OR_FORMAT); | |||||
break; | |||||
} | |||||
/* All unused entries shall be zero */ | /* All unused entries shall be zero */ | ||||
bzero(dest, sizeof(uint32_t) * 1024); | bzero(buff, sizeof(buff)); | ||||
((uint32_t *)dest)[0] = 1; | ((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; | break; | ||||
case 0x03: /* list of NSID structures in CDW1.NSID, 4096 bytes */ | case 0x03: /* list of NSID structures in CDW1.NSID, 4096 bytes */ | ||||
if (command->nsid != 1) { | if (command->nsid != 1) { | ||||
pci_nvme_status_genc(&status, | pci_nvme_status_genc(&status, | ||||
NVME_SC_INVALID_NAMESPACE_OR_FORMAT); | NVME_SC_INVALID_NAMESPACE_OR_FORMAT); | ||||
break; | break; | ||||
} | } | ||||
dest = vm_map_gpa(sc->nsc_pi->pi_vmctx, command->prp1, | |||||
sizeof(uint32_t) * 1024); | |||||
/* All bytes after the descriptor shall be zero */ | /* 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 */ | /* Return NIDT=1 (i.e. EUI64) descriptor */ | ||||
((uint8_t *)dest)[0] = 1; | ((uint8_t *)buff)[0] = 1; | ||||
((uint8_t *)dest)[1] = sizeof(uint64_t); | ((uint8_t *)buff)[1] = sizeof(uint64_t); | ||||
bcopy(sc->nsdata.eui64, ((uint8_t *)dest) + 4, 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; | break; | ||||
default: | default: | ||||
DPRINTF("%s unsupported identify command requested 0x%x", | DPRINTF("%s unsupported identify command requested 0x%x", | ||||
__func__, command->cdw10 & 0xFF); | __func__, command->cdw10 & 0xFF); | ||||
pci_nvme_status_genc(&status, NVME_SC_INVALID_FIELD); | pci_nvme_status_genc(&status, NVME_SC_INVALID_FIELD); | ||||
break; | break; | ||||
} | } | ||||
compl->status = status; | compl->status = status; | ||||
▲ Show 20 Lines • Show All 1,649 Lines • Show Last 20 Lines |