svn commit: r218810 - in stable/8/sys: amd64/conf conf dev/bwn dev/mps dev/siba dev/sis mips/mips modules modules/mps

Kenneth D. Merry ken at FreeBSD.org
Fri Feb 18 16:29:39 UTC 2011


Author: ken
Date: Fri Feb 18 16:29:38 2011
New Revision: 218810
URL: http://svn.freebsd.org/changeset/base/218810

Log:
  MFC: 212420, 212616, 212772, 212802, 213535, 213702, 213704, 213707, 213708,
       213743, 213839, 213840, 213882, 213898, 216088, 216227, 216363, 216368:
  
  Merge the mps(4) driver into stable/8.  This is currently only included in
  GENERIC on amd64, since that is the only architecture it has been tested
  on.

Added:
  stable/8/sys/dev/mps/
     - copied from r212420, head/sys/dev/mps/
  stable/8/sys/modules/mps/
     - copied from r212420, head/sys/modules/mps/
Modified:
  stable/8/sys/amd64/conf/GENERIC
  stable/8/sys/conf/files
  stable/8/sys/dev/bwn/if_bwn.c
  stable/8/sys/dev/mps/mps.c
  stable/8/sys/dev/mps/mps_ioctl.h
  stable/8/sys/dev/mps/mps_pci.c
  stable/8/sys/dev/mps/mps_sas.c
  stable/8/sys/dev/mps/mps_user.c
  stable/8/sys/dev/mps/mpsvar.h
  stable/8/sys/dev/siba/siba_bwn.c
  stable/8/sys/dev/sis/if_sisreg.h
  stable/8/sys/mips/mips/mp_machdep.c
  stable/8/sys/modules/Makefile
  stable/8/sys/modules/mps/Makefile
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/amd64/conf/GENERIC
==============================================================================
--- stable/8/sys/amd64/conf/GENERIC	Fri Feb 18 16:21:09 2011	(r218809)
+++ stable/8/sys/amd64/conf/GENERIC	Fri Feb 18 16:29:38 2011	(r218810)
@@ -114,6 +114,7 @@ device		hptiop		# Highpoint RocketRaid 3
 device		isp		# Qlogic family
 #device		ispfw		# Firmware for QLogic HBAs- normally a module
 device		mpt		# LSI-Logic MPT-Fusion
+device		mps		# LSI-Logic MPT-Fusion 2
 #device		ncr		# NCR/Symbios Logic
 device		sym		# NCR/Symbios Logic (newer chipsets + those of `ncr')
 device		trm		# Tekram DC395U/UW/F DC315U adapters

Modified: stable/8/sys/conf/files
==============================================================================
--- stable/8/sys/conf/files	Fri Feb 18 16:21:09 2011	(r218809)
+++ stable/8/sys/conf/files	Fri Feb 18 16:29:38 2011	(r218810)
@@ -1303,6 +1303,11 @@ dev/mmc/mmcbr_if.m		standard
 dev/mmc/mmcbus_if.m		standard
 dev/mmc/mmcsd.c			optional mmcsd
 dev/mn/if_mn.c			optional mn pci
+dev/mps/mps.c			optional mps
+dev/mps/mps_pci.c		optional mps pci
+dev/mps/mps_sas.c		optional mps
+dev/mps/mps_table.c		optional mps
+dev/mps/mps_user.c		optional mps
 dev/mpt/mpt.c			optional mpt
 dev/mpt/mpt_cam.c		optional mpt
 dev/mpt/mpt_debug.c		optional mpt

Modified: stable/8/sys/dev/bwn/if_bwn.c
==============================================================================
--- stable/8/sys/dev/bwn/if_bwn.c	Fri Feb 18 16:21:09 2011	(r218809)
+++ stable/8/sys/dev/bwn/if_bwn.c	Fri Feb 18 16:29:38 2011	(r218810)
@@ -2882,7 +2882,7 @@ bwn_set_channel(struct ieee80211com *ic)
 
 	error = bwn_switch_band(sc, ic->ic_curchan);
 	if (error)
