Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Sep 2017 01:51:27 +0000 (UTC)
From:      Scott Long <scottl@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r323412 - in head/sys/dev: mpr mps
Message-ID:  <201709110151.v8B1pRQR053947@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: scottl
Date: Mon Sep 11 01:51:27 2017
New Revision: 323412
URL: https://svnweb.freebsd.org/changeset/base/323412

Log:
  Add infrastructure for allocating multiple MSI-X interrupts.  Also
  add more fine-tuned controls for allocating requests and replies.
  
  Sponsored by:	Netflix

Modified:
  head/sys/dev/mpr/mpr.c
  head/sys/dev/mpr/mpr_pci.c
  head/sys/dev/mpr/mpr_sas.c
  head/sys/dev/mpr/mprvar.h
  head/sys/dev/mps/mps.c
  head/sys/dev/mps/mps_pci.c
  head/sys/dev/mps/mps_sas.c
  head/sys/dev/mps/mpsvar.h

Modified: head/sys/dev/mpr/mpr.c
==============================================================================
--- head/sys/dev/mpr/mpr.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mpr/mpr.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$");
 
 static int mpr_diag_reset(struct mpr_softc *sc, int sleep_flag);
 static int mpr_init_queues(struct mpr_softc *sc);
+static void mpr_resize_queues(struct mpr_softc *sc);
 static int mpr_message_unit_reset(struct mpr_softc *sc, int sleep_flag);
 static int mpr_transition_operational(struct mpr_softc *sc);
 static int mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t attaching);
@@ -374,6 +375,46 @@ mpr_transition_operational(struct mpr_softc *sc)
 	return (error);
 }
 
