xref: /titanic_44/usr/src/uts/common/io/multidata.c (revision 75d94465dbafa487b716482dc36d5150a4ec9853)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23bd118333Smeem  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Multidata, as described in the following papers:
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * Adi Masputra,
317c478bd9Sstevel@tonic-gate  * Multidata V.2: VA-Disjoint Packet Extents Framework Interface
327c478bd9Sstevel@tonic-gate  * Design Specification.  August 2004.
337c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2004/594/materials/mmd2.pdf.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * Adi Masputra,
367c478bd9Sstevel@tonic-gate  * Multidata Interface Design Specification.  Sep 2002.
377c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mmd.pdf.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * Adi Masputra, Frank DiMambro, Kacheong Poon,
407c478bd9Sstevel@tonic-gate  * An Efficient Networking Transmit Mechanism for Solaris:
417c478bd9Sstevel@tonic-gate  * Multidata Transmit (MDT).  May 2002.
427c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mdt.pdf.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/stream.h>
477c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
487c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
497c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
507c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
517c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
527c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
537c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
547c478bd9Sstevel@tonic-gate #include <sys/debug.h>
557c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
567c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
597c478bd9Sstevel@tonic-gate #include <sys/multidata_impl.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate static int mmd_constructor(void *, void *, int);
627c478bd9Sstevel@tonic-gate static void mmd_destructor(void *, void *);
637c478bd9Sstevel@tonic-gate static int pdslab_constructor(void *, void *, int);
647c478bd9Sstevel@tonic-gate static void pdslab_destructor(void *, void *);
657c478bd9Sstevel@tonic-gate static int pattbl_constructor(void *, void *, int);
667c478bd9Sstevel@tonic-gate static void pattbl_destructor(void *, void *);
677c478bd9Sstevel@tonic-gate static void mmd_esballoc_free(caddr_t);
687c478bd9Sstevel@tonic-gate static int mmd_copy_pattbl(patbkt_t *, multidata_t *, pdesc_t *, int);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static boolean_t pbuf_ref_valid(multidata_t *, pdescinfo_t *);
717c478bd9Sstevel@tonic-gate #pragma inline(pbuf_ref_valid)
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static boolean_t pdi_in_range(pdescinfo_t *, pdescinfo_t *);
747c478bd9Sstevel@tonic-gate #pragma inline(pdi_in_range)
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static pdesc_t *mmd_addpdesc_int(multidata_t *, pdescinfo_t *, int *, int);
777c478bd9Sstevel@tonic-gate #pragma inline(mmd_addpdesc_int)
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static void mmd_destroy_pattbl(patbkt_t **);
807c478bd9Sstevel@tonic-gate #pragma inline(mmd_destroy_pattbl)
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static pattr_t *mmd_find_pattr(patbkt_t *, uint_t);
837c478bd9Sstevel@tonic-gate #pragma inline(mmd_find_pattr)
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static pdesc_t *mmd_destroy_pdesc(multidata_t *, pdesc_t *);
867c478bd9Sstevel@tonic-gate #pragma inline(mmd_destroy_pdesc)
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static pdesc_t *mmd_getpdesc(multidata_t *, pdesc_t *, pdescinfo_t *, uint_t,
897c478bd9Sstevel@tonic-gate     boolean_t);
907c478bd9Sstevel@tonic-gate #pragma inline(mmd_getpdesc)
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static struct kmem_cache *mmd_cache;
937c478bd9Sstevel@tonic-gate static struct kmem_cache *pd_slab_cache;
947c478bd9Sstevel@tonic-gate static struct kmem_cache *pattbl_cache;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate int mmd_debug = 1;
977c478bd9Sstevel@tonic-gate #define	MMD_DEBUG(s)	if (mmd_debug > 0) cmn_err s
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Set to this to true to bypass pdesc bounds checking.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate boolean_t mmd_speed_over_safety = B_FALSE;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * Patchable kmem_cache flags.
1067c478bd9Sstevel@tonic-gate  */
1077c478bd9Sstevel@tonic-gate int mmd_kmem_flags = 0;
1087c478bd9Sstevel@tonic-gate int pdslab_kmem_flags = 0;
1097c478bd9Sstevel@tonic-gate int pattbl_kmem_flags = 0;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Alignment (in bytes) of our kmem caches.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate #define	MULTIDATA_CACHE_ALIGN	64
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate  * Default number of packet descriptors per descriptor slab.  Making
1187c478bd9Sstevel@tonic-gate  * this too small will trigger more descriptor slab allocation; making
1197c478bd9Sstevel@tonic-gate  * it too large will create too many unclaimed descriptors.
1207c478bd9Sstevel@tonic-gate  */
1217c478bd9Sstevel@tonic-gate #define	PDSLAB_SZ	15
1227c478bd9Sstevel@tonic-gate uint_t pdslab_sz = PDSLAB_SZ;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * Default attribute hash table size.  It's okay to set this to a small
1267c478bd9Sstevel@tonic-gate  * value (even to 1) because there aren't that many attributes currently
1277c478bd9Sstevel@tonic-gate  * defined, and because we assume there won't be many attributes associated
1287c478bd9Sstevel@tonic-gate  * with a Multidata at a given time.  Increasing the size will reduce
1297c478bd9Sstevel@tonic-gate  * attribute search time (given a large number of attributes in a Multidata),
1307c478bd9Sstevel@tonic-gate  * and decreasing it will reduce the memory footprints and the overhead
1317c478bd9Sstevel@tonic-gate  * associated with managing the table.
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate #define	PATTBL_SZ	1
1347c478bd9Sstevel@tonic-gate uint_t pattbl_sz = PATTBL_SZ;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * Attribute hash key.
1387c478bd9Sstevel@tonic-gate  */
1397c478bd9Sstevel@tonic-gate #define	PATTBL_HASH(x, sz)	((x) % (sz))
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*
1427c478bd9Sstevel@tonic-gate  * Structure that precedes each Multidata metadata.
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate struct mmd_buf_info {
1457c478bd9Sstevel@tonic-gate 	frtn_t	frp;		/* free routine */
1467c478bd9Sstevel@tonic-gate 	uint_t	buf_len;	/* length of kmem buffer */
1477c478bd9Sstevel@tonic-gate };
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * The size of each metadata buffer.
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate #define	MMD_CACHE_SIZE	\
1537c478bd9Sstevel@tonic-gate 	(sizeof (struct mmd_buf_info) + sizeof (multidata_t))
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Called during startup in order to create the Multidata kmem caches.
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate void
mmd_init(void)1597c478bd9Sstevel@tonic-gate mmd_init(void)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	pdslab_sz = MAX(1, pdslab_sz);	/* at least 1 descriptor */
1627c478bd9Sstevel@tonic-gate 	pattbl_sz = MAX(1, pattbl_sz);	/* at least 1 bucket */
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	mmd_cache = kmem_cache_create("multidata", MMD_CACHE_SIZE,
1657c478bd9Sstevel@tonic-gate 	    MULTIDATA_CACHE_ALIGN, mmd_constructor, mmd_destructor,
1667c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, mmd_kmem_flags);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	pd_slab_cache = kmem_cache_create("multidata_pdslab",
1697c478bd9Sstevel@tonic-gate 	    PDESC_SLAB_SIZE(pdslab_sz), MULTIDATA_CACHE_ALIGN,
1707c478bd9Sstevel@tonic-gate 	    pdslab_constructor, pdslab_destructor, NULL,
1717c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)pdslab_sz, NULL, pdslab_kmem_flags);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	pattbl_cache = kmem_cache_create("multidata_pattbl",
1747c478bd9Sstevel@tonic-gate 	    sizeof (patbkt_t) * pattbl_sz, MULTIDATA_CACHE_ALIGN,
1757c478bd9Sstevel@tonic-gate 	    pattbl_constructor, pattbl_destructor, NULL,
1767c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)pattbl_sz, NULL, pattbl_kmem_flags);
1777c478bd9Sstevel@tonic-gate }
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * Create a Multidata message block.
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate multidata_t *
mmd_alloc(mblk_t * hdr_mp,mblk_t ** mmd_mp,int kmflags)1837c478bd9Sstevel@tonic-gate mmd_alloc(mblk_t *hdr_mp, mblk_t **mmd_mp, int kmflags)
1847c478bd9Sstevel@tonic-gate {
1857c478bd9Sstevel@tonic-gate 	uchar_t *buf;
1867c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
1877c478bd9Sstevel@tonic-gate 	uint_t mmd_mplen;
1887c478bd9Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	ASSERT(hdr_mp != NULL);
1917c478bd9Sstevel@tonic-gate 	ASSERT(mmd_mp != NULL);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/*
1947c478bd9Sstevel@tonic-gate 	 * Caller should never pass in a chain of mblks since we
1957c478bd9Sstevel@tonic-gate 	 * only care about the first one, hence the assertions.
1967c478bd9Sstevel@tonic-gate 	 */
1977c478bd9Sstevel@tonic-gate 	ASSERT(hdr_mp->b_cont == NULL);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if ((buf = kmem_cache_alloc(mmd_cache, kmflags)) == NULL)
2007c478bd9Sstevel@tonic-gate 		return (NULL);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
2037c478bd9Sstevel@tonic-gate 	buf_info->frp.free_arg = (caddr_t)buf;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
2067c478bd9Sstevel@tonic-gate 	mmd_mplen = sizeof (*mmd);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if ((*mmd_mp = desballoc((uchar_t *)mmd, mmd_mplen, BPRI_HI,
2097c478bd9Sstevel@tonic-gate 	    &(buf_info->frp))) == NULL) {
2107c478bd9Sstevel@tonic-gate 		kmem_cache_free(mmd_cache, buf);
2117c478bd9Sstevel@tonic-gate 		return (NULL);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	DB_TYPE(*mmd_mp) = M_MULTIDATA;
2157c478bd9Sstevel@tonic-gate 	(*mmd_mp)->b_wptr += mmd_mplen;
2167c478bd9Sstevel@tonic-gate 	mmd->mmd_dp = (*mmd_mp)->b_datap;
2177c478bd9Sstevel@tonic-gate 	mmd->mmd_hbuf = hdr_mp;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	return (mmd);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * Associate additional payload buffer to the Multidata.
2247c478bd9Sstevel@tonic-gate  */
2257c478bd9Sstevel@tonic-gate int
mmd_addpldbuf(multidata_t * mmd,mblk_t * pld_mp)2267c478bd9Sstevel@tonic-gate mmd_addpldbuf(multidata_t *mmd, mblk_t *pld_mp)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	int i;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
2317c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
2327c478bd9Sstevel@tonic-gate 	ASSERT(pld_mp != NULL);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
2357c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS &&
2367c478bd9Sstevel@tonic-gate 	    mmd->mmd_pbuf_cnt < MULTIDATA_MAX_PBUFS; i++) {
2377c478bd9Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] == pld_mp) {
2387c478bd9Sstevel@tonic-gate 			/* duplicate entry */
2397c478bd9Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding "
2407c478bd9Sstevel@tonic-gate 			    "pld 0x%p to mmd 0x%p since it has been "
2417c478bd9Sstevel@tonic-gate 			    "previously added into slot %d (total %d)\n",
2427c478bd9Sstevel@tonic-gate 			    (void *)pld_mp, (void *)mmd, i, mmd->mmd_pbuf_cnt));
2437c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
2447c478bd9Sstevel@tonic-gate 			return (-1);
2457c478bd9Sstevel@tonic-gate 		} else if (mmd->mmd_pbuf[i] == NULL) {
2467c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = pld_mp;
2477c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt++;
2487c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
2497c478bd9Sstevel@tonic-gate 			return (i);
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/* all slots are taken */
2547c478bd9Sstevel@tonic-gate 	MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding pld 0x%p to mmd 0x%p "
2557c478bd9Sstevel@tonic-gate 	    "since no slot space is left (total %d max %d)\n", (void *)pld_mp,
2567c478bd9Sstevel@tonic-gate 	    (void *)mmd, mmd->mmd_pbuf_cnt, MULTIDATA_MAX_PBUFS));
2577c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	return (-1);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate  * Multidata metadata kmem cache constructor routine.
2647c478bd9Sstevel@tonic-gate  */
2657c478bd9Sstevel@tonic-gate /* ARGSUSED */
2667c478bd9Sstevel@tonic-gate static int
mmd_constructor(void * buf,void * cdrarg,int kmflags)2677c478bd9Sstevel@tonic-gate mmd_constructor(void *buf, void *cdrarg, int kmflags)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
2707c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	bzero((void *)buf, MMD_CACHE_SIZE);
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
2757c478bd9Sstevel@tonic-gate 	buf_info->frp.free_func = mmd_esballoc_free;
2767c478bd9Sstevel@tonic-gate 	buf_info->buf_len = MMD_CACHE_SIZE;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
2797c478bd9Sstevel@tonic-gate 	mmd->mmd_magic = MULTIDATA_MAGIC;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	mutex_init(&(mmd->mmd_pd_slab_lock), NULL, MUTEX_DRIVER, NULL);
2827c478bd9Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_slab_q));
2837c478bd9Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_q));
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	return (0);
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * Multidata metadata kmem cache destructor routine.
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate /* ARGSUSED */
2927c478bd9Sstevel@tonic-gate static void
mmd_destructor(void * buf,void * cdrarg)2937c478bd9Sstevel@tonic-gate mmd_destructor(void *buf, void *cdrarg)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
2967c478bd9Sstevel@tonic-gate #ifdef DEBUG
2977c478bd9Sstevel@tonic-gate 	int i;
2987c478bd9Sstevel@tonic-gate #endif
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)((uchar_t *)buf + sizeof (struct mmd_buf_info));
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
3037c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp == NULL);
3047c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf == NULL);
3057c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
3067c478bd9Sstevel@tonic-gate #ifdef DEBUG
3077c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++)
3087c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] == NULL);
3097c478bd9Sstevel@tonic-gate #endif
3107c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pattbl == NULL);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	mutex_destroy(&(mmd->mmd_pd_slab_lock));
3137c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
3147c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
3157c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
3167c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
3177c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
3187c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * Multidata message block free callback routine.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate static void
mmd_esballoc_free(caddr_t buf)3257c478bd9Sstevel@tonic-gate mmd_esballoc_free(caddr_t buf)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
3287c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
3297c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
3307c478bd9Sstevel@tonic-gate 	int i;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
3337c478bd9Sstevel@tonic-gate 	ASSERT(((struct mmd_buf_info *)buf)->buf_len == MMD_CACHE_SIZE);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf + sizeof (struct mmd_buf_info));
3367c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp != NULL);
3397c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp->db_ref == 1);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	/* remove all packet descriptors and private attributes */
3427c478bd9Sstevel@tonic-gate 	pd = Q2PD(mmd->mmd_pd_q.ql_next);
3437c478bd9Sstevel@tonic-gate 	while (pd != Q2PD(&(mmd->mmd_pd_q)))
3447c478bd9Sstevel@tonic-gate 		pd = mmd_destroy_pdesc(mmd, pd);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
3477c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
3487c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
3497c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/* remove all global attributes */
3527c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL)
3537c478bd9Sstevel@tonic-gate 		mmd_destroy_pattbl(&(mmd->mmd_pattbl));
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* remove all descriptor slabs */
3567c478bd9Sstevel@tonic-gate 	slab = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_next);
3577c478bd9Sstevel@tonic-gate 	while (slab != Q2PDSLAB(&(mmd->mmd_pd_slab_q))) {
3587c478bd9Sstevel@tonic-gate 		pdesc_slab_t *slab_next = Q2PDSLAB(slab->pds_next);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		remque(&(slab->pds_next));
3617c478bd9Sstevel@tonic-gate 		slab->pds_next = NULL;
3627c478bd9Sstevel@tonic-gate 		slab->pds_prev = NULL;
3637c478bd9Sstevel@tonic-gate 		slab->pds_mmd = NULL;
3647c478bd9Sstevel@tonic-gate 		slab->pds_used = 0;
3657c478bd9Sstevel@tonic-gate 		kmem_cache_free(pd_slab_cache, slab);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_slab_cnt > 0);
3687c478bd9Sstevel@tonic-gate 		mmd->mmd_slab_cnt--;
3697c478bd9Sstevel@tonic-gate 		slab = slab_next;
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
3727c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	mmd->mmd_dp = NULL;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* finally, free all associated message blocks */
3777c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
3787c478bd9Sstevel@tonic-gate 		freeb(mmd->mmd_hbuf);
3797c478bd9Sstevel@tonic-gate 		mmd->mmd_hbuf = NULL;
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++) {
3837c478bd9Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] != NULL) {
3847c478bd9Sstevel@tonic-gate 			freeb(mmd->mmd_pbuf[i]);
3857c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = NULL;
3867c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_cnt > 0);
3877c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt--;
3887c478bd9Sstevel@tonic-gate 		}
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
3927c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&(mmd->mmd_pd_slab_lock)));
3937c478bd9Sstevel@tonic-gate 	kmem_cache_free(mmd_cache, buf);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate  * Multidata message block copy routine, called by copyb() when it
3987c478bd9Sstevel@tonic-gate  * encounters a M_MULTIDATA data block type.  This routine should
3997c478bd9Sstevel@tonic-gate  * not be called by anyone other than copyb(), since it may go away
4007c478bd9Sstevel@tonic-gate  * (read: become static to this module) once some sort of copy callback
4017c478bd9Sstevel@tonic-gate  * routine is made available.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate mblk_t *
mmd_copy(mblk_t * bp,int kmflags)4047c478bd9Sstevel@tonic-gate mmd_copy(mblk_t *bp, int kmflags)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	multidata_t *mmd, *n_mmd;
4077c478bd9Sstevel@tonic-gate 	mblk_t *n_hbuf = NULL, *n_pbuf[MULTIDATA_MAX_PBUFS];
4087c478bd9Sstevel@tonic-gate 	mblk_t **pmp_last = &n_pbuf[MULTIDATA_MAX_PBUFS - 1];
4097c478bd9Sstevel@tonic-gate 	mblk_t **pmp;
4107c478bd9Sstevel@tonic-gate 	mblk_t *n_bp = NULL;
4117c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
4127c478bd9Sstevel@tonic-gate 	uint_t n_pbuf_cnt = 0;
4137c478bd9Sstevel@tonic-gate 	int idx, i;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate #define	FREE_PBUFS() {					\
4167c478bd9Sstevel@tonic-gate 	for (pmp = &n_pbuf[0]; pmp <= pmp_last; pmp++)	\
4177c478bd9Sstevel@tonic-gate 		if (*pmp != NULL) freeb(*pmp);		\
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate #define	REL_OFF(p, base, n_base)			\
4217c478bd9Sstevel@tonic-gate 	((uchar_t *)(n_base) + ((uchar_t *)(p) - (uchar_t *)base))
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL && DB_TYPE(bp) == M_MULTIDATA);
4247c478bd9Sstevel@tonic-gate 	mmd = mmd_getmultidata(bp);
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/* copy the header buffer */
4277c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL && (n_hbuf = copyb(mmd->mmd_hbuf)) == NULL)
4287c478bd9Sstevel@tonic-gate 		return (NULL);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* copy the payload buffer(s) */
4317c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
4327c478bd9Sstevel@tonic-gate 	bzero((void *)&n_pbuf[0], sizeof (mblk_t *) * MULTIDATA_MAX_PBUFS);
4337c478bd9Sstevel@tonic-gate 	n_pbuf_cnt = mmd->mmd_pbuf_cnt;
4347c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_pbuf_cnt; i++) {
4357c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
4367c478bd9Sstevel@tonic-gate 		n_pbuf[i] = copyb(mmd->mmd_pbuf[i]);
4377c478bd9Sstevel@tonic-gate 		if (n_pbuf[i] == NULL) {
4387c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
4397c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
4407c478bd9Sstevel@tonic-gate 			return (NULL);
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/* allocate new Multidata */
4457c478bd9Sstevel@tonic-gate 	n_mmd = mmd_alloc(n_hbuf, &n_bp, kmflags);
4467c478bd9Sstevel@tonic-gate 	if (n_mmd == NULL) {
4477c478bd9Sstevel@tonic-gate 		if (n_hbuf != NULL)
4487c478bd9Sstevel@tonic-gate 			freeb(n_hbuf);
4497c478bd9Sstevel@tonic-gate 		if (n_pbuf_cnt != 0)
4507c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
4517c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
4527c478bd9Sstevel@tonic-gate 		return (NULL);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/*
4567c478bd9Sstevel@tonic-gate 	 * Add payload buffer(s); upon success, leave n_pbuf array
4577c478bd9Sstevel@tonic-gate 	 * alone, as the newly-created Multidata had already contained
4587c478bd9Sstevel@tonic-gate 	 * the mblk pointers stored in the array.  These will be freed
4597c478bd9Sstevel@tonic-gate 	 * along with the Multidata itself.
4607c478bd9Sstevel@tonic-gate 	 */
4617c478bd9Sstevel@tonic-gate 	for (i = 0, pmp = &n_pbuf[0]; i < n_pbuf_cnt; i++, pmp++) {
4627c478bd9Sstevel@tonic-gate 		idx = mmd_addpldbuf(n_mmd, *pmp);
4637c478bd9Sstevel@tonic-gate 		if (idx < 0) {
4647c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
4657c478bd9Sstevel@tonic-gate 			freeb(n_bp);
4667c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
4677c478bd9Sstevel@tonic-gate 			return (NULL);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/* copy over global attributes */
4727c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL &&
4737c478bd9Sstevel@tonic-gate 	    mmd_copy_pattbl(mmd->mmd_pattbl, n_mmd, NULL, kmflags) < 0) {
4747c478bd9Sstevel@tonic-gate 		freeb(n_bp);
4757c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
4767c478bd9Sstevel@tonic-gate 		return (NULL);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* copy over packet descriptors and their atttributes */
4807c478bd9Sstevel@tonic-gate 	pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);	/* first pdesc */
4817c478bd9Sstevel@tonic-gate 	while (pd != NULL) {
4827c478bd9Sstevel@tonic-gate 		pdesc_t *n_pd;
4837c478bd9Sstevel@tonic-gate 		pdescinfo_t *pdi, n_pdi;
4847c478bd9Sstevel@tonic-gate 		uchar_t *n_base, *base;
4857c478bd9Sstevel@tonic-gate 		pdesc_t *pd_next;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		/* next pdesc */
4887c478bd9Sstevel@tonic-gate 		pd_next = mmd_getpdesc(pd->pd_slab->pds_mmd, pd, NULL,
4897c478bd9Sstevel@tonic-gate 		    1, B_TRUE);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 		/* skip if already removed */
4927c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_REM_DEFER) {
4937c478bd9Sstevel@tonic-gate 			pd = pd_next;
4947c478bd9Sstevel@tonic-gate 			continue;
4957c478bd9Sstevel@tonic-gate 		}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		pdi = &(pd->pd_pdi);
4987c478bd9Sstevel@tonic-gate 		bzero(&n_pdi, sizeof (n_pdi));
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 		/*
5017c478bd9Sstevel@tonic-gate 		 * Calculate new descriptor values based on the offset of
5027c478bd9Sstevel@tonic-gate 		 * each pointer relative to the associated buffer(s).
5037c478bd9Sstevel@tonic-gate 		 */
5047c478bd9Sstevel@tonic-gate 		ASSERT(pdi->flags & PDESC_HAS_REF);
5057c478bd9Sstevel@tonic-gate 		if (pdi->flags & PDESC_HBUF_REF) {
5067c478bd9Sstevel@tonic-gate 			n_base = n_mmd->mmd_hbuf->b_rptr;
5077c478bd9Sstevel@tonic-gate 			base = mmd->mmd_hbuf->b_rptr;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 			n_pdi.flags |= PDESC_HBUF_REF;
5107c478bd9Sstevel@tonic-gate 			n_pdi.hdr_base = REL_OFF(pdi->hdr_base, base, n_base);
5117c478bd9Sstevel@tonic-gate 			n_pdi.hdr_rptr = REL_OFF(pdi->hdr_rptr, base, n_base);
5127c478bd9Sstevel@tonic-gate 			n_pdi.hdr_wptr = REL_OFF(pdi->hdr_wptr, base, n_base);
5137c478bd9Sstevel@tonic-gate 			n_pdi.hdr_lim = REL_OFF(pdi->hdr_lim, base, n_base);
5147c478bd9Sstevel@tonic-gate 		}
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		if (pdi->flags & PDESC_PBUF_REF) {
5177c478bd9Sstevel@tonic-gate 			n_pdi.flags |= PDESC_PBUF_REF;
5187c478bd9Sstevel@tonic-gate 			n_pdi.pld_cnt = pdi->pld_cnt;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 			for (i = 0; i < pdi->pld_cnt; i++) {
5217c478bd9Sstevel@tonic-gate 				idx = pdi->pld_ary[i].pld_pbuf_idx;
5227c478bd9Sstevel@tonic-gate 				ASSERT(idx < MULTIDATA_MAX_PBUFS);
5237c478bd9Sstevel@tonic-gate 				ASSERT(n_mmd->mmd_pbuf[idx] != NULL);
5247c478bd9Sstevel@tonic-gate 				ASSERT(mmd->mmd_pbuf[idx] != NULL);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 				n_base = n_mmd->mmd_pbuf[idx]->b_rptr;
5277c478bd9Sstevel@tonic-gate 				base = mmd->mmd_pbuf[idx]->b_rptr;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_pbuf_idx = idx;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 				/*
5327c478bd9Sstevel@tonic-gate 				 * We can't copy the pointers just like that,
5337c478bd9Sstevel@tonic-gate 				 * so calculate the relative offset.
5347c478bd9Sstevel@tonic-gate 				 */
5357c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_rptr =
5367c478bd9Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_rptr,
5377c478bd9Sstevel@tonic-gate 					base, n_base);
5387c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_wptr =
5397c478bd9Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_wptr,
5407c478bd9Sstevel@tonic-gate 					base, n_base);
5417c478bd9Sstevel@tonic-gate 			}
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		/* add the new descriptor to the new Multidata */
5457c478bd9Sstevel@tonic-gate 		n_pd = mmd_addpdesc_int(n_mmd, &n_pdi, NULL, kmflags);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 		if (n_pd == NULL || (pd->pd_pattbl != NULL &&
5487c478bd9Sstevel@tonic-gate 		    mmd_copy_pattbl(pd->pd_pattbl, n_mmd, n_pd, kmflags) < 0)) {
5497c478bd9Sstevel@tonic-gate 			freeb(n_bp);
5507c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
5517c478bd9Sstevel@tonic-gate 			return (NULL);
5527c478bd9Sstevel@tonic-gate 		}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 		pd = pd_next;
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate #undef REL_OFF
5577c478bd9Sstevel@tonic-gate #undef FREE_PBUFS
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
5607c478bd9Sstevel@tonic-gate 	return (n_bp);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate /*
5647c478bd9Sstevel@tonic-gate  * Given a Multidata message block, return the Multidata metadata handle.
5657c478bd9Sstevel@tonic-gate  */
5667c478bd9Sstevel@tonic-gate multidata_t *
mmd_getmultidata(mblk_t * mp)5677c478bd9Sstevel@tonic-gate mmd_getmultidata(mblk_t *mp)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_MULTIDATA)
5747c478bd9Sstevel@tonic-gate 		return (NULL);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)mp->b_rptr;
5777c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	return (mmd);
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate  * Return the start and end addresses of the associated buffer(s).
5847c478bd9Sstevel@tonic-gate  */
5857c478bd9Sstevel@tonic-gate void
mmd_getregions(multidata_t * mmd,mbufinfo_t * mbi)5867c478bd9Sstevel@tonic-gate mmd_getregions(multidata_t *mmd, mbufinfo_t *mbi)
5877c478bd9Sstevel@tonic-gate {
5887c478bd9Sstevel@tonic-gate 	int i;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
5917c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
5927c478bd9Sstevel@tonic-gate 	ASSERT(mbi != NULL);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	bzero((void *)mbi, sizeof (mbufinfo_t));
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
5977c478bd9Sstevel@tonic-gate 		mbi->hbuf_rptr = mmd->mmd_hbuf->b_rptr;
5987c478bd9Sstevel@tonic-gate 		mbi->hbuf_wptr = mmd->mmd_hbuf->b_wptr;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
6027c478bd9Sstevel@tonic-gate 	for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
6037c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
6047c478bd9Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_rptr = mmd->mmd_pbuf[i]->b_rptr;
6057c478bd9Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_wptr = mmd->mmd_pbuf[i]->b_wptr;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 	mbi->pbuf_cnt = mmd->mmd_pbuf_cnt;
6097c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate  * Return the Multidata statistics.
6147c478bd9Sstevel@tonic-gate  */
6157c478bd9Sstevel@tonic-gate uint_t
mmd_getcnt(multidata_t * mmd,uint_t * hbuf_ref,uint_t * pbuf_ref)6167c478bd9Sstevel@tonic-gate mmd_getcnt(multidata_t *mmd, uint_t *hbuf_ref, uint_t *pbuf_ref)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	uint_t pd_cnt;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
6217c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
6247c478bd9Sstevel@tonic-gate 	if (hbuf_ref != NULL)
6257c478bd9Sstevel@tonic-gate 		*hbuf_ref = mmd->mmd_hbuf_ref;
6267c478bd9Sstevel@tonic-gate 	if (pbuf_ref != NULL)
6277c478bd9Sstevel@tonic-gate 		*pbuf_ref = mmd->mmd_pbuf_ref;
6287c478bd9Sstevel@tonic-gate 	pd_cnt = mmd->mmd_pd_cnt;
6297c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	return (pd_cnt);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate #define	HBUF_REF_VALID(mmd, pdi)					\
6357c478bd9Sstevel@tonic-gate 	((mmd)->mmd_hbuf != NULL && (pdi)->hdr_rptr != NULL &&		\
6367c478bd9Sstevel@tonic-gate 	(pdi)->hdr_wptr != NULL && (pdi)->hdr_base != NULL &&		\
6377c478bd9Sstevel@tonic-gate 	(pdi)->hdr_lim != NULL && (pdi)->hdr_lim >= (pdi)->hdr_base &&	\
6387c478bd9Sstevel@tonic-gate 	(pdi)->hdr_wptr >= (pdi)->hdr_rptr &&				\
6397c478bd9Sstevel@tonic-gate 	(pdi)->hdr_base <= (pdi)->hdr_rptr &&				\
6407c478bd9Sstevel@tonic-gate 	(pdi)->hdr_lim >= (pdi)->hdr_wptr &&				\
6417c478bd9Sstevel@tonic-gate 	(pdi)->hdr_base >= (mmd)->mmd_hbuf->b_rptr &&			\
6427c478bd9Sstevel@tonic-gate 	MBLKIN((mmd)->mmd_hbuf,						\
6437c478bd9Sstevel@tonic-gate 	(pdi->hdr_base - (mmd)->mmd_hbuf->b_rptr),			\
6447c478bd9Sstevel@tonic-gate 	PDESC_HDRSIZE(pdi)))
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate  * Bounds check payload area(s).
6487c478bd9Sstevel@tonic-gate  */
6497c478bd9Sstevel@tonic-gate static boolean_t
pbuf_ref_valid(multidata_t * mmd,pdescinfo_t * pdi)6507c478bd9Sstevel@tonic-gate pbuf_ref_valid(multidata_t *mmd, pdescinfo_t *pdi)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	int i = 0, idx;
6537c478bd9Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
6547c478bd9Sstevel@tonic-gate 	struct pld_ary_s *pa;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
6577c478bd9Sstevel@tonic-gate 	if (pdi->pld_cnt == 0 || pdi->pld_cnt > mmd->mmd_pbuf_cnt) {
6587c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
6597c478bd9Sstevel@tonic-gate 		return (B_FALSE);
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	pa = &pdi->pld_ary[0];
6637c478bd9Sstevel@tonic-gate 	while (valid && i < pdi->pld_cnt) {
6647c478bd9Sstevel@tonic-gate 		valid = (((idx = pa->pld_pbuf_idx) < mmd->mmd_pbuf_cnt) &&
6657c478bd9Sstevel@tonic-gate 		    pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
6667c478bd9Sstevel@tonic-gate 		    pa->pld_wptr >= pa->pld_rptr &&
6677c478bd9Sstevel@tonic-gate 		    pa->pld_rptr >= mmd->mmd_pbuf[idx]->b_rptr &&
6687c478bd9Sstevel@tonic-gate 		    MBLKIN(mmd->mmd_pbuf[idx], (pa->pld_rptr -
6697c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[idx]->b_rptr),
6707c478bd9Sstevel@tonic-gate 			PDESC_PLD_SPAN_SIZE(pdi, i)));
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		if (!valid) {
6737c478bd9Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN,
6747c478bd9Sstevel@tonic-gate 			    "pbuf_ref_valid: pdi 0x%p pld out of bound; "
6757c478bd9Sstevel@tonic-gate 			    "index %d has pld_cnt %d pbuf_idx %d "
6767c478bd9Sstevel@tonic-gate 			    "(mmd_pbuf_cnt %d), "
6777c478bd9Sstevel@tonic-gate 			    "pld_rptr 0x%p pld_wptr 0x%p len %d "
6787c478bd9Sstevel@tonic-gate 			    "(valid 0x%p-0x%p len %d)\n", (void *)pdi,
6797c478bd9Sstevel@tonic-gate 			    i, pdi->pld_cnt, idx, mmd->mmd_pbuf_cnt,
6807c478bd9Sstevel@tonic-gate 			    (void *)pa->pld_rptr,
6817c478bd9Sstevel@tonic-gate 			    (void *)pa->pld_wptr,
6827c478bd9Sstevel@tonic-gate 			    (int)PDESC_PLD_SPAN_SIZE(pdi, i),
6837c478bd9Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_rptr,
6847c478bd9Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_wptr,
6857c478bd9Sstevel@tonic-gate 			    (int)MBLKL(mmd->mmd_pbuf[idx])));
6867c478bd9Sstevel@tonic-gate 		}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 		/* advance to next entry */
6897c478bd9Sstevel@tonic-gate 		i++;
6907c478bd9Sstevel@tonic-gate 		pa++;
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
6947c478bd9Sstevel@tonic-gate 	return (valid);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * Add a packet descriptor to the Multidata.
6997c478bd9Sstevel@tonic-gate  */
7007c478bd9Sstevel@tonic-gate pdesc_t *
mmd_addpdesc(multidata_t * mmd,pdescinfo_t * pdi,int * err,int kmflags)7017c478bd9Sstevel@tonic-gate mmd_addpdesc(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
7047c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
7057c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
7067c478bd9Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
7097c478bd9Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
7107c478bd9Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
7117c478bd9Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi)))) {
7127c478bd9Sstevel@tonic-gate 		if (err != NULL)
7137c478bd9Sstevel@tonic-gate 			*err = EINVAL;
7147c478bd9Sstevel@tonic-gate 		return (NULL);
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	return (mmd_addpdesc_int(mmd, pdi, err, kmflags));
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate  * Internal routine to add a packet descriptor, called when mmd_addpdesc
7227c478bd9Sstevel@tonic-gate  * or mmd_copy tries to allocate and add a descriptor to a Multidata.
7237c478bd9Sstevel@tonic-gate  */
7247c478bd9Sstevel@tonic-gate static pdesc_t *
mmd_addpdesc_int(multidata_t * mmd,pdescinfo_t * pdi,int * err,int kmflags)7257c478bd9Sstevel@tonic-gate mmd_addpdesc_int(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
7267c478bd9Sstevel@tonic-gate {
7277c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab, *slab_last;
7287c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
7317c478bd9Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_HBUF_REF) || HBUF_REF_VALID(mmd, pdi));
7327c478bd9Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_PBUF_REF) || pbuf_ref_valid(mmd, pdi));
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (err != NULL)
7357c478bd9Sstevel@tonic-gate 		*err = 0;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
7387c478bd9Sstevel@tonic-gate 	/*
7397c478bd9Sstevel@tonic-gate 	 * Is slab list empty or the last-added slab is full?  If so,
7407c478bd9Sstevel@tonic-gate 	 * allocate new slab for the descriptor; otherwise, use the
7417c478bd9Sstevel@tonic-gate 	 * last-added slab instead.
7427c478bd9Sstevel@tonic-gate 	 */
7437c478bd9Sstevel@tonic-gate 	slab_last = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_prev);
7447c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q) ||
7457c478bd9Sstevel@tonic-gate 	    slab_last->pds_used == slab_last->pds_sz) {
7467c478bd9Sstevel@tonic-gate 		slab = kmem_cache_alloc(pd_slab_cache, kmflags);
7477c478bd9Sstevel@tonic-gate 		if (slab == NULL) {
7487c478bd9Sstevel@tonic-gate 			if (err != NULL)
7497c478bd9Sstevel@tonic-gate 				*err = ENOMEM;
7507c478bd9Sstevel@tonic-gate 			mutex_exit(&(mmd->mmd_pd_slab_lock));
7517c478bd9Sstevel@tonic-gate 			return (NULL);
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 		slab->pds_mmd = mmd;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		ASSERT(slab->pds_used == 0);
7567c478bd9Sstevel@tonic-gate 		ASSERT(slab->pds_next == NULL && slab->pds_prev == NULL);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		/* insert slab at end of list */
7597c478bd9Sstevel@tonic-gate 		insque(&(slab->pds_next), mmd->mmd_pd_slab_q.ql_prev);
7607c478bd9Sstevel@tonic-gate 		mmd->mmd_slab_cnt++;
7617c478bd9Sstevel@tonic-gate 	} else {
7627c478bd9Sstevel@tonic-gate 		slab = slab_last;
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_used < slab->pds_sz);
7657c478bd9Sstevel@tonic-gate 	pd = &(slab->pds_free_desc[slab->pds_used++]);
7667c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
7677c478bd9Sstevel@tonic-gate 	pd->pd_next = NULL;
7687c478bd9Sstevel@tonic-gate 	pd->pd_prev = NULL;
7697c478bd9Sstevel@tonic-gate 	pd->pd_slab = slab;
7707c478bd9Sstevel@tonic-gate 	pd->pd_pattbl = NULL;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
7737c478bd9Sstevel@tonic-gate 	PDI_COPY(pdi, &(pd->pd_pdi));
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_HBUF_REF)
7767c478bd9Sstevel@tonic-gate 		mmd->mmd_hbuf_ref++;
7777c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_PBUF_REF)
7787c478bd9Sstevel@tonic-gate 		mmd->mmd_pbuf_ref += pd->pd_pdi.pld_cnt;
7797c478bd9Sstevel@tonic-gate 	mmd->mmd_pd_cnt++;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	/* insert descriptor at end of list */
7827c478bd9Sstevel@tonic-gate 	insque(&(pd->pd_next), mmd->mmd_pd_q.ql_prev);
7837c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	return (pd);
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate /*
7897c478bd9Sstevel@tonic-gate  * Packet descriptor slab kmem cache constructor routine.
7907c478bd9Sstevel@tonic-gate  */
7917c478bd9Sstevel@tonic-gate /* ARGSUSED */
7927c478bd9Sstevel@tonic-gate static int
pdslab_constructor(void * buf,void * cdrarg,int kmflags)7937c478bd9Sstevel@tonic-gate pdslab_constructor(void *buf, void *cdrarg, int kmflags)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
7967c478bd9Sstevel@tonic-gate 	uint_t cnt = (uint_t)(uintptr_t)cdrarg;
7977c478bd9Sstevel@tonic-gate 	int i;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	ASSERT(cnt > 0);	/* slab size can't be zero */
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
8027c478bd9Sstevel@tonic-gate 	slab->pds_next = NULL;
8037c478bd9Sstevel@tonic-gate 	slab->pds_prev = NULL;
8047c478bd9Sstevel@tonic-gate 	slab->pds_mmd = NULL;
8057c478bd9Sstevel@tonic-gate 	slab->pds_used = 0;
8067c478bd9Sstevel@tonic-gate 	slab->pds_sz = cnt;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
8097c478bd9Sstevel@tonic-gate 		pdesc_t *pd = &(slab->pds_free_desc[i]);
8107c478bd9Sstevel@tonic-gate 		pd->pd_magic = PDESC_MAGIC;
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 	return (0);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate /*
8167c478bd9Sstevel@tonic-gate  * Packet descriptor slab kmem cache destructor routine.
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate /* ARGSUSED */
8197c478bd9Sstevel@tonic-gate static void
pdslab_destructor(void * buf,void * cdrarg)8207c478bd9Sstevel@tonic-gate pdslab_destructor(void *buf, void *cdrarg)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
8257c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_next == NULL);
8267c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_prev == NULL);
8277c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_mmd == NULL);
8287c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_used == 0);
8297c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_sz > 0);
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate  * Remove a packet descriptor from the in-use descriptor list,
8347c478bd9Sstevel@tonic-gate  * called by mmd_rempdesc or during free.
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate static pdesc_t *
mmd_destroy_pdesc(multidata_t * mmd,pdesc_t * pd)8377c478bd9Sstevel@tonic-gate mmd_destroy_pdesc(multidata_t *mmd, pdesc_t *pd)
8387c478bd9Sstevel@tonic-gate {
8397c478bd9Sstevel@tonic-gate 	pdesc_t *pd_next;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	pd_next = Q2PD(pd->pd_next);
8427c478bd9Sstevel@tonic-gate 	remque(&(pd->pd_next));
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	/* remove all local attributes */
8457c478bd9Sstevel@tonic-gate 	if (pd->pd_pattbl != NULL)
8467c478bd9Sstevel@tonic-gate 		mmd_destroy_pattbl(&(pd->pd_pattbl));
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/* don't decrease counts for a removed descriptor */
8497c478bd9Sstevel@tonic-gate 	if (!(pd->pd_flags & PDESC_REM_DEFER)) {
8507c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
8517c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
8527c478bd9Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
8557c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
8567c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
8577c478bd9Sstevel@tonic-gate 		}
8587c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
8597c478bd9Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 	return (pd_next);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate /*
8657c478bd9Sstevel@tonic-gate  * Remove a packet descriptor from the Multidata.
8667c478bd9Sstevel@tonic-gate  */
8677c478bd9Sstevel@tonic-gate void
mmd_rempdesc(pdesc_t * pd)8687c478bd9Sstevel@tonic-gate mmd_rempdesc(pdesc_t *pd)
8697c478bd9Sstevel@tonic-gate {
8707c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
8737c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
8767c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
8797c478bd9Sstevel@tonic-gate 	/*
8807c478bd9Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
8817c478bd9Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
8827c478bd9Sstevel@tonic-gate 	 * descriptor handle value is held by those threads.  That's why
8837c478bd9Sstevel@tonic-gate 	 * we simply mark the entry as "removed" and decrement the counts.
8847c478bd9Sstevel@tonic-gate 	 * If there are no other threads, then we free the descriptor.
8857c478bd9Sstevel@tonic-gate 	 */
8867c478bd9Sstevel@tonic-gate 	if (mmd->mmd_dp->db_ref > 1) {
8877c478bd9Sstevel@tonic-gate 		pd->pd_flags |= PDESC_REM_DEFER;
8887c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
8897c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
8907c478bd9Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
8917c478bd9Sstevel@tonic-gate 		}
8927c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
8937c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
8947c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
8977c478bd9Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
8987c478bd9Sstevel@tonic-gate 	} else {
8997c478bd9Sstevel@tonic-gate 		(void) mmd_destroy_pdesc(mmd, pd);
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate /*
9057c478bd9Sstevel@tonic-gate  * A generic routine to traverse the packet descriptor in-use list.
9067c478bd9Sstevel@tonic-gate  */
9077c478bd9Sstevel@tonic-gate static pdesc_t *
mmd_getpdesc(multidata_t * mmd,pdesc_t * pd,pdescinfo_t * pdi,uint_t forw,boolean_t mutex_held)9087c478bd9Sstevel@tonic-gate mmd_getpdesc(multidata_t *mmd, pdesc_t *pd, pdescinfo_t *pdi, uint_t forw,
9097c478bd9Sstevel@tonic-gate     boolean_t mutex_held)
9107c478bd9Sstevel@tonic-gate {
9117c478bd9Sstevel@tonic-gate 	pdesc_t *pd_head;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_slab->pds_mmd == mmd);
9147c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
9157c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_held || MUTEX_HELD(&(mmd->mmd_pd_slab_lock)));
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (!mutex_held)
9187c478bd9Sstevel@tonic-gate 		mutex_enter(&(mmd->mmd_pd_slab_lock));
9197c478bd9Sstevel@tonic-gate 	pd_head = Q2PD(&(mmd->mmd_pd_q));
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	if (pd == NULL) {
9227c478bd9Sstevel@tonic-gate 		/*
9237c478bd9Sstevel@tonic-gate 		 * We're called by mmd_get{first,last}pdesc, and so
9247c478bd9Sstevel@tonic-gate 		 * return either the first or last list element.
9257c478bd9Sstevel@tonic-gate 		 */
9267c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(mmd->mmd_pd_q.ql_next) :
9277c478bd9Sstevel@tonic-gate 		    Q2PD(mmd->mmd_pd_q.ql_prev);
9287c478bd9Sstevel@tonic-gate 	} else {
9297c478bd9Sstevel@tonic-gate 		/*
9307c478bd9Sstevel@tonic-gate 		 * We're called by mmd_get{next,prev}pdesc, and so
9317c478bd9Sstevel@tonic-gate 		 * return either the next or previous list element.
9327c478bd9Sstevel@tonic-gate 		 */
9337c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	while (pd != pd_head) {
9377c478bd9Sstevel@tonic-gate 		/* skip element if it has been removed */
9387c478bd9Sstevel@tonic-gate 		if (!(pd->pd_flags & PDESC_REM_DEFER))
9397c478bd9Sstevel@tonic-gate 			break;
9407c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 	if (!mutex_held)
9437c478bd9Sstevel@tonic-gate 		mutex_exit(&(mmd->mmd_pd_slab_lock));
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/* return NULL if we're back at the beginning */
9467c478bd9Sstevel@tonic-gate 	if (pd == pd_head)
9477c478bd9Sstevel@tonic-gate 		pd = NULL;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	/* got an entry; copy descriptor info to caller */
9507c478bd9Sstevel@tonic-gate 	if (pd != NULL && pdi != NULL)
9517c478bd9Sstevel@tonic-gate 		PDI_COPY(&(pd->pd_pdi), pdi);
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
9547c478bd9Sstevel@tonic-gate 	return (pd);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate /*
9597c478bd9Sstevel@tonic-gate  * Return the first packet descriptor in the in-use list.
9607c478bd9Sstevel@tonic-gate  */
9617c478bd9Sstevel@tonic-gate pdesc_t *
mmd_getfirstpdesc(multidata_t * mmd,pdescinfo_t * pdi)9627c478bd9Sstevel@tonic-gate mmd_getfirstpdesc(multidata_t *mmd, pdescinfo_t *pdi)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 1, B_FALSE));
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate /*
9687c478bd9Sstevel@tonic-gate  * Return the last packet descriptor in the in-use list.
9697c478bd9Sstevel@tonic-gate  */
9707c478bd9Sstevel@tonic-gate pdesc_t *
mmd_getlastpdesc(multidata_t * mmd,pdescinfo_t * pdi)9717c478bd9Sstevel@tonic-gate mmd_getlastpdesc(multidata_t *mmd, pdescinfo_t *pdi)
9727c478bd9Sstevel@tonic-gate {
9737c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 0, B_FALSE));
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate /*
9777c478bd9Sstevel@tonic-gate  * Return the next packet descriptor in the in-use list.
9787c478bd9Sstevel@tonic-gate  */
9797c478bd9Sstevel@tonic-gate pdesc_t *
mmd_getnextpdesc(pdesc_t * pd,pdescinfo_t * pdi)9807c478bd9Sstevel@tonic-gate mmd_getnextpdesc(pdesc_t *pd, pdescinfo_t *pdi)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 1, B_FALSE));
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * Return the previous packet descriptor in the in-use list.
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate pdesc_t *
mmd_getprevpdesc(pdesc_t * pd,pdescinfo_t * pdi)9897c478bd9Sstevel@tonic-gate mmd_getprevpdesc(pdesc_t *pd, pdescinfo_t *pdi)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 0, B_FALSE));
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate  * Check to see if pdi stretches over c_pdi; used to ensure that a packet
9967c478bd9Sstevel@tonic-gate  * descriptor's header and payload span may not be extended beyond the
9977c478bd9Sstevel@tonic-gate  * current boundaries.
9987c478bd9Sstevel@tonic-gate  */
9997c478bd9Sstevel@tonic-gate static boolean_t
pdi_in_range(pdescinfo_t * pdi,pdescinfo_t * c_pdi)10007c478bd9Sstevel@tonic-gate pdi_in_range(pdescinfo_t *pdi, pdescinfo_t *c_pdi)
10017c478bd9Sstevel@tonic-gate {
10027c478bd9Sstevel@tonic-gate 	int i;
10037c478bd9Sstevel@tonic-gate 	struct pld_ary_s *pa = &pdi->pld_ary[0];
10047c478bd9Sstevel@tonic-gate 	struct pld_ary_s *c_pa = &c_pdi->pld_ary[0];
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	if (pdi->hdr_base < c_pdi->hdr_base || pdi->hdr_lim > c_pdi->hdr_lim)
10077c478bd9Sstevel@tonic-gate 		return (B_FALSE);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/*
10107c478bd9Sstevel@tonic-gate 	 * We don't allow the number of span to be reduced, for the sake
10117c478bd9Sstevel@tonic-gate 	 * of simplicity.  Instead, we provide PDESC_PLD_SPAN_CLEAR() to
10127c478bd9Sstevel@tonic-gate 	 * clear a packet descriptor.  Note that we allow the span count to
10137c478bd9Sstevel@tonic-gate 	 * be increased, and the bounds check for the new one happens
10147c478bd9Sstevel@tonic-gate 	 * in pbuf_ref_valid.
10157c478bd9Sstevel@tonic-gate 	 */
10167c478bd9Sstevel@tonic-gate 	if (pdi->pld_cnt < c_pdi->pld_cnt)
10177c478bd9Sstevel@tonic-gate 		return (B_FALSE);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/* compare only those which are currently defined */
10207c478bd9Sstevel@tonic-gate 	for (i = 0; i < c_pdi->pld_cnt; i++, pa++, c_pa++) {
10217c478bd9Sstevel@tonic-gate 		if (pa->pld_pbuf_idx != c_pa->pld_pbuf_idx ||
10227c478bd9Sstevel@tonic-gate 		    pa->pld_rptr < c_pa->pld_rptr ||
10237c478bd9Sstevel@tonic-gate 		    pa->pld_wptr > c_pa->pld_wptr)
10247c478bd9Sstevel@tonic-gate 			return (B_FALSE);
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 	return (B_TRUE);
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate /*
10307c478bd9Sstevel@tonic-gate  * Modify the layout of a packet descriptor.
10317c478bd9Sstevel@tonic-gate  */
10327c478bd9Sstevel@tonic-gate pdesc_t *
mmd_adjpdesc(pdesc_t * pd,pdescinfo_t * pdi)10337c478bd9Sstevel@tonic-gate mmd_adjpdesc(pdesc_t *pd, pdescinfo_t *pdi)
10347c478bd9Sstevel@tonic-gate {
10357c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
10367c478bd9Sstevel@tonic-gate 	pdescinfo_t *c_pdi;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
10397c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
10407c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
10437c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	/* entry has been removed */
10467c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
10477c478bd9Sstevel@tonic-gate 		return (NULL);
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	/* caller doesn't intend to specify any buffer reference? */
10507c478bd9Sstevel@tonic-gate 	if (!(pdi->flags & PDESC_HAS_REF))
10517c478bd9Sstevel@tonic-gate 		return (NULL);
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
10547c478bd9Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
10557c478bd9Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
10567c478bd9Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi))))
10577c478bd9Sstevel@tonic-gate 		return (NULL);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* they're not subsets of current references? */
10607c478bd9Sstevel@tonic-gate 	c_pdi = &(pd->pd_pdi);
10617c478bd9Sstevel@tonic-gate 	if (!pdi_in_range(pdi, c_pdi))
10627c478bd9Sstevel@tonic-gate 		return (NULL);
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
10657c478bd9Sstevel@tonic-gate 	PDI_COPY(pdi, c_pdi);
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	return (pd);
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate /*
10717c478bd9Sstevel@tonic-gate  * Copy the contents of a packet descriptor into a new buffer.  If the
10727c478bd9Sstevel@tonic-gate  * descriptor points to more than one buffer fragments, the contents
10737c478bd9Sstevel@tonic-gate  * of both fragments will be joined, with the header buffer fragment
10747c478bd9Sstevel@tonic-gate  * preceding the payload buffer fragment(s).
10757c478bd9Sstevel@tonic-gate  */
10767c478bd9Sstevel@tonic-gate mblk_t *
mmd_transform(pdesc_t * pd)10777c478bd9Sstevel@tonic-gate mmd_transform(pdesc_t *pd)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
10807c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
10817c478bd9Sstevel@tonic-gate 	mblk_t *mp;
10827c478bd9Sstevel@tonic-gate 	int h_size = 0, p_size = 0;
10837c478bd9Sstevel@tonic-gate 	int i, len;
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
10867c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
10897c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	/* entry has been removed */
10927c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
10937c478bd9Sstevel@tonic-gate 		return (NULL);
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
10967c478bd9Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
10977c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_HBUF_REF)
10987c478bd9Sstevel@tonic-gate 		h_size = PDESC_HDRL(pdi);
10997c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
11007c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++)
11017c478bd9Sstevel@tonic-gate 			p_size += PDESC_PLD_SPAN_SIZE(pdi, i);
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	/* allocate space large enough to hold the fragment(s) */
11057c478bd9Sstevel@tonic-gate 	ASSERT(h_size + p_size >= 0);
11067c478bd9Sstevel@tonic-gate 	if ((mp = allocb(h_size + p_size, BPRI_HI)) == NULL) {
11077c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
11087c478bd9Sstevel@tonic-gate 		return (NULL);
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	/* copy over the header fragment */
11127c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF) && h_size > 0) {
11137c478bd9Sstevel@tonic-gate 		bcopy(pdi->hdr_rptr, mp->b_wptr, h_size);
11147c478bd9Sstevel@tonic-gate 		mp->b_wptr += h_size;
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	/* copy over the payload fragment */
11187c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_PBUF_REF) && p_size > 0) {
11197c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++) {
11207c478bd9Sstevel@tonic-gate 			len = PDESC_PLD_SPAN_SIZE(pdi, i);
11217c478bd9Sstevel@tonic-gate 			if (len > 0) {
11227c478bd9Sstevel@tonic-gate 				bcopy(pdi->pld_ary[i].pld_rptr,
11237c478bd9Sstevel@tonic-gate 				    mp->b_wptr, len);
11247c478bd9Sstevel@tonic-gate 				mp->b_wptr += len;
11257c478bd9Sstevel@tonic-gate 			}
11267c478bd9Sstevel@tonic-gate 		}
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
11307c478bd9Sstevel@tonic-gate 	return (mp);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate  * Return a chain of mblks representing the Multidata packet.
11357c478bd9Sstevel@tonic-gate  */
11367c478bd9Sstevel@tonic-gate mblk_t *
mmd_transform_link(pdesc_t * pd)11377c478bd9Sstevel@tonic-gate mmd_transform_link(pdesc_t *pd)
11387c478bd9Sstevel@tonic-gate {
11397c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
11407c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
11417c478bd9Sstevel@tonic-gate 	mblk_t *nmp = NULL;
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
11447c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
11477c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	/* entry has been removed */
11507c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
11517c478bd9Sstevel@tonic-gate 		return (NULL);
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/* duplicate header buffer */
11567c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF)) {
11577c478bd9Sstevel@tonic-gate 		if ((nmp = dupb(mmd->mmd_hbuf)) == NULL)
11587c478bd9Sstevel@tonic-gate 			return (NULL);
11597c478bd9Sstevel@tonic-gate 		nmp->b_rptr = pdi->hdr_rptr;
11607c478bd9Sstevel@tonic-gate 		nmp->b_wptr = pdi->hdr_wptr;
11617c478bd9Sstevel@tonic-gate 	}
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	/* duplicate payload buffer(s) */
11647c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
11657c478bd9Sstevel@tonic-gate 		int i;
11667c478bd9Sstevel@tonic-gate 		mblk_t *mp;
11677c478bd9Sstevel@tonic-gate 		struct pld_ary_s *pa = &pdi->pld_ary[0];
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
11707c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++, pa++) {
11717c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[pa->pld_pbuf_idx] != NULL);
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 			/* skip empty ones */
11747c478bd9Sstevel@tonic-gate 			if (PDESC_PLD_SPAN_SIZE(pdi, i) == 0)
11757c478bd9Sstevel@tonic-gate 				continue;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[pa->pld_pbuf_idx]);
11787c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
11797c478bd9Sstevel@tonic-gate 				if (nmp != NULL)
11807c478bd9Sstevel@tonic-gate 					freemsg(nmp);
11817c478bd9Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
11827c478bd9Sstevel@tonic-gate 				return (NULL);
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 			mp->b_rptr = pa->pld_rptr;
11857c478bd9Sstevel@tonic-gate 			mp->b_wptr = pa->pld_wptr;
11867c478bd9Sstevel@tonic-gate 			if (nmp == NULL)
11877c478bd9Sstevel@tonic-gate 				nmp = mp;
11887c478bd9Sstevel@tonic-gate 			else
11897c478bd9Sstevel@tonic-gate 				linkb(nmp, mp);
11907c478bd9Sstevel@tonic-gate 		}
11917c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	return (nmp);
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate  * Return duplicate message block(s) of the associated buffer(s).
11997c478bd9Sstevel@tonic-gate  */
12007c478bd9Sstevel@tonic-gate int
mmd_dupbufs(multidata_t * mmd,mblk_t ** hmp,mblk_t ** pmp)12017c478bd9Sstevel@tonic-gate mmd_dupbufs(multidata_t *mmd, mblk_t **hmp, mblk_t **pmp)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
12047c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	if (hmp != NULL) {
12077c478bd9Sstevel@tonic-gate 		*hmp = NULL;
12087c478bd9Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL &&
12097c478bd9Sstevel@tonic-gate 		    (*hmp = dupb(mmd->mmd_hbuf)) == NULL)
12107c478bd9Sstevel@tonic-gate 			return (-1);
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	if (pmp != NULL) {
12147c478bd9Sstevel@tonic-gate 		int i;
12157c478bd9Sstevel@tonic-gate 		mblk_t *mp;
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
12187c478bd9Sstevel@tonic-gate 		*pmp = NULL;
12197c478bd9Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
12207c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
12217c478bd9Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[i]);
12227c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
12237c478bd9Sstevel@tonic-gate 				if (hmp != NULL && *hmp != NULL)
12247c478bd9Sstevel@tonic-gate 					freeb(*hmp);
12257c478bd9Sstevel@tonic-gate 				if (*pmp != NULL)
12267c478bd9Sstevel@tonic-gate 					freemsg(*pmp);
12277c478bd9Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
12287c478bd9Sstevel@tonic-gate 				return (-1);
12297c478bd9Sstevel@tonic-gate 			}
12307c478bd9Sstevel@tonic-gate 			if (*pmp == NULL)
12317c478bd9Sstevel@tonic-gate 				*pmp = mp;
12327c478bd9Sstevel@tonic-gate 			else
12337c478bd9Sstevel@tonic-gate 				linkb(*pmp, mp);
12347c478bd9Sstevel@tonic-gate 		}
12357c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
12367c478bd9Sstevel@tonic-gate 	}
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	return (0);
12397c478bd9Sstevel@tonic-gate }
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate /*
12427c478bd9Sstevel@tonic-gate  * Return the layout of a packet descriptor.
12437c478bd9Sstevel@tonic-gate  */
12447c478bd9Sstevel@tonic-gate int
mmd_getpdescinfo(pdesc_t * pd,pdescinfo_t * pdi)12457c478bd9Sstevel@tonic-gate mmd_getpdescinfo(pdesc_t *pd, pdescinfo_t *pdi)
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
12487c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
12497c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
12507c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab->pds_mmd->mmd_magic == MULTIDATA_MAGIC);
12517c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	/* entry has been removed */
12547c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
12557c478bd9Sstevel@tonic-gate 		return (-1);
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	/* copy descriptor info to caller */
12587c478bd9Sstevel@tonic-gate 	PDI_COPY(&(pd->pd_pdi), pdi);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	return (0);
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate /*
12647c478bd9Sstevel@tonic-gate  * Add a global or local attribute to a Multidata.  Global attribute
12657c478bd9Sstevel@tonic-gate  * association is specified by a NULL packet descriptor.
12667c478bd9Sstevel@tonic-gate  */
12677c478bd9Sstevel@tonic-gate pattr_t *
mmd_addpattr(multidata_t * mmd,pdesc_t * pd,pattrinfo_t * pai,boolean_t persistent,int kmflags)12687c478bd9Sstevel@tonic-gate mmd_addpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai,
12697c478bd9Sstevel@tonic-gate     boolean_t persistent, int kmflags)
12707c478bd9Sstevel@tonic-gate {
12717c478bd9Sstevel@tonic-gate 	patbkt_t **tbl_p;
12727c478bd9Sstevel@tonic-gate 	patbkt_t *tbl, *o_tbl;
12737c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
12747c478bd9Sstevel@tonic-gate 	pattr_t *pa;
12757c478bd9Sstevel@tonic-gate 	uint_t size;
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
12787c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
12797c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
12807c478bd9Sstevel@tonic-gate 	ASSERT(pai != NULL);
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	/* pointer to the attribute hash table (local or global) */
12837c478bd9Sstevel@tonic-gate 	tbl_p = pd != NULL ? &(pd->pd_pattbl) : &(mmd->mmd_pattbl);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	/*
12867c478bd9Sstevel@tonic-gate 	 * See if the hash table has not yet been created; if so,
12877c478bd9Sstevel@tonic-gate 	 * we create the table and store its address atomically.
12887c478bd9Sstevel@tonic-gate 	 */
12897c478bd9Sstevel@tonic-gate 	if ((tbl = *tbl_p) == NULL) {
12907c478bd9Sstevel@tonic-gate 		tbl = kmem_cache_alloc(pattbl_cache, kmflags);
12917c478bd9Sstevel@tonic-gate 		if (tbl == NULL)
12927c478bd9Sstevel@tonic-gate 			return (NULL);
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		/* if someone got there first, use his table instead */
1295*75d94465SJosef 'Jeff' Sipek 		if ((o_tbl = atomic_cas_ptr(tbl_p, NULL, tbl)) != NULL) {
12967c478bd9Sstevel@tonic-gate 			kmem_cache_free(pattbl_cache, tbl);
12977c478bd9Sstevel@tonic-gate 			tbl = o_tbl;
12987c478bd9Sstevel@tonic-gate 		}
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
13027c478bd9Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 	/* attribute of the same type already exists? */
13057c478bd9Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL)
13067c478bd9Sstevel@tonic-gate 		return (NULL);
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	size = sizeof (*pa) + pai->len;
13097c478bd9Sstevel@tonic-gate 	if ((pa = kmem_zalloc(size, kmflags)) == NULL)
13107c478bd9Sstevel@tonic-gate 		return (NULL);
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	pa->pat_magic = PATTR_MAGIC;
13137c478bd9Sstevel@tonic-gate 	pa->pat_lock = &(bkt->pbkt_lock);
13147c478bd9Sstevel@tonic-gate 	pa->pat_mmd = mmd;
13157c478bd9Sstevel@tonic-gate 	pa->pat_buflen = size;
13167c478bd9Sstevel@tonic-gate 	pa->pat_type = pai->type;
13177c478bd9Sstevel@tonic-gate 	pai->buf = pai->len > 0 ? ((uchar_t *)(pa + 1)) : NULL;
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 	if (persistent)
13207c478bd9Sstevel@tonic-gate 		pa->pat_flags = PATTR_PERSIST;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	/* insert attribute at end of hash chain */
13237c478bd9Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
13247c478bd9Sstevel@tonic-gate 	insque(&(pa->pat_next), bkt->pbkt_pattr_q.ql_prev);
13257c478bd9Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	return (pa);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate /*
13317c478bd9Sstevel@tonic-gate  * Attribute hash table kmem cache constructor routine.
13327c478bd9Sstevel@tonic-gate  */
13337c478bd9Sstevel@tonic-gate /* ARGSUSED */
13347c478bd9Sstevel@tonic-gate static int
pattbl_constructor(void * buf,void * cdrarg,int kmflags)13357c478bd9Sstevel@tonic-gate pattbl_constructor(void *buf, void *cdrarg, int kmflags)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
13387c478bd9Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
13397c478bd9Sstevel@tonic-gate 	uint_t i;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
13447c478bd9Sstevel@tonic-gate 		mutex_init(&(bkt->pbkt_lock), NULL, MUTEX_DRIVER, NULL);
13457c478bd9Sstevel@tonic-gate 		QL_INIT(&(bkt->pbkt_pattr_q));
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 		/* first bucket contains the table size */
13487c478bd9Sstevel@tonic-gate 		bkt->pbkt_tbl_sz = i == 0 ? tbl_sz : 0;
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 	return (0);
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate  * Attribute hash table kmem cache destructor routine.
13557c478bd9Sstevel@tonic-gate  */
13567c478bd9Sstevel@tonic-gate /* ARGSUSED */
13577c478bd9Sstevel@tonic-gate static void
pattbl_destructor(void * buf,void * cdrarg)13587c478bd9Sstevel@tonic-gate pattbl_destructor(void *buf, void *cdrarg)
13597c478bd9Sstevel@tonic-gate {
13607c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
13617c478bd9Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
13627c478bd9Sstevel@tonic-gate 	uint_t i;
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
13677c478bd9Sstevel@tonic-gate 		mutex_destroy(&(bkt->pbkt_lock));
13687c478bd9Sstevel@tonic-gate 		ASSERT(bkt->pbkt_pattr_q.ql_next == &(bkt->pbkt_pattr_q));
13697c478bd9Sstevel@tonic-gate 		ASSERT(i > 0 || bkt->pbkt_tbl_sz == tbl_sz);
13707c478bd9Sstevel@tonic-gate 	}
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate /*
13747c478bd9Sstevel@tonic-gate  * Destroy an attribute hash table, called by mmd_rempdesc or during free.
13757c478bd9Sstevel@tonic-gate  */
13767c478bd9Sstevel@tonic-gate static void
mmd_destroy_pattbl(patbkt_t ** tbl)13777c478bd9Sstevel@tonic-gate mmd_destroy_pattbl(patbkt_t **tbl)
13787c478bd9Sstevel@tonic-gate {
13797c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
13807c478bd9Sstevel@tonic-gate 	pattr_t *pa, *pa_next;
13817c478bd9Sstevel@tonic-gate 	uint_t i, tbl_sz;
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 	ASSERT(tbl != NULL);
13847c478bd9Sstevel@tonic-gate 	bkt = *tbl;
13857c478bd9Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
13887c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	/* destroy the contents of each bucket */
13917c478bd9Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
13927c478bd9Sstevel@tonic-gate 		/* we ought to be exclusive at this point */
13937c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&(bkt->pbkt_lock)));
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
13967c478bd9Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
13977c478bd9Sstevel@tonic-gate 			ASSERT(pa->pat_magic == PATTR_MAGIC);
13987c478bd9Sstevel@tonic-gate 			pa_next = Q2PATTR(pa->pat_next);
13997c478bd9Sstevel@tonic-gate 			remque(&(pa->pat_next));
14007c478bd9Sstevel@tonic-gate 			kmem_free(pa, pa->pat_buflen);
14017c478bd9Sstevel@tonic-gate 			pa = pa_next;
14027c478bd9Sstevel@tonic-gate 		}
14037c478bd9Sstevel@tonic-gate 	}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	kmem_cache_free(pattbl_cache, *tbl);
14067c478bd9Sstevel@tonic-gate 	*tbl = NULL;
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	/* commit all previous stores */
14097c478bd9Sstevel@tonic-gate 	membar_producer();
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate  * Copy the contents of an attribute hash table, called by mmd_copy.
14147c478bd9Sstevel@tonic-gate  */
14157c478bd9Sstevel@tonic-gate static int
mmd_copy_pattbl(patbkt_t * src_tbl,multidata_t * n_mmd,pdesc_t * n_pd,int kmflags)14167c478bd9Sstevel@tonic-gate mmd_copy_pattbl(patbkt_t *src_tbl, multidata_t *n_mmd, pdesc_t *n_pd,
14177c478bd9Sstevel@tonic-gate     int kmflags)
14187c478bd9Sstevel@tonic-gate {
14197c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
14207c478bd9Sstevel@tonic-gate 	pattr_t *pa;
14217c478bd9Sstevel@tonic-gate 	pattrinfo_t pai;
14227c478bd9Sstevel@tonic-gate 	uint_t i, tbl_sz;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	ASSERT(src_tbl != NULL);
14257c478bd9Sstevel@tonic-gate 	bkt = src_tbl;
14267c478bd9Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
14297c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
14327c478bd9Sstevel@tonic-gate 		mutex_enter(&(bkt->pbkt_lock));
14337c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
14347c478bd9Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
14357c478bd9Sstevel@tonic-gate 			pattr_t *pa_next = Q2PATTR(pa->pat_next);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 			/* skip if it's removed */
14387c478bd9Sstevel@tonic-gate 			if (pa->pat_flags & PATTR_REM_DEFER) {
14397c478bd9Sstevel@tonic-gate 				pa = pa_next;
14407c478bd9Sstevel@tonic-gate 				continue;
14417c478bd9Sstevel@tonic-gate 			}
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 			pai.type = pa->pat_type;
14447c478bd9Sstevel@tonic-gate 			pai.len = pa->pat_buflen - sizeof (*pa);
14457c478bd9Sstevel@tonic-gate 			if (mmd_addpattr(n_mmd, n_pd, &pai, (pa->pat_flags &
14467c478bd9Sstevel@tonic-gate 			    PATTR_PERSIST) != 0, kmflags) == NULL) {
14477c478bd9Sstevel@tonic-gate 				mutex_exit(&(bkt->pbkt_lock));
14487c478bd9Sstevel@tonic-gate 				return (-1);
14497c478bd9Sstevel@tonic-gate 			}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 			/* copy over the contents */
14527c478bd9Sstevel@tonic-gate 			if (pai.buf != NULL)
14537c478bd9Sstevel@tonic-gate 				bcopy(pa + 1, pai.buf, pai.len);
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 			pa = pa_next;
14567c478bd9Sstevel@tonic-gate 		}
14577c478bd9Sstevel@tonic-gate 		mutex_exit(&(bkt->pbkt_lock));
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 	return (0);
14617c478bd9Sstevel@tonic-gate }
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate  * Search for an attribute type within an attribute hash bucket.
14657c478bd9Sstevel@tonic-gate  */
14667c478bd9Sstevel@tonic-gate static pattr_t *
mmd_find_pattr(patbkt_t * bkt,uint_t type)14677c478bd9Sstevel@tonic-gate mmd_find_pattr(patbkt_t *bkt, uint_t type)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate 	pattr_t *pa_head, *pa;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
14727c478bd9Sstevel@tonic-gate 	pa_head = Q2PATTR(&(bkt->pbkt_pattr_q));
14737c478bd9Sstevel@tonic-gate 	pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	while (pa != pa_head) {
14767c478bd9Sstevel@tonic-gate 		ASSERT(pa->pat_magic == PATTR_MAGIC);
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 		/* return a match; we treat removed entry as non-existent */
14797c478bd9Sstevel@tonic-gate 		if (pa->pat_type == type && !(pa->pat_flags & PATTR_REM_DEFER))
14807c478bd9Sstevel@tonic-gate 			break;
14817c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(pa->pat_next);
14827c478bd9Sstevel@tonic-gate 	}
14837c478bd9Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
14847c478bd9Sstevel@tonic-gate 
14857c478bd9Sstevel@tonic-gate 	return (pa == pa_head ? NULL : pa);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate /*
14897c478bd9Sstevel@tonic-gate  * Remove an attribute from a Multidata.
14907c478bd9Sstevel@tonic-gate  */
14917c478bd9Sstevel@tonic-gate void
mmd_rempattr(pattr_t * pa)14927c478bd9Sstevel@tonic-gate mmd_rempattr(pattr_t *pa)
14937c478bd9Sstevel@tonic-gate {
14947c478bd9Sstevel@tonic-gate 	kmutex_t *pat_lock = pa->pat_lock;
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	ASSERT(pa->pat_magic == PATTR_MAGIC);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	/* ignore if attribute was marked as persistent */
14997c478bd9Sstevel@tonic-gate 	if ((pa->pat_flags & PATTR_PERSIST) != 0)
15007c478bd9Sstevel@tonic-gate 		return;
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 	mutex_enter(pat_lock);
15037c478bd9Sstevel@tonic-gate 	/*
15047c478bd9Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
15057c478bd9Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
15067c478bd9Sstevel@tonic-gate 	 * attribute handle value is held by those threads.  That's why
15077c478bd9Sstevel@tonic-gate 	 * we simply mark the entry as "removed".  If there are no other
15087c478bd9Sstevel@tonic-gate 	 * threads, then we free the attribute.
15097c478bd9Sstevel@tonic-gate 	 */
15107c478bd9Sstevel@tonic-gate 	if (pa->pat_mmd->mmd_dp->db_ref > 1) {
15117c478bd9Sstevel@tonic-gate 		pa->pat_flags |= PATTR_REM_DEFER;
15127c478bd9Sstevel@tonic-gate 	} else {
15137c478bd9Sstevel@tonic-gate 		remque(&(pa->pat_next));
15147c478bd9Sstevel@tonic-gate 		kmem_free(pa, pa->pat_buflen);
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate 	mutex_exit(pat_lock);
15177c478bd9Sstevel@tonic-gate }
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate /*
15207c478bd9Sstevel@tonic-gate  * Find an attribute (according to its type) and return its handle.
15217c478bd9Sstevel@tonic-gate  */
15227c478bd9Sstevel@tonic-gate pattr_t *
mmd_getpattr(multidata_t * mmd,pdesc_t * pd,pattrinfo_t * pai)15237c478bd9Sstevel@tonic-gate mmd_getpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate 	patbkt_t *tbl, *bkt;
15267c478bd9Sstevel@tonic-gate 	pattr_t *pa;
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
15297c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
15307c478bd9Sstevel@tonic-gate 	ASSERT(pai != NULL);
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	/* get the right attribute hash table (local or global) */
15337c478bd9Sstevel@tonic-gate 	tbl = pd != NULL ? pd->pd_pattbl : mmd->mmd_pattbl;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	/* attribute hash table doesn't exist? */
15367c478bd9Sstevel@tonic-gate 	if (tbl == NULL)
15377c478bd9Sstevel@tonic-gate 		return (NULL);
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
15407c478bd9Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL) {
15437c478bd9Sstevel@tonic-gate 		ASSERT(pa->pat_buflen >= sizeof (*pa));
15447c478bd9Sstevel@tonic-gate 		pai->len = pa->pat_buflen - sizeof (*pa);
15457c478bd9Sstevel@tonic-gate 		pai->buf = pai->len > 0 ?
15467c478bd9Sstevel@tonic-gate 		    (uchar_t *)pa + sizeof (pattr_t) : NULL;
15477c478bd9Sstevel@tonic-gate 	}
15487c478bd9Sstevel@tonic-gate 	ASSERT(pa == NULL || pa->pat_magic == PATTR_MAGIC);
15497c478bd9Sstevel@tonic-gate 	return (pa);
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate /*
15537c478bd9Sstevel@tonic-gate  * Return total size of buffers and total size of areas referenced
15547c478bd9Sstevel@tonic-gate  * by all in-use (unremoved) packet descriptors.
15557c478bd9Sstevel@tonic-gate  */
15567c478bd9Sstevel@tonic-gate void
mmd_getsize(multidata_t * mmd,uint_t * ptotal,uint_t * pinuse)15577c478bd9Sstevel@tonic-gate mmd_getsize(multidata_t *mmd, uint_t *ptotal, uint_t *pinuse)
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
15607c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
15617c478bd9Sstevel@tonic-gate 	int i;
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
15647c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
15677c478bd9Sstevel@tonic-gate 	if (ptotal != NULL) {
15687c478bd9Sstevel@tonic-gate 		*ptotal = 0;
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL)
15717c478bd9Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_hbuf);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
15747c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
15757c478bd9Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_pbuf[i]);
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate 	if (pinuse != NULL) {
15797c478bd9Sstevel@tonic-gate 		*pinuse = 0;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 		/* first pdesc */
15827c478bd9Sstevel@tonic-gate 		pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);
15837c478bd9Sstevel@tonic-gate 		while (pd != NULL) {
15847c478bd9Sstevel@tonic-gate 			pdi = &pd->pd_pdi;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 			/* next pdesc */
15877c478bd9Sstevel@tonic-gate 			pd = mmd_getpdesc(mmd, pd, NULL, 1, B_TRUE);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 			/* skip over removed descriptor */
15907c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_REM_DEFER)
15917c478bd9Sstevel@tonic-gate 				continue;
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_HBUF_REF)
15947c478bd9Sstevel@tonic-gate 				*pinuse += PDESC_HDRL(pdi);
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_PBUF_REF) {
15977c478bd9Sstevel@tonic-gate 				for (i = 0; i < pdi->pld_cnt; i++)
15987c478bd9Sstevel@tonic-gate 					*pinuse += PDESC_PLDL(pdi, i);
15997c478bd9Sstevel@tonic-gate 			}
16007c478bd9Sstevel@tonic-gate 		}
16017c478bd9Sstevel@tonic-gate 	}
16027c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
16037c478bd9Sstevel@tonic-gate }
1604