-		goto fail;;
+		goto fail;
 	bwn_mac_suspend(mac);
 	bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
 	chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
@@ -8260,7 +8260,7 @@ bwn_switch_band(struct bwn_softc *sc, st
 	device_printf(sc->sc_dev, "switching to %s-GHz band\n",
 	    IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
 
-	down_dev = sc->sc_curmac;;
+	down_dev = sc->sc_curmac;
 	status = down_dev->mac_status;
 	if (status >= BWN_MAC_STATUS_STARTED)
 		bwn_core_stop(down_dev);

Modified: stable/8/sys/dev/mps/mps.c
==============================================================================
--- head/sys/dev/mps/mps.c	Fri Sep 10 15:03:56 2010	(r212420)
+++ stable/8/sys/dev/mps/mps.c	Fri Feb 18 16:29:38 2011	(r218810)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/uio.h>
 #include <sys/sysctl.h>
+#include <sys/endian.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -380,7 +381,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)
 {
 
@@ -607,9 +608,16 @@ mps_alloc_queues(struct mps_softc *sc)
 static int
 mps_alloc_replies(struct mps_softc *sc)
 {
-	int rsize;
+	int rsize, num_replies;
+
+	/*
+	 * sc->num_replies should be one less than sc->fqdepth.  We need to
+	 * allocate space for sc->fqdepth replies, but only sc->num_replies
+	 * replies can be used at once.
+	 */
+	num_replies = max(sc->fqdepth, sc->num_replies);
 
-	rsize = sc->facts->ReplyFrameSize * sc->num_replies * 4; 
+	rsize = sc->facts->ReplyFrameSize * num_replies * 4; 
         if (bus_dma_tag_create( sc->mps_parent_dmat,    /* parent */
 				4, 0,			/* algnmnt, boundary */
 				BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
@@ -782,11 +790,19 @@ mps_init_queues(struct mps_softc *sc)
 
 	memset((uint8_t *)sc->post_queue, 0xff, sc->pqdepth * 8);
 
+	/*
+	 * According to the spec, we need to use one less reply than we
+	 * have space for on the queue.  So sc->num_replies (the number we
+	 * use) should be less than sc->fqdepth (allocated size).
+	 */
 	if (sc->num_replies >= sc->fqdepth)
 		return (EINVAL);
 
-	for (i = 0; i < sc->num_replies; i++)
-		sc->free_queue[i] = sc->reply_busaddr + i * sc->facts->ReplyFrameSize * 4;
+	/*
+	 * Initialize all of the free queue entries.
+	 */
+	for (i = 0; i < sc->fqdepth; i++)
+		sc->free_queue[i] = sc->reply_busaddr + (i * sc->facts->ReplyFrameSize * 4);
 	sc->replyfreeindex = sc->num_replies;
 
 	return (0);
@@ -805,6 +821,9 @@ mps_attach(struct mps_softc *sc)
 	snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.debug_level",
 	    device_get_unit(sc->mps_dev));
 	TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug);
+	snprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.allow_multiple_tm_cmds",
+	    device_get_unit(sc->mps_dev));
+	TUNABLE_INT_FETCH(tmpstr, &sc->allow_multiple_tm_cmds);
 
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
 
@@ -831,6 +850,11 @@ mps_attach(struct mps_softc *sc)
 	    OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0,
 	    "mps debug level");
 
+	SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+	    OID_AUTO, "allow_multiple_tm_cmds", CTLFLAG_RW,
+	    &sc->allow_multiple_tm_cmds, 0,
+	    "allow multiple simultaneous task management cmds");
+
 	if ((error = mps_transition_ready(sc)) != 0)
 		return (error);
 
@@ -873,6 +897,7 @@ mps_attach(struct mps_softc *sc)
 	    sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
 	TAILQ_INIT(&sc->req_list);
 	TAILQ_INIT(&sc->chain_list);
+	TAILQ_INIT(&sc->tm_list);
 
 	if (((error = mps_alloc_queues(sc)) != 0) ||
 	    ((error = mps_alloc_replies(sc)) != 0) ||
@@ -898,7 +923,6 @@ mps_attach(struct mps_softc *sc)
 	 * replies.
 	 */
 	sc->replypostindex = 0;
-	sc->replycurindex = 0;
 	mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
 	mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, 0);
 
@@ -915,7 +939,10 @@ mps_attach(struct mps_softc *sc)
 	/* Attach the subsystems so they can prepare their event masks. */
 	/* XXX Should be dynamic so that IM/IR and user modules can attach */
 	if (((error = mps_attach_log(sc)) != 0) ||
-	    ((error = mps_attach_sas(sc)) != 0)) {
+	    ((error = mps_attach_sas(sc)) != 0) ||
+	    ((error = mps_attach_user(sc)) != 0)) {
+		mps_printf(sc, "%s failed to attach all subsystems: error %d\n",
+		    __func__, error);
 		mps_free(sc);
 		return (error);
 	}
@@ -1199,7 +1226,8 @@ mps_intr_locked(void *data)
 		desc = &sc->post_queue[pq];
 		flags = desc->Default.ReplyFlags &
 		    MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
-		if (flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+		if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+		 || (desc->Words.High == 0xffffffff))
 			break;
 
 		switch (flags) {
@@ -1212,9 +1240,36 @@ mps_intr_locked(void *data)
 			uint32_t baddr;
 			uint8_t *reply;
 
+			/*
+			 * Re-compose the reply address from the address
+			 * sent back from the chip.  The ReplyFrameAddress
+			 * is the lower 32 bits of the physical address of
+			 * particular reply frame.  Convert that address to
+			 * host format, and then use that to provide the
+			 * offset against the virtual address base
+			 * (sc->reply_frames).
+			 */
+			baddr = le32toh(desc->AddressReply.ReplyFrameAddress);
 			reply = sc->reply_frames +
-			    sc->replycurindex * sc->facts->ReplyFrameSize * 4;
-			baddr = desc->AddressReply.ReplyFrameAddress;
+				(baddr - ((uint32_t)sc->reply_busaddr));
+			/*
+			 * Make sure the reply we got back is in a valid
+			 * range.  If not, go ahead and panic here, since
+			 * we'll probably panic as soon as we deference the
+			 * reply pointer anyway.
+			 */
+			if ((reply < sc->reply_frames)
+			 || (reply > (sc->reply_frames +
+			     (sc->fqdepth * sc->facts->ReplyFrameSize * 4)))) {
+				printf("%s: WARNING: reply %p out of range!\n",
+				       __func__, reply);
+				printf("%s: reply_frames %p, fqdepth %d, "
+				       "frame size %d\n", __func__,
+				       sc->reply_frames, sc->fqdepth,
+				       sc->facts->ReplyFrameSize * 4);
+				printf("%s: baddr %#x,\n", __func__, baddr);
+				panic("Reply address out of range");
+			}
 			if (desc->AddressReply.SMID == 0) {
 				mps_dispatch_event(sc, baddr,
 				   (MPI2_EVENT_NOTIFICATION_REPLY *) reply);
@@ -1224,8 +1279,6 @@ mps_intr_locked(void *data)
 				cm->cm_reply_data =
 				    desc->AddressReply.ReplyFrameAddress;
 			}
-			if (++sc->replycurindex >= sc->fqdepth)
-				sc->replycurindex = 0;
 			break;
 		}
 		case MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS:
@@ -1270,7 +1323,7 @@ mps_dispatch_event(struct mps_softc *sc,
     MPI2_EVENT_NOTIFICATION_REPLY *reply)
 {
 	struct mps_event_handle *eh;
-	int event, handled = 0;;
+	int event, handled = 0;
 
 	event = reply->Event;
 	TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
@@ -1365,33 +1418,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
@@ -1399,70 +1507,164 @@ 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! */
-				printf("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);
+	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);
+	}
 
-			sgc = (MPI2_SGE_CHAIN32 *)sge;
-			sgc->Length = 128;
-			sgc->NextChainOffset = 0;
-			sgc->Flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT;
-			sgc->Address = chain->chain_busaddr;
+#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
 
-			sge = (MPI2_SGE_SIMPLE64 *)&chain->chain->MpiSimple;
-			sglspace = 128;
-		}
+	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);
+	}
 