+static void
+mpr_resize_queues(struct mpr_softc *sc)
+{
+	int reqcr, prireqcr;
+
+	/*
+	 * Size the queues. Since the reply queues always need one free
+	 * entry, we'll deduct one reply message here.  The LSI documents
+	 * suggest instead to add a count to the request queue, but I think
+	 * that it's better to deduct from reply queue.
+	 */
+	prireqcr = MAX(1, sc->max_prireqframes);
+	prireqcr = MIN(prireqcr, sc->facts->HighPriorityCredit);
+
+	reqcr = MAX(2, sc->max_reqframes);
+	reqcr = MIN(reqcr, sc->facts->RequestCredit);
+
+	sc->num_reqs = prireqcr + reqcr;
+	sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes,
+	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+
+	/*
+	 * Figure out the number of MSIx-based queues.  If the firmware or
+	 * user has done something crazy and not allowed enough credit for
+	 * the queues to be useful then don't enable multi-queue.
+	 */
+	if (sc->facts->MaxMSIxVectors < 2)
+		sc->msi_msgs = 1;
+
+	if (sc->msi_msgs > 1) {
+		sc->msi_msgs = MIN(sc->msi_msgs, mp_ncpus);
+		sc->msi_msgs = MIN(sc->msi_msgs, sc->facts->MaxMSIxVectors);
+		if (sc->num_reqs / sc->msi_msgs < 2)
+			sc->msi_msgs = 1;
+	}
+
+	mpr_dprint(sc, MPR_INIT, "Sized queues to q=%d reqs=%d replies=%d\n",
+	    sc->msi_msgs, sc->num_reqs, sc->num_replies);
+}
+
 /*
  * This is called during attach and when re-initializing due to a Diag Reset.
  * IOC Facts is used to allocate many of the structures needed by the driver.
@@ -530,13 +571,7 @@ mpr_iocfacts_allocate(struct mpr_softc *sc, uint8_t at
 		    MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ)
 			sc->atomic_desc_capable = TRUE;
 
-		/*
-		 * Size the queues. Since the reply queues always need one free
-		 * entry, we'll just deduct one reply message here.
-		 */
-		sc->num_reqs = MIN(MPR_REQ_FRAMES, sc->facts->RequestCredit);
-		sc->num_replies = MIN(MPR_REPLY_FRAMES + MPR_EVT_REPLY_FRAMES,
-		    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+		mpr_resize_queues(sc);
 
 		/*
 		 * Initialize all Tail Queues
@@ -1146,11 +1181,11 @@ mpr_alloc_queues(struct mpr_softc *sc)
 	struct mpr_queue *q;
 	int nq, i;
 
-	nq = MIN(sc->msi_msgs, mp_ncpus);
-	sc->msi_msgs = nq;
+	nq = sc->msi_msgs;
 	mpr_dprint(sc, MPR_INIT|MPR_XINFO, "Allocating %d I/O queues\n", nq);
 
-	sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR, M_NOWAIT|M_ZERO);
+	sc->queues = malloc(sizeof(struct mpr_queue) * nq, M_MPR,
+	     M_NOWAIT|M_ZERO);
 	if (sc->queues == NULL)
 		return (ENOMEM);
 
@@ -1562,11 +1597,16 @@ mpr_get_tunables(struct mpr_softc *sc)
 	sc->mpr_debug = MPR_INFO | MPR_FAULT;
 	sc->disable_msix = 0;
 	sc->disable_msi = 0;
+	sc->max_msix = MPR_MSIX_MAX;
 	sc->max_chains = MPR_CHAIN_FRAMES;
 	sc->max_io_pages = MPR_MAXIO_PAGES;
 	sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD;
 	sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
 	sc->use_phynum = 1;
+	sc->max_reqframes = MPR_REQ_FRAMES;
+	sc->max_prireqframes = MPR_PRI_REQ_FRAMES;
+	sc->max_replyframes = MPR_REPLY_FRAMES;
+	sc->max_evtframes = MPR_EVT_REPLY_FRAMES;
 
 	/*
 	 * Grab the global variables.
@@ -1574,11 +1614,16 @@ mpr_get_tunables(struct mpr_softc *sc)
 	TUNABLE_INT_FETCH("hw.mpr.debug_level", &sc->mpr_debug);
 	TUNABLE_INT_FETCH("hw.mpr.disable_msix", &sc->disable_msix);
 	TUNABLE_INT_FETCH("hw.mpr.disable_msi", &sc->disable_msi);
+	TUNABLE_INT_FETCH("hw.mpr.max_msix", &sc->max_msix);
 	TUNABLE_INT_FETCH("hw.mpr.max_chains", &sc->max_chains);
 	TUNABLE_INT_FETCH("hw.mpr.max_io_pages", &sc->max_io_pages);
 	TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu);
 	TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time);
 	TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum);
+	TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes);
+	TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes);
+	TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes);
+	TUNABLE_INT_FETCH("hw.mpr.max_evtframes", &sc->max_evtframes);
 
 	/* Grab the unit-instance variables */
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.debug_level",
@@ -1593,6 +1638,10 @@ mpr_get_tunables(struct mpr_softc *sc)
 	    device_get_unit(sc->mpr_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi);
 
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_msix",
+	    device_get_unit(sc->mpr_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_msix);
+
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_chains",
 	    device_get_unit(sc->mpr_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
@@ -1617,6 +1666,22 @@ mpr_get_tunables(struct mpr_softc *sc)
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.use_phy_num",
 	    device_get_unit(sc->mpr_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes",
+	    device_get_unit(sc->mpr_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_prireqframes",
+	    device_get_unit(sc->mpr_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_prireqframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_replyframes",
+	    device_get_unit(sc->mpr_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_replyframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_evtframes",
+	    device_get_unit(sc->mpr_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_evtframes);
 }
 
 static void
@@ -1658,8 +1723,28 @@ mpr_setup_sysctl(struct mpr_softc *sc)
 	    "Disable the use of MSI-X interrupts");
 
 	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
-	    OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0,
-	    "Disable the use of MSI interrupts");
+	    OID_AUTO, "max_msix", CTLFLAG_RD, &sc->max_msix, 0,
+	    "User-defined maximum number of MSIX queues");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "msix_msgs", CTLFLAG_RD, &sc->msi_msgs, 0,
+	    "Negotiated number of MSIX queues");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_reqframes", CTLFLAG_RD, &sc->max_reqframes, 0,
+	    "Total number of allocated request frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_prireqframes", CTLFLAG_RD, &sc->max_prireqframes, 0,
+	    "Total number of allocated high priority request frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_replyframes", CTLFLAG_RD, &sc->max_replyframes, 0,
+	    "Total number of allocated reply frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_evtframes", CTLFLAG_RD, &sc->max_evtframes, 0,
+	    "Total number of event frames allocated");
 
 	SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
 	    OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version,

