svn commit: r213839 - head/sys/dev/mps

Matthew D Fleming mdf at FreeBSD.org
Thu Oct 14 16:44:06 UTC 2010


Author: mdf
Date: Thu Oct 14 16:44:05 2010
New Revision: 213839
URL: http://svn.freebsd.org/changeset/base/213839

Log:
  Re-work the internals of adding items to the driver's scatter-gather
  list.  Use the new internals to simplify adding transaction context
  elements, and in future diffs, more complicated SGLs.

Modified:
  head/sys/dev/mps/mps.c
  head/sys/dev/mps/mps_user.c
  head/sys/dev/mps/mpsvar.h

Modified: head/sys/dev/mps/mps.c
==============================================================================
--- head/sys/dev/mps/mps.c	Thu Oct 14 15:42:32 2010	(r213838)
+++ head/sys/dev/mps/mps.c	Thu Oct 14 16:44:05 2010	(r213839)
@@ -380,7 +380,7 @@ mps_request_sync(struct mps_softc *sc, v
 	return (0);
 }
 
-static void
+void
 mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm)
 {
 
@@ -1374,33 +1374,88 @@ mps_deregister_events(struct mps_softc *
 	return (mps_update_events(sc, NULL, NULL));
 }
 
-static void
-mps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+/*
+ * Add a chain element as the next SGE for the specified command.
+ * Reset cm_sge and cm_sgesize to indicate all the available space.
+ */
+static int
+mps_add_chain(struct mps_command *cm)
 {
-	MPI2_SGE_SIMPLE64 *sge;
 	MPI2_SGE_CHAIN32 *sgc;
-	struct mps_softc *sc;
-	struct mps_command *cm;
 	struct mps_chain *chain;
-	u_int i, segsleft, sglspace, dir, flags, sflags;
+	int space;
 
-	cm = (struct mps_command *)arg;
-	sc = cm->cm_sc;
+	if (cm->cm_sglsize < MPS_SGC_SIZE)
+		panic("MPS: Need SGE Error Code\n");
 
-        segsleft = nsegs;
-        sglspace = cm->cm_sglsize;
-        sge = (MPI2_SGE_SIMPLE64 *)&cm->cm_sge->MpiSimple;
+	chain = mps_alloc_chain(cm->cm_sc);
+	if (chain == NULL)
+		return (ENOBUFS);
+
+	space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
 
 	/*
-	 * Set up DMA direction flags.  Note no support for
-	 * bi-directional transactions.
+	 * Note: a double-linked list is used to make it easier to
+	 * walk for debugging.
 	 */
-        sflags = MPI2_SGE_FLAGS_ADDRESS_SIZE;
-        if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) {
-                sflags |= MPI2_SGE_FLAGS_DIRECTION;
-		dir = BUS_DMASYNC_PREWRITE;
-	} else
-		dir = BUS_DMASYNC_PREREAD;
+	TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain, chain_link);
+
+	sgc = (MPI2_SGE_CHAIN32 *)&cm->cm_sge->MpiChain;
+	sgc->Length = space;
+	sgc->NextChainOffset = 0;
+	sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT;
+	sgc->Address = chain->chain_busaddr;
+
+	cm->cm_sge = (MPI2_SGE_IO_UNION *)&chain->chain->MpiSimple;
+	cm->cm_sglsize = space;
+	return (0);
+}
+
+/*
+ * Add one scatter-gather element (chain, simple, transaction context)
+ * to the scatter-gather list for a command.  Maintain cm_sglsize and
+ * cm_sge as the remaining size and pointer to the next SGE to fill
+ * in, respectively.
+ */
+int
+mps_push_sge(struct mps_command *cm, void *sgep, size_t len, int segsleft)
+{
+	MPI2_SGE_TRANSACTION_UNION *tc = sgep;
+	MPI2_SGE_SIMPLE64 *sge = sgep;
+	int error, type;
+
+	type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
+
+#ifdef INVARIANTS
+	switch (type) {
+	case MPI2_SGE_FLAGS_TRANSACTION_ELEMENT: {
+		if (len != tc->DetailsLength + 4)
+			panic("TC %p length %u or %zu?", tc,
+			    tc->DetailsLength + 4, len);
+		}
+		break;
+	case MPI2_SGE_FLAGS_CHAIN_ELEMENT:
+		/* Driver only uses 32-bit chain elements */
+		if (len != MPS_SGC_SIZE)
+			panic("CHAIN %p length %u or %zu?", sgep,
+			    MPS_SGC_SIZE, len);
+		break;
+	case MPI2_SGE_FLAGS_SIMPLE_ELEMENT:
+		/* Driver only uses 64-bit SGE simple elements */
+		sge = sgep;
+		if (len != MPS_SGE64_SIZE)
+			panic("SGE simple %p length %u or %zu?", sge,
+			    MPS_SGE64_SIZE, len);
+		if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) &
+		    MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
+			panic("SGE simple %p flags %02x not marked 64-bit?",
+			    sge, sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT);
+
+		break;
+	default:
+		panic("Unexpected SGE %p, flags %02x", tc, tc->Flags);
+	}
+#endif
 
 	/*
 	 * case 1: 1 more segment, enough room for it
@@ -1408,70 +1463,128 @@ mps_data_cb(void *arg, bus_dma_segment_t
 	 * case 3: >=2 more segments, only enough room for 1 and a chain
 	 * case 4: >=1 more segment, enough room for only a chain
 	 * case 5: >=1 more segment, no room for anything (error)
-	 */
+         */
 
