svn commit: r325794 - in head/sys: cam cam/nvme dev/nvme

Warner Losh imp at FreeBSD.org
Tue Nov 14 05:05:18 UTC 2017


Author: imp
Date: Tue Nov 14 05:05:16 2017
New Revision: 325794
URL: https://svnweb.freebsd.org/changeset/base/325794

Log:
  Provide link speed data in XPT_GET_TRAN_SETTINGS. Provide full version
  information for that and XPT_PATH_INQ. Provide macros to encode/decode
  major/minor versions.  Read the link speed and lane count to compute
  the base_transfer_speed for XPT_PATH_INQ.
  
  Sponsored by: Netflix

Modified:
  head/sys/cam/cam_ccb.h
  head/sys/cam/nvme/nvme_all.h
  head/sys/cam/nvme/nvme_xpt.c
  head/sys/dev/nvme/nvme.h
  head/sys/dev/nvme/nvme_sim.c

Modified: head/sys/cam/cam_ccb.h
==============================================================================
--- head/sys/cam/cam_ccb.h	Tue Nov 14 05:05:05 2017	(r325793)
+++ head/sys/cam/cam_ccb.h	Tue Nov 14 05:05:16 2017	(r325794)
@@ -1016,11 +1016,14 @@ struct ccb_trans_settings_nvme 
 	u_int     	valid;		/* Which fields to honor */
 #define CTS_NVME_VALID_SPEC	0x01
 #define CTS_NVME_VALID_CAPS	0x02
-	u_int		spec_major;	/* Major version of spec supported */
-	u_int		spec_minor;	/* Minor verison of spec supported */
-	u_int		spec_tiny;	/* Tiny version of spec supported */
-	u_int		max_xfer;	/* Max transfer size (0 -> unlimited */
-	u_int		caps;
+#define CTS_NVME_VALID_LINK	0x04
+	uint32_t	spec;		/* NVMe spec implemented -- same as vs register */
+	uint32_t	max_xfer;	/* Max transfer size (0 -> unlimited */
+	uint32_t	caps;
+	uint8_t		lanes;		/* Number of PCIe lanes */
+	uint8_t		speed;		/* PCIe generation for each lane */
+	uint8_t		max_lanes;	/* Number of PCIe lanes */
+	uint8_t		max_speed;	/* PCIe generation for each lane */
 };
 
 #include <cam/mmc/mmc_bus.h>

Modified: head/sys/cam/nvme/nvme_all.h
==============================================================================
--- head/sys/cam/nvme/nvme_all.h	Tue Nov 14 05:05:05 2017	(r325793)
+++ head/sys/cam/nvme/nvme_all.h	Tue Nov 14 05:05:16 2017	(r325794)
@@ -33,8 +33,6 @@
 
 struct ccb_nvmeio;
 
-#define NVME_REV_1	1	/* Supports NVMe 1.2 or earlier */
-
 void	nvme_ns_cmd(struct ccb_nvmeio *nvmeio, uint8_t cmd, uint32_t nsid,
     uint32_t cdw10, uint32_t cdw11, uint32_t cdw12, uint32_t cdw13,
     uint32_t cdw14, uint32_t cdw15);

Modified: head/sys/cam/nvme/nvme_xpt.c
==============================================================================
--- head/sys/cam/nvme/nvme_xpt.c	Tue Nov 14 05:05:05 2017	(r325793)
+++ head/sys/cam/nvme/nvme_xpt.c	Tue Nov 14 05:05:16 2017	(r325794)
@@ -639,12 +639,14 @@ nvme_announce_periph(struct cam_periph *periph)
 static void
 nvme_proto_announce(struct cam_ed *device)
 {
+
 	nvme_print_ident(device->nvme_cdata, device->nvme_data);
 }
 
 static void
 nvme_proto_denounce(struct cam_ed *device)
 {
+
 	nvme_print_ident(device->nvme_cdata, device->nvme_data);
 }
 

Modified: head/sys/dev/nvme/nvme.h
==============================================================================
--- head/sys/dev/nvme/nvme.h	Tue Nov 14 05:05:05 2017	(r325793)
+++ head/sys/dev/nvme/nvme.h	Tue Nov 14 05:05:16 2017	(r325794)
@@ -42,6 +42,13 @@
 #define	NVME_BIO_TEST			_IOWR('n', 101, struct nvme_io_test)
 
 /*
+ * Macros to deal with NVME revisions, as defined VS register
+ */
+#define NVME_REV(x, y)			(((x) << 16) | ((y) << 8))
+#define NVME_MAJOR(r)			(((r) >> 16) & 0xffff)
+#define NVME_MINOR(r)			(((r) >> 8) & 0xff)
+
+/*
  * Use to mark a command to apply to all namespaces, or to retrieve global
  *  log pages.
  */

