Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Feb 2018 00:55:46 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r329096 - in head/sys/dev: mpr mps
Message-ID:  <201802100055.w1A0tkHg098637@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Feb 10 00:55:46 2018
New Revision: 329096
URL: https://svnweb.freebsd.org/changeset/base/329096

Log:
  Teach mps(4) and mpr(4) drivers to autotune chain frames.
  
  This is a first part of the change.  It makes the drivers to calculate
  the required number of chain frames to satisfy worst case scenarios, but
  it does not change existing overly strict limits on them.  The next step
  will be to rewrite the allocator to not require megabytes of physically
  contiguous address space, that may be problematic if done after boot,
  after doing which the limits can be removed.  Until that this code can
  just correct user set limits, if they are set too high.
  
  Sponsored by:	iXsystems, Inc.
  Differential Revision:	https://reviews.freebsd.org/D14261

Modified:
  head/sys/dev/mpr/mpr.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_sas.c
  head/sys/dev/mps/mpsvar.h

Modified: head/sys/dev/mpr/mpr.c
==============================================================================
--- head/sys/dev/mpr/mpr.c	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mpr/mpr.c	Sat Feb 10 00:55:46 2018	(r329096)
@@ -382,7 +382,7 @@ mpr_transition_operational(struct mpr_softc *sc)
 static void
 mpr_resize_queues(struct mpr_softc *sc)
 {
-	int reqcr, prireqcr;
+	u_int reqcr, prireqcr, maxio, sges_per_frame;
 
 	/*
 	 * Size the queues. Since the reply queues always need one free
@@ -401,7 +401,61 @@ mpr_resize_queues(struct mpr_softc *sc)
 	sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes,
 	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
 
+	/* Store the request frame size in bytes rather than as 32bit words */
+	sc->reqframesz = sc->facts->IOCRequestFrameSize * 4;
+
 	/*
+	 * Gen3 and beyond uses the IOCMaxChainSegmentSize from IOC Facts to
+	 * get the size of a Chain Frame.  Previous versions use the size as a
+	 * Request Frame for the Chain Frame size.  If IOCMaxChainSegmentSize
+	 * is 0, use the default value.  The IOCMaxChainSegmentSize is the
+	 * number of 16-byte elelements that can fit in a Chain Frame, which is
+	 * the size of an IEEE Simple SGE.
+	 */
+	if (sc->facts->MsgVersion >= MPI2_VERSION_02_05) {
+		sc->chain_seg_size =
+		    htole16(sc->facts->IOCMaxChainSegmentSize);
+		if (sc->chain_seg_size == 0) {
+			sc->chain_frame_size = MPR_DEFAULT_CHAIN_SEG_SIZE *
+			    MPR_MAX_CHAIN_ELEMENT_SIZE;
+		} else {
+			sc->chain_frame_size = sc->chain_seg_size *
+			    MPR_MAX_CHAIN_ELEMENT_SIZE;
+		}
+	} else {
+		sc->chain_frame_size = sc->reqframesz;
+	}
+
+	/*
+	 * Max IO Size is Page Size * the following:
+	 * ((SGEs per frame - 1 for chain element) * Max Chain Depth)
+	 * + 1 for no chain needed in last frame
+	 *
+	 * If user suggests a Max IO size to use, use the smaller of the
+	 * user's value and the calculated value as long as the user's
+	 * value is larger than 0. The user's value is in pages.
+	 */
+	sges_per_frame = sc->chain_frame_size/sizeof(MPI2_IEEE_SGE_SIMPLE64)-1;
+	maxio = (sges_per_frame * sc->facts->MaxChainDepth + 1) * PAGE_SIZE;
+
+	/*
+	 * If I/O size limitation requested then use it and pass up to CAM.
+	 * If not, use MAXPHYS as an optimization hint, but report HW limit.
+	 */
+	if (sc->max_io_pages > 0) {
+		maxio = min(maxio, sc->max_io_pages * PAGE_SIZE);
+		sc->maxio = maxio;
+	} else {
+		sc->maxio = maxio;
+		maxio = min(maxio, MAXPHYS);
+	}
+
+	sc->num_chains = (maxio / PAGE_SIZE + sges_per_frame - 2) /
+	    sges_per_frame * reqcr;
+	if (sc->max_chains > 0 && sc->max_chains < sc->num_chains)
+		sc->num_chains = sc->max_chains;
+
+	/*
 	 * 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.
@@ -1355,9 +1409,6 @@ mpr_alloc_requests(struct mpr_softc *sc)
 	struct mpr_chain *chain;
 	int i, rsize, nsegs;
 
-	/* Store the request frame size in bytes rather than as 32bit words */
-	sc->reqframesz = sc->facts->IOCRequestFrameSize * 4;
-
 	rsize = sc->reqframesz * sc->num_reqs;
         if (bus_dma_tag_create( sc->mpr_parent_dmat,    /* parent */
 				16, 0,			/* algnmnt, boundary */
@@ -1382,28 +1433,7 @@ mpr_alloc_requests(struct mpr_softc *sc)
         bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize,
 	    mpr_memaddr_cb, &sc->req_busaddr, 0);
 
-	/*
-	 * Gen3 and beyond uses the IOCMaxChainSegmentSize from IOC Facts to
-	 * get the size of a Chain Frame.  Previous versions use the size as a
-	 * Request Frame for the Chain Frame size.  If IOCMaxChainSegmentSize
-	 * is 0, use the default value.  The IOCMaxChainSegmentSize is the
-	 * number of 16-byte elelements that can fit in a Chain Frame, which is
-	 * the size of an IEEE Simple SGE.
-	 */
-	if (sc->facts->MsgVersion >= MPI2_VERSION_02_05) {
-		sc->chain_seg_size =
-		    htole16(sc->facts->IOCMaxChainSegmentSize);
-		if (sc->chain_seg_size == 0) {
-			sc->chain_frame_size = MPR_DEFAULT_CHAIN_SEG_SIZE *
-			    MPR_MAX_CHAIN_ELEMENT_SIZE;
-		} else {
-			sc->chain_frame_size = sc->chain_seg_size *
-			    MPR_MAX_CHAIN_ELEMENT_SIZE;
-		}
-	} else {
-		sc->chain_frame_size = sc->reqframesz;
-	}
-	rsize = sc->chain_frame_size * sc->max_chains;
+	rsize = sc->chain_frame_size * sc->num_chains;
         if (bus_dma_tag_create( sc->mpr_parent_dmat,    /* parent */
 				16, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR,	/* lowaddr */
@@ -1451,13 +1481,13 @@ mpr_alloc_requests(struct mpr_softc *sc)
         bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize,
 	    mpr_memaddr_cb, &sc->sense_busaddr, 0);
 
-	sc->chains = malloc(sizeof(struct mpr_chain) * sc->max_chains, M_MPR,
+	sc->chains = malloc(sizeof(struct mpr_chain) * sc->num_chains, M_MPR,
 	    M_WAITOK | M_ZERO);
 	if (!sc->chains) {
 		mpr_dprint(sc, MPR_ERROR, "Cannot allocate chain memory\n");
 		return (ENOMEM);
 	}
-	for (i = 0; i < sc->max_chains; i++) {
+	for (i = 0; i < sc->num_chains; i++) {
 		chain = &sc->chains[i];
 		chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames +
 		    i * sc->chain_frame_size);
@@ -1477,8 +1507,7 @@ mpr_alloc_requests(struct mpr_softc *sc)
 			return (ENOMEM);
 	}
 
-	/* XXX Need to pick a more precise value */
-	nsegs = (MAXPHYS / PAGE_SIZE) + 1;
+	nsegs = (sc->maxio / PAGE_SIZE) + 1;
         if (bus_dma_tag_create( sc->mpr_parent_dmat,    /* parent */
 				1, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR,	/* lowaddr */

Modified: head/sys/dev/mpr/mpr_sas.c
==============================================================================
--- head/sys/dev/mpr/mpr_sas.c	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mpr/mpr_sas.c	Sat Feb 10 00:55:46 2018	(r329096)
@@ -1009,7 +1009,6 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb)
 	{
 		struct ccb_pathinq *cpi = &ccb->cpi;
 		struct mpr_softc *sc = sassc->sc;
-		uint8_t sges_per_frame;
 
 		cpi->version_num = 1;
 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
@@ -1043,24 +1042,7 @@ mprsas_action(struct cam_sim *sim, union ccb *ccb)
 		cpi->transport_version = 0;
 		cpi->protocol = PROTO_SCSI;
 		cpi->protocol_version = SCSI_REV_SPC;
-
-		/*
-		 * Max IO Size is Page Size * the following:
-		 * ((SGEs per frame - 1 for chain element) *
-		 * Max Chain Depth) + 1 for no chain needed in last frame
-		 *
-		 * If user suggests a Max IO size to use, use the smaller of the
-		 * user's value and the calculated value as long as the user's
-		 * value is larger than 0. The user's value is in pages.
-		 */
-		sges_per_frame = (sc->chain_frame_size /
-		    sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1;
-		cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1;
-		cpi->maxio *= PAGE_SIZE;
-		if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
-		    cpi->maxio))
-			cpi->maxio = sc->max_io_pages * PAGE_SIZE;
-		sc->maxio = cpi->maxio;
+		cpi->maxio = sc->maxio;
 		mprsas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	}

Modified: head/sys/dev/mpr/mprvar.h
==============================================================================
--- head/sys/dev/mpr/mprvar.h	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mpr/mprvar.h	Sat Feb 10 00:55:46 2018	(r329096)
@@ -361,6 +361,7 @@ struct mpr_softc {
 	int				num_reqs;
 	int				num_prireqs;
 	int				num_replies;
+	int				num_chains;
 	int				fqdepth;	/* Free queue */
 	int				pqdepth;	/* Post queue */
 

Modified: head/sys/dev/mps/mps.c
==============================================================================
--- head/sys/dev/mps/mps.c	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mps/mps.c	Sat Feb 10 00:55:46 2018	(r329096)
@@ -379,8 +379,8 @@ mps_transition_operational(struct mps_softc *sc)
 static void
 mps_resize_queues(struct mps_softc *sc)
 {
-	int reqcr, prireqcr;
- 
+	u_int reqcr, prireqcr, maxio, sges_per_frame;
+
 	/*
 	 * Size the queues. Since the reply queues always need one free
 	 * entry, we'll deduct one reply message here.  The LSI documents
@@ -398,7 +398,39 @@ mps_resize_queues(struct mps_softc *sc)
 	sc->num_replies = MIN(sc->max_replyframes + sc->max_evtframes,
 	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
 
+	/* Store the request frame size in bytes rather than as 32bit words */
+	sc->reqframesz = sc->facts->IOCRequestFrameSize * 4;
+
 	/*
+	 * Max IO Size is Page Size * the following:
+	 * ((SGEs per frame - 1 for chain element) * Max Chain Depth)
+	 * + 1 for no chain needed in last frame
+	 *
+	 * If user suggests a Max IO size to use, use the smaller of the
+	 * user's value and the calculated value as long as the user's
+	 * value is larger than 0. The user's value is in pages.
+	 */
+	sges_per_frame = sc->reqframesz / sizeof(MPI2_SGE_SIMPLE64) - 1;
+	maxio = (sges_per_frame * sc->facts->MaxChainDepth + 1) * PAGE_SIZE;
+
+	/*
+	 * If I/O size limitation requested, then use it and pass up to CAM.
+	 * If not, use MAXPHYS as an optimization hint, but report HW limit.
+	 */
+	if (sc->max_io_pages > 0) {
+		maxio = min(maxio, sc->max_io_pages * PAGE_SIZE);
+		sc->maxio = maxio;
+	} else {
+		sc->maxio = maxio;
+		maxio = min(maxio, MAXPHYS);
+	}
+
+	sc->num_chains = (maxio / PAGE_SIZE + sges_per_frame - 2) /
+	    sges_per_frame * reqcr;
+	if (sc->max_chains > 0 && sc->max_chains < sc->num_chains)
+		sc->num_chains = sc->max_chains;
+
+	/*
 	 * 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.
@@ -1334,9 +1366,6 @@ mps_alloc_requests(struct mps_softc *sc)
 	struct mps_chain *chain;
 	int i, rsize, nsegs;
 
-	/* Store the request frame size in bytes rather than as 32bit words */
-	sc->reqframesz = sc->facts->IOCRequestFrameSize * 4;
-
 	rsize = sc->reqframesz * sc->num_reqs;
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 				16, 0,			/* algnmnt, boundary */
@@ -1361,7 +1390,7 @@ mps_alloc_requests(struct mps_softc *sc)
         bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize,
 	    mps_memaddr_cb, &sc->req_busaddr, 0);
 
-	rsize = sc->reqframesz * sc->max_chains;
+	rsize = sc->reqframesz * sc->num_chains;
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 				16, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -1409,13 +1438,13 @@ mps_alloc_requests(struct mps_softc *sc)
         bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize,
 	    mps_memaddr_cb, &sc->sense_busaddr, 0);
 
-	sc->chains = malloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2,
+	sc->chains = malloc(sizeof(struct mps_chain) * sc->num_chains, M_MPT2,
 	    M_WAITOK | M_ZERO);
 	if(!sc->chains) {
 		mps_dprint(sc, MPS_ERROR, "Cannot allocate chains memory\n");
 		return (ENOMEM);
 	}
-	for (i = 0; i < sc->max_chains; i++) {
+	for (i = 0; i < sc->num_chains; i++) {
 		chain = &sc->chains[i];
 		chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames +
 		    i * sc->reqframesz);
@@ -1425,8 +1454,7 @@ mps_alloc_requests(struct mps_softc *sc)
 		sc->chain_free_lowwater++;
 	}
 
-	/* XXX Need to pick a more precise value */
-	nsegs = (MAXPHYS / PAGE_SIZE) + 1;
+	nsegs = (sc->maxio / PAGE_SIZE) + 1;
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 				1, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR,	/* lowaddr */

Modified: head/sys/dev/mps/mps_sas.c
==============================================================================
--- head/sys/dev/mps/mps_sas.c	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mps/mps_sas.c	Sat Feb 10 00:55:46 2018	(r329096)
@@ -958,7 +958,6 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb)
 	{
 		struct ccb_pathinq *cpi = &ccb->cpi;
 		struct mps_softc *sc = sassc->sc;
-		uint8_t sges_per_frame;
 
 		cpi->version_num = 1;
 		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
@@ -987,23 +986,7 @@ mpssas_action(struct cam_sim *sim, union ccb *ccb)
 		cpi->transport_version = 0;
 		cpi->protocol = PROTO_SCSI;
 		cpi->protocol_version = SCSI_REV_SPC;
-
-		/*
-		 * Max IO Size is Page Size * the following:
-		 * ((SGEs per frame - 1 for chain element) *
-		 * Max Chain Depth) + 1 for no chain needed in last frame
-		 *
-		 * If user suggests a Max IO size to use, use the smaller of the
-		 * user's value and the calculated value as long as the user's
-		 * value is larger than 0. The user's value is in pages.
-		 */
-		sges_per_frame = ((sc->reqframesz) /
-		    sizeof(MPI2_SGE_SIMPLE64)) - 1;
-		cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1;
-		cpi->maxio *= PAGE_SIZE;
-		if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE <
-		    cpi->maxio))
-			cpi->maxio = sc->max_io_pages * PAGE_SIZE;
+		cpi->maxio = sc->maxio;
 		mpssas_set_ccbstatus(ccb, CAM_REQ_CMP);
 		break;
 	}

Modified: head/sys/dev/mps/mpsvar.h
==============================================================================
--- head/sys/dev/mps/mpsvar.h	Sat Feb 10 00:39:34 2018	(r329095)
+++ head/sys/dev/mps/mpsvar.h	Sat Feb 10 00:55:46 2018	(r329096)
@@ -315,6 +315,7 @@ struct mps_softc {
 	int				chain_free;
 	int				max_chains;
 	int				max_io_pages;
+	u_int				maxio;
 	int				chain_free_lowwater;
 	u_int				enable_ssu;
 	int				spinup_wait_time;
@@ -349,6 +350,7 @@ struct mps_softc {
 	int				num_reqs;
 	int				num_prireqs;
 	int				num_replies;
+	int				num_chains;
 	int				fqdepth;	/* Free queue */
 	int				pqdepth;	/* Post queue */
 



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