Modified: head/sys/dev/mpr/mpr_pci.c
==============================================================================
--- head/sys/dev/mpr/mpr_pci.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mpr/mpr_pci.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -262,23 +262,38 @@ mpr_pci_alloc_interrupts(struct mpr_softc *sc)
 	error = 0;
 	msgs = 0;
 
-	if ((sc->disable_msix == 0) &&
-	    ((msgs = pci_msix_count(dev)) >= MPR_MSI_COUNT))
-		error = mpr_alloc_msix(sc, MPR_MSI_COUNT);
-	if ((error != 0) && (sc->disable_msi == 0) &&
-	    ((msgs = pci_msi_count(dev)) >= MPR_MSI_COUNT))
-		error = mpr_alloc_msi(sc, MPR_MSI_COUNT);
-	if (error != 0) {
+	if (sc->disable_msix == 0) {
+		msgs = pci_msix_count(dev);
+		mpr_dprint(sc, MPR_INIT, "Counted %d MSI-X messages\n", msgs);
+		msgs = min(msgs, sc->max_msix);
+		msgs = min(msgs, MPR_MSIX_MAX);
+		msgs = min(msgs, 1);	/* XXX */
+		if (msgs != 0) {
+			mpr_dprint(sc, MPR_INIT, "Attempting to allocate %d MSI-X "
+			    "messages\n", msgs);
+			error = mpr_alloc_msix(sc, msgs);
+		}
+	}
+	if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) {
+		msgs = pci_msi_count(dev);
+		mpr_dprint(sc, MPR_INIT, "Counted %d MSI messages\n", msgs);
+		msgs = min(msgs, MPR_MSI_MAX);
+		if (msgs != 0) {
+			mpr_dprint(sc, MPR_INIT, "Attempting to allocated %d MSI "
+			    "messages\n", MPR_MSI_MAX);
+			error = mpr_alloc_msi(sc, MPR_MSI_MAX);
+		}
+	}
+	if ((error != 0) || (msgs == 0)) {
 		/*
 		 * If neither MSI or MSI-X are available, assume legacy INTx.
 		 * This also implies that there will be only 1 queue.
 		 */
+		mpr_dprint(sc, MPR_INIT, "Falling back to legacy INTx\n");
 		sc->mpr_flags |= MPR_FLAGS_INTX;
 		msgs = 1;
-	} else {
+	} else
 		sc->mpr_flags |= MPR_FLAGS_MSI;
-		msgs = MPR_MSI_COUNT;	/* XXX */
-	}
 
 	sc->msi_msgs = msgs;
 	mpr_dprint(sc, MPR_INIT, "Allocated %d interrupts\n", msgs);
@@ -318,6 +333,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc)
 		if (q->irq == NULL) {
 			mpr_dprint(sc, MPR_ERROR|MPR_INIT,
 			    "Cannot allocate interrupt RID %d\n", rid);
+			sc->msi_msgs = i;
 			break;
 		}
 		error = bus_setup_intr(dev, q->irq,
@@ -326,6 +342,7 @@ mpr_pci_setup_interrupts(struct mpr_softc *sc)
 		if (error) {
 			mpr_dprint(sc, MPR_ERROR|MPR_INIT,
 			    "Cannot setup interrupt RID %d\n", rid);
+			sc->msi_msgs = i;
 			break;
 		}
 	}

Modified: head/sys/dev/mpr/mpr_sas.c
==============================================================================
--- head/sys/dev/mpr/mpr_sas.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mpr/mpr_sas.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -924,6 +924,9 @@ mpr_detach_sas(struct mpr_softc *sc)
 	/* Make sure CAM doesn't wedge if we had to bail out early. */
 	mpr_lock(sc);
 
