Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Jul 2020 23:45:49 +0000 (UTC)
From:      Chuck Tuffli <chuck@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r363349 - stable/12/usr.sbin/bhyve
Message-ID:  <202007192345.06JNjnau071268@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: chuck
Date: Sun Jul 19 23:45:49 2020
New Revision: 363349
URL: https://svnweb.freebsd.org/changeset/base/363349

Log:
  MFC r362759 bhyve: implement NVMe SMART data I/O statistics

Modified:
  stable/12/usr.sbin/bhyve/pci_nvme.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/usr.sbin/bhyve/pci_nvme.c
==============================================================================
--- stable/12/usr.sbin/bhyve/pci_nvme.c	Sun Jul 19 23:42:46 2020	(r363348)
+++ stable/12/usr.sbin/bhyve/pci_nvme.c	Sun Jul 19 23:45:49 2020	(r363349)
@@ -218,6 +218,7 @@ struct pci_nvme_ioreq {
 
 	uint64_t	prev_gpaddr;
 	size_t		prev_size;
+	size_t		bytes;
 
 	struct blockif_req io_req;
 
@@ -287,6 +288,14 @@ struct pci_nvme_softc {
 	struct nvme_feature_obj feat[NVME_FID_MAX];
 
 	enum nvme_dsm_type dataset_management;
+
+	/* Accounting for SMART data */
+	__uint128_t	read_data_units;
+	__uint128_t	write_data_units;
+	__uint128_t	read_commands;
+	__uint128_t	write_commands;
+	uint32_t	read_dunits_remainder;
+	uint32_t	write_dunits_remainder;
 };
 
 
@@ -576,6 +585,10 @@ pci_nvme_init_logpages(struct pci_nvme_softc *sc)
 	memset(&sc->err_log, 0, sizeof(sc->err_log));
 	memset(&sc->health_log, 0, sizeof(sc->health_log));
 	memset(&sc->fw_log, 0, sizeof(sc->fw_log));
+
+	/* Set read/write remainder to round up according to spec */
+	sc->read_dunits_remainder = 999;
+	sc->write_dunits_remainder = 999;
 }
 
 static void
@@ -961,7 +974,17 @@ nvme_opc_get_log_page(struct pci_nvme_softc* sc, struc
 		    NVME_COPY_TO_PRP);
 		break;
 	case NVME_LOG_HEALTH_INFORMATION:
-		/* TODO: present some smart info */
+		pthread_mutex_lock(&sc->mtx);
+		memcpy(&sc->health_log.data_units_read, &sc->read_data_units,
+		    sizeof(sc->health_log.data_units_read));
+		memcpy(&sc->health_log.data_units_written, &sc->write_data_units,
+		    sizeof(sc->health_log.data_units_written));
+		memcpy(&sc->health_log.host_read_commands, &sc->read_commands,
+		    sizeof(sc->health_log.host_read_commands));
+		memcpy(&sc->health_log.host_write_commands, &sc->write_commands,
+		    sizeof(sc->health_log.host_write_commands));
+		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)),
@@ -1464,6 +1487,47 @@ pci_nvme_handle_admin_cmd(struct pci_nvme_softc* sc, u
 	pthread_mutex_unlock(&sq->mtx);
 }
 
+/*
+ * Update the Write and Read statistics reported in SMART data
+ *
+ * NVMe defines "data unit" as thousand's of 512 byte blocks and is rounded up.
+ * E.g. 1 data unit is 1 - 1,000 512 byte blocks. 3 data units are 2,001 - 3,000
+ * 512 byte blocks. Rounding up is acheived by initializing the remainder to 999.
+ */
+static void
+pci_nvme_stats_write_read_update(struct pci_nvme_softc *sc, uint8_t opc,
+    size_t bytes, uint16_t status)
+{
+
+	pthread_mutex_lock(&sc->mtx);
+	switch (opc) {
+	case NVME_OPC_WRITE:
+		sc->write_commands++;
+		if (status != NVME_SC_SUCCESS)
+			break;
+		sc->write_dunits_remainder += (bytes / 512);
+		while (sc->write_dunits_remainder >= 1000) {
+			sc->write_data_units++;
+			sc->write_dunits_remainder -= 1000;
+		}
+		break;
+	case NVME_OPC_READ:
+		sc->read_commands++;
+		if (status != NVME_SC_SUCCESS)
+			break;
+		sc->read_dunits_remainder += (bytes / 512);
+		while (sc->read_dunits_remainder >= 1000) {
+			sc->read_data_units++;
+			sc->read_dunits_remainder -= 1000;
+		}
+		break;
+	default:
+		DPRINTF("%s: Invalid OPC 0x%02x for stats", __func__, opc);
+		break;
+	}
+	pthread_mutex_unlock(&sc->mtx);
+}
+
 static int
 pci_nvme_append_iov_req(struct pci_nvme_softc *sc, struct pci_nvme_ioreq *req,
 	uint64_t gpaddr, size_t size, int do_write, uint64_t lba)
@@ -1604,6 +1668,8 @@ pci_nvme_io_done(struct blockif_req *br, int err)
 	pci_nvme_status_genc(&status, code);
 
 	pci_nvme_set_completion(req->sc, sq, req->sqid, req->cid, 0, status);
+	pci_nvme_stats_write_read_update(req->sc, req->opc,
+	    req->bytes, status);
 	pci_nvme_release_ioreq(req->sc, req);
 }
 
@@ -1778,6 +1844,7 @@ nvme_opc_write_read(struct pci_nvme_softc *sc,
 		goto out;
 	}
 
+	req->bytes = bytes;
 	req->io_req.br_offset = lba;
 
 	/* PRP bits 1:0 must be zero */
@@ -1795,6 +1862,9 @@ nvme_opc_write_read(struct pci_nvme_softc *sc,
 			pending = true;
 	}
 out:
+	if (!pending)
+		pci_nvme_stats_write_read_update(sc, cmd->opc, bytes, *status);
+
 	return (pending);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202007192345.06JNjnau071268>