-		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);
+	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);
+}
 
-		/* Case 1, Fill in one SGE element and break */
-		if (segsleft == 1)
-			break;
+/*
+ * 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);
 
-		sglspace -= MPS_SGE64_SIZE;
-		segsleft--;
+	return (mps_push_sge(cm, &sge, sizeof sge, 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;
+
+	/*
+	 * In this case, just print out a warning and let the chip tell the
+	 * user they did the wrong thing.
+	 */
+	if ((cm->cm_max_segs != 0) && (nsegs > cm->cm_max_segs)) {
+		mps_printf(sc, "%s: warning: busdma returned %d segments, "
+			   "more than the %d allowed\n", __func__, nsegs,
+			   cm->cm_max_segs);
+	}
+
+	/*
+	 * Set up DMA direction flags.  Note that we don't support
+	 * bi-directional transfers, with the exception of SMP passthrough.
+	 */
+	sflags = 0;
+	if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) {
+		/*
+		 * We have to add a special case for SMP passthrough, there
+		 * is no easy way to generically handle it.  The first
+		 * S/G element is used for the command (therefore the
+		 * direction bit needs to be set).  The second one is used
+		 * for the reply.  We'll leave it to the caller to make
+		 * sure we only have two buffers.
+		 */
+		/*
+		 * Even though the busdma man page says it doesn't make
+		 * sense to have both direction flags, it does in this case.
+		 * We have one s/g element being accessed in each direction.
+		 */
+		dir = BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD;
+
+		/*
+		 * Set the direction flag on the first buffer in the SMP
+		 * passthrough request.  We'll clear it for the second one.
+		 */
+		sflags |= MPI2_SGE_FLAGS_DIRECTION |
+			  MPI2_SGE_FLAGS_END_OF_BUFFER;
+	} else 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++) {
+		if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS)
+		 && (i != 0)) {
+			sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
+		}
+		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);
@@ -1470,13 +1672,27 @@ mps_data_cb(void *arg, bus_dma_segment_t
 	return;
 }
 