+	while (sassc->startup_refcount != 0)
+		mprsas_startup_decrement(sassc);
+
 	/* Deregister our async handler */
 	if (sassc->path != NULL) {
 		xpt_register_async(0, mprsas_async, sc, sassc->path);

Modified: head/sys/dev/mpr/mprvar.h
==============================================================================
--- head/sys/dev/mpr/mprvar.h	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mpr/mprvar.h	Mon Sep 11 01:51:27 2017	(r323412)
@@ -37,13 +37,15 @@
 
 #define MPR_DB_MAX_WAIT		2500
 
-#define MPR_REQ_FRAMES		1024
+#define MPR_REQ_FRAMES		2048
+#define MPR_PRI_REQ_FRAMES	128
 #define MPR_EVT_REPLY_FRAMES	32
 #define MPR_REPLY_FRAMES	MPR_REQ_FRAMES
 #define MPR_CHAIN_FRAMES	2048
 #define MPR_MAXIO_PAGES		(-1)
 #define MPR_SENSE_LEN		SSD_FULL_SIZE
-#define MPR_MSI_COUNT		1
+#define MPR_MSI_MAX		1
+#define MPR_MSIX_MAX		96
 #define MPR_SGE64_SIZE		12
 #define MPR_SGE32_SIZE		8
 #define MPR_SGC_SIZE		8
@@ -296,8 +298,6 @@ struct mpr_softc {
 #define	MPR_FLAGS_GEN35_IOC	(1 << 6)
 #define	MPR_FLAGS_REALLOCATED	(1 << 7)
 	u_int				mpr_debug;
-	u_int				disable_msix;
-	u_int				disable_msi;
 	int				msi_msgs;
 	u_int				atomic_desc_capable;
 	int				tm_cmds_active;
@@ -446,7 +446,16 @@ struct mpr_softc {
 	uint32_t			SSU_refcount;
 	uint8_t				SSU_started;
 
+	/* Configuration tunables */
+	u_int				disable_msix;
+	u_int				disable_msi;
+	u_int				max_msix;
+	u_int				max_reqframes;
+	u_int				max_prireqframes;
+	u_int				max_replyframes;
+	u_int				max_evtframes;
 	char				exclude_ids[80];
+
 	struct timeval			lastfail;
 };
 

Modified: head/sys/dev/mps/mps.c
==============================================================================
--- head/sys/dev/mps/mps.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mps/mps.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$");
 
 static int mps_diag_reset(struct mps_softc *sc, int sleep_flag);
 static int mps_init_queues(struct mps_softc *sc);
+static void mps_resize_queues(struct mps_softc *sc);
 static int mps_message_unit_reset(struct mps_softc *sc, int sleep_flag);
 static int mps_transition_operational(struct mps_softc *sc);
 static int mps_iocfacts_allocate(struct mps_softc *sc, uint8_t attaching);
@@ -368,6 +369,46 @@ mps_transition_operational(struct mps_softc *sc)
 	return (error);
 }
 
+static void
+mps_resize_queues(struct mps_softc *sc)
+{
+	int reqcr, prireqcr;
+ 
+	/*
+	 * Size the queues. Since the reply queues always need one free
+	 * entry, we'll deduct one reply message here.  The LSI documents
+	 * suggest instead to add a count to the request queue, but I think
+	 * that it's better to deduct from reply queue.
+	 */
+	prireqcr = MAX(1, sc->max_prireqframes);
+	prireqcr = MIN(prireqcr, sc->facts->HighPriorityCredit);
+
+	reqcr = MAX(2, sc->max_reqframes);
+	reqcr = MIN(reqcr, sc->facts->RequestCredit);
+
+	sc->num_reqs = prireqcr + reqcr;
+	sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes,
+	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+
+	/*
+	 * Figure out the number of MSIx-based queues.  If the firmware or
+	 * user has done something crazy and not allowed enough credit for
+	 * the queues to be useful then don't enable multi-queue.
+	 */
+	if (sc->facts->MaxMSIxVectors < 2)
+		sc->msi_msgs = 1;
+
+	if (sc->msi_msgs > 1) {
+		sc->msi_msgs = MIN(sc->msi_msgs, mp_ncpus);
+		sc->msi_msgs = MIN(sc->msi_msgs, sc->facts->MaxMSIxVectors);
+		if (sc->num_reqs / sc->msi_msgs < 2)
+			sc->msi_msgs = 1;
+	}
+
+	mps_dprint(sc, MPS_INIT, "Sized queues to q=%d reqs=%d replies=%d\n",
+	    sc->msi_msgs, sc->num_reqs, sc->num_replies);
+}
+
 /*
  * This is called during attach and when re-initializing due to a Diag Reset.
  * IOC Facts is used to allocate many of the structures needed by the driver.
@@ -518,13 +559,7 @@ mps_iocfacts_allocate(struct mps_softc *sc, uint8_t at
 		if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
 			sc->control_TLR = TRUE;
 
-		/*
-		 * Size the queues. Since the reply queues always need one free
-		 * entry, we'll just deduct one reply message here.
-		 */
-		sc->num_reqs = MIN(MPS_REQ_FRAMES, sc->facts->RequestCredit);
-		sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES,
-		    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
+		mps_resize_queues(sc);
 
 		/*
 		 * Initialize all Tail Queues
@@ -1121,11 +1156,11 @@ mps_alloc_queues(struct mps_softc *sc)
 	struct mps_queue *q;
 	int nq, i;
 
-	nq = MIN(sc->msi_msgs, mp_ncpus);
-	sc->msi_msgs = nq;
+	nq = sc->msi_msgs;
 	mps_dprint(sc, MPS_INIT|MPS_XINFO, "Allocating %d I/O queues\n", nq);
 
-	sc->queues = malloc(sizeof(struct mps_queue) * nq, M_MPT2, M_NOWAIT|M_ZERO);
+	sc->queues = malloc(sizeof(struct mps_queue) * nq, M_MPT2,
+	    M_NOWAIT|M_ZERO);
 	if (sc->queues == NULL)
 		return (ENOMEM);
 
@@ -1423,11 +1458,16 @@ mps_get_tunables(struct mps_softc *sc)
 	sc->mps_debug = MPS_INFO|MPS_FAULT;
 	sc->disable_msix = 0;
 	sc->disable_msi = 0;
+	sc->max_msix = MPS_MSIX_MAX;
 	sc->max_chains = MPS_CHAIN_FRAMES;
 	sc->max_io_pages = MPS_MAXIO_PAGES;
 	sc->enable_ssu = MPS_SSU_ENABLE_SSD_DISABLE_HDD;
 	sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
 	sc->use_phynum = 1;
+	sc->max_reqframes = MPS_REQ_FRAMES;
+	sc->max_prireqframes = MPS_PRI_REQ_FRAMES;
+	sc->max_replyframes = MPS_REPLY_FRAMES;
+	sc->max_evtframes = MPS_EVT_REPLY_FRAMES;
 
 	/*
 	 * Grab the global variables.
@@ -1435,11 +1475,16 @@ mps_get_tunables(struct mps_softc *sc)
 	TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug);
 	TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix);
 	TUNABLE_INT_FETCH("hw.mps.disable_msi", &sc->disable_msi);
+	TUNABLE_INT_FETCH("hw.mps.max_msix", &sc->max_msix);
 	TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains);
 	TUNABLE_INT_FETCH("hw.mps.max_io_pages", &sc->max_io_pages);
 	TUNABLE_INT_FETCH("hw.mps.enable_ssu", &sc->enable_ssu);
 	TUNABLE_INT_FETCH("hw.mps.spinup_wait_time", &sc->spinup_wait_time);
 	TUNABLE_INT_FETCH("hw.mps.use_phy_num", &sc->use_phynum);
+	TUNABLE_INT_FETCH("hw.mps.max_reqframes", &sc->max_reqframes);
+	TUNABLE_INT_FETCH("hw.mps.max_prireqframes", &sc->max_prireqframes);
+	TUNABLE_INT_FETCH("hw.mps.max_replyframes", &sc->max_replyframes);
+	TUNABLE_INT_FETCH("hw.mps.max_evtframes", &sc->max_evtframes);
 
 	/* Grab the unit-instance variables */
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level",
@@ -1454,6 +1499,10 @@ mps_get_tunables(struct mps_softc *sc)
 	    device_get_unit(sc->mps_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->disable_msi);
 
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_msix",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_msix);
+
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains",
 	    device_get_unit(sc->mps_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
@@ -1478,6 +1527,23 @@ mps_get_tunables(struct mps_softc *sc)
 	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.use_phy_num",
 	    device_get_unit(sc->mps_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_reqframes",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_prireqframes",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_prireqframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_replyframes",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_replyframes);
+
+	snprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_evtframes",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->max_evtframes);
+
 }
 
 static void
@@ -1521,6 +1587,30 @@ mps_setup_sysctl(struct mps_softc *sc)
 	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
 	    OID_AUTO, "disable_msi", CTLFLAG_RD, &sc->disable_msi, 0,
 	    "Disable the use of MSI interrupts");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_msix", CTLFLAG_RD, &sc->max_msix, 0,
+	    "User-defined maximum number of MSIX queues");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "msix_msgs", CTLFLAG_RD, &sc->msi_msgs, 0,
+	    "Negotiated number of MSIX queues");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_reqframes", CTLFLAG_RD, &sc->max_reqframes, 0,
+	    "Total number of allocated request frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_prireqframes", CTLFLAG_RD, &sc->max_prireqframes, 0,
+	    "Total number of allocated high priority request frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_replyframes", CTLFLAG_RD, &sc->max_replyframes, 0,
+	    "Total number of allocated reply frames");
+
+	SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+	    OID_AUTO, "max_evtframes", CTLFLAG_RD, &sc->max_evtframes, 0,
+	    "Total number of event frames allocated");
 
 	SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
 	    OID_AUTO, "firmware_version", CTLFLAG_RW, sc->fw_version,

