xref: /onnv-gate/usr/src/uts/common/io/multidata.c (revision 455:d7392d9146c7)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*455Smeem  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Multidata, as described in the following papers:
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * Adi Masputra,
330Sstevel@tonic-gate  * Multidata V.2: VA-Disjoint Packet Extents Framework Interface
340Sstevel@tonic-gate  * Design Specification.  August 2004.
350Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2004/594/materials/mmd2.pdf.
360Sstevel@tonic-gate  *
370Sstevel@tonic-gate  * Adi Masputra,
380Sstevel@tonic-gate  * Multidata Interface Design Specification.  Sep 2002.
390Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mmd.pdf.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * Adi Masputra, Frank DiMambro, Kacheong Poon,
420Sstevel@tonic-gate  * An Efficient Networking Transmit Mechanism for Solaris:
430Sstevel@tonic-gate  * Multidata Transmit (MDT).  May 2002.
440Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mdt.pdf.
450Sstevel@tonic-gate  */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #include <sys/types.h>
480Sstevel@tonic-gate #include <sys/stream.h>
490Sstevel@tonic-gate #include <sys/dlpi.h>
500Sstevel@tonic-gate #include <sys/stropts.h>
510Sstevel@tonic-gate #include <sys/strsun.h>
520Sstevel@tonic-gate #include <sys/strlog.h>
530Sstevel@tonic-gate #include <sys/strsubr.h>
540Sstevel@tonic-gate #include <sys/sysmacros.h>
550Sstevel@tonic-gate #include <sys/cmn_err.h>
560Sstevel@tonic-gate #include <sys/debug.h>
570Sstevel@tonic-gate #include <sys/kmem.h>
580Sstevel@tonic-gate #include <sys/atomic.h>
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #include <sys/multidata.h>
610Sstevel@tonic-gate #include <sys/multidata_impl.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static int mmd_constructor(void *, void *, int);
640Sstevel@tonic-gate static void mmd_destructor(void *, void *);
650Sstevel@tonic-gate static int pdslab_constructor(void *, void *, int);
660Sstevel@tonic-gate static void pdslab_destructor(void *, void *);
670Sstevel@tonic-gate static int pattbl_constructor(void *, void *, int);
680Sstevel@tonic-gate static void pattbl_destructor(void *, void *);
690Sstevel@tonic-gate static void mmd_esballoc_free(caddr_t);
700Sstevel@tonic-gate static int mmd_copy_pattbl(patbkt_t *, multidata_t *, pdesc_t *, int);
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static boolean_t pbuf_ref_valid(multidata_t *, pdescinfo_t *);
730Sstevel@tonic-gate #pragma inline(pbuf_ref_valid)
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static boolean_t pdi_in_range(pdescinfo_t *, pdescinfo_t *);
760Sstevel@tonic-gate #pragma inline(pdi_in_range)
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static pdesc_t *mmd_addpdesc_int(multidata_t *, pdescinfo_t *, int *, int);
790Sstevel@tonic-gate #pragma inline(mmd_addpdesc_int)
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static void mmd_destroy_pattbl(patbkt_t **);
820Sstevel@tonic-gate #pragma inline(mmd_destroy_pattbl)
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static pattr_t *mmd_find_pattr(patbkt_t *, uint_t);
850Sstevel@tonic-gate #pragma inline(mmd_find_pattr)
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static pdesc_t *mmd_destroy_pdesc(multidata_t *, pdesc_t *);
880Sstevel@tonic-gate #pragma inline(mmd_destroy_pdesc)
890Sstevel@tonic-gate 
900Sstevel@tonic-gate static pdesc_t *mmd_getpdesc(multidata_t *, pdesc_t *, pdescinfo_t *, uint_t,
910Sstevel@tonic-gate     boolean_t);
920Sstevel@tonic-gate #pragma inline(mmd_getpdesc)
930Sstevel@tonic-gate 
940Sstevel@tonic-gate static struct kmem_cache *mmd_cache;
950Sstevel@tonic-gate static struct kmem_cache *pd_slab_cache;
960Sstevel@tonic-gate static struct kmem_cache *pattbl_cache;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate int mmd_debug = 1;
990Sstevel@tonic-gate #define	MMD_DEBUG(s)	if (mmd_debug > 0) cmn_err s
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Set to this to true to bypass pdesc bounds checking.
1030Sstevel@tonic-gate  */
1040Sstevel@tonic-gate boolean_t mmd_speed_over_safety = B_FALSE;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate /*
1070Sstevel@tonic-gate  * Patchable kmem_cache flags.
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate int mmd_kmem_flags = 0;
1100Sstevel@tonic-gate int pdslab_kmem_flags = 0;
1110Sstevel@tonic-gate int pattbl_kmem_flags = 0;
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Alignment (in bytes) of our kmem caches.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate #define	MULTIDATA_CACHE_ALIGN	64
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate  * Default number of packet descriptors per descriptor slab.  Making
1200Sstevel@tonic-gate  * this too small will trigger more descriptor slab allocation; making
1210Sstevel@tonic-gate  * it too large will create too many unclaimed descriptors.
1220Sstevel@tonic-gate  */
1230Sstevel@tonic-gate #define	PDSLAB_SZ	15
1240Sstevel@tonic-gate uint_t pdslab_sz = PDSLAB_SZ;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Default attribute hash table size.  It's okay to set this to a small
1280Sstevel@tonic-gate  * value (even to 1) because there aren't that many attributes currently
1290Sstevel@tonic-gate  * defined, and because we assume there won't be many attributes associated
1300Sstevel@tonic-gate  * with a Multidata at a given time.  Increasing the size will reduce
1310Sstevel@tonic-gate  * attribute search time (given a large number of attributes in a Multidata),
1320Sstevel@tonic-gate  * and decreasing it will reduce the memory footprints and the overhead
1330Sstevel@tonic-gate  * associated with managing the table.
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate #define	PATTBL_SZ	1
1360Sstevel@tonic-gate uint_t pattbl_sz = PATTBL_SZ;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate  * Attribute hash key.
1400Sstevel@tonic-gate  */
1410Sstevel@tonic-gate #define	PATTBL_HASH(x, sz)	((x) % (sz))
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate /*
1440Sstevel@tonic-gate  * Structure that precedes each Multidata metadata.
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate struct mmd_buf_info {
1470Sstevel@tonic-gate 	frtn_t	frp;		/* free routine */
1480Sstevel@tonic-gate 	uint_t	buf_len;	/* length of kmem buffer */
1490Sstevel@tonic-gate };
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate /*
1520Sstevel@tonic-gate  * The size of each metadata buffer.
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate #define	MMD_CACHE_SIZE	\
1550Sstevel@tonic-gate 	(sizeof (struct mmd_buf_info) + sizeof (multidata_t))
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Called during startup in order to create the Multidata kmem caches.
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate void
mmd_init(void)1610Sstevel@tonic-gate mmd_init(void)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	pdslab_sz = MAX(1, pdslab_sz);	/* at least 1 descriptor */
1640Sstevel@tonic-gate 	pattbl_sz = MAX(1, pattbl_sz);	/* at least 1 bucket */
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	mmd_cache = kmem_cache_create("multidata", MMD_CACHE_SIZE,
1670Sstevel@tonic-gate 	    MULTIDATA_CACHE_ALIGN, mmd_constructor, mmd_destructor,
1680Sstevel@tonic-gate 	    NULL, NULL, NULL, mmd_kmem_flags);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	pd_slab_cache = kmem_cache_create("multidata_pdslab",
1710Sstevel@tonic-gate 	    PDESC_SLAB_SIZE(pdslab_sz), MULTIDATA_CACHE_ALIGN,
1720Sstevel@tonic-gate 	    pdslab_constructor, pdslab_destructor, NULL,
1730Sstevel@tonic-gate 	    (void *)(uintptr_t)pdslab_sz, NULL, pdslab_kmem_flags);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	pattbl_cache = kmem_cache_create("multidata_pattbl",
1760Sstevel@tonic-gate 	    sizeof (patbkt_t) * pattbl_sz, MULTIDATA_CACHE_ALIGN,
1770Sstevel@tonic-gate 	    pattbl_constructor, pattbl_destructor, NULL,
1780Sstevel@tonic-gate 	    (void *)(uintptr_t)pattbl_sz, NULL, pattbl_kmem_flags);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * Create a Multidata message block.
1830Sstevel@tonic-gate  */
1840Sstevel@tonic-gate multidata_t *
mmd_alloc(mblk_t * hdr_mp,mblk_t ** mmd_mp,int kmflags)1850Sstevel@tonic-gate mmd_alloc(mblk_t *hdr_mp, mblk_t **mmd_mp, int kmflags)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	uchar_t *buf;
1880Sstevel@tonic-gate 	multidata_t *mmd;
1890Sstevel@tonic-gate 	uint_t mmd_mplen;
1900Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	ASSERT(hdr_mp != NULL);
1930Sstevel@tonic-gate 	ASSERT(mmd_mp != NULL);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/*
1960Sstevel@tonic-gate 	 * Caller should never pass in a chain of mblks since we
1970Sstevel@tonic-gate 	 * only care about the first one, hence the assertions.
1980Sstevel@tonic-gate 	 */
1990Sstevel@tonic-gate 	ASSERT(hdr_mp->b_cont == NULL);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if ((buf = kmem_cache_alloc(mmd_cache, kmflags)) == NULL)
2020Sstevel@tonic-gate 		return (NULL);
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
2050Sstevel@tonic-gate 	buf_info->frp.free_arg = (caddr_t)buf;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
2080Sstevel@tonic-gate 	mmd_mplen = sizeof (*mmd);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	if ((*mmd_mp = desballoc((uchar_t *)mmd, mmd_mplen, BPRI_HI,
2110Sstevel@tonic-gate 	    &(buf_info->frp))) == NULL) {
2120Sstevel@tonic-gate 		kmem_cache_free(mmd_cache, buf);
2130Sstevel@tonic-gate 		return (NULL);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	DB_TYPE(*mmd_mp) = M_MULTIDATA;
2170Sstevel@tonic-gate 	(*mmd_mp)->b_wptr += mmd_mplen;
2180Sstevel@tonic-gate 	mmd->mmd_dp = (*mmd_mp)->b_datap;
2190Sstevel@tonic-gate 	mmd->mmd_hbuf = hdr_mp;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	return (mmd);
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate /*
2250Sstevel@tonic-gate  * Associate additional payload buffer to the Multidata.
2260Sstevel@tonic-gate  */
2270Sstevel@tonic-gate int
mmd_addpldbuf(multidata_t * mmd,mblk_t * pld_mp)2280Sstevel@tonic-gate mmd_addpldbuf(multidata_t *mmd, mblk_t *pld_mp)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate 	int i;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	ASSERT(mmd != NULL);
2330Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
2340Sstevel@tonic-gate 	ASSERT(pld_mp != NULL);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
2370Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS &&
2380Sstevel@tonic-gate 	    mmd->mmd_pbuf_cnt < MULTIDATA_MAX_PBUFS; i++) {
2390Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] == pld_mp) {
2400Sstevel@tonic-gate 			/* duplicate entry */
2410Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding "
2420Sstevel@tonic-gate 			    "pld 0x%p to mmd 0x%p since it has been "
2430Sstevel@tonic-gate 			    "previously added into slot %d (total %d)\n",
2440Sstevel@tonic-gate 			    (void *)pld_mp, (void *)mmd, i, mmd->mmd_pbuf_cnt));
2450Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
2460Sstevel@tonic-gate 			return (-1);
2470Sstevel@tonic-gate 		} else if (mmd->mmd_pbuf[i] == NULL) {
2480Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = pld_mp;
2490Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt++;
2500Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
2510Sstevel@tonic-gate 			return (i);
2520Sstevel@tonic-gate 		}
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	/* all slots are taken */
2560Sstevel@tonic-gate 	MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding pld 0x%p to mmd 0x%p "
2570Sstevel@tonic-gate 	    "since no slot space is left (total %d max %d)\n", (void *)pld_mp,
2580Sstevel@tonic-gate 	    (void *)mmd, mmd->mmd_pbuf_cnt, MULTIDATA_MAX_PBUFS));
2590Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	return (-1);
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate  * Multidata metadata kmem cache constructor routine.
2660Sstevel@tonic-gate  */
2670Sstevel@tonic-gate /* ARGSUSED */
2680Sstevel@tonic-gate static int
mmd_constructor(void * buf,void * cdrarg,int kmflags)2690Sstevel@tonic-gate mmd_constructor(void *buf, void *cdrarg, int kmflags)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
2720Sstevel@tonic-gate 	multidata_t *mmd;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	bzero((void *)buf, MMD_CACHE_SIZE);
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
2770Sstevel@tonic-gate 	buf_info->frp.free_func = mmd_esballoc_free;
2780Sstevel@tonic-gate 	buf_info->buf_len = MMD_CACHE_SIZE;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
2810Sstevel@tonic-gate 	mmd->mmd_magic = MULTIDATA_MAGIC;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	mutex_init(&(mmd->mmd_pd_slab_lock), NULL, MUTEX_DRIVER, NULL);
2840Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_slab_q));
2850Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_q));
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	return (0);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate /*
2910Sstevel@tonic-gate  * Multidata metadata kmem cache destructor routine.
2920Sstevel@tonic-gate  */
2930Sstevel@tonic-gate /* ARGSUSED */
2940Sstevel@tonic-gate static void
mmd_destructor(void * buf,void * cdrarg)2950Sstevel@tonic-gate mmd_destructor(void *buf, void *cdrarg)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate 	multidata_t *mmd;
2980Sstevel@tonic-gate #ifdef DEBUG
2990Sstevel@tonic-gate 	int i;
3000Sstevel@tonic-gate #endif
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	mmd = (multidata_t *)((uchar_t *)buf + sizeof (struct mmd_buf_info));
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
3050Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp == NULL);
3060Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf == NULL);
3070Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
3080Sstevel@tonic-gate #ifdef DEBUG
3090Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++)
3100Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] == NULL);
3110Sstevel@tonic-gate #endif
3120Sstevel@tonic-gate 	ASSERT(mmd->mmd_pattbl == NULL);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	mutex_destroy(&(mmd->mmd_pd_slab_lock));
3150Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
3160Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
3170Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
3180Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
3190Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
3200Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate  * Multidata message block free callback routine.
3250Sstevel@tonic-gate  */
3260Sstevel@tonic-gate static void
mmd_esballoc_free(caddr_t buf)3270Sstevel@tonic-gate mmd_esballoc_free(caddr_t buf)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	multidata_t *mmd;
3300Sstevel@tonic-gate 	pdesc_t *pd;
3310Sstevel@tonic-gate 	pdesc_slab_t *slab;
3320Sstevel@tonic-gate 	int i;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	ASSERT(buf != NULL);
3350Sstevel@tonic-gate 	ASSERT(((struct mmd_buf_info *)buf)->buf_len == MMD_CACHE_SIZE);
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	mmd = (multidata_t *)(buf + sizeof (struct mmd_buf_info));
3380Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp != NULL);
3410Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp->db_ref == 1);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/* remove all packet descriptors and private attributes */
3440Sstevel@tonic-gate 	pd = Q2PD(mmd->mmd_pd_q.ql_next);
3450Sstevel@tonic-gate 	while (pd != Q2PD(&(mmd->mmd_pd_q)))
3460Sstevel@tonic-gate 		pd = mmd_destroy_pdesc(mmd, pd);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
3490Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
3500Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
3510Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/* remove all global attributes */
3540Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL)
3550Sstevel@tonic-gate 		mmd_destroy_pattbl(&(mmd->mmd_pattbl));
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	/* remove all descriptor slabs */
3580Sstevel@tonic-gate 	slab = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_next);
3590Sstevel@tonic-gate 	while (slab != Q2PDSLAB(&(mmd->mmd_pd_slab_q))) {
3600Sstevel@tonic-gate 		pdesc_slab_t *slab_next = Q2PDSLAB(slab->pds_next);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		remque(&(slab->pds_next));
3630Sstevel@tonic-gate 		slab->pds_next = NULL;
3640Sstevel@tonic-gate 		slab->pds_prev = NULL;
3650Sstevel@tonic-gate 		slab->pds_mmd = NULL;
3660Sstevel@tonic-gate 		slab->pds_used = 0;
3670Sstevel@tonic-gate 		kmem_cache_free(pd_slab_cache, slab);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		ASSERT(mmd->mmd_slab_cnt > 0);
3700Sstevel@tonic-gate 		mmd->mmd_slab_cnt--;
3710Sstevel@tonic-gate 		slab = slab_next;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
3740Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	mmd->mmd_dp = NULL;
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/* finally, free all associated message blocks */
3790Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
3800Sstevel@tonic-gate 		freeb(mmd->mmd_hbuf);
3810Sstevel@tonic-gate 		mmd->mmd_hbuf = NULL;
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++) {
3850Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] != NULL) {
3860Sstevel@tonic-gate 			freeb(mmd->mmd_pbuf[i]);
3870Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = NULL;
3880Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_cnt > 0);
3890Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt--;
3900Sstevel@tonic-gate 		}
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
3940Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&(mmd->mmd_pd_slab_lock)));
3950Sstevel@tonic-gate 	kmem_cache_free(mmd_cache, buf);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate  * Multidata message block copy routine, called by copyb() when it
4000Sstevel@tonic-gate  * encounters a M_MULTIDATA data block type.  This routine should
4010Sstevel@tonic-gate  * not be called by anyone other than copyb(), since it may go away
4020Sstevel@tonic-gate  * (read: become static to this module) once some sort of copy callback
4030Sstevel@tonic-gate  * routine is made available.
4040Sstevel@tonic-gate  */
4050Sstevel@tonic-gate mblk_t *
mmd_copy(mblk_t * bp,int kmflags)4060Sstevel@tonic-gate mmd_copy(mblk_t *bp, int kmflags)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	multidata_t *mmd, *n_mmd;
4090Sstevel@tonic-gate 	mblk_t *n_hbuf = NULL, *n_pbuf[MULTIDATA_MAX_PBUFS];
4100Sstevel@tonic-gate 	mblk_t **pmp_last = &n_pbuf[MULTIDATA_MAX_PBUFS - 1];
4110Sstevel@tonic-gate 	mblk_t **pmp;
4120Sstevel@tonic-gate 	mblk_t *n_bp = NULL;
4130Sstevel@tonic-gate 	pdesc_t *pd;
4140Sstevel@tonic-gate 	uint_t n_pbuf_cnt = 0;
4150Sstevel@tonic-gate 	int idx, i;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate #define	FREE_PBUFS() {					\
4180Sstevel@tonic-gate 	for (pmp = &n_pbuf[0]; pmp <= pmp_last; pmp++)	\
4190Sstevel@tonic-gate 		if (*pmp != NULL) freeb(*pmp);		\
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate #define	REL_OFF(p, base, n_base)			\
4230Sstevel@tonic-gate 	((uchar_t *)(n_base) + ((uchar_t *)(p) - (uchar_t *)base))
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	ASSERT(bp != NULL && DB_TYPE(bp) == M_MULTIDATA);
4260Sstevel@tonic-gate 	mmd = mmd_getmultidata(bp);
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	/* copy the header buffer */
4290Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL && (n_hbuf = copyb(mmd->mmd_hbuf)) == NULL)
4300Sstevel@tonic-gate 		return (NULL);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	/* copy the payload buffer(s) */
4330Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
4340Sstevel@tonic-gate 	bzero((void *)&n_pbuf[0], sizeof (mblk_t *) * MULTIDATA_MAX_PBUFS);
4350Sstevel@tonic-gate 	n_pbuf_cnt = mmd->mmd_pbuf_cnt;
4360Sstevel@tonic-gate 	for (i = 0; i < n_pbuf_cnt; i++) {
4370Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
4380Sstevel@tonic-gate 		n_pbuf[i] = copyb(mmd->mmd_pbuf[i]);
4390Sstevel@tonic-gate 		if (n_pbuf[i] == NULL) {
4400Sstevel@tonic-gate 			FREE_PBUFS();
4410Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
4420Sstevel@tonic-gate 			return (NULL);
4430Sstevel@tonic-gate 		}
4440Sstevel@tonic-gate 	}
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* allocate new Multidata */
4470Sstevel@tonic-gate 	n_mmd = mmd_alloc(n_hbuf, &n_bp, kmflags);
4480Sstevel@tonic-gate 	if (n_mmd == NULL) {
4490Sstevel@tonic-gate 		if (n_hbuf != NULL)
4500Sstevel@tonic-gate 			freeb(n_hbuf);
4510Sstevel@tonic-gate 		if (n_pbuf_cnt != 0)
4520Sstevel@tonic-gate 			FREE_PBUFS();
4530Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
4540Sstevel@tonic-gate 		return (NULL);
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	/*
4580Sstevel@tonic-gate 	 * Add payload buffer(s); upon success, leave n_pbuf array
4590Sstevel@tonic-gate 	 * alone, as the newly-created Multidata had already contained
4600Sstevel@tonic-gate 	 * the mblk pointers stored in the array.  These will be freed
4610Sstevel@tonic-gate 	 * along with the Multidata itself.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate 	for (i = 0, pmp = &n_pbuf[0]; i < n_pbuf_cnt; i++, pmp++) {
4640Sstevel@tonic-gate 		idx = mmd_addpldbuf(n_mmd, *pmp);
4650Sstevel@tonic-gate 		if (idx < 0) {
4660Sstevel@tonic-gate 			FREE_PBUFS();
4670Sstevel@tonic-gate 			freeb(n_bp);
4680Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
4690Sstevel@tonic-gate 			return (NULL);
4700Sstevel@tonic-gate 		}
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/* copy over global attributes */
4740Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL &&
4750Sstevel@tonic-gate 	    mmd_copy_pattbl(mmd->mmd_pattbl, n_mmd, NULL, kmflags) < 0) {
4760Sstevel@tonic-gate 		freeb(n_bp);
4770Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
4780Sstevel@tonic-gate 		return (NULL);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	/* copy over packet descriptors and their atttributes */
4820Sstevel@tonic-gate 	pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);	/* first pdesc */
4830Sstevel@tonic-gate 	while (pd != NULL) {
4840Sstevel@tonic-gate 		pdesc_t *n_pd;
4850Sstevel@tonic-gate 		pdescinfo_t *pdi, n_pdi;
4860Sstevel@tonic-gate 		uchar_t *n_base, *base;
4870Sstevel@tonic-gate 		pdesc_t *pd_next;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		/* next pdesc */
4900Sstevel@tonic-gate 		pd_next = mmd_getpdesc(pd->pd_slab->pds_mmd, pd, NULL,
4910Sstevel@tonic-gate 		    1, B_TRUE);
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 		/* skip if already removed */
4940Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_REM_DEFER) {
4950Sstevel@tonic-gate 			pd = pd_next;
4960Sstevel@tonic-gate 			continue;
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 		pdi = &(pd->pd_pdi);
5000Sstevel@tonic-gate 		bzero(&n_pdi, sizeof (n_pdi));
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 		/*
5030Sstevel@tonic-gate 		 * Calculate new descriptor values based on the offset of
5040Sstevel@tonic-gate 		 * each pointer relative to the associated buffer(s).
5050Sstevel@tonic-gate 		 */
5060Sstevel@tonic-gate 		ASSERT(pdi->flags & PDESC_HAS_REF);
5070Sstevel@tonic-gate 		if (pdi->flags & PDESC_HBUF_REF) {
5080Sstevel@tonic-gate 			n_base = n_mmd->mmd_hbuf->b_rptr;
5090Sstevel@tonic-gate 			base = mmd->mmd_hbuf->b_rptr;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 			n_pdi.flags |= PDESC_HBUF_REF;
5120Sstevel@tonic-gate 			n_pdi.hdr_base = REL_OFF(pdi->hdr_base, base, n_base);
5130Sstevel@tonic-gate 			n_pdi.hdr_rptr = REL_OFF(pdi->hdr_rptr, base, n_base);
5140Sstevel@tonic-gate 			n_pdi.hdr_wptr = REL_OFF(pdi->hdr_wptr, base, n_base);
5150Sstevel@tonic-gate 			n_pdi.hdr_lim = REL_OFF(pdi->hdr_lim, base, n_base);
5160Sstevel@tonic-gate 		}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 		if (pdi->flags & PDESC_PBUF_REF) {
5190Sstevel@tonic-gate 			n_pdi.flags |= PDESC_PBUF_REF;
5200Sstevel@tonic-gate 			n_pdi.pld_cnt = pdi->pld_cnt;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 			for (i = 0; i < pdi->pld_cnt; i++) {
5230Sstevel@tonic-gate 				idx = pdi->pld_ary[i].pld_pbuf_idx;
5240Sstevel@tonic-gate 				ASSERT(idx < MULTIDATA_MAX_PBUFS);
5250Sstevel@tonic-gate 				ASSERT(n_mmd->mmd_pbuf[idx] != NULL);
5260Sstevel@tonic-gate 				ASSERT(mmd->mmd_pbuf[idx] != NULL);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 				n_base = n_mmd->mmd_pbuf[idx]->b_rptr;
5290Sstevel@tonic-gate 				base = mmd->mmd_pbuf[idx]->b_rptr;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_pbuf_idx = idx;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 				/*
5340Sstevel@tonic-gate 				 * We can't copy the pointers just like that,
5350Sstevel@tonic-gate 				 * so calculate the relative offset.
5360Sstevel@tonic-gate 				 */
5370Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_rptr =
5380Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_rptr,
5390Sstevel@tonic-gate 					base, n_base);
5400Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_wptr =
5410Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_wptr,
5420Sstevel@tonic-gate 					base, n_base);
5430Sstevel@tonic-gate 			}
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 		/* add the new descriptor to the new Multidata */
5470Sstevel@tonic-gate 		n_pd = mmd_addpdesc_int(n_mmd, &n_pdi, NULL, kmflags);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		if (n_pd == NULL || (pd->pd_pattbl != NULL &&
5500Sstevel@tonic-gate 		    mmd_copy_pattbl(pd->pd_pattbl, n_mmd, n_pd, kmflags) < 0)) {
5510Sstevel@tonic-gate 			freeb(n_bp);
5520Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
5530Sstevel@tonic-gate 			return (NULL);
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		pd = pd_next;
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate #undef REL_OFF
5590Sstevel@tonic-gate #undef FREE_PBUFS
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
5620Sstevel@tonic-gate 	return (n_bp);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate /*
5660Sstevel@tonic-gate  * Given a Multidata message block, return the Multidata metadata handle.
5670Sstevel@tonic-gate  */
5680Sstevel@tonic-gate multidata_t *
mmd_getmultidata(mblk_t * mp)5690Sstevel@tonic-gate mmd_getmultidata(mblk_t *mp)
5700Sstevel@tonic-gate {
5710Sstevel@tonic-gate 	multidata_t *mmd;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	ASSERT(mp != NULL);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_MULTIDATA)
5760Sstevel@tonic-gate 		return (NULL);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	mmd = (multidata_t *)mp->b_rptr;
5790Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	return (mmd);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate /*
5850Sstevel@tonic-gate  * Return the start and end addresses of the associated buffer(s).
5860Sstevel@tonic-gate  */
5870Sstevel@tonic-gate void
mmd_getregions(multidata_t * mmd,mbufinfo_t * mbi)5880Sstevel@tonic-gate mmd_getregions(multidata_t *mmd, mbufinfo_t *mbi)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	int i;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	ASSERT(mmd != NULL);
5930Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
5940Sstevel@tonic-gate 	ASSERT(mbi != NULL);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	bzero((void *)mbi, sizeof (mbufinfo_t));
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
5990Sstevel@tonic-gate 		mbi->hbuf_rptr = mmd->mmd_hbuf->b_rptr;
6000Sstevel@tonic-gate 		mbi->hbuf_wptr = mmd->mmd_hbuf->b_wptr;
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
6040Sstevel@tonic-gate 	for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
6050Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
6060Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_rptr = mmd->mmd_pbuf[i]->b_rptr;
6070Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_wptr = mmd->mmd_pbuf[i]->b_wptr;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 	mbi->pbuf_cnt = mmd->mmd_pbuf_cnt;
6110Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate  * Return the Multidata statistics.
6160Sstevel@tonic-gate  */
6170Sstevel@tonic-gate uint_t
mmd_getcnt(multidata_t * mmd,uint_t * hbuf_ref,uint_t * pbuf_ref)6180Sstevel@tonic-gate mmd_getcnt(multidata_t *mmd, uint_t *hbuf_ref, uint_t *pbuf_ref)
6190Sstevel@tonic-gate {
6200Sstevel@tonic-gate 	uint_t pd_cnt;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	ASSERT(mmd != NULL);
6230Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
6260Sstevel@tonic-gate 	if (hbuf_ref != NULL)
6270Sstevel@tonic-gate 		*hbuf_ref = mmd->mmd_hbuf_ref;
6280Sstevel@tonic-gate 	if (pbuf_ref != NULL)
6290Sstevel@tonic-gate 		*pbuf_ref = mmd->mmd_pbuf_ref;
6300Sstevel@tonic-gate 	pd_cnt = mmd->mmd_pd_cnt;
6310Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	return (pd_cnt);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate #define	HBUF_REF_VALID(mmd, pdi)					\
6370Sstevel@tonic-gate 	((mmd)->mmd_hbuf != NULL && (pdi)->hdr_rptr != NULL &&		\
6380Sstevel@tonic-gate 	(pdi)->hdr_wptr != NULL && (pdi)->hdr_base != NULL &&		\
6390Sstevel@tonic-gate 	(pdi)->hdr_lim != NULL && (pdi)->hdr_lim >= (pdi)->hdr_base &&	\
6400Sstevel@tonic-gate 	(pdi)->hdr_wptr >= (pdi)->hdr_rptr &&				\
6410Sstevel@tonic-gate 	(pdi)->hdr_base <= (pdi)->hdr_rptr &&				\
6420Sstevel@tonic-gate 	(pdi)->hdr_lim >= (pdi)->hdr_wptr &&				\
6430Sstevel@tonic-gate 	(pdi)->hdr_base >= (mmd)->mmd_hbuf->b_rptr &&			\
6440Sstevel@tonic-gate 	MBLKIN((mmd)->mmd_hbuf,						\
6450Sstevel@tonic-gate 	(pdi->hdr_base - (mmd)->mmd_hbuf->b_rptr),			\
6460Sstevel@tonic-gate 	PDESC_HDRSIZE(pdi)))
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate /*
6490Sstevel@tonic-gate  * Bounds check payload area(s).
6500Sstevel@tonic-gate  */
6510Sstevel@tonic-gate static boolean_t
pbuf_ref_valid(multidata_t * mmd,pdescinfo_t * pdi)6520Sstevel@tonic-gate pbuf_ref_valid(multidata_t *mmd, pdescinfo_t *pdi)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate 	int i = 0, idx;
6550Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
6560Sstevel@tonic-gate 	struct pld_ary_s *pa;
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
6590Sstevel@tonic-gate 	if (pdi->pld_cnt == 0 || pdi->pld_cnt > mmd->mmd_pbuf_cnt) {
6600Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
6610Sstevel@tonic-gate 		return (B_FALSE);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	pa = &pdi->pld_ary[0];
6650Sstevel@tonic-gate 	while (valid && i < pdi->pld_cnt) {
6660Sstevel@tonic-gate 		valid = (((idx = pa->pld_pbuf_idx) < mmd->mmd_pbuf_cnt) &&
6670Sstevel@tonic-gate 		    pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
6680Sstevel@tonic-gate 		    pa->pld_wptr >= pa->pld_rptr &&
6690Sstevel@tonic-gate 		    pa->pld_rptr >= mmd->mmd_pbuf[idx]->b_rptr &&
6700Sstevel@tonic-gate 		    MBLKIN(mmd->mmd_pbuf[idx], (pa->pld_rptr -
6710Sstevel@tonic-gate 			mmd->mmd_pbuf[idx]->b_rptr),
6720Sstevel@tonic-gate 			PDESC_PLD_SPAN_SIZE(pdi, i)));
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 		if (!valid) {
6750Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN,
6760Sstevel@tonic-gate 			    "pbuf_ref_valid: pdi 0x%p pld out of bound; "
6770Sstevel@tonic-gate 			    "index %d has pld_cnt %d pbuf_idx %d "
6780Sstevel@tonic-gate 			    "(mmd_pbuf_cnt %d), "
6790Sstevel@tonic-gate 			    "pld_rptr 0x%p pld_wptr 0x%p len %d "
6800Sstevel@tonic-gate 			    "(valid 0x%p-0x%p len %d)\n", (void *)pdi,
6810Sstevel@tonic-gate 			    i, pdi->pld_cnt, idx, mmd->mmd_pbuf_cnt,
6820Sstevel@tonic-gate 			    (void *)pa->pld_rptr,
6830Sstevel@tonic-gate 			    (void *)pa->pld_wptr,
6840Sstevel@tonic-gate 			    (int)PDESC_PLD_SPAN_SIZE(pdi, i),
6850Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_rptr,
6860Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_wptr,
6870Sstevel@tonic-gate 			    (int)MBLKL(mmd->mmd_pbuf[idx])));
6880Sstevel@tonic-gate 		}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 		/* advance to next entry */
6910Sstevel@tonic-gate 		i++;
6920Sstevel@tonic-gate 		pa++;
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
6960Sstevel@tonic-gate 	return (valid);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate  * Add a packet descriptor to the Multidata.
7010Sstevel@tonic-gate  */
7020Sstevel@tonic-gate pdesc_t *
mmd_addpdesc(multidata_t * mmd,pdescinfo_t * pdi,int * err,int kmflags)7030Sstevel@tonic-gate mmd_addpdesc(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	ASSERT(mmd != NULL);
7060Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
7070Sstevel@tonic-gate 	ASSERT(pdi != NULL);
7080Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
7110Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
7120Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
7130Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi)))) {
7140Sstevel@tonic-gate 		if (err != NULL)
7150Sstevel@tonic-gate 			*err = EINVAL;
7160Sstevel@tonic-gate 		return (NULL);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	return (mmd_addpdesc_int(mmd, pdi, err, kmflags));
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate  * Internal routine to add a packet descriptor, called when mmd_addpdesc
7240Sstevel@tonic-gate  * or mmd_copy tries to allocate and add a descriptor to a Multidata.
7250Sstevel@tonic-gate  */
7260Sstevel@tonic-gate static pdesc_t *
mmd_addpdesc_int(multidata_t * mmd,pdescinfo_t * pdi,int * err,int kmflags)7270Sstevel@tonic-gate mmd_addpdesc_int(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
7280Sstevel@tonic-gate {
7290Sstevel@tonic-gate 	pdesc_slab_t *slab, *slab_last;
7300Sstevel@tonic-gate 	pdesc_t *pd;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
7330Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_HBUF_REF) || HBUF_REF_VALID(mmd, pdi));
7340Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_PBUF_REF) || pbuf_ref_valid(mmd, pdi));
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (err != NULL)
7370Sstevel@tonic-gate 		*err = 0;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
7400Sstevel@tonic-gate 	/*
7410Sstevel@tonic-gate 	 * Is slab list empty or the last-added slab is full?  If so,
7420Sstevel@tonic-gate 	 * allocate new slab for the descriptor; otherwise, use the
7430Sstevel@tonic-gate 	 * last-added slab instead.
7440Sstevel@tonic-gate 	 */
7450Sstevel@tonic-gate 	slab_last = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_prev);
7460Sstevel@tonic-gate 	if (mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q) ||
7470Sstevel@tonic-gate 	    slab_last->pds_used == slab_last->pds_sz) {
7480Sstevel@tonic-gate 		slab = kmem_cache_alloc(pd_slab_cache, kmflags);
7490Sstevel@tonic-gate 		if (slab == NULL) {
7500Sstevel@tonic-gate 			if (err != NULL)
7510Sstevel@tonic-gate 				*err = ENOMEM;
7520Sstevel@tonic-gate 			mutex_exit(&(mmd->mmd_pd_slab_lock));
7530Sstevel@tonic-gate 			return (NULL);
7540Sstevel@tonic-gate 		}
7550Sstevel@tonic-gate 		slab->pds_mmd = mmd;
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 		ASSERT(slab->pds_used == 0);
7580Sstevel@tonic-gate 		ASSERT(slab->pds_next == NULL && slab->pds_prev == NULL);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 		/* insert slab at end of list */
7610Sstevel@tonic-gate 		insque(&(slab->pds_next), mmd->mmd_pd_slab_q.ql_prev);
7620Sstevel@tonic-gate 		mmd->mmd_slab_cnt++;
7630Sstevel@tonic-gate 	} else {
7640Sstevel@tonic-gate 		slab = slab_last;
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 	ASSERT(slab->pds_used < slab->pds_sz);
7670Sstevel@tonic-gate 	pd = &(slab->pds_free_desc[slab->pds_used++]);
7680Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
7690Sstevel@tonic-gate 	pd->pd_next = NULL;
7700Sstevel@tonic-gate 	pd->pd_prev = NULL;
7710Sstevel@tonic-gate 	pd->pd_slab = slab;
7720Sstevel@tonic-gate 	pd->pd_pattbl = NULL;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
7750Sstevel@tonic-gate 	PDI_COPY(pdi, &(pd->pd_pdi));
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_HBUF_REF)
7780Sstevel@tonic-gate 		mmd->mmd_hbuf_ref++;
7790Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_PBUF_REF)
7800Sstevel@tonic-gate 		mmd->mmd_pbuf_ref += pd->pd_pdi.pld_cnt;
7810Sstevel@tonic-gate 	mmd->mmd_pd_cnt++;
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	/* insert descriptor at end of list */
7840Sstevel@tonic-gate 	insque(&(pd->pd_next), mmd->mmd_pd_q.ql_prev);
7850Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	return (pd);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate /*
7910Sstevel@tonic-gate  * Packet descriptor slab kmem cache constructor routine.
7920Sstevel@tonic-gate  */
7930Sstevel@tonic-gate /* ARGSUSED */
7940Sstevel@tonic-gate static int
pdslab_constructor(void * buf,void * cdrarg,int kmflags)7950Sstevel@tonic-gate pdslab_constructor(void *buf, void *cdrarg, int kmflags)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	pdesc_slab_t *slab;
7980Sstevel@tonic-gate 	uint_t cnt = (uint_t)(uintptr_t)cdrarg;
7990Sstevel@tonic-gate 	int i;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	ASSERT(cnt > 0);	/* slab size can't be zero */
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
8040Sstevel@tonic-gate 	slab->pds_next = NULL;
8050Sstevel@tonic-gate 	slab->pds_prev = NULL;
8060Sstevel@tonic-gate 	slab->pds_mmd = NULL;
8070Sstevel@tonic-gate 	slab->pds_used = 0;
8080Sstevel@tonic-gate 	slab->pds_sz = cnt;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
8110Sstevel@tonic-gate 		pdesc_t *pd = &(slab->pds_free_desc[i]);
8120Sstevel@tonic-gate 		pd->pd_magic = PDESC_MAGIC;
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 	return (0);
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate /*
8180Sstevel@tonic-gate  * Packet descriptor slab kmem cache destructor routine.
8190Sstevel@tonic-gate  */
8200Sstevel@tonic-gate /* ARGSUSED */
8210Sstevel@tonic-gate static void
pdslab_destructor(void * buf,void * cdrarg)8220Sstevel@tonic-gate pdslab_destructor(void *buf, void *cdrarg)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	pdesc_slab_t *slab;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
8270Sstevel@tonic-gate 	ASSERT(slab->pds_next == NULL);
8280Sstevel@tonic-gate 	ASSERT(slab->pds_prev == NULL);
8290Sstevel@tonic-gate 	ASSERT(slab->pds_mmd == NULL);
8300Sstevel@tonic-gate 	ASSERT(slab->pds_used == 0);
8310Sstevel@tonic-gate 	ASSERT(slab->pds_sz > 0);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * Remove a packet descriptor from the in-use descriptor list,
8360Sstevel@tonic-gate  * called by mmd_rempdesc or during free.
8370Sstevel@tonic-gate  */
8380Sstevel@tonic-gate static pdesc_t *
mmd_destroy_pdesc(multidata_t * mmd,pdesc_t * pd)8390Sstevel@tonic-gate mmd_destroy_pdesc(multidata_t *mmd, pdesc_t *pd)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	pdesc_t *pd_next;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	pd_next = Q2PD(pd->pd_next);
8440Sstevel@tonic-gate 	remque(&(pd->pd_next));
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	/* remove all local attributes */
8470Sstevel@tonic-gate 	if (pd->pd_pattbl != NULL)
8480Sstevel@tonic-gate 		mmd_destroy_pattbl(&(pd->pd_pattbl));
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/* don't decrease counts for a removed descriptor */
8510Sstevel@tonic-gate 	if (!(pd->pd_flags & PDESC_REM_DEFER)) {
8520Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
8530Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
8540Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
8550Sstevel@tonic-gate 		}
8560Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
8570Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
8580Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
8590Sstevel@tonic-gate 		}
8600Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
8610Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 	return (pd_next);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate /*
8670Sstevel@tonic-gate  * Remove a packet descriptor from the Multidata.
8680Sstevel@tonic-gate  */
8690Sstevel@tonic-gate void
mmd_rempdesc(pdesc_t * pd)8700Sstevel@tonic-gate mmd_rempdesc(pdesc_t *pd)
8710Sstevel@tonic-gate {
8720Sstevel@tonic-gate 	multidata_t *mmd;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
8750Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
8780Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
8810Sstevel@tonic-gate 	/*
8820Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
8830Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
8840Sstevel@tonic-gate 	 * descriptor handle value is held by those threads.  That's why
8850Sstevel@tonic-gate 	 * we simply mark the entry as "removed" and decrement the counts.
8860Sstevel@tonic-gate 	 * If there are no other threads, then we free the descriptor.
8870Sstevel@tonic-gate 	 */
8880Sstevel@tonic-gate 	if (mmd->mmd_dp->db_ref > 1) {
8890Sstevel@tonic-gate 		pd->pd_flags |= PDESC_REM_DEFER;
8900Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
8910Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
8920Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
8930Sstevel@tonic-gate 		}
8940Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
8950Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
8960Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
8970Sstevel@tonic-gate 		}
8980Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
8990Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
9000Sstevel@tonic-gate 	} else {
9010Sstevel@tonic-gate 		(void) mmd_destroy_pdesc(mmd, pd);
9020Sstevel@tonic-gate 	}
9030Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate  * A generic routine to traverse the packet descriptor in-use list.
9080Sstevel@tonic-gate  */
9090Sstevel@tonic-gate static pdesc_t *
mmd_getpdesc(multidata_t * mmd,pdesc_t * pd,pdescinfo_t * pdi,uint_t forw,boolean_t mutex_held)9100Sstevel@tonic-gate mmd_getpdesc(multidata_t *mmd, pdesc_t *pd, pdescinfo_t *pdi, uint_t forw,
9110Sstevel@tonic-gate     boolean_t mutex_held)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	pdesc_t *pd_head;
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_slab->pds_mmd == mmd);
9160Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
9170Sstevel@tonic-gate 	ASSERT(!mutex_held || MUTEX_HELD(&(mmd->mmd_pd_slab_lock)));
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	if (!mutex_held)
9200Sstevel@tonic-gate 		mutex_enter(&(mmd->mmd_pd_slab_lock));
9210Sstevel@tonic-gate 	pd_head = Q2PD(&(mmd->mmd_pd_q));
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate 	if (pd == NULL) {
9240Sstevel@tonic-gate 		/*
9250Sstevel@tonic-gate 		 * We're called by mmd_get{first,last}pdesc, and so
9260Sstevel@tonic-gate 		 * return either the first or last list element.
9270Sstevel@tonic-gate 		 */
9280Sstevel@tonic-gate 		pd = forw ? Q2PD(mmd->mmd_pd_q.ql_next) :
9290Sstevel@tonic-gate 		    Q2PD(mmd->mmd_pd_q.ql_prev);
9300Sstevel@tonic-gate 	} else {
9310Sstevel@tonic-gate 		/*
9320Sstevel@tonic-gate 		 * We're called by mmd_get{next,prev}pdesc, and so
9330Sstevel@tonic-gate 		 * return either the next or previous list element.
9340Sstevel@tonic-gate 		 */
9350Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
9360Sstevel@tonic-gate 	}
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	while (pd != pd_head) {
9390Sstevel@tonic-gate 		/* skip element if it has been removed */
9400Sstevel@tonic-gate 		if (!(pd->pd_flags & PDESC_REM_DEFER))
9410Sstevel@tonic-gate 			break;
9420Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 	if (!mutex_held)
9450Sstevel@tonic-gate 		mutex_exit(&(mmd->mmd_pd_slab_lock));
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	/* return NULL if we're back at the beginning */
9480Sstevel@tonic-gate 	if (pd == pd_head)
9490Sstevel@tonic-gate 		pd = NULL;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	/* got an entry; copy descriptor info to caller */
9520Sstevel@tonic-gate 	if (pd != NULL && pdi != NULL)
9530Sstevel@tonic-gate 		PDI_COPY(&(pd->pd_pdi), pdi);
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
9560Sstevel@tonic-gate 	return (pd);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate /*
9610Sstevel@tonic-gate  * Return the first packet descriptor in the in-use list.
9620Sstevel@tonic-gate  */
9630Sstevel@tonic-gate pdesc_t *
mmd_getfirstpdesc(multidata_t * mmd,pdescinfo_t * pdi)9640Sstevel@tonic-gate mmd_getfirstpdesc(multidata_t *mmd, pdescinfo_t *pdi)
9650Sstevel@tonic-gate {
9660Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 1, B_FALSE));
9670Sstevel@tonic-gate }
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate /*
9700Sstevel@tonic-gate  * Return the last packet descriptor in the in-use list.
9710Sstevel@tonic-gate  */
9720Sstevel@tonic-gate pdesc_t *
mmd_getlastpdesc(multidata_t * mmd,pdescinfo_t * pdi)9730Sstevel@tonic-gate mmd_getlastpdesc(multidata_t *mmd, pdescinfo_t *pdi)
9740Sstevel@tonic-gate {
9750Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 0, B_FALSE));
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate /*
9790Sstevel@tonic-gate  * Return the next packet descriptor in the in-use list.
9800Sstevel@tonic-gate  */
9810Sstevel@tonic-gate pdesc_t *
mmd_getnextpdesc(pdesc_t * pd,pdescinfo_t * pdi)9820Sstevel@tonic-gate mmd_getnextpdesc(pdesc_t *pd, pdescinfo_t *pdi)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 1, B_FALSE));
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate /*
9880Sstevel@tonic-gate  * Return the previous packet descriptor in the in-use list.
9890Sstevel@tonic-gate  */
9900Sstevel@tonic-gate pdesc_t *
mmd_getprevpdesc(pdesc_t * pd,pdescinfo_t * pdi)9910Sstevel@tonic-gate mmd_getprevpdesc(pdesc_t *pd, pdescinfo_t *pdi)
9920Sstevel@tonic-gate {
9930Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 0, B_FALSE));
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate /*
9970Sstevel@tonic-gate  * Check to see if pdi stretches over c_pdi; used to ensure that a packet
9980Sstevel@tonic-gate  * descriptor's header and payload span may not be extended beyond the
9990Sstevel@tonic-gate  * current boundaries.
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate static boolean_t
pdi_in_range(pdescinfo_t * pdi,pdescinfo_t * c_pdi)10020Sstevel@tonic-gate pdi_in_range(pdescinfo_t *pdi, pdescinfo_t *c_pdi)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	int i;
10050Sstevel@tonic-gate 	struct pld_ary_s *pa = &pdi->pld_ary[0];
10060Sstevel@tonic-gate 	struct pld_ary_s *c_pa = &c_pdi->pld_ary[0];
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	if (pdi->hdr_base < c_pdi->hdr_base || pdi->hdr_lim > c_pdi->hdr_lim)
10090Sstevel@tonic-gate 		return (B_FALSE);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	/*
10120Sstevel@tonic-gate 	 * We don't allow the number of span to be reduced, for the sake
10130Sstevel@tonic-gate 	 * of simplicity.  Instead, we provide PDESC_PLD_SPAN_CLEAR() to
10140Sstevel@tonic-gate 	 * clear a packet descriptor.  Note that we allow the span count to
10150Sstevel@tonic-gate 	 * be increased, and the bounds check for the new one happens
10160Sstevel@tonic-gate 	 * in pbuf_ref_valid.
10170Sstevel@tonic-gate 	 */
10180Sstevel@tonic-gate 	if (pdi->pld_cnt < c_pdi->pld_cnt)
10190Sstevel@tonic-gate 		return (B_FALSE);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/* compare only those which are currently defined */
10220Sstevel@tonic-gate 	for (i = 0; i < c_pdi->pld_cnt; i++, pa++, c_pa++) {
10230Sstevel@tonic-gate 		if (pa->pld_pbuf_idx != c_pa->pld_pbuf_idx ||
10240Sstevel@tonic-gate 		    pa->pld_rptr < c_pa->pld_rptr ||
10250Sstevel@tonic-gate 		    pa->pld_wptr > c_pa->pld_wptr)
10260Sstevel@tonic-gate 			return (B_FALSE);
10270Sstevel@tonic-gate 	}
10280Sstevel@tonic-gate 	return (B_TRUE);
10290Sstevel@tonic-gate }
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate /*
10320Sstevel@tonic-gate  * Modify the layout of a packet descriptor.
10330Sstevel@tonic-gate  */
10340Sstevel@tonic-gate pdesc_t *
mmd_adjpdesc(pdesc_t * pd,pdescinfo_t * pdi)10350Sstevel@tonic-gate mmd_adjpdesc(pdesc_t *pd, pdescinfo_t *pdi)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate 	multidata_t *mmd;
10380Sstevel@tonic-gate 	pdescinfo_t *c_pdi;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	ASSERT(pd != NULL);
10410Sstevel@tonic-gate 	ASSERT(pdi != NULL);
10420Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
10450Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	/* entry has been removed */
10480Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
10490Sstevel@tonic-gate 		return (NULL);
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	/* caller doesn't intend to specify any buffer reference? */
10520Sstevel@tonic-gate 	if (!(pdi->flags & PDESC_HAS_REF))
10530Sstevel@tonic-gate 		return (NULL);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
10560Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
10570Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
10580Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi))))
10590Sstevel@tonic-gate 		return (NULL);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	/* they're not subsets of current references? */
10620Sstevel@tonic-gate 	c_pdi = &(pd->pd_pdi);
10630Sstevel@tonic-gate 	if (!pdi_in_range(pdi, c_pdi))
10640Sstevel@tonic-gate 		return (NULL);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
10670Sstevel@tonic-gate 	PDI_COPY(pdi, c_pdi);
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	return (pd);
10700Sstevel@tonic-gate }
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate /*
10730Sstevel@tonic-gate  * Copy the contents of a packet descriptor into a new buffer.  If the
10740Sstevel@tonic-gate  * descriptor points to more than one buffer fragments, the contents
10750Sstevel@tonic-gate  * of both fragments will be joined, with the header buffer fragment
10760Sstevel@tonic-gate  * preceding the payload buffer fragment(s).
10770Sstevel@tonic-gate  */
10780Sstevel@tonic-gate mblk_t *
mmd_transform(pdesc_t * pd)10790Sstevel@tonic-gate mmd_transform(pdesc_t *pd)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate 	multidata_t *mmd;
10820Sstevel@tonic-gate 	pdescinfo_t *pdi;
10830Sstevel@tonic-gate 	mblk_t *mp;
10840Sstevel@tonic-gate 	int h_size = 0, p_size = 0;
10850Sstevel@tonic-gate 	int i, len;
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	ASSERT(pd != NULL);
10880Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
10910Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	/* entry has been removed */
10940Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
10950Sstevel@tonic-gate 		return (NULL);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
10980Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
10990Sstevel@tonic-gate 	if (pdi->flags & PDESC_HBUF_REF)
11000Sstevel@tonic-gate 		h_size = PDESC_HDRL(pdi);
11010Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
11020Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++)
11030Sstevel@tonic-gate 			p_size += PDESC_PLD_SPAN_SIZE(pdi, i);
11040Sstevel@tonic-gate 	}
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	/* allocate space large enough to hold the fragment(s) */
11070Sstevel@tonic-gate 	ASSERT(h_size + p_size >= 0);
11080Sstevel@tonic-gate 	if ((mp = allocb(h_size + p_size, BPRI_HI)) == NULL) {
11090Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
11100Sstevel@tonic-gate 		return (NULL);
11110Sstevel@tonic-gate 	}
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	/* copy over the header fragment */
11140Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF) && h_size > 0) {
11150Sstevel@tonic-gate 		bcopy(pdi->hdr_rptr, mp->b_wptr, h_size);
11160Sstevel@tonic-gate 		mp->b_wptr += h_size;
11170Sstevel@tonic-gate 	}
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	/* copy over the payload fragment */
11200Sstevel@tonic-gate 	if ((pdi->flags & PDESC_PBUF_REF) && p_size > 0) {
11210Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++) {
11220Sstevel@tonic-gate 			len = PDESC_PLD_SPAN_SIZE(pdi, i);
11230Sstevel@tonic-gate 			if (len > 0) {
11240Sstevel@tonic-gate 				bcopy(pdi->pld_ary[i].pld_rptr,
11250Sstevel@tonic-gate 				    mp->b_wptr, len);
11260Sstevel@tonic-gate 				mp->b_wptr += len;
11270Sstevel@tonic-gate 			}
11280Sstevel@tonic-gate 		}
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
11320Sstevel@tonic-gate 	return (mp);
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate /*
11360Sstevel@tonic-gate  * Return a chain of mblks representing the Multidata packet.
11370Sstevel@tonic-gate  */
11380Sstevel@tonic-gate mblk_t *
mmd_transform_link(pdesc_t * pd)11390Sstevel@tonic-gate mmd_transform_link(pdesc_t *pd)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate 	multidata_t *mmd;
11420Sstevel@tonic-gate 	pdescinfo_t *pdi;
11430Sstevel@tonic-gate 	mblk_t *nmp = NULL;
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	ASSERT(pd != NULL);
11460Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
11490Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 	/* entry has been removed */
11520Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
11530Sstevel@tonic-gate 		return (NULL);
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	/* duplicate header buffer */
11580Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF)) {
11590Sstevel@tonic-gate 		if ((nmp = dupb(mmd->mmd_hbuf)) == NULL)
11600Sstevel@tonic-gate 			return (NULL);
11610Sstevel@tonic-gate 		nmp->b_rptr = pdi->hdr_rptr;
11620Sstevel@tonic-gate 		nmp->b_wptr = pdi->hdr_wptr;
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	/* duplicate payload buffer(s) */
11660Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
11670Sstevel@tonic-gate 		int i;
11680Sstevel@tonic-gate 		mblk_t *mp;
11690Sstevel@tonic-gate 		struct pld_ary_s *pa = &pdi->pld_ary[0];
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
11720Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++, pa++) {
11730Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[pa->pld_pbuf_idx] != NULL);
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 			/* skip empty ones */
11760Sstevel@tonic-gate 			if (PDESC_PLD_SPAN_SIZE(pdi, i) == 0)
11770Sstevel@tonic-gate 				continue;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[pa->pld_pbuf_idx]);
11800Sstevel@tonic-gate 			if (mp == NULL) {
11810Sstevel@tonic-gate 				if (nmp != NULL)
11820Sstevel@tonic-gate 					freemsg(nmp);
11830Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
11840Sstevel@tonic-gate 				return (NULL);
11850Sstevel@tonic-gate 			}
11860Sstevel@tonic-gate 			mp->b_rptr = pa->pld_rptr;
11870Sstevel@tonic-gate 			mp->b_wptr = pa->pld_wptr;
11880Sstevel@tonic-gate 			if (nmp == NULL)
11890Sstevel@tonic-gate 				nmp = mp;
11900Sstevel@tonic-gate 			else
11910Sstevel@tonic-gate 				linkb(nmp, mp);
11920Sstevel@tonic-gate 		}
11930Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
11940Sstevel@tonic-gate 	}
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	return (nmp);
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate /*
12000Sstevel@tonic-gate  * Return duplicate message block(s) of the associated buffer(s).
12010Sstevel@tonic-gate  */
12020Sstevel@tonic-gate int
mmd_dupbufs(multidata_t * mmd,mblk_t ** hmp,mblk_t ** pmp)12030Sstevel@tonic-gate mmd_dupbufs(multidata_t *mmd, mblk_t **hmp, mblk_t **pmp)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate 	ASSERT(mmd != NULL);
12060Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	if (hmp != NULL) {
12090Sstevel@tonic-gate 		*hmp = NULL;
12100Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL &&
12110Sstevel@tonic-gate 		    (*hmp = dupb(mmd->mmd_hbuf)) == NULL)
12120Sstevel@tonic-gate 			return (-1);
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	if (pmp != NULL) {
12160Sstevel@tonic-gate 		int i;
12170Sstevel@tonic-gate 		mblk_t *mp;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
12200Sstevel@tonic-gate 		*pmp = NULL;
12210Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
12220Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
12230Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[i]);
12240Sstevel@tonic-gate 			if (mp == NULL) {
12250Sstevel@tonic-gate 				if (hmp != NULL && *hmp != NULL)
12260Sstevel@tonic-gate 					freeb(*hmp);
12270Sstevel@tonic-gate 				if (*pmp != NULL)
12280Sstevel@tonic-gate 					freemsg(*pmp);
12290Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
12300Sstevel@tonic-gate 				return (-1);
12310Sstevel@tonic-gate 			}
12320Sstevel@tonic-gate 			if (*pmp == NULL)
12330Sstevel@tonic-gate 				*pmp = mp;
12340Sstevel@tonic-gate 			else
12350Sstevel@tonic-gate 				linkb(*pmp, mp);
12360Sstevel@tonic-gate 		}
12370Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	return (0);
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate /*
12440Sstevel@tonic-gate  * Return the layout of a packet descriptor.
12450Sstevel@tonic-gate  */
12460Sstevel@tonic-gate int
mmd_getpdescinfo(pdesc_t * pd,pdescinfo_t * pdi)12470Sstevel@tonic-gate mmd_getpdescinfo(pdesc_t *pd, pdescinfo_t *pdi)
12480Sstevel@tonic-gate {
12490Sstevel@tonic-gate 	ASSERT(pd != NULL);
12500Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
12510Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
12520Sstevel@tonic-gate 	ASSERT(pd->pd_slab->pds_mmd->mmd_magic == MULTIDATA_MAGIC);
12530Sstevel@tonic-gate 	ASSERT(pdi != NULL);
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	/* entry has been removed */
12560Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
12570Sstevel@tonic-gate 		return (-1);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	/* copy descriptor info to caller */
12600Sstevel@tonic-gate 	PDI_COPY(&(pd->pd_pdi), pdi);
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	return (0);
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate /*
12660Sstevel@tonic-gate  * Add a global or local attribute to a Multidata.  Global attribute
12670Sstevel@tonic-gate  * association is specified by a NULL packet descriptor.
12680Sstevel@tonic-gate  */
12690Sstevel@tonic-gate pattr_t *
mmd_addpattr(multidata_t * mmd,pdesc_t * pd,pattrinfo_t * pai,boolean_t persistent,int kmflags)12700Sstevel@tonic-gate mmd_addpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai,
12710Sstevel@tonic-gate     boolean_t persistent, int kmflags)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	patbkt_t **tbl_p;
12740Sstevel@tonic-gate 	patbkt_t *tbl, *o_tbl;
12750Sstevel@tonic-gate 	patbkt_t *bkt;
12760Sstevel@tonic-gate 	pattr_t *pa;
12770Sstevel@tonic-gate 	uint_t size;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 	ASSERT(mmd != NULL);
12800Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
12810Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
12820Sstevel@tonic-gate 	ASSERT(pai != NULL);
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	/* pointer to the attribute hash table (local or global) */
12850Sstevel@tonic-gate 	tbl_p = pd != NULL ? &(pd->pd_pattbl) : &(mmd->mmd_pattbl);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	/*
12880Sstevel@tonic-gate 	 * See if the hash table has not yet been created; if so,
12890Sstevel@tonic-gate 	 * we create the table and store its address atomically.
12900Sstevel@tonic-gate 	 */
12910Sstevel@tonic-gate 	if ((tbl = *tbl_p) == NULL) {
12920Sstevel@tonic-gate 		tbl = kmem_cache_alloc(pattbl_cache, kmflags);
12930Sstevel@tonic-gate 		if (tbl == NULL)
12940Sstevel@tonic-gate 			return (NULL);
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		/* if someone got there first, use his table instead */
12970Sstevel@tonic-gate 		if ((o_tbl = casptr(tbl_p, NULL, tbl)) != NULL) {
12980Sstevel@tonic-gate 			kmem_cache_free(pattbl_cache, tbl);
12990Sstevel@tonic-gate 			tbl = o_tbl;
13000Sstevel@tonic-gate 		}
13010Sstevel@tonic-gate 	}
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
13040Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
13050Sstevel@tonic-gate 
13060Sstevel@tonic-gate 	/* attribute of the same type already exists? */
13070Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL)
13080Sstevel@tonic-gate 		return (NULL);
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate 	size = sizeof (*pa) + pai->len;
13110Sstevel@tonic-gate 	if ((pa = kmem_zalloc(size, kmflags)) == NULL)
13120Sstevel@tonic-gate 		return (NULL);
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	pa->pat_magic = PATTR_MAGIC;
13150Sstevel@tonic-gate 	pa->pat_lock = &(bkt->pbkt_lock);
13160Sstevel@tonic-gate 	pa->pat_mmd = mmd;
13170Sstevel@tonic-gate 	pa->pat_buflen = size;
13180Sstevel@tonic-gate 	pa->pat_type = pai->type;
13190Sstevel@tonic-gate 	pai->buf = pai->len > 0 ? ((uchar_t *)(pa + 1)) : NULL;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	if (persistent)
13220Sstevel@tonic-gate 		pa->pat_flags = PATTR_PERSIST;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	/* insert attribute at end of hash chain */
13250Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
13260Sstevel@tonic-gate 	insque(&(pa->pat_next), bkt->pbkt_pattr_q.ql_prev);
13270Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	return (pa);
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate /*
13330Sstevel@tonic-gate  * Attribute hash table kmem cache constructor routine.
13340Sstevel@tonic-gate  */
13350Sstevel@tonic-gate /* ARGSUSED */
13360Sstevel@tonic-gate static int
pattbl_constructor(void * buf,void * cdrarg,int kmflags)13370Sstevel@tonic-gate pattbl_constructor(void *buf, void *cdrarg, int kmflags)
13380Sstevel@tonic-gate {
13390Sstevel@tonic-gate 	patbkt_t *bkt;
13400Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
13410Sstevel@tonic-gate 	uint_t i;
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
13460Sstevel@tonic-gate 		mutex_init(&(bkt->pbkt_lock), NULL, MUTEX_DRIVER, NULL);
13470Sstevel@tonic-gate 		QL_INIT(&(bkt->pbkt_pattr_q));
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 		/* first bucket contains the table size */
13500Sstevel@tonic-gate 		bkt->pbkt_tbl_sz = i == 0 ? tbl_sz : 0;
13510Sstevel@tonic-gate 	}
13520Sstevel@tonic-gate 	return (0);
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate /*
13560Sstevel@tonic-gate  * Attribute hash table kmem cache destructor routine.
13570Sstevel@tonic-gate  */
13580Sstevel@tonic-gate /* ARGSUSED */
13590Sstevel@tonic-gate static void
pattbl_destructor(void * buf,void * cdrarg)13600Sstevel@tonic-gate pattbl_destructor(void *buf, void *cdrarg)
13610Sstevel@tonic-gate {
13620Sstevel@tonic-gate 	patbkt_t *bkt;
13630Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
13640Sstevel@tonic-gate 	uint_t i;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
13690Sstevel@tonic-gate 		mutex_destroy(&(bkt->pbkt_lock));
13700Sstevel@tonic-gate 		ASSERT(bkt->pbkt_pattr_q.ql_next == &(bkt->pbkt_pattr_q));
13710Sstevel@tonic-gate 		ASSERT(i > 0 || bkt->pbkt_tbl_sz == tbl_sz);
13720Sstevel@tonic-gate 	}
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate /*
13760Sstevel@tonic-gate  * Destroy an attribute hash table, called by mmd_rempdesc or during free.
13770Sstevel@tonic-gate  */
13780Sstevel@tonic-gate static void
mmd_destroy_pattbl(patbkt_t ** tbl)13790Sstevel@tonic-gate mmd_destroy_pattbl(patbkt_t **tbl)
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate 	patbkt_t *bkt;
13820Sstevel@tonic-gate 	pattr_t *pa, *pa_next;
13830Sstevel@tonic-gate 	uint_t i, tbl_sz;
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 	ASSERT(tbl != NULL);
13860Sstevel@tonic-gate 	bkt = *tbl;
13870Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
13900Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	/* destroy the contents of each bucket */
13930Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
13940Sstevel@tonic-gate 		/* we ought to be exclusive at this point */
13950Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&(bkt->pbkt_lock)));
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
13980Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
13990Sstevel@tonic-gate 			ASSERT(pa->pat_magic == PATTR_MAGIC);
14000Sstevel@tonic-gate 			pa_next = Q2PATTR(pa->pat_next);
14010Sstevel@tonic-gate 			remque(&(pa->pat_next));
14020Sstevel@tonic-gate 			kmem_free(pa, pa->pat_buflen);
14030Sstevel@tonic-gate 			pa = pa_next;
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 
14070Sstevel@tonic-gate 	kmem_cache_free(pattbl_cache, *tbl);
14080Sstevel@tonic-gate 	*tbl = NULL;
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 	/* commit all previous stores */
14110Sstevel@tonic-gate 	membar_producer();
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate /*
14150Sstevel@tonic-gate  * Copy the contents of an attribute hash table, called by mmd_copy.
14160Sstevel@tonic-gate  */
14170Sstevel@tonic-gate static int
mmd_copy_pattbl(patbkt_t * src_tbl,multidata_t * n_mmd,pdesc_t * n_pd,int kmflags)14180Sstevel@tonic-gate mmd_copy_pattbl(patbkt_t *src_tbl, multidata_t *n_mmd, pdesc_t *n_pd,
14190Sstevel@tonic-gate     int kmflags)
14200Sstevel@tonic-gate {
14210Sstevel@tonic-gate 	patbkt_t *bkt;
14220Sstevel@tonic-gate 	pattr_t *pa;
14230Sstevel@tonic-gate 	pattrinfo_t pai;
14240Sstevel@tonic-gate 	uint_t i, tbl_sz;
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	ASSERT(src_tbl != NULL);
14270Sstevel@tonic-gate 	bkt = src_tbl;
14280Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
14310Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
14340Sstevel@tonic-gate 		mutex_enter(&(bkt->pbkt_lock));
14350Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
14360Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
14370Sstevel@tonic-gate 			pattr_t *pa_next = Q2PATTR(pa->pat_next);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 			/* skip if it's removed */
14400Sstevel@tonic-gate 			if (pa->pat_flags & PATTR_REM_DEFER) {
14410Sstevel@tonic-gate 				pa = pa_next;
14420Sstevel@tonic-gate 				continue;
14430Sstevel@tonic-gate 			}
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 			pai.type = pa->pat_type;
14460Sstevel@tonic-gate 			pai.len = pa->pat_buflen - sizeof (*pa);
14470Sstevel@tonic-gate 			if (mmd_addpattr(n_mmd, n_pd, &pai, (pa->pat_flags &
14480Sstevel@tonic-gate 			    PATTR_PERSIST) != 0, kmflags) == NULL) {
14490Sstevel@tonic-gate 				mutex_exit(&(bkt->pbkt_lock));
14500Sstevel@tonic-gate 				return (-1);
14510Sstevel@tonic-gate 			}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 			/* copy over the contents */
14540Sstevel@tonic-gate 			if (pai.buf != NULL)
14550Sstevel@tonic-gate 				bcopy(pa + 1, pai.buf, pai.len);
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 			pa = pa_next;
14580Sstevel@tonic-gate 		}
14590Sstevel@tonic-gate 		mutex_exit(&(bkt->pbkt_lock));
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	return (0);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate /*
14660Sstevel@tonic-gate  * Search for an attribute type within an attribute hash bucket.
14670Sstevel@tonic-gate  */
14680Sstevel@tonic-gate static pattr_t *
mmd_find_pattr(patbkt_t * bkt,uint_t type)14690Sstevel@tonic-gate mmd_find_pattr(patbkt_t *bkt, uint_t type)
14700Sstevel@tonic-gate {
14710Sstevel@tonic-gate 	pattr_t *pa_head, *pa;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
14740Sstevel@tonic-gate 	pa_head = Q2PATTR(&(bkt->pbkt_pattr_q));
14750Sstevel@tonic-gate 	pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	while (pa != pa_head) {
14780Sstevel@tonic-gate 		ASSERT(pa->pat_magic == PATTR_MAGIC);
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 		/* return a match; we treat removed entry as non-existent */
14810Sstevel@tonic-gate 		if (pa->pat_type == type && !(pa->pat_flags & PATTR_REM_DEFER))
14820Sstevel@tonic-gate 			break;
14830Sstevel@tonic-gate 		pa = Q2PATTR(pa->pat_next);
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	return (pa == pa_head ? NULL : pa);
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate /*
14910Sstevel@tonic-gate  * Remove an attribute from a Multidata.
14920Sstevel@tonic-gate  */
14930Sstevel@tonic-gate void
mmd_rempattr(pattr_t * pa)14940Sstevel@tonic-gate mmd_rempattr(pattr_t *pa)
14950Sstevel@tonic-gate {
14960Sstevel@tonic-gate 	kmutex_t *pat_lock = pa->pat_lock;
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	ASSERT(pa->pat_magic == PATTR_MAGIC);
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	/* ignore if attribute was marked as persistent */
15010Sstevel@tonic-gate 	if ((pa->pat_flags & PATTR_PERSIST) != 0)
15020Sstevel@tonic-gate 		return;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	mutex_enter(pat_lock);
15050Sstevel@tonic-gate 	/*
15060Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
15070Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
15080Sstevel@tonic-gate 	 * attribute handle value is held by those threads.  That's why
15090Sstevel@tonic-gate 	 * we simply mark the entry as "removed".  If there are no other
15100Sstevel@tonic-gate 	 * threads, then we free the attribute.
15110Sstevel@tonic-gate 	 */
15120Sstevel@tonic-gate 	if (pa->pat_mmd->mmd_dp->db_ref > 1) {
15130Sstevel@tonic-gate 		pa->pat_flags |= PATTR_REM_DEFER;
15140Sstevel@tonic-gate 	} else {
15150Sstevel@tonic-gate 		remque(&(pa->pat_next));
15160Sstevel@tonic-gate 		kmem_free(pa, pa->pat_buflen);
15170Sstevel@tonic-gate 	}
15180Sstevel@tonic-gate 	mutex_exit(pat_lock);
15190Sstevel@tonic-gate }
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate /*
15220Sstevel@tonic-gate  * Find an attribute (according to its type) and return its handle.
15230Sstevel@tonic-gate  */
15240Sstevel@tonic-gate pattr_t *
mmd_getpattr(multidata_t * mmd,pdesc_t * pd,pattrinfo_t * pai)15250Sstevel@tonic-gate mmd_getpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai)
15260Sstevel@tonic-gate {
15270Sstevel@tonic-gate 	patbkt_t *tbl, *bkt;
15280Sstevel@tonic-gate 	pattr_t *pa;
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	ASSERT(mmd != NULL);
15310Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
15320Sstevel@tonic-gate 	ASSERT(pai != NULL);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	/* get the right attribute hash table (local or global) */
15350Sstevel@tonic-gate 	tbl = pd != NULL ? pd->pd_pattbl : mmd->mmd_pattbl;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	/* attribute hash table doesn't exist? */
15380Sstevel@tonic-gate 	if (tbl == NULL)
15390Sstevel@tonic-gate 		return (NULL);
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
15420Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL) {
15450Sstevel@tonic-gate 		ASSERT(pa->pat_buflen >= sizeof (*pa));
15460Sstevel@tonic-gate 		pai->len = pa->pat_buflen - sizeof (*pa);
15470Sstevel@tonic-gate 		pai->buf = pai->len > 0 ?
15480Sstevel@tonic-gate 		    (uchar_t *)pa + sizeof (pattr_t) : NULL;
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 	ASSERT(pa == NULL || pa->pat_magic == PATTR_MAGIC);
15510Sstevel@tonic-gate 	return (pa);
15520Sstevel@tonic-gate }
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate /*
15550Sstevel@tonic-gate  * Return total size of buffers and total size of areas referenced
15560Sstevel@tonic-gate  * by all in-use (unremoved) packet descriptors.
15570Sstevel@tonic-gate  */
15580Sstevel@tonic-gate void
mmd_getsize(multidata_t * mmd,uint_t * ptotal,uint_t * pinuse)15590Sstevel@tonic-gate mmd_getsize(multidata_t *mmd, uint_t *ptotal, uint_t *pinuse)
15600Sstevel@tonic-gate {
15610Sstevel@tonic-gate 	pdesc_t *pd;
15620Sstevel@tonic-gate 	pdescinfo_t *pdi;
15630Sstevel@tonic-gate 	int i;
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 	ASSERT(mmd != NULL);
15660Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
15690Sstevel@tonic-gate 	if (ptotal != NULL) {
15700Sstevel@tonic-gate 		*ptotal = 0;
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL)
15730Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_hbuf);
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
15760Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
15770Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_pbuf[i]);
15780Sstevel@tonic-gate 		}
15790Sstevel@tonic-gate 	}
15800Sstevel@tonic-gate 	if (pinuse != NULL) {
15810Sstevel@tonic-gate 		*pinuse = 0;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 		/* first pdesc */
15840Sstevel@tonic-gate 		pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);
15850Sstevel@tonic-gate 		while (pd != NULL) {
15860Sstevel@tonic-gate 			pdi = &pd->pd_pdi;
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 			/* next pdesc */
15890Sstevel@tonic-gate 			pd = mmd_getpdesc(mmd, pd, NULL, 1, B_TRUE);
15900Sstevel@tonic-gate 
15910Sstevel@tonic-gate 			/* skip over removed descriptor */
15920Sstevel@tonic-gate 			if (pdi->flags & PDESC_REM_DEFER)
15930Sstevel@tonic-gate 				continue;
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 			if (pdi->flags & PDESC_HBUF_REF)
15960Sstevel@tonic-gate 				*pinuse += PDESC_HDRL(pdi);
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 			if (pdi->flags & PDESC_PBUF_REF) {
15990Sstevel@tonic-gate 				for (i = 0; i < pdi->pld_cnt; i++)
16000Sstevel@tonic-gate 					*pinuse += PDESC_PLDL(pdi, i);
16010Sstevel@tonic-gate 			}
16020Sstevel@tonic-gate 		}
16030Sstevel@tonic-gate 	}
16040Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
16050Sstevel@tonic-gate }
1606