Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_nvme.c
Show First 20 Lines • Show All 290 Lines • ▼ Show 20 Lines | struct pci_nvme_softc { | ||||
struct nvme_registers regs; | struct nvme_registers regs; | ||||
struct nvme_namespace_data nsdata; | struct nvme_namespace_data nsdata; | ||||
struct nvme_controller_data ctrldata; | struct nvme_controller_data ctrldata; | ||||
struct nvme_error_information_entry err_log; | struct nvme_error_information_entry err_log; | ||||
struct nvme_health_information_page health_log; | struct nvme_health_information_page health_log; | ||||
struct nvme_firmware_page fw_log; | struct nvme_firmware_page fw_log; | ||||
uint32_t *ns_log; | |||||
wanpengqian_gmail.com: Can we have an array here? we can avoid `calloc` later. also avoid check `NULL` in… | |||||
struct pci_nvme_blockstore nvstore; | struct pci_nvme_blockstore nvstore; | ||||
uint16_t max_qentries; /* max entries per queue */ | uint16_t max_qentries; /* max entries per queue */ | ||||
uint32_t max_queues; /* max number of IO SQ's or CQ's */ | uint32_t max_queues; /* max number of IO SQ's or CQ's */ | ||||
uint32_t num_cqueues; | uint32_t num_cqueues; | ||||
uint32_t num_squeues; | uint32_t num_squeues; | ||||
bool num_q_is_set; /* Has host set Number of Queues */ | bool num_q_is_set; /* Has host set Number of Queues */ | ||||
▲ Show 20 Lines • Show All 286 Lines • ▼ Show 20 Lines | crc16(uint16_t crc, const void *buffer, unsigned int len) | ||||
while (len--) | while (len--) | ||||
crc = (((crc >> 8) & 0xffU) ^ | crc = (((crc >> 8) & 0xffU) ^ | ||||
crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; | crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; | ||||
return crc; | return crc; | ||||
} | } | ||||
static void | static void | ||||
pci_nvme_init_nsdata(struct pci_nvme_softc *sc, | pci_nvme_init_nsdata_size(struct pci_nvme_blockstore *nvstore, | ||||
struct nvme_namespace_data *nd, uint32_t nsid, | struct nvme_namespace_data *nd) | ||||
struct pci_nvme_blockstore *nvstore) | |||||
{ | { | ||||
/* Get capacity and block size information from backing store */ | /* Get capacity and block size information from backing store */ | ||||
nd->nsze = nvstore->size / nvstore->sectsz; | nd->nsze = nvstore->size / nvstore->sectsz; | ||||
nd->ncap = nd->nsze; | nd->ncap = nd->nsze; | ||||
nd->nuse = nd->nsze; | nd->nuse = nd->nsze; | ||||
} | |||||
static void | |||||
pci_nvme_init_nsdata(struct pci_nvme_softc *sc, | |||||
struct nvme_namespace_data *nd, uint32_t nsid, | |||||
struct pci_nvme_blockstore *nvstore) | |||||
{ | |||||
pci_nvme_init_nsdata_size(nvstore, nd); | |||||
if (nvstore->type == NVME_STOR_BLOCKIF) | if (nvstore->type == NVME_STOR_BLOCKIF) | ||||
nvstore->deallocate = blockif_candelete(nvstore->ctx); | nvstore->deallocate = blockif_candelete(nvstore->ctx); | ||||
nd->nlbaf = 0; /* NLBAF is a 0's based value (i.e. 1 LBA Format) */ | nd->nlbaf = 0; /* NLBAF is a 0's based value (i.e. 1 LBA Format) */ | ||||
nd->flbas = 0; | nd->flbas = 0; | ||||
/* Create an EUI-64 if user did not provide one */ | /* Create an EUI-64 if user did not provide one */ | ||||
if (nvstore->eui64 == 0) { | if (nvstore->eui64 == 0) { | ||||
Show All 18 Lines | |||||
static void | static void | ||||
pci_nvme_init_logpages(struct pci_nvme_softc *sc) | pci_nvme_init_logpages(struct pci_nvme_softc *sc) | ||||
{ | { | ||||
memset(&sc->err_log, 0, sizeof(sc->err_log)); | memset(&sc->err_log, 0, sizeof(sc->err_log)); | ||||
memset(&sc->health_log, 0, sizeof(sc->health_log)); | memset(&sc->health_log, 0, sizeof(sc->health_log)); | ||||
memset(&sc->fw_log, 0, sizeof(sc->fw_log)); | memset(&sc->fw_log, 0, sizeof(sc->fw_log)); | ||||
sc->ns_log = calloc(1024, sizeof(uint32_t)); | |||||
wanpengqian_gmail.comUnsubmitted Not Done Inline Actionsdo we need to check the result value. wanpengqian_gmail.com: do we need to check the result value. | |||||
/* Set read/write remainder to round up according to spec */ | /* Set read/write remainder to round up according to spec */ | ||||
sc->read_dunits_remainder = 999; | sc->read_dunits_remainder = 999; | ||||
sc->write_dunits_remainder = 999; | sc->write_dunits_remainder = 999; | ||||
/* Set nominal Health values checked by implementations */ | /* Set nominal Health values checked by implementations */ | ||||
sc->health_log.temperature = 310; | sc->health_log.temperature = 310; | ||||
sc->health_log.available_spare = 100; | sc->health_log.available_spare = 100; | ||||
▲ Show 20 Lines • Show All 691 Lines • ▼ Show 20 Lines | nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | ||||
NVME_COPY_TO_PRP); | NVME_COPY_TO_PRP); | ||||
break; | break; | ||||
case NVME_LOG_FIRMWARE_SLOT: | case NVME_LOG_FIRMWARE_SLOT: | ||||
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->fw_log, | command->prp2, (uint8_t *)&sc->fw_log, | ||||
MIN(logsize, sizeof(sc->fw_log)), | MIN(logsize, sizeof(sc->fw_log)), | ||||
NVME_COPY_TO_PRP); | NVME_COPY_TO_PRP); | ||||
break; | break; | ||||
case NVME_LOG_CHANGED_NAMESPACE: | |||||
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1, | |||||
command->prp2, (uint8_t *)sc->ns_log, | |||||
MIN(logsize, 1024 * sizeof(uint32_t)), | |||||
NVME_COPY_TO_PRP); | |||||
memset(sc->ns_log, 0, 1024 * sizeof(uint32_t)); | |||||
break; | |||||
default: | default: | ||||
DPRINTF("%s get log page %x command not supported", | DPRINTF("%s get log page %x command not supported", | ||||
__func__, logpage); | __func__, logpage); | ||||
pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC, | pci_nvme_status_tc(&compl->status, NVME_SCT_COMMAND_SPECIFIC, | ||||
NVME_SC_INVALID_LOG_PAGE); | NVME_SC_INVALID_LOG_PAGE); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,584 Lines • ▼ Show 20 Lines | for (sc->nvstore.sectsz_bits = 9; | ||||
sc->nvstore.sectsz_bits++); | sc->nvstore.sectsz_bits++); | ||||
if (sc->max_queues <= 0 || sc->max_queues > NVME_QUEUES) | if (sc->max_queues <= 0 || sc->max_queues > NVME_QUEUES) | ||||
sc->max_queues = NVME_QUEUES; | sc->max_queues = NVME_QUEUES; | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | |||||
pci_nvme_resized(struct blockif_ctxt *bctxt, void *arg, size_t new_size) | |||||
{ | |||||
struct pci_nvme_softc *sc; | |||||
struct pci_nvme_blockstore *nvstore; | |||||
struct nvme_namespace_data *nd; | |||||
sc = arg; | |||||
nvstore = &sc->nvstore; | |||||
nd = &sc->nsdata; | |||||
nvstore->size = new_size; | |||||
pci_nvme_init_nsdata_size(nvstore, nd); | |||||
if (sc->ns_log == NULL) { | |||||
EPRINTLN("%s: namespace log is NULL?!?", __func__); | |||||
Not Done Inline ActionsIs the NSID always 1? imp: Is the NSID always 1? | |||||
Done Inline ActionsYes, NSID will always be 0x1 as the emulation only supports a single namespace. chuck: Yes, NSID will always be `0x1` as the emulation only supports a single namespace. | |||||
return; | |||||
} | |||||
/* Add changed NSID to list */ | |||||
sc->ns_log[0] = 1; | |||||
sc->ns_log[1] = 0; | |||||
pci_nvme_aen_post(sc, PCI_NVME_AE_TYPE_NOTICE, | |||||
PCI_NVME_AE_INFO_NS_ATTR_CHANGED); | |||||
} | |||||
static int | static int | ||||
pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
{ | { | ||||
struct pci_nvme_softc *sc; | struct pci_nvme_softc *sc; | ||||
uint32_t pci_membar_sz; | uint32_t pci_membar_sz; | ||||
int error; | int error; | ||||
error = 0; | error = 0; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | pci_nvme_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
error = pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_INT_EP); | error = pci_emul_add_pciecap(pi, PCIEM_TYPE_ROOT_INT_EP); | ||||
if (error) { | if (error) { | ||||
WPRINTF("%s pci add Express capability failed", __func__); | WPRINTF("%s pci add Express capability failed", __func__); | ||||
goto done; | goto done; | ||||
} | } | ||||
pthread_mutex_init(&sc->mtx, NULL); | pthread_mutex_init(&sc->mtx, NULL); | ||||
sem_init(&sc->iosemlock, 0, sc->ioslots); | sem_init(&sc->iosemlock, 0, sc->ioslots); | ||||
blockif_register_resize_callback(sc->nvstore.ctx, pci_nvme_resized, sc); | |||||
pci_nvme_init_queues(sc, sc->max_queues, sc->max_queues); | pci_nvme_init_queues(sc, sc->max_queues, sc->max_queues); | ||||
/* | /* | ||||
* Controller data depends on Namespace data so initialize Namespace | * Controller data depends on Namespace data so initialize Namespace | ||||
* data first. | * data first. | ||||
*/ | */ | ||||
pci_nvme_init_nsdata(sc, &sc->nsdata, 1, &sc->nvstore); | pci_nvme_init_nsdata(sc, &sc->nsdata, 1, &sc->nvstore); | ||||
pci_nvme_init_ctrldata(sc); | pci_nvme_init_ctrldata(sc); | ||||
▲ Show 20 Lines • Show All 44 Lines • Show Last 20 Lines |
Can we have an array here? we can avoid calloc later. also avoid check NULL in pci_nvme_resized()