+static void
+mps_data_cb2(void *arg, bus_dma_segment_t *segs, int nsegs, bus_size_t mapsize,
+	     int error)
+{
+	mps_data_cb(arg, segs, nsegs, error);
+}
+
+/*
+ * Note that the only error path here is from bus_dmamap_load(), which can
+ * return EINPROGRESS if it is waiting for resources.
+ */
 int
 mps_map_command(struct mps_softc *sc, struct mps_command *cm)
 {
 	MPI2_SGE_SIMPLE32 *sge;
 	int error = 0;
 
-	if ((cm->cm_data != NULL) && (cm->cm_length != 0)) {
+	if (cm->cm_flags & MPS_CM_FLAGS_USE_UIO) {
+		error = bus_dmamap_load_uio(sc->buffer_dmat, cm->cm_dmamap,
+		    &cm->cm_uio, mps_data_cb2, cm, 0);
+	} else if ((cm->cm_data != NULL) && (cm->cm_length != 0)) {
 		error = bus_dmamap_load(sc->buffer_dmat, cm->cm_dmamap,
 		    cm->cm_data, cm->cm_length, mps_data_cb, cm, 0);
 	} else {
@@ -1490,7 +1706,7 @@ mps_map_command(struct mps_softc *sc, st
 			    MPI2_SGE_FLAGS_SHIFT;
 			sge->Address = 0;
 		}
-		mps_enqueue_request(sc, cm);	
+		mps_enqueue_request(sc, cm);
 	}
 
 	return (error);
@@ -1549,9 +1765,9 @@ mps_read_config_page(struct mps_softc *s
 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 
+	cm->cm_complete_data = params;
 	if (params->callback != NULL) {
 		cm->cm_complete = mps_config_complete;
-		cm->cm_complete_data = params;
 		return (mps_map_command(sc, cm));
 	} else {
 		cm->cm_complete = NULL;

Modified: stable/8/sys/dev/mps/mps_ioctl.h
==============================================================================
--- head/sys/dev/mps/mps_ioctl.h	Fri Sep 10 15:03:56 2010	(r212420)
+++ stable/8/sys/dev/mps/mps_ioctl.h	Fri Feb 18 16:29:38 2011	(r218810)
@@ -103,44 +103,4 @@ struct mps_usr_command {
 #define	MPSIO_RAID_ACTION	_IOWR('M', 205, struct mps_raid_action)
 #define	MPSIO_MPS_COMMAND	_IOWR('M', 210, struct mps_usr_command)
 
-#if defined(__amd64__)
-struct mps_cfg_page_req32 {
-	MPI2_CONFIG_PAGE_HEADER header;
-	uint32_t page_address;
-	uint32_t buf;
-	int	len;	
-	uint16_t ioc_status;
-};
-
-struct mps_ext_cfg_page_req32 {
-	MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
-	uint32_t page_address;
-	uint32_t buf;
-	int	len;
-	uint16_t ioc_status;
-};
-
-struct mps_raid_action32 {
-	uint8_t action;
-	uint8_t volume_bus;
-	uint8_t volume_id;
-	uint8_t phys_disk_num;
-	uint32_t action_data_word;
-	uint32_t buf;
-	int len;
-	uint32_t volume_status;
-	uint32_t action_data[4];
-	uint16_t action_status;
-	uint16_t ioc_status;
-	uint8_t write;
-};
-
-#define	MPSIO_READ_CFG_HEADER32	_IOWR('M', 100, struct mps_cfg_page_req32)
-#define	MPSIO_READ_CFG_PAGE32	_IOWR('M', 101, struct mps_cfg_page_req32)
-#define	MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 102, struct mps_ext_cfg_page_req32)
-#define	MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 103, struct mps_ext_cfg_page_req32)
-#define	MPSIO_WRITE_CFG_PAGE32	_IOWR('M', 104, struct mps_cfg_page_req32)
-#define	MPSIO_RAID_ACTION32	_IOWR('M', 105, struct mps_raid_action32)
-#endif
-
 #endif /* !_MPS_IOCTL_H_ */

Modified: stable/8/sys/dev/mps/mps_pci.c
==============================================================================
--- head/sys/dev/mps/mps_pci.c	Fri Sep 10 15:03:56 2010	(r212420)
+++ stable/8/sys/dev/mps/mps_pci.c	Fri Feb 18 16:29:38 2011	(r218810)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/malloc.h>
 #include <sys/sysctl.h>
+#include <sys/uio.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>

Modified: stable/8/sys/dev/mps/mps_sas.c
==============================================================================
--- head/sys/dev/mps/mps_sas.c	Fri Sep 10 15:03:56 2010	(r212420)
+++ stable/8/sys/dev/mps/mps_sas.c	Fri Feb 18 16:29:38 2011	(r218810)
@@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/uio.h>
 #include <sys/sysctl.h>
+#include <sys/sglist.h>
+#include <sys/endian.h>
 
 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -55,6 +57,9 @@ __FBSDID("$FreeBSD$");
 #include <cam/cam_periph.h>
 #include <cam/scsi/scsi_all.h>
 #include <cam/scsi/scsi_message.h>
+#if __FreeBSD_version >= 900026
+#include <cam/scsi/smp_all.h>
+#endif
 
 #include <dev/mps/mpi/mpi2_type.h>
 #include <dev/mps/mpi/mpi2.h>
@@ -69,9 +74,11 @@ struct mpssas_target {
 	uint16_t	handle;
 	uint8_t		linkrate;
 	uint64_t	devname;
+	uint64_t	sasaddr;
 	uint32_t	devinfo;
 	uint16_t	encl_handle;
 	uint16_t	encl_slot;
+	uint16_t	parent_handle;
 	int		flags;
 #define MPSSAS_TARGET_INABORT	(1 << 0)
 #define MPSSAS_TARGET_INRESET	(1 << 1)
@@ -114,6 +121,7 @@ struct mpssas_devprobe {
 
 MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
 
+static __inline int mpssas_set_lun(uint8_t *lun, u_int ccblun);
 static struct mpssas_target * mpssas_alloc_target(struct mpssas_softc *,
     struct mpssas_target *);
 static struct mpssas_target * mpssas_find_target(struct mpssas_softc *, int,
@@ -135,14 +143,64 @@ static void mpssas_probe_device_complete
 static void mpssas_scsiio_timeout(void *data);
 static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
 static void mpssas_recovery(struct mps_softc *, struct mps_command *);
+static int mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm);
+static void mpssas_issue_tm_request(struct mps_softc *sc,
+				    struct mps_command *cm);
+static void mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm,
+			       int error);
+static int mpssas_complete_tm_request(struct mps_softc *sc,
+				      struct mps_command *cm, int free_cm);
 static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
 static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
-static int mpssas_resetdev(struct mpssas_softc *, struct mps_command *);
+#if __FreeBSD_version >= 900026
+static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
+static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
+			       uint64_t sasaddr);
+static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
+#endif /* __FreeBSD_version >= 900026 */
+static void mpssas_resetdev(struct mpssas_softc *, struct mps_command *);
 static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
 static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
 static void mpssas_freeze_device(struct mpssas_softc *, struct mpssas_target *);
 static void mpssas_unfreeze_device(struct mpssas_softc *, struct mpssas_target *) __unused;
 
+/*
+ * Abstracted so that the driver can be backwards and forwards compatible
+ * with future versions of CAM that will provide this functionality.
+ */
+#define MPS_SET_LUN(lun, ccblun)	\
+	mpssas_set_lun(lun, ccblun)
+
+static __inline int
+mpssas_set_lun(uint8_t *lun, u_int ccblun)
+{
+	uint64_t *newlun;
+
+	newlun = (uint64_t *)lun;
+	*newlun = 0;
+	if (ccblun <= 0xff) {
+		/* Peripheral device address method, LUN is 0 to 255 */
+		lun[1] = ccblun;
+	} else if (ccblun <= 0x3fff) {
+		/* Flat space address method, LUN is <= 16383 */
+		scsi_ulto2b(ccblun, lun);
+		lun[0] |= 0x40;
+	} else if (ccblun <= 0xffffff) {
+		/* Extended flat space address method, LUN is <= 16777215 */
+		scsi_ulto3b(ccblun, &lun[1]);
+		/* Extended Flat space address method */
+		lun[0] = 0xc0;
+		/* Length = 1, i.e. LUN is 3 bytes long */
+		lun[0] |= 0x10;
+		/* Extended Address Method */
+		lun[0] |= 0x02;
+	} else {
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
 static struct mpssas_target *
 mpssas_alloc_target(struct mpssas_softc *sassc, struct mpssas_target *probe)
 {
@@ -305,6 +363,8 @@ mpssas_probe_device_complete(struct mps_
 		probe->target.devinfo = buf->DeviceInfo;
 		probe->target.encl_handle = buf->EnclosureHandle;
 		probe->target.encl_slot = buf->Slot;
+		probe->target.sasaddr = mps_to_u64(&buf->SASAddress);
+		probe->target.parent_handle = buf->ParentDevHandle;
 
 		if (buf->DeviceInfo & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) {
 			params->page_address =
@@ -438,7 +498,7 @@ mpssas_prepare_remove(struct mpssas_soft
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 	cm->cm_complete = mpssas_remove_device;
 	cm->cm_targ = targ;
-	mps_map_command(sc, cm);
+	mpssas_issue_tm_request(sc, cm);
 }
 
 static void
@@ -453,6 +513,9 @@ mpssas_remove_device(struct mps_softc *s
 
 	reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
 	handle = cm->cm_targ->handle;
+
+	mpssas_complete_tm_request(sc, cm, /*free_cm*/ 0);
+
 	if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
 		mps_printf(sc, "Failure 0x%x reseting device 0x%04x\n", 
 		   reply->IOCStatus, handle);
@@ -594,6 +657,7 @@ mps_attach_sas(struct mps_softc *sc)
 {
 	struct mpssas_softc *sassc;
 	int error = 0;
+	int num_sim_reqs;
 
 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
 
@@ -603,15 +667,30 @@ mps_attach_sas(struct mps_softc *sc)
 	sc->sassc = sassc;
 	sassc->sc = sc;
 
-	if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) {
+	/*
+	 * Tell CAM that we can handle 5 fewer requests than we have
+	 * allocated.  If we allow the full number of requests, all I/O
+	 * will halt when we run out of resources.  Things work fine with
+	 * just 1 less request slot given to CAM than we have allocated.
+	 * We also need a couple of extra commands so that we can send down
+	 * abort, reset, etc. requests when commands time out.  Otherwise
+	 * we could wind up in a situation with sc->num_reqs requests down
+	 * on the card and no way to send an abort.
+	 *
+	 * XXX KDM need to figure out why I/O locks up if all commands are
+	 * used.
+	 */
+	num_sim_reqs = sc->num_reqs - 5;
+
+	if ((sassc->devq = cam_simq_alloc(num_sim_reqs)) == NULL) {
 		mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n");
 		error = ENOMEM;
 		goto out;
 	}
 
 	sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
-	    device_get_unit(sc->mps_dev), &sc->mps_mtx, sc->num_reqs, sc->num_reqs,
-	    sassc->devq);
+	    device_get_unit(sc->mps_dev), &sc->mps_mtx, num_sim_reqs,
+	    num_sim_reqs, sassc->devq);
 	if (sassc->sim == NULL) {
 		mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n");
 		error = EINVAL;
@@ -890,6 +969,11 @@ mpssas_action(struct cam_sim *sim, union
 	case XPT_SCSI_IO:
 		mpssas_action_scsiio(sassc, ccb);
 		return;
+#if __FreeBSD_version >= 900026
+	case XPT_SMP_IO:
+		mpssas_action_smpio(sassc, ccb);
+		return;
+#endif /* __FreeBSD_version >= 900026 */
 	default:
 		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
 		break;
@@ -928,6 +1012,9 @@ mpssas_scsiio_timeout(void *data)
 	struct mps_softc *sc;
 	struct mps_command *cm;
 	struct mpssas_target *targ;
+#if 0
+	char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
+#endif
 
 	cm = (struct mps_command *)data;
 	sc = cm->cm_sc;
@@ -952,6 +1039,22 @@ mpssas_scsiio_timeout(void *data)
 
 	xpt_print(ccb->ccb_h.path, "SCSI command timeout on device handle "
 		  "0x%04x SMID %d\n", targ->handle, cm->cm_desc.Default.SMID);
+	/*
+	 * XXX KDM this is useful for debugging purposes, but the existing
+	 * scsi_op_desc() implementation can't handle a NULL value for
+	 * inq_data.  So this will remain commented out until I bring in
+	 * those changes as well.
+	 */
+#if 0
+	xpt_print(ccb->ccb_h.path, "Timed out command: %s. CDB %s\n",
+		  scsi_op_desc((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+		  		ccb->csio.cdb_io.cdb_ptr[0] :
+				ccb->csio.cdb_io.cdb_bytes[0], NULL),
+		  scsi_cdb_string((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
+				   ccb->csio.cdb_io.cdb_ptr :
+				   ccb->csio.cdb_io.cdb_bytes, cdb_str,
+		  		   sizeof(cdb_str)));
+#endif
 
 	/* Inform CAM about the timeout and that recovery is starting. */
 #if 0
@@ -983,7 +1086,7 @@ mpssas_abort_complete(struct mps_softc *
 	mps_printf(sc, "%s: abort request on handle %#04x SMID %d "
 		   "complete\n", __func__, req->DevHandle, req->TaskMID);
 
-	mps_free_command(sc, cm);
+	mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1);
 }
 
 static void
@@ -991,7 +1094,6 @@ mpssas_recovery(struct mps_softc *sc, st
 {
 	struct mps_command *cm;
 	MPI2_SCSI_TASK_MANAGE_REQUEST *req, *orig_req;
-	int error;
 
 	cm = mps_alloc_command(sc);
 	if (cm == NULL) {
@@ -1013,25 +1115,204 @@ mpssas_recovery(struct mps_softc *sc, st
 	cm->cm_data = NULL;
 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
 
+	mpssas_issue_tm_request(sc, cm);
+
+}
+
+/*
+ * Can return 0 or EINPROGRESS on success.  Any other value means failure.
+ */
+static int
+mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm)
+{
+	int error;
+
+	error = 0;
+
+	cm->cm_flags |= MPS_CM_FLAGS_ACTIVE;
 	error = mps_map_command(sc, cm);
+	if ((error == 0)
+	 || (error == EINPROGRESS))
+		sc->tm_cmds_active++;
 
-	if (error != 0) {
-		mps_printf(sc, "%s: error mapping abort request!\n", __func__);
-	}
-#if 0
-	error = mpssas_reset(sc, targ, &resetcm);
-	if ((error != 0) && (error != EBUSY)) {
-		mps_printf(sc, "Error resetting device!\n");
-		mps_unlock(sc);
-		return;
+	return (error);
+}
+
+static void
+mpssas_issue_tm_request(struct mps_softc *sc, struct mps_command *cm)
+{
+	int freeze_queue, send_command, error;
+
+	freeze_queue = 0;
+	send_command = 0;
+	error = 0;
+
+	mtx_assert(&sc->mps_mtx, MA_OWNED);
+
+	/*
+	 * If there are no other pending task management commands, go
+	 * ahead and send this one.  There is a small amount of anecdotal
+	 * evidence that sending lots of task management commands at once
+	 * may cause the controller to lock up.  Or, if the user has
+	 * configured the driver (via the allow_multiple_tm_cmds variable) to
+	 * not serialize task management commands, go ahead and send the
+	 * command if even other task management commands are pending.
+	 */
+	if (TAILQ_FIRST(&sc->tm_list) == NULL) {
+		send_command = 1;
+		freeze_queue = 1;
+	} else if (sc->allow_multiple_tm_cmds != 0)
+		send_command = 1;
+
+	TAILQ_INSERT_TAIL(&sc->tm_list, cm, cm_link);
+	if (send_command != 0) {
+		/*
+		 * Freeze the SIM queue while we issue the task management
+		 * command.  According to the Fusion-MPT 2.0 spec, task
+		 * management requests are serialized, and so the host
+		 * should not send any I/O requests while task management
+		 * requests are pending.
+		 */
+		if (freeze_queue != 0)
+			xpt_freeze_simq(sc->sassc->sim, 1);
+
+		error = mpssas_map_tm_request(sc, cm);
+
+		/*
+		 * At present, there is no error path back from
+		 * mpssas_map_tm_request() (which calls mps_map_command())
+		 * when cm->cm_data == NULL.  But since there is a return
+		 * value, we check it just in case the implementation
+		 * changes later.
+		 */
+		if ((error != 0)
+		 && (error != EINPROGRESS))
+			mpssas_tm_complete(sc, cm,
+			    MPI2_SCSITASKMGMT_RSP_TM_FAILED);
 	}
+}
+
+static void
+mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, int error)
+{
+	MPI2_SCSI_TASK_MANAGE_REPLY *resp;
+
+	resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
 
-	targ->flags |= MPSSAS_TARGET_INRESET;
+	resp->ResponseCode = error;
 
-	cm->cm_complete = mpssas_resettimeout_complete;
-	cm->cm_complete_data = cm;
-	mps_map_command(sassc->sc, cm);
-#endif
+	/*
+	 * Call the callback for this command, it will be
+	 * removed from the list and freed via the callback.
+	 */
+	cm->cm_complete(sc, cm);
+}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list