git: b1b2a4d9e87e - main - bhyve nvme: Implement Log Page Offset

From: Chuck Tuffli <chuck_at_FreeBSD.org>
Date: Sat, 29 Jan 2022 23:15:39 UTC
The branch main has been updated by chuck:

URL: https://cgit.FreeBSD.org/src/commit/?id=b1b2a4d9e87e0eec413781e4580cd14edf74af7f

commit b1b2a4d9e87e0eec413781e4580cd14edf74af7f
Author:     Chuck Tuffli <chuck@FreeBSD.org>
AuthorDate: 2022-01-30 07:06:46 +0000
Commit:     Chuck Tuffli <chuck@FreeBSD.org>
CommitDate: 2022-01-30 07:06:46 +0000

    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
---
 usr.sbin/bhyve/pci_nvme.c | 42 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 34 insertions(+), 8 deletions(-)

diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c
index e5def8ef8165..43426f5f1f59 100644
--- a/usr.sbin/bhyve/pci_nvme.c
+++ b/usr.sbin/bhyve/pci_nvme.c
@@ -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;