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-stable-8
mailing list