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);
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to