Modified: head/sys/dev/nvme/nvme_sim.c
==============================================================================
--- head/sys/dev/nvme/nvme_sim.c	Tue Nov 14 05:05:05 2017	(r325793)
+++ head/sys/dev/nvme/nvme_sim.c	Tue Nov 14 05:05:16 2017	(r325794)
@@ -44,6 +44,9 @@ __FBSDID("$FreeBSD$");
 #include <cam/cam_xpt_internal.h>	// Yes, this is wrong.
 #include <cam/cam_debug.h>
 
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
 #include "nvme_private.h"
 
 #define ccb_accb_ptr spriv_ptr0
@@ -122,6 +125,22 @@ nvme_sim_nvmeio(struct cam_sim *sim, union ccb *ccb)
 	ccb->ccb_h.status |= CAM_SIM_QUEUED;
 }
 
+static uint32_t
+nvme_link_kBps(struct nvme_controller *ctrlr)
+{
+	uint32_t speed, lanes, link[] = { 1, 250000, 500000, 985000, 1970000 };
+
+	speed = pcie_link_status(ctrlr->dev) & PCIEM_LINK_STA_SPEED;
+	lanes = (pcie_link_status(ctrlr->dev) & PCIEM_LINK_STA_WIDTH) >> 4;
+	/*
+	 * Failsafe on link speed indicator. If it is insane report the number of
+	 * lanes as the speed. Not 100% accurate, but may be diagnostic.
+	 */
+	if (speed >= nitems(link))
+		speed = 0;
+	return link[speed] * lanes;
+}
+
 static void
 nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
 {
@@ -179,15 +198,15 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
 		cpi->maxio = nvme_ns_get_max_io_xfer_size(ns);
 		cpi->initiator_id = 0;
 		cpi->bus_id = cam_sim_bus(sim);
-		cpi->base_transfer_speed = 4000000;	/* 4 GB/s 4 lanes pcie 3 */
+		cpi->base_transfer_speed = nvme_link_kBps(ctrlr);
 		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
 		strlcpy(cpi->hba_vid, "NVMe", HBA_IDLEN);
 		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
 		cpi->unit_number = cam_sim_unit(sim);
 		cpi->transport = XPORT_NVME;		/* XXX XPORT_PCIE ? */
-		cpi->transport_version = 1;		/* XXX Get PCIe spec ? */
+		cpi->transport_version = nvme_mmio_read_4(ctrlr, vs);
 		cpi->protocol = PROTO_NVME;
-		cpi->protocol_version = NVME_REV_1;	/* Groks all 1.x NVMe cards */
+		cpi->protocol_version = nvme_mmio_read_4(ctrlr, vs);
 		cpi->xport_specific.nvme.nsid = ns->id;
 		cpi->ccb_h.status = CAM_REQ_CMP;
 		break;
@@ -197,20 +216,24 @@ nvme_sim_action(struct cam_sim *sim, union ccb *ccb)
 		struct ccb_trans_settings	*cts;
 		struct ccb_trans_settings_nvme	*nvmep;
 		struct ccb_trans_settings_nvme	*nvmex;
+		device_t dev;
 
+		dev = ctrlr->dev;
 		cts = &ccb->cts;
 		nvmex = &cts->xport_specific.nvme;
 		nvmep = &cts->proto_specific.nvme;
 
-		nvmex->valid = CTS_NVME_VALID_SPEC;
-		nvmex->spec_major = 1;			/* XXX read from card */
-		nvmex->spec_minor = 2;
-		nvmex->spec_tiny = 0;
+		nvmex->valid = CTS_NVME_VALID_SPEC | CTS_NVME_VALID_LINK;
+		nvmex->spec = nvme_mmio_read_4(ctrlr, vs);
+		nvmex->speed = pcie_link_status(dev) & PCIEM_LINK_STA_SPEED;
+		nvmex->lanes = (pcie_link_status(dev) & PCIEM_LINK_STA_WIDTH) >> 4;
+		nvmex->max_speed = pcie_link_caps(dev) & PCIEM_LINK_CAP_MAX_SPEED;
+		nvmex->max_lanes = (pcie_link_caps(dev) & PCIEM_LINK_CAP_MAX_WIDTH) >> 4;
 
-		nvmep->valid = CTS_NVME_VALID_SPEC;
-		nvmep->spec_major = 1;			/* XXX read from card */
-		nvmep->spec_minor = 2;
-		nvmep->spec_tiny = 0;
+		/* XXX these should be something else maybe ? */
+		nvmep->valid = 1;
+		nvmep->spec = nvmex->spec;
+
 		cts->transport = XPORT_NVME;
 		cts->protocol = PROTO_NVME;
 		cts->ccb_h.status = CAM_REQ_CMP;


More information about the svn-src-head mailing list