bhyve nvme: Implement Log Page Offset

Modify the Get Log Page command to parse the Log Page Offset fields to
support more recent versions of the NVMe specification.

Fixes various tests for UNH Test 1.3.*

Reviewed by:	imp, allanjude
Tested by:      jason@tubnor.net
MFC after:      1 month
Differential Revision:	https://reviews.freebsd.org/D33568
This commit is contained in:
Chuck Tuffli 2022-01-29 23:06:46 -08:00
parent 62d47feceb
commit b1b2a4d9e8

View File

@ -1329,6 +1329,7 @@ static int
nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
struct nvme_completion* compl)
{
uint64_t logoff;
uint32_t logsize;
uint8_t logpage = command->cdw10 & 0xFF;
@ -1342,15 +1343,28 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
*/
logsize = ((command->cdw11 << 16) | (command->cdw10 >> 16)) + 1;
logsize *= sizeof(uint32_t);
logoff = ((uint64_t)(command->cdw13) << 32) | command->cdw12;
switch (logpage) {
case NVME_LOG_ERROR:
if (logoff >= sizeof(sc->err_log)) {
pci_nvme_status_genc(&compl->status,
NVME_SC_INVALID_FIELD);
break;
}
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
command->prp2, (uint8_t *)&sc->err_log,
MIN(logsize, sizeof(sc->err_log)),
command->prp2, (uint8_t *)&sc->err_log + logoff,
MIN(logsize - logoff, sizeof(sc->err_log)),
NVME_COPY_TO_PRP);
break;
case NVME_LOG_HEALTH_INFORMATION:
if (logoff >= sizeof(sc->health_log)) {
pci_nvme_status_genc(&compl->status,
NVME_SC_INVALID_FIELD);
break;
}
pthread_mutex_lock(&sc->mtx);
memcpy(&sc->health_log.data_units_read, &sc->read_data_units,
sizeof(sc->health_log.data_units_read));
@ -1363,20 +1377,32 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struct nvme_command* command,
pthread_mutex_unlock(&sc->mtx);
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
command->prp2, (uint8_t *)&sc->health_log,
MIN(logsize, sizeof(sc->health_log)),
command->prp2, (uint8_t *)&sc->health_log + logoff,
MIN(logsize - logoff, sizeof(sc->health_log)),
NVME_COPY_TO_PRP);
break;
case NVME_LOG_FIRMWARE_SLOT:
if (logoff >= sizeof(sc->fw_log)) {
pci_nvme_status_genc(&compl->status,
NVME_SC_INVALID_FIELD);
break;
}
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
command->prp2, (uint8_t *)&sc->fw_log,
MIN(logsize, sizeof(sc->fw_log)),
command->prp2, (uint8_t *)&sc->fw_log + logoff,
MIN(logsize - logoff, sizeof(sc->fw_log)),
NVME_COPY_TO_PRP);
break;
case NVME_LOG_CHANGED_NAMESPACE:
if (logoff >= sizeof(sc->ns_log)) {
pci_nvme_status_genc(&compl->status,
NVME_SC_INVALID_FIELD);
break;
}
nvme_prp_memcpy(sc->nsc_pi->pi_vmctx, command->prp1,
command->prp2, (uint8_t *)&sc->ns_log,
MIN(logsize, sizeof(sc->ns_log)),
command->prp2, (uint8_t *)&sc->ns_log + logoff,
MIN(logsize - logoff, sizeof(sc->ns_log)),
NVME_COPY_TO_PRP);
memset(&sc->ns_log, 0, sizeof(sc->ns_log));
break;