Modified: head/sys/dev/mps/mps_pci.c
==============================================================================
--- head/sys/dev/mps/mps_pci.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mps/mps_pci.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -247,23 +247,38 @@ mps_pci_alloc_interrupts(struct mps_softc *sc)
 	error = 0;
 	msgs = 0;
 
-	if ((sc->disable_msix == 0) &&
-	    ((msgs = pci_msix_count(dev)) >= MPS_MSI_COUNT))
-		error = mps_alloc_msix(sc, MPS_MSI_COUNT);
-	if ((error != 0) && (sc->disable_msi == 0) &&
-	    ((msgs = pci_msi_count(dev)) >= MPS_MSI_COUNT))
-		error = mps_alloc_msi(sc, MPS_MSI_COUNT);
-	if (error != 0) {
+	if (sc->disable_msix == 0) {
+		msgs = pci_msix_count(dev);
+		mps_dprint(sc, MPS_INIT, "Counted %d MSI-X messages\n", msgs);
+		msgs = min(msgs, sc->max_msix);
+		msgs = min(msgs, MPS_MSIX_MAX);
+		msgs = min(msgs, 1);	/* XXX */
+		if (msgs != 0) {
+			mps_dprint(sc, MPS_INIT, "Attempting to allocate %d MSI-X "
+			    "messages\n", msgs);
+			error = mps_alloc_msix(sc, msgs);
+		}
+	}
+	if (((error != 0) || (msgs == 0)) && (sc->disable_msi == 0)) {
+		msgs = pci_msi_count(dev);
+		mps_dprint(sc, MPS_INIT, "Counted %d MSI messages\n", msgs);
+		msgs = min(msgs, MPS_MSI_MAX);
+		if (msgs != 0) {
+			mps_dprint(sc, MPS_INIT, "Attempting to allocate %d MSI "
+			    "messages\n", MPS_MSI_MAX);
+			error = mps_alloc_msi(sc, MPS_MSI_MAX);
+		}
+	}
+	if ((error != 0) || (msgs == 0)) {
 		/*
 		 * If neither MSI or MSI-X are avaiable, assume legacy INTx.
 		 * This also implies that there will be only 1 queue.
 		 */
+		mps_dprint(sc, MPS_INIT, "Falling back to legacy INTx\n");
 		sc->mps_flags |= MPS_FLAGS_INTX;
 		msgs = 1;
-	} else {
+	} else
 		sc->mps_flags |= MPS_FLAGS_MSI;
-		msgs = 1;	/* XXX */
-	}
 
 	sc->msi_msgs = msgs;
 	mps_dprint(sc, MPS_INIT, "Allocated %d interrupts\n", msgs);