-	for (i = 0; i < nsegs; i++) {
+	/*
+	 * There should be room for at least a chain element, or this
+	 * code is buggy.  Case (5).
+	 */
+	if (cm->cm_sglsize < MPS_SGC_SIZE)
+		panic("MPS: Need SGE Error Code\n");
 
-		/* Case 5 Error.  This should never happen. */
-		if (sglspace < MPS_SGC_SIZE) {
-			panic("MPS: Need SGE Error Code\n");
+	if (segsleft >= 2 &&
+	    cm->cm_sglsize < len + MPS_SGC_SIZE + MPS_SGE64_SIZE) {
+		/*
+		 * There are 2 or more segments left to add, and only
+		 * enough room for 1 and a chain.  Case (3).
+		 *
+		 * Mark as last element in this chain if necessary.
+		 */
+		if (type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
+			sge->FlagsLength |=
+				(MPI2_SGE_FLAGS_LAST_ELEMENT << MPI2_SGE_FLAGS_SHIFT);
 		}
 
 		/*
-		 * Case 4, Fill in a chain element, allocate a chain,
-		 * fill in one SGE element, continue.
+		 * Add the item then a chain.  Do the chain now,
+		 * rather than on the next iteration, to simplify
+		 * understanding the code.
 		 */
-		if ((sglspace >= MPS_SGC_SIZE) && (sglspace < MPS_SGE64_SIZE)) {
-			chain = mps_alloc_chain(sc);
-			if (chain == NULL) {
-				/* Resource shortage, roll back! */
-				mps_printf(sc, "out of chain frames\n");
-				return;
-			}
+		cm->cm_sglsize -= len;
+		bcopy(sgep, cm->cm_sge, len);
+		cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
+		return (mps_add_chain(cm));
+	}
 
-			/*
-			 * Note: a double-linked list is used to make it
-			 * easier to walk for debugging.
-			 */
-			TAILQ_INSERT_TAIL(&cm->cm_chain_list, chain,chain_link);
-
-			sgc = (MPI2_SGE_CHAIN32 *)sge;
-			sgc->Length = 128;
-			sgc->NextChainOffset = 0;
-			sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT;
-			sgc->Address = chain->chain_busaddr;
+	if (segsleft >= 1 && cm->cm_sglsize < len + MPS_SGC_SIZE) {
+		/*
+		 * 1 or more segment, enough room for only a chain.
+		 * Hope the previous element wasn't a Simple entry
+		 * that needed to be marked with
+		 * MPI2_SGE_FLAGS_LAST_ELEMENT.  Case (4).
+		 */
+		if ((error = mps_add_chain(cm)) != 0)
+			return (error);
+	}
 
-			sge = (MPI2_SGE_SIMPLE64 *)&chain->chain->MpiSimple;
-			sglspace = 128;
-		}
+#ifdef INVARIANTS
+	/* Case 1: 1 more segment, enough room for it. */
+	if (segsleft == 1 && cm->cm_sglsize < len)
+		panic("1 seg left and no room? %u versus %zu",
+		    cm->cm_sglsize, len);
+
+	/* Case 2: 2 more segments, enough room for both */
+	if (segsleft == 2 && cm->cm_sglsize < len + MPS_SGE64_SIZE)
+		panic("2 segs left and no room? %u versus %zu",
+		    cm->cm_sglsize, len);
+#endif
 
-		flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
-		sge->FlagsLength = segs[i].ds_len |
-		   ((sflags | flags) << MPI2_SGE_FLAGS_SHIFT);
-		mps_from_u64(segs[i].ds_addr, &sge->Address);
+	if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
+		/*
+		 * Last element of the last segment of the entire
+		 * buffer.
+		 */
+		sge->FlagsLength |= ((MPI2_SGE_FLAGS_LAST_ELEMENT |
+		    MPI2_SGE_FLAGS_END_OF_BUFFER |
+		    MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+	}
 
-		/* Case 1, Fill in one SGE element and break */
-		if (segsleft == 1)
-			break;
+	cm->cm_sglsize -= len;
+	bcopy(sgep, cm->cm_sge, len);
+	cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge + len);
+	return (0);
+}
+
+/*
+ * Add one dma segment to the scatter-gather list for a command.
+ */
+int
+mps_add_dmaseg(struct mps_command *cm, vm_paddr_t pa, size_t len, u_int flags,
+    int segsleft)
+{
+	MPI2_SGE_SIMPLE64 sge;
+
+	/*
+	 * This driver always uses 64-bit address elements for
+	 * simplicity.
+	 */
+	flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_ADDRESS_SIZE;
+	sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
+	mps_from_u64(pa, &sge.Address);
+
+	return (mps_push_sge(cm, &sge, sizeof sge, segsleft));
+}
 
-		sglspace -= MPS_SGE64_SIZE;
-		segsleft--;
+static void
+mps_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	struct mps_softc *sc;
+	struct mps_command *cm;
+	u_int i, dir, sflags;
 
-		/* Case 3, prepare for a chain on the next loop */
-		if ((segsleft > 0) && (sglspace < MPS_SGE64_SIZE))
-			sge->FlagsLength |= 
-			    (MPI2_SGE_FLAGS_LAST_ELEMENT <<
-			    MPI2_SGE_FLAGS_SHIFT);
-
-		/* Advance to the next element to be filled in. */
-		sge++;
-	}
-
-	/* Last element of the last segment of the entire buffer */
-	flags = MPI2_SGE_FLAGS_LAST_ELEMENT |
-	    MPI2_SGE_FLAGS_END_OF_BUFFER |
-	    MPI2_SGE_FLAGS_END_OF_LIST;
-	sge->FlagsLength |= (flags << MPI2_SGE_FLAGS_SHIFT);
+	cm = (struct mps_command *)arg;
+	sc = cm->cm_sc;
+
+	/*
+	 * Set up DMA direction flags.  Note no support for
+	 * bi-directional transactions.
+	 */
+	sflags = 0;
+	if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) {
+		sflags |= MPI2_SGE_FLAGS_DIRECTION;
+		dir = BUS_DMASYNC_PREWRITE;
+	} else
+		dir = BUS_DMASYNC_PREREAD;
+
+	for (i = 0; i < nsegs; i++) {
+		error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len,
+		    sflags, nsegs - i);
+		if (error != 0) {
+			/* Resource shortage, roll back! */
+			mps_printf(sc, "out of chain frames\n");
+			return;
+		}
+	}
 
 	bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
 	mps_enqueue_request(sc, cm);

