The following diff replaces the hand rolled code to deal with really long mbuf chains with the use of m_defrag().
Index: xl.c =================================================================== RCS file: /cvs/src/sys/dev/ic/xl.c,v retrieving revision 1.88 diff -u -p -r1.88 xl.c --- xl.c 22 Dec 2009 21:10:25 -0000 1.88 +++ xl.c 24 Dec 2009 07:57:00 -0000 @@ -1614,23 +1614,25 @@ xl_encap(struct xl_softc *sc, struct xl_ map = sc->sc_tx_sparemap; -reload: error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m_head, BUS_DMA_NOWAIT); - - if (error && error != EFBIG) { - m_freem(m_head); - return (1); + if (error != 0 && error != EFBIG) + goto drop; + if (error != 0) { + if (m_defrag(m_head, M_DONTWAIT)) + goto drop; + error = bus_dmamap_load_mbuf(sc->sc_dmat, map, + m_head, BUS_DMA_NOWAIT); + if (error != 0) + goto drop; } /* * Start packing the mbufs in this chain into - * the fragment pointers. Stop when we run out - * of fragments or hit the end of the mbuf chain. + * the fragment pointers. Stop when we hit the + * end of the mbuf chain. */ for (frag = 0, total_len = 0; frag < map->dm_nsegs; frag++) { - if (frag == XL_MAXFRAGS) - break; total_len += map->dm_segs[frag].ds_len; c->xl_ptr->xl_frag[frag].xl_addr = htole32(map->dm_segs[frag].ds_addr); @@ -1638,38 +1640,6 @@ reload: htole32(map->dm_segs[frag].ds_len); } - /* - * Handle special case: we used up all 63 fragments, - * but we have more mbufs left in the chain. Copy the - * data into an mbuf cluster. Note that we don't - * bother clearing the values in the other fragment - * pointers/counters; it wouldn't gain us anything, - * and would waste cycles. - */ - if (error) { - struct mbuf *m_new = NULL; - - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) { - m_freem(m_head); - return (1); - } - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - m_freem(m_head); - return (1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - m_freem(m_head); - m_head = m_new; - goto reload; - } - bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, BUS_DMASYNC_PREWRITE); @@ -1708,6 +1678,10 @@ reload: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); + + drop: + m_freem(m_head); + return (1); } /* -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.