@@ -302,7 +317,8 @@ mps_pci_setup_interrupts(struct mps_softc *sc)
 		    &q->irq_rid, RF_ACTIVE);
 		if (q->irq == NULL) {
 			mps_dprint(sc, MPS_ERROR|MPS_INIT,
-			    "Cannot allocate interrupt RID%d\n", rid);
+			    "Cannot allocate interrupt RID %d\n", rid);
+			sc->msi_msgs = i;
 			break;
 		}
 		error = bus_setup_intr(dev, q->irq,
@@ -311,6 +327,7 @@ mps_pci_setup_interrupts(struct mps_softc *sc)
 		if (error) {
 			mps_dprint(sc, MPS_ERROR|MPS_INIT,
 			    "Cannot setup interrupt RID %d\n", rid);
+			sc->msi_msgs = i;
 			break;
 		}
 	}

Modified: head/sys/dev/mps/mps_sas.c
==============================================================================
--- head/sys/dev/mps/mps_sas.c	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mps/mps_sas.c	Mon Sep 11 01:51:27 2017	(r323412)
@@ -871,6 +871,9 @@ mps_detach_sas(struct mps_softc *sc)
 	/* Make sure CAM doesn't wedge if we had to bail out early. */
 	mps_lock(sc);
 
+	while (sassc->startup_refcount != 0)
+		mpssas_startup_decrement(sassc);
+
 	/* Deregister our async handler */
 	if (sassc->path != NULL) {
 		xpt_register_async(0, mpssas_async, sc, sassc->path);

Modified: head/sys/dev/mps/mpsvar.h
==============================================================================
--- head/sys/dev/mps/mpsvar.h	Mon Sep 11 01:26:26 2017	(r323411)
+++ head/sys/dev/mps/mpsvar.h	Mon Sep 11 01:51:27 2017	(r323412)
@@ -37,13 +37,15 @@
 
 #define MPS_DB_MAX_WAIT		2500
 
-#define MPS_REQ_FRAMES		1024
+#define MPS_REQ_FRAMES		2048
+#define MPS_PRI_REQ_FRAMES	128
 #define MPS_EVT_REPLY_FRAMES	32
 #define MPS_REPLY_FRAMES	MPS_REQ_FRAMES
 #define MPS_CHAIN_FRAMES	2048
 #define MPS_MAXIO_PAGES		(-1)
 #define MPS_SENSE_LEN		SSD_FULL_SIZE
-#define MPS_MSI_COUNT		1
+#define MPS_MSI_MAX		1
+#define MPS_MSIX_MAX		16
 #define MPS_SGE64_SIZE		12
 #define MPS_SGE32_SIZE		8
 #define MPS_SGC_SIZE		8
@@ -292,8 +294,6 @@ struct mps_softc {
 #define	MPS_FLAGS_WD_AVAILABLE	(1 << 6)
 #define	MPS_FLAGS_REALLOCATED	(1 << 7)
 	u_int				mps_debug;
-	u_int				disable_msix;
-	u_int				disable_msi;
 	u_int				msi_msgs;
 	int				tm_cmds_active;
 	int				io_cmds_active;
@@ -437,12 +437,21 @@ struct mps_softc {
 	uint64_t			DD_max_lba;
 	struct mps_column_map		DD_column_map[MPS_MAX_DISKS_IN_VOL];
 
-	char				exclude_ids[80];
-	struct timeval			lastfail;
-
 	/* StartStopUnit command handling at shutdown */
 	uint32_t			SSU_refcount;
 	uint8_t				SSU_started;
+
+	/* Configuration tunables */
+	u_int				disable_msix;
+	u_int				disable_msi;
+	u_int				max_msix;
+	u_int				max_reqframes;
+	u_int				max_prireqframes;
+	u_int				max_replyframes;
+	u_int				max_evtframes;
+	char				exclude_ids[80];
+
+	struct timeval			lastfail;
 };
 
 struct mps_config_params {



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