Modified: head/sys/dev/mps/mps_user.c
==============================================================================
--- head/sys/dev/mps/mps_user.c	Thu Oct 14 15:42:32 2010	(r213838)
+++ head/sys/dev/mps/mps_user.c	Thu Oct 14 16:44:05 2010	(r213839)
@@ -322,6 +322,21 @@ mps_user_write_cfg_page(struct mps_softc
 	return (0);
 }
 
+static void
+mpi_init_sge(struct mps_command *cm, void *req, void *sge)
+{
+	int off, space;
+
+	space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
+	off = (uintptr_t)sge - (uintptr_t)req;
+
+	KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
+            req, sge, off, space));
+
+	cm->cm_sge = sge;
+	cm->cm_sglsize = space - off;
+}
+
 /*
  * Prepare the mps_command for an IOC_FACTS request.
  */
@@ -374,8 +389,7 @@ mpi_pre_fw_download(struct mps_command *
 	if (cmd->rpl_len != sizeof *rpl)
 		return (EINVAL);
 
-	cm->cm_sge = (MPI2_SGE_IO_UNION *)&req->SGL;
-	cm->cm_sglsize = sizeof req->SGL;
+	mpi_init_sge(cm, req, &req->SGL);
 	return (0);
 }
 
@@ -387,45 +401,41 @@ mpi_pre_fw_upload(struct mps_command *cm
 {
 	MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
 	MPI2_FW_UPLOAD_REPLY *rpl;
-	MPI2_FW_UPLOAD_TCSGE *tc;
+	MPI2_FW_UPLOAD_TCSGE tc;
 
 	/*
 	 * This code assumes there is room in the request's SGL for
 	 * the TransactionContext plus at least a SGL chain element.
 	 */
-	CTASSERT(sizeof req->SGL >= sizeof *tc + MPS_SGC_SIZE);
+	CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
 
 	if (cmd->req_len != sizeof *req)
 		return (EINVAL);
 	if (cmd->rpl_len != sizeof *rpl)
 		return (EINVAL);
 
-	cm->cm_sglsize = sizeof req->SGL;
+	mpi_init_sge(cm, req, &req->SGL);
 	if (cmd->len == 0) {
 		/* Perhaps just asking what the size of the fw is? */
-		cm->cm_sge = (MPI2_SGE_IO_UNION *)&req->SGL;
 		return (0);
 	}
 
-	tc = (void *)&req->SGL;
-	bzero(tc, sizeof *tc);
+	bzero(&tc, sizeof tc);
 
 	/*
 	 * The value of the first two elements is specified in the
 	 * Fusion-MPT Message Passing Interface document.
 	 */
-	tc->ContextSize = 0;
-	tc->DetailsLength = 12;
+	tc.ContextSize = 0;
+	tc.DetailsLength = 12;
 	/*
 	 * XXX Is there any reason to fetch a partial image?  I.e. to
 	 * set ImageOffset to something other than 0?
 	 */
-	tc->ImageOffset = 0;
-	tc->ImageSize = cmd->len;
-	cm->cm_sge = (MPI2_SGE_IO_UNION *)(tc + 1);
-	cm->cm_sglsize -= sizeof *tc;
+	tc.ImageOffset = 0;
+	tc.ImageSize = cmd->len;
 
-	return (0);
+	return (mps_push_sge(cm, &tc, sizeof tc, 0));
 }
 
 /*
@@ -442,8 +452,7 @@ mpi_pre_sata_passthrough(struct mps_comm
 	if (cmd->rpl_len != sizeof *rpl)
 		return (EINVAL);
 
-	cm->cm_sge = (MPI2_SGE_IO_UNION *)&req->SGL;
-	cm->cm_sglsize = sizeof req->SGL;
+	mpi_init_sge(cm, req, &req->SGL);
 	return (0);
 }
 
@@ -461,8 +470,7 @@ mpi_pre_smp_passthrough(struct mps_comma
 	if (cmd->rpl_len != sizeof *rpl)
 		return (EINVAL);
 
-	cm->cm_sge = (MPI2_SGE_IO_UNION *)&req->SGL;
-	cm->cm_sglsize = sizeof req->SGL;
+	mpi_init_sge(cm, req, &req->SGL);
 	return (0);
 }
 
@@ -480,8 +488,7 @@ mpi_pre_config(struct mps_command *cm, s
 	if (cmd->rpl_len != sizeof *rpl)
 		return (EINVAL);
 
-	cm->cm_sge = (MPI2_SGE_IO_UNION *)&req->PageBufferSGE;
-	cm->cm_sglsize = sizeof req->PageBufferSGE;
+	mpi_init_sge(cm, req, &req->PageBufferSGE);
 	return (0);
 }
 

Modified: head/sys/dev/mps/mpsvar.h
==============================================================================
--- head/sys/dev/mps/mpsvar.h	Thu Oct 14 15:42:32 2010	(r213838)
+++ head/sys/dev/mps/mpsvar.h	Thu Oct 14 16:44:05 2010	(r213839)
@@ -359,6 +359,9 @@ int mps_register_events(struct mps_softc
 int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *);
 int mps_deregister_events(struct mps_softc *, struct mps_event_handle *);
 int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
+void mps_enqueue_request(struct mps_softc *, struct mps_command *);
+int mps_push_sge(struct mps_command *, void *, size_t, int);
+int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int);
 int mps_attach_sas(struct mps_softc *sc);
 int mps_detach_sas(struct mps_softc *sc);
 int mps_map_command(struct mps_softc *sc, struct mps_command *cm);


More information about the svn-src-all mailing list