xref: /titanic_50/usr/src/uts/common/io/multidata.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Multidata, as described in the following papers:
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Adi Masputra,
33*7c478bd9Sstevel@tonic-gate  * Multidata V.2: VA-Disjoint Packet Extents Framework Interface
34*7c478bd9Sstevel@tonic-gate  * Design Specification.  August 2004.
35*7c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2004/594/materials/mmd2.pdf.
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * Adi Masputra,
38*7c478bd9Sstevel@tonic-gate  * Multidata Interface Design Specification.  Sep 2002.
39*7c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mmd.pdf.
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * Adi Masputra, Frank DiMambro, Kacheong Poon,
42*7c478bd9Sstevel@tonic-gate  * An Efficient Networking Transmit Mechanism for Solaris:
43*7c478bd9Sstevel@tonic-gate  * Multidata Transmit (MDT).  May 2002.
44*7c478bd9Sstevel@tonic-gate  * Available as http://sac.sfbay/PSARC/2002/276/materials/mdt.pdf.
45*7c478bd9Sstevel@tonic-gate  */
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/multidata_impl.h>
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate extern mblk_t *desballoc(unsigned char *, size_t, uint_t, frtn_t *);
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static int mmd_constructor(void *, void *, int);
66*7c478bd9Sstevel@tonic-gate static void mmd_destructor(void *, void *);
67*7c478bd9Sstevel@tonic-gate static int pdslab_constructor(void *, void *, int);
68*7c478bd9Sstevel@tonic-gate static void pdslab_destructor(void *, void *);
69*7c478bd9Sstevel@tonic-gate static int pattbl_constructor(void *, void *, int);
70*7c478bd9Sstevel@tonic-gate static void pattbl_destructor(void *, void *);
71*7c478bd9Sstevel@tonic-gate static void mmd_esballoc_free(caddr_t);
72*7c478bd9Sstevel@tonic-gate static int mmd_copy_pattbl(patbkt_t *, multidata_t *, pdesc_t *, int);
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate static boolean_t pbuf_ref_valid(multidata_t *, pdescinfo_t *);
75*7c478bd9Sstevel@tonic-gate #pragma inline(pbuf_ref_valid)
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static boolean_t pdi_in_range(pdescinfo_t *, pdescinfo_t *);
78*7c478bd9Sstevel@tonic-gate #pragma inline(pdi_in_range)
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static pdesc_t *mmd_addpdesc_int(multidata_t *, pdescinfo_t *, int *, int);
81*7c478bd9Sstevel@tonic-gate #pragma inline(mmd_addpdesc_int)
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static void mmd_destroy_pattbl(patbkt_t **);
84*7c478bd9Sstevel@tonic-gate #pragma inline(mmd_destroy_pattbl)
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static pattr_t *mmd_find_pattr(patbkt_t *, uint_t);
87*7c478bd9Sstevel@tonic-gate #pragma inline(mmd_find_pattr)
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static pdesc_t *mmd_destroy_pdesc(multidata_t *, pdesc_t *);
90*7c478bd9Sstevel@tonic-gate #pragma inline(mmd_destroy_pdesc)
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate static pdesc_t *mmd_getpdesc(multidata_t *, pdesc_t *, pdescinfo_t *, uint_t,
93*7c478bd9Sstevel@tonic-gate     boolean_t);
94*7c478bd9Sstevel@tonic-gate #pragma inline(mmd_getpdesc)
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static struct kmem_cache *mmd_cache;
97*7c478bd9Sstevel@tonic-gate static struct kmem_cache *pd_slab_cache;
98*7c478bd9Sstevel@tonic-gate static struct kmem_cache *pattbl_cache;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate int mmd_debug = 1;
101*7c478bd9Sstevel@tonic-gate #define	MMD_DEBUG(s)	if (mmd_debug > 0) cmn_err s
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate  * Set to this to true to bypass pdesc bounds checking.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate boolean_t mmd_speed_over_safety = B_FALSE;
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate  * Patchable kmem_cache flags.
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate int mmd_kmem_flags = 0;
112*7c478bd9Sstevel@tonic-gate int pdslab_kmem_flags = 0;
113*7c478bd9Sstevel@tonic-gate int pattbl_kmem_flags = 0;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate  * Alignment (in bytes) of our kmem caches.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate #define	MULTIDATA_CACHE_ALIGN	64
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate /*
121*7c478bd9Sstevel@tonic-gate  * Default number of packet descriptors per descriptor slab.  Making
122*7c478bd9Sstevel@tonic-gate  * this too small will trigger more descriptor slab allocation; making
123*7c478bd9Sstevel@tonic-gate  * it too large will create too many unclaimed descriptors.
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate #define	PDSLAB_SZ	15
126*7c478bd9Sstevel@tonic-gate uint_t pdslab_sz = PDSLAB_SZ;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate /*
129*7c478bd9Sstevel@tonic-gate  * Default attribute hash table size.  It's okay to set this to a small
130*7c478bd9Sstevel@tonic-gate  * value (even to 1) because there aren't that many attributes currently
131*7c478bd9Sstevel@tonic-gate  * defined, and because we assume there won't be many attributes associated
132*7c478bd9Sstevel@tonic-gate  * with a Multidata at a given time.  Increasing the size will reduce
133*7c478bd9Sstevel@tonic-gate  * attribute search time (given a large number of attributes in a Multidata),
134*7c478bd9Sstevel@tonic-gate  * and decreasing it will reduce the memory footprints and the overhead
135*7c478bd9Sstevel@tonic-gate  * associated with managing the table.
136*7c478bd9Sstevel@tonic-gate  */
137*7c478bd9Sstevel@tonic-gate #define	PATTBL_SZ	1
138*7c478bd9Sstevel@tonic-gate uint_t pattbl_sz = PATTBL_SZ;
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Attribute hash key.
142*7c478bd9Sstevel@tonic-gate  */
143*7c478bd9Sstevel@tonic-gate #define	PATTBL_HASH(x, sz)	((x) % (sz))
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate /*
146*7c478bd9Sstevel@tonic-gate  * Structure that precedes each Multidata metadata.
147*7c478bd9Sstevel@tonic-gate  */
148*7c478bd9Sstevel@tonic-gate struct mmd_buf_info {
149*7c478bd9Sstevel@tonic-gate 	frtn_t	frp;		/* free routine */
150*7c478bd9Sstevel@tonic-gate 	uint_t	buf_len;	/* length of kmem buffer */
151*7c478bd9Sstevel@tonic-gate };
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * The size of each metadata buffer.
155*7c478bd9Sstevel@tonic-gate  */
156*7c478bd9Sstevel@tonic-gate #define	MMD_CACHE_SIZE	\
157*7c478bd9Sstevel@tonic-gate 	(sizeof (struct mmd_buf_info) + sizeof (multidata_t))
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate /*
160*7c478bd9Sstevel@tonic-gate  * Called during startup in order to create the Multidata kmem caches.
161*7c478bd9Sstevel@tonic-gate  */
162*7c478bd9Sstevel@tonic-gate void
163*7c478bd9Sstevel@tonic-gate mmd_init(void)
164*7c478bd9Sstevel@tonic-gate {
165*7c478bd9Sstevel@tonic-gate 	pdslab_sz = MAX(1, pdslab_sz);	/* at least 1 descriptor */
166*7c478bd9Sstevel@tonic-gate 	pattbl_sz = MAX(1, pattbl_sz);	/* at least 1 bucket */
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	mmd_cache = kmem_cache_create("multidata", MMD_CACHE_SIZE,
169*7c478bd9Sstevel@tonic-gate 	    MULTIDATA_CACHE_ALIGN, mmd_constructor, mmd_destructor,
170*7c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL, mmd_kmem_flags);
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	pd_slab_cache = kmem_cache_create("multidata_pdslab",
173*7c478bd9Sstevel@tonic-gate 	    PDESC_SLAB_SIZE(pdslab_sz), MULTIDATA_CACHE_ALIGN,
174*7c478bd9Sstevel@tonic-gate 	    pdslab_constructor, pdslab_destructor, NULL,
175*7c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)pdslab_sz, NULL, pdslab_kmem_flags);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	pattbl_cache = kmem_cache_create("multidata_pattbl",
178*7c478bd9Sstevel@tonic-gate 	    sizeof (patbkt_t) * pattbl_sz, MULTIDATA_CACHE_ALIGN,
179*7c478bd9Sstevel@tonic-gate 	    pattbl_constructor, pattbl_destructor, NULL,
180*7c478bd9Sstevel@tonic-gate 	    (void *)(uintptr_t)pattbl_sz, NULL, pattbl_kmem_flags);
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate /*
184*7c478bd9Sstevel@tonic-gate  * Create a Multidata message block.
185*7c478bd9Sstevel@tonic-gate  */
186*7c478bd9Sstevel@tonic-gate multidata_t *
187*7c478bd9Sstevel@tonic-gate mmd_alloc(mblk_t *hdr_mp, mblk_t **mmd_mp, int kmflags)
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	uchar_t *buf;
190*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
191*7c478bd9Sstevel@tonic-gate 	uint_t mmd_mplen;
192*7c478bd9Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	ASSERT(hdr_mp != NULL);
195*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd_mp != NULL);
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	/*
198*7c478bd9Sstevel@tonic-gate 	 * Caller should never pass in a chain of mblks since we
199*7c478bd9Sstevel@tonic-gate 	 * only care about the first one, hence the assertions.
200*7c478bd9Sstevel@tonic-gate 	 */
201*7c478bd9Sstevel@tonic-gate 	ASSERT(hdr_mp->b_cont == NULL);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	if ((buf = kmem_cache_alloc(mmd_cache, kmflags)) == NULL)
204*7c478bd9Sstevel@tonic-gate 		return (NULL);
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
207*7c478bd9Sstevel@tonic-gate 	buf_info->frp.free_arg = (caddr_t)buf;
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
210*7c478bd9Sstevel@tonic-gate 	mmd_mplen = sizeof (*mmd);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	if ((*mmd_mp = desballoc((uchar_t *)mmd, mmd_mplen, BPRI_HI,
213*7c478bd9Sstevel@tonic-gate 	    &(buf_info->frp))) == NULL) {
214*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(mmd_cache, buf);
215*7c478bd9Sstevel@tonic-gate 		return (NULL);
216*7c478bd9Sstevel@tonic-gate 	}
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	DB_TYPE(*mmd_mp) = M_MULTIDATA;
219*7c478bd9Sstevel@tonic-gate 	(*mmd_mp)->b_wptr += mmd_mplen;
220*7c478bd9Sstevel@tonic-gate 	mmd->mmd_dp = (*mmd_mp)->b_datap;
221*7c478bd9Sstevel@tonic-gate 	mmd->mmd_hbuf = hdr_mp;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	return (mmd);
224*7c478bd9Sstevel@tonic-gate }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate /*
227*7c478bd9Sstevel@tonic-gate  * Associate additional payload buffer to the Multidata.
228*7c478bd9Sstevel@tonic-gate  */
229*7c478bd9Sstevel@tonic-gate int
230*7c478bd9Sstevel@tonic-gate mmd_addpldbuf(multidata_t *mmd, mblk_t *pld_mp)
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	int i;
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
235*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
236*7c478bd9Sstevel@tonic-gate 	ASSERT(pld_mp != NULL);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
239*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS &&
240*7c478bd9Sstevel@tonic-gate 	    mmd->mmd_pbuf_cnt < MULTIDATA_MAX_PBUFS; i++) {
241*7c478bd9Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] == pld_mp) {
242*7c478bd9Sstevel@tonic-gate 			/* duplicate entry */
243*7c478bd9Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding "
244*7c478bd9Sstevel@tonic-gate 			    "pld 0x%p to mmd 0x%p since it has been "
245*7c478bd9Sstevel@tonic-gate 			    "previously added into slot %d (total %d)\n",
246*7c478bd9Sstevel@tonic-gate 			    (void *)pld_mp, (void *)mmd, i, mmd->mmd_pbuf_cnt));
247*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
248*7c478bd9Sstevel@tonic-gate 			return (-1);
249*7c478bd9Sstevel@tonic-gate 		} else if (mmd->mmd_pbuf[i] == NULL) {
250*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = pld_mp;
251*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt++;
252*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
253*7c478bd9Sstevel@tonic-gate 			return (i);
254*7c478bd9Sstevel@tonic-gate 		}
255*7c478bd9Sstevel@tonic-gate 	}
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	/* all slots are taken */
258*7c478bd9Sstevel@tonic-gate 	MMD_DEBUG((CE_WARN, "mmd_addpldbuf: error adding pld 0x%p to mmd 0x%p "
259*7c478bd9Sstevel@tonic-gate 	    "since no slot space is left (total %d max %d)\n", (void *)pld_mp,
260*7c478bd9Sstevel@tonic-gate 	    (void *)mmd, mmd->mmd_pbuf_cnt, MULTIDATA_MAX_PBUFS));
261*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	return (-1);
264*7c478bd9Sstevel@tonic-gate }
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate /*
267*7c478bd9Sstevel@tonic-gate  * Multidata metadata kmem cache constructor routine.
268*7c478bd9Sstevel@tonic-gate  */
269*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
270*7c478bd9Sstevel@tonic-gate static int
271*7c478bd9Sstevel@tonic-gate mmd_constructor(void *buf, void *cdrarg, int kmflags)
272*7c478bd9Sstevel@tonic-gate {
273*7c478bd9Sstevel@tonic-gate 	struct mmd_buf_info *buf_info;
274*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	bzero((void *)buf, MMD_CACHE_SIZE);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	buf_info = (struct mmd_buf_info *)buf;
279*7c478bd9Sstevel@tonic-gate 	buf_info->frp.free_func = mmd_esballoc_free;
280*7c478bd9Sstevel@tonic-gate 	buf_info->buf_len = MMD_CACHE_SIZE;
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf_info + 1);
283*7c478bd9Sstevel@tonic-gate 	mmd->mmd_magic = MULTIDATA_MAGIC;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	mutex_init(&(mmd->mmd_pd_slab_lock), NULL, MUTEX_DRIVER, NULL);
286*7c478bd9Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_slab_q));
287*7c478bd9Sstevel@tonic-gate 	QL_INIT(&(mmd->mmd_pd_q));
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	return (0);
290*7c478bd9Sstevel@tonic-gate }
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate /*
293*7c478bd9Sstevel@tonic-gate  * Multidata metadata kmem cache destructor routine.
294*7c478bd9Sstevel@tonic-gate  */
295*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
296*7c478bd9Sstevel@tonic-gate static void
297*7c478bd9Sstevel@tonic-gate mmd_destructor(void *buf, void *cdrarg)
298*7c478bd9Sstevel@tonic-gate {
299*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
300*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
301*7c478bd9Sstevel@tonic-gate 	int i;
302*7c478bd9Sstevel@tonic-gate #endif
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)((uchar_t *)buf + sizeof (struct mmd_buf_info));
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
307*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp == NULL);
308*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf == NULL);
309*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
310*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
311*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++)
312*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] == NULL);
313*7c478bd9Sstevel@tonic-gate #endif
314*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pattbl == NULL);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&(mmd->mmd_pd_slab_lock));
317*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
318*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
319*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
320*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
321*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
322*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
323*7c478bd9Sstevel@tonic-gate }
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate /*
326*7c478bd9Sstevel@tonic-gate  * Multidata message block free callback routine.
327*7c478bd9Sstevel@tonic-gate  */
328*7c478bd9Sstevel@tonic-gate static void
329*7c478bd9Sstevel@tonic-gate mmd_esballoc_free(caddr_t buf)
330*7c478bd9Sstevel@tonic-gate {
331*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
332*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
333*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
334*7c478bd9Sstevel@tonic-gate 	int i;
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
337*7c478bd9Sstevel@tonic-gate 	ASSERT(((struct mmd_buf_info *)buf)->buf_len == MMD_CACHE_SIZE);
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)(buf + sizeof (struct mmd_buf_info));
340*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp != NULL);
343*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_dp->db_ref == 1);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	/* remove all packet descriptors and private attributes */
346*7c478bd9Sstevel@tonic-gate 	pd = Q2PD(mmd->mmd_pd_q.ql_next);
347*7c478bd9Sstevel@tonic-gate 	while (pd != Q2PD(&(mmd->mmd_pd_q)))
348*7c478bd9Sstevel@tonic-gate 		pd = mmd_destroy_pdesc(mmd, pd);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_q.ql_next == &(mmd->mmd_pd_q));
351*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_cnt == 0);
352*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_hbuf_ref == 0);
353*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_ref == 0);
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	/* remove all global attributes */
356*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL)
357*7c478bd9Sstevel@tonic-gate 		mmd_destroy_pattbl(&(mmd->mmd_pattbl));
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	/* remove all descriptor slabs */
360*7c478bd9Sstevel@tonic-gate 	slab = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_next);
361*7c478bd9Sstevel@tonic-gate 	while (slab != Q2PDSLAB(&(mmd->mmd_pd_slab_q))) {
362*7c478bd9Sstevel@tonic-gate 		pdesc_slab_t *slab_next = Q2PDSLAB(slab->pds_next);
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 		remque(&(slab->pds_next));
365*7c478bd9Sstevel@tonic-gate 		slab->pds_next = NULL;
366*7c478bd9Sstevel@tonic-gate 		slab->pds_prev = NULL;
367*7c478bd9Sstevel@tonic-gate 		slab->pds_mmd = NULL;
368*7c478bd9Sstevel@tonic-gate 		slab->pds_used = 0;
369*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(pd_slab_cache, slab);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_slab_cnt > 0);
372*7c478bd9Sstevel@tonic-gate 		mmd->mmd_slab_cnt--;
373*7c478bd9Sstevel@tonic-gate 		slab = slab_next;
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q));
376*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_slab_cnt == 0);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	mmd->mmd_dp = NULL;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	/* finally, free all associated message blocks */
381*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
382*7c478bd9Sstevel@tonic-gate 		freeb(mmd->mmd_hbuf);
383*7c478bd9Sstevel@tonic-gate 		mmd->mmd_hbuf = NULL;
384*7c478bd9Sstevel@tonic-gate 	}
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MULTIDATA_MAX_PBUFS; i++) {
387*7c478bd9Sstevel@tonic-gate 		if (mmd->mmd_pbuf[i] != NULL) {
388*7c478bd9Sstevel@tonic-gate 			freeb(mmd->mmd_pbuf[i]);
389*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[i] = NULL;
390*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_cnt > 0);
391*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_cnt--;
392*7c478bd9Sstevel@tonic-gate 		}
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_pbuf_cnt == 0);
396*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&(mmd->mmd_pd_slab_lock)));
397*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(mmd_cache, buf);
398*7c478bd9Sstevel@tonic-gate }
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate /*
401*7c478bd9Sstevel@tonic-gate  * Multidata message block copy routine, called by copyb() when it
402*7c478bd9Sstevel@tonic-gate  * encounters a M_MULTIDATA data block type.  This routine should
403*7c478bd9Sstevel@tonic-gate  * not be called by anyone other than copyb(), since it may go away
404*7c478bd9Sstevel@tonic-gate  * (read: become static to this module) once some sort of copy callback
405*7c478bd9Sstevel@tonic-gate  * routine is made available.
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate mblk_t *
408*7c478bd9Sstevel@tonic-gate mmd_copy(mblk_t *bp, int kmflags)
409*7c478bd9Sstevel@tonic-gate {
410*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd, *n_mmd;
411*7c478bd9Sstevel@tonic-gate 	mblk_t *n_hbuf = NULL, *n_pbuf[MULTIDATA_MAX_PBUFS];
412*7c478bd9Sstevel@tonic-gate 	mblk_t **pmp_last = &n_pbuf[MULTIDATA_MAX_PBUFS - 1];
413*7c478bd9Sstevel@tonic-gate 	mblk_t **pmp;
414*7c478bd9Sstevel@tonic-gate 	mblk_t *n_bp = NULL;
415*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
416*7c478bd9Sstevel@tonic-gate 	uint_t n_pbuf_cnt = 0;
417*7c478bd9Sstevel@tonic-gate 	int idx, i;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate #define	FREE_PBUFS() {					\
420*7c478bd9Sstevel@tonic-gate 	for (pmp = &n_pbuf[0]; pmp <= pmp_last; pmp++)	\
421*7c478bd9Sstevel@tonic-gate 		if (*pmp != NULL) freeb(*pmp);		\
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate #define	REL_OFF(p, base, n_base)			\
425*7c478bd9Sstevel@tonic-gate 	((uchar_t *)(n_base) + ((uchar_t *)(p) - (uchar_t *)base))
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	ASSERT(bp != NULL && DB_TYPE(bp) == M_MULTIDATA);
428*7c478bd9Sstevel@tonic-gate 	mmd = mmd_getmultidata(bp);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	/* copy the header buffer */
431*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL && (n_hbuf = copyb(mmd->mmd_hbuf)) == NULL)
432*7c478bd9Sstevel@tonic-gate 		return (NULL);
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	/* copy the payload buffer(s) */
435*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
436*7c478bd9Sstevel@tonic-gate 	bzero((void *)&n_pbuf[0], sizeof (mblk_t *) * MULTIDATA_MAX_PBUFS);
437*7c478bd9Sstevel@tonic-gate 	n_pbuf_cnt = mmd->mmd_pbuf_cnt;
438*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < n_pbuf_cnt; i++) {
439*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
440*7c478bd9Sstevel@tonic-gate 		n_pbuf[i] = copyb(mmd->mmd_pbuf[i]);
441*7c478bd9Sstevel@tonic-gate 		if (n_pbuf[i] == NULL) {
442*7c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
443*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
444*7c478bd9Sstevel@tonic-gate 			return (NULL);
445*7c478bd9Sstevel@tonic-gate 		}
446*7c478bd9Sstevel@tonic-gate 	}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	/* allocate new Multidata */
449*7c478bd9Sstevel@tonic-gate 	n_mmd = mmd_alloc(n_hbuf, &n_bp, kmflags);
450*7c478bd9Sstevel@tonic-gate 	if (n_mmd == NULL) {
451*7c478bd9Sstevel@tonic-gate 		if (n_hbuf != NULL)
452*7c478bd9Sstevel@tonic-gate 			freeb(n_hbuf);
453*7c478bd9Sstevel@tonic-gate 		if (n_pbuf_cnt != 0)
454*7c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
455*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
456*7c478bd9Sstevel@tonic-gate 		return (NULL);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	/*
460*7c478bd9Sstevel@tonic-gate 	 * Add payload buffer(s); upon success, leave n_pbuf array
461*7c478bd9Sstevel@tonic-gate 	 * alone, as the newly-created Multidata had already contained
462*7c478bd9Sstevel@tonic-gate 	 * the mblk pointers stored in the array.  These will be freed
463*7c478bd9Sstevel@tonic-gate 	 * along with the Multidata itself.
464*7c478bd9Sstevel@tonic-gate 	 */
465*7c478bd9Sstevel@tonic-gate 	for (i = 0, pmp = &n_pbuf[0]; i < n_pbuf_cnt; i++, pmp++) {
466*7c478bd9Sstevel@tonic-gate 		idx = mmd_addpldbuf(n_mmd, *pmp);
467*7c478bd9Sstevel@tonic-gate 		if (idx < 0) {
468*7c478bd9Sstevel@tonic-gate 			FREE_PBUFS();
469*7c478bd9Sstevel@tonic-gate 			freeb(n_bp);
470*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
471*7c478bd9Sstevel@tonic-gate 			return (NULL);
472*7c478bd9Sstevel@tonic-gate 		}
473*7c478bd9Sstevel@tonic-gate 	}
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	/* copy over global attributes */
476*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pattbl != NULL &&
477*7c478bd9Sstevel@tonic-gate 	    mmd_copy_pattbl(mmd->mmd_pattbl, n_mmd, NULL, kmflags) < 0) {
478*7c478bd9Sstevel@tonic-gate 		freeb(n_bp);
479*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
480*7c478bd9Sstevel@tonic-gate 		return (NULL);
481*7c478bd9Sstevel@tonic-gate 	}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	/* copy over packet descriptors and their atttributes */
484*7c478bd9Sstevel@tonic-gate 	pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);	/* first pdesc */
485*7c478bd9Sstevel@tonic-gate 	while (pd != NULL) {
486*7c478bd9Sstevel@tonic-gate 		pdesc_t *n_pd;
487*7c478bd9Sstevel@tonic-gate 		pdescinfo_t *pdi, n_pdi;
488*7c478bd9Sstevel@tonic-gate 		uchar_t *n_base, *base;
489*7c478bd9Sstevel@tonic-gate 		pdesc_t *pd_next;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 		/* next pdesc */
492*7c478bd9Sstevel@tonic-gate 		pd_next = mmd_getpdesc(pd->pd_slab->pds_mmd, pd, NULL,
493*7c478bd9Sstevel@tonic-gate 		    1, B_TRUE);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 		/* skip if already removed */
496*7c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_REM_DEFER) {
497*7c478bd9Sstevel@tonic-gate 			pd = pd_next;
498*7c478bd9Sstevel@tonic-gate 			continue;
499*7c478bd9Sstevel@tonic-gate 		}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 		pdi = &(pd->pd_pdi);
502*7c478bd9Sstevel@tonic-gate 		bzero(&n_pdi, sizeof (n_pdi));
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 		/*
505*7c478bd9Sstevel@tonic-gate 		 * Calculate new descriptor values based on the offset of
506*7c478bd9Sstevel@tonic-gate 		 * each pointer relative to the associated buffer(s).
507*7c478bd9Sstevel@tonic-gate 		 */
508*7c478bd9Sstevel@tonic-gate 		ASSERT(pdi->flags & PDESC_HAS_REF);
509*7c478bd9Sstevel@tonic-gate 		if (pdi->flags & PDESC_HBUF_REF) {
510*7c478bd9Sstevel@tonic-gate 			n_base = n_mmd->mmd_hbuf->b_rptr;
511*7c478bd9Sstevel@tonic-gate 			base = mmd->mmd_hbuf->b_rptr;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 			n_pdi.flags |= PDESC_HBUF_REF;
514*7c478bd9Sstevel@tonic-gate 			n_pdi.hdr_base = REL_OFF(pdi->hdr_base, base, n_base);
515*7c478bd9Sstevel@tonic-gate 			n_pdi.hdr_rptr = REL_OFF(pdi->hdr_rptr, base, n_base);
516*7c478bd9Sstevel@tonic-gate 			n_pdi.hdr_wptr = REL_OFF(pdi->hdr_wptr, base, n_base);
517*7c478bd9Sstevel@tonic-gate 			n_pdi.hdr_lim = REL_OFF(pdi->hdr_lim, base, n_base);
518*7c478bd9Sstevel@tonic-gate 		}
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 		if (pdi->flags & PDESC_PBUF_REF) {
521*7c478bd9Sstevel@tonic-gate 			n_pdi.flags |= PDESC_PBUF_REF;
522*7c478bd9Sstevel@tonic-gate 			n_pdi.pld_cnt = pdi->pld_cnt;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < pdi->pld_cnt; i++) {
525*7c478bd9Sstevel@tonic-gate 				idx = pdi->pld_ary[i].pld_pbuf_idx;
526*7c478bd9Sstevel@tonic-gate 				ASSERT(idx < MULTIDATA_MAX_PBUFS);
527*7c478bd9Sstevel@tonic-gate 				ASSERT(n_mmd->mmd_pbuf[idx] != NULL);
528*7c478bd9Sstevel@tonic-gate 				ASSERT(mmd->mmd_pbuf[idx] != NULL);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 				n_base = n_mmd->mmd_pbuf[idx]->b_rptr;
531*7c478bd9Sstevel@tonic-gate 				base = mmd->mmd_pbuf[idx]->b_rptr;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_pbuf_idx = idx;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 				/*
536*7c478bd9Sstevel@tonic-gate 				 * We can't copy the pointers just like that,
537*7c478bd9Sstevel@tonic-gate 				 * so calculate the relative offset.
538*7c478bd9Sstevel@tonic-gate 				 */
539*7c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_rptr =
540*7c478bd9Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_rptr,
541*7c478bd9Sstevel@tonic-gate 					base, n_base);
542*7c478bd9Sstevel@tonic-gate 				n_pdi.pld_ary[i].pld_wptr =
543*7c478bd9Sstevel@tonic-gate 				    REL_OFF(pdi->pld_ary[i].pld_wptr,
544*7c478bd9Sstevel@tonic-gate 					base, n_base);
545*7c478bd9Sstevel@tonic-gate 			}
546*7c478bd9Sstevel@tonic-gate 		}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 		/* add the new descriptor to the new Multidata */
549*7c478bd9Sstevel@tonic-gate 		n_pd = mmd_addpdesc_int(n_mmd, &n_pdi, NULL, kmflags);
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 		if (n_pd == NULL || (pd->pd_pattbl != NULL &&
552*7c478bd9Sstevel@tonic-gate 		    mmd_copy_pattbl(pd->pd_pattbl, n_mmd, n_pd, kmflags) < 0)) {
553*7c478bd9Sstevel@tonic-gate 			freeb(n_bp);
554*7c478bd9Sstevel@tonic-gate 			mutex_exit(&mmd->mmd_pd_slab_lock);
555*7c478bd9Sstevel@tonic-gate 			return (NULL);
556*7c478bd9Sstevel@tonic-gate 		}
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 		pd = pd_next;
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate #undef REL_OFF
561*7c478bd9Sstevel@tonic-gate #undef FREE_PBUFS
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
564*7c478bd9Sstevel@tonic-gate 	return (n_bp);
565*7c478bd9Sstevel@tonic-gate }
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate /*
568*7c478bd9Sstevel@tonic-gate  * Given a Multidata message block, return the Multidata metadata handle.
569*7c478bd9Sstevel@tonic-gate  */
570*7c478bd9Sstevel@tonic-gate multidata_t *
571*7c478bd9Sstevel@tonic-gate mmd_getmultidata(mblk_t *mp)
572*7c478bd9Sstevel@tonic-gate {
573*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	if (DB_TYPE(mp) != M_MULTIDATA)
578*7c478bd9Sstevel@tonic-gate 		return (NULL);
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	mmd = (multidata_t *)mp->b_rptr;
581*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	return (mmd);
584*7c478bd9Sstevel@tonic-gate }
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate /*
587*7c478bd9Sstevel@tonic-gate  * Return the start and end addresses of the associated buffer(s).
588*7c478bd9Sstevel@tonic-gate  */
589*7c478bd9Sstevel@tonic-gate void
590*7c478bd9Sstevel@tonic-gate mmd_getregions(multidata_t *mmd, mbufinfo_t *mbi)
591*7c478bd9Sstevel@tonic-gate {
592*7c478bd9Sstevel@tonic-gate 	int i;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
595*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
596*7c478bd9Sstevel@tonic-gate 	ASSERT(mbi != NULL);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	bzero((void *)mbi, sizeof (mbufinfo_t));
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_hbuf != NULL) {
601*7c478bd9Sstevel@tonic-gate 		mbi->hbuf_rptr = mmd->mmd_hbuf->b_rptr;
602*7c478bd9Sstevel@tonic-gate 		mbi->hbuf_wptr = mmd->mmd_hbuf->b_wptr;
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
606*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
607*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pbuf[i] != NULL);
608*7c478bd9Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_rptr = mmd->mmd_pbuf[i]->b_rptr;
609*7c478bd9Sstevel@tonic-gate 		mbi->pbuf_ary[i].pbuf_wptr = mmd->mmd_pbuf[i]->b_wptr;
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	mbi->pbuf_cnt = mmd->mmd_pbuf_cnt;
613*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
614*7c478bd9Sstevel@tonic-gate }
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate /*
617*7c478bd9Sstevel@tonic-gate  * Return the Multidata statistics.
618*7c478bd9Sstevel@tonic-gate  */
619*7c478bd9Sstevel@tonic-gate uint_t
620*7c478bd9Sstevel@tonic-gate mmd_getcnt(multidata_t *mmd, uint_t *hbuf_ref, uint_t *pbuf_ref)
621*7c478bd9Sstevel@tonic-gate {
622*7c478bd9Sstevel@tonic-gate 	uint_t pd_cnt;
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
625*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
628*7c478bd9Sstevel@tonic-gate 	if (hbuf_ref != NULL)
629*7c478bd9Sstevel@tonic-gate 		*hbuf_ref = mmd->mmd_hbuf_ref;
630*7c478bd9Sstevel@tonic-gate 	if (pbuf_ref != NULL)
631*7c478bd9Sstevel@tonic-gate 		*pbuf_ref = mmd->mmd_pbuf_ref;
632*7c478bd9Sstevel@tonic-gate 	pd_cnt = mmd->mmd_pd_cnt;
633*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	return (pd_cnt);
636*7c478bd9Sstevel@tonic-gate }
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate #define	HBUF_REF_VALID(mmd, pdi)					\
639*7c478bd9Sstevel@tonic-gate 	((mmd)->mmd_hbuf != NULL && (pdi)->hdr_rptr != NULL &&		\
640*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_wptr != NULL && (pdi)->hdr_base != NULL &&		\
641*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_lim != NULL && (pdi)->hdr_lim >= (pdi)->hdr_base &&	\
642*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_wptr >= (pdi)->hdr_rptr &&				\
643*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_base <= (pdi)->hdr_rptr &&				\
644*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_lim >= (pdi)->hdr_wptr &&				\
645*7c478bd9Sstevel@tonic-gate 	(pdi)->hdr_base >= (mmd)->mmd_hbuf->b_rptr &&			\
646*7c478bd9Sstevel@tonic-gate 	MBLKIN((mmd)->mmd_hbuf,						\
647*7c478bd9Sstevel@tonic-gate 	(pdi->hdr_base - (mmd)->mmd_hbuf->b_rptr),			\
648*7c478bd9Sstevel@tonic-gate 	PDESC_HDRSIZE(pdi)))
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate /*
651*7c478bd9Sstevel@tonic-gate  * Bounds check payload area(s).
652*7c478bd9Sstevel@tonic-gate  */
653*7c478bd9Sstevel@tonic-gate static boolean_t
654*7c478bd9Sstevel@tonic-gate pbuf_ref_valid(multidata_t *mmd, pdescinfo_t *pdi)
655*7c478bd9Sstevel@tonic-gate {
656*7c478bd9Sstevel@tonic-gate 	int i = 0, idx;
657*7c478bd9Sstevel@tonic-gate 	boolean_t valid = B_TRUE;
658*7c478bd9Sstevel@tonic-gate 	struct pld_ary_s *pa;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
661*7c478bd9Sstevel@tonic-gate 	if (pdi->pld_cnt == 0 || pdi->pld_cnt > mmd->mmd_pbuf_cnt) {
662*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
663*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	pa = &pdi->pld_ary[0];
667*7c478bd9Sstevel@tonic-gate 	while (valid && i < pdi->pld_cnt) {
668*7c478bd9Sstevel@tonic-gate 		valid = (((idx = pa->pld_pbuf_idx) < mmd->mmd_pbuf_cnt) &&
669*7c478bd9Sstevel@tonic-gate 		    pa->pld_rptr != NULL && pa->pld_wptr != NULL &&
670*7c478bd9Sstevel@tonic-gate 		    pa->pld_wptr >= pa->pld_rptr &&
671*7c478bd9Sstevel@tonic-gate 		    pa->pld_rptr >= mmd->mmd_pbuf[idx]->b_rptr &&
672*7c478bd9Sstevel@tonic-gate 		    MBLKIN(mmd->mmd_pbuf[idx], (pa->pld_rptr -
673*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf[idx]->b_rptr),
674*7c478bd9Sstevel@tonic-gate 			PDESC_PLD_SPAN_SIZE(pdi, i)));
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 		if (!valid) {
677*7c478bd9Sstevel@tonic-gate 			MMD_DEBUG((CE_WARN,
678*7c478bd9Sstevel@tonic-gate 			    "pbuf_ref_valid: pdi 0x%p pld out of bound; "
679*7c478bd9Sstevel@tonic-gate 			    "index %d has pld_cnt %d pbuf_idx %d "
680*7c478bd9Sstevel@tonic-gate 			    "(mmd_pbuf_cnt %d), "
681*7c478bd9Sstevel@tonic-gate 			    "pld_rptr 0x%p pld_wptr 0x%p len %d "
682*7c478bd9Sstevel@tonic-gate 			    "(valid 0x%p-0x%p len %d)\n", (void *)pdi,
683*7c478bd9Sstevel@tonic-gate 			    i, pdi->pld_cnt, idx, mmd->mmd_pbuf_cnt,
684*7c478bd9Sstevel@tonic-gate 			    (void *)pa->pld_rptr,
685*7c478bd9Sstevel@tonic-gate 			    (void *)pa->pld_wptr,
686*7c478bd9Sstevel@tonic-gate 			    (int)PDESC_PLD_SPAN_SIZE(pdi, i),
687*7c478bd9Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_rptr,
688*7c478bd9Sstevel@tonic-gate 			    (void *)mmd->mmd_pbuf[idx]->b_wptr,
689*7c478bd9Sstevel@tonic-gate 			    (int)MBLKL(mmd->mmd_pbuf[idx])));
690*7c478bd9Sstevel@tonic-gate 		}
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 		/* advance to next entry */
693*7c478bd9Sstevel@tonic-gate 		i++;
694*7c478bd9Sstevel@tonic-gate 		pa++;
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
698*7c478bd9Sstevel@tonic-gate 	return (valid);
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate /*
702*7c478bd9Sstevel@tonic-gate  * Add a packet descriptor to the Multidata.
703*7c478bd9Sstevel@tonic-gate  */
704*7c478bd9Sstevel@tonic-gate pdesc_t *
705*7c478bd9Sstevel@tonic-gate mmd_addpdesc(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
706*7c478bd9Sstevel@tonic-gate {
707*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
708*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
709*7c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
710*7c478bd9Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
713*7c478bd9Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
714*7c478bd9Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
715*7c478bd9Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi)))) {
716*7c478bd9Sstevel@tonic-gate 		if (err != NULL)
717*7c478bd9Sstevel@tonic-gate 			*err = EINVAL;
718*7c478bd9Sstevel@tonic-gate 		return (NULL);
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	return (mmd_addpdesc_int(mmd, pdi, err, kmflags));
722*7c478bd9Sstevel@tonic-gate }
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate /*
725*7c478bd9Sstevel@tonic-gate  * Internal routine to add a packet descriptor, called when mmd_addpdesc
726*7c478bd9Sstevel@tonic-gate  * or mmd_copy tries to allocate and add a descriptor to a Multidata.
727*7c478bd9Sstevel@tonic-gate  */
728*7c478bd9Sstevel@tonic-gate static pdesc_t *
729*7c478bd9Sstevel@tonic-gate mmd_addpdesc_int(multidata_t *mmd, pdescinfo_t *pdi, int *err, int kmflags)
730*7c478bd9Sstevel@tonic-gate {
731*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab, *slab_last;
732*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	ASSERT(pdi->flags & PDESC_HAS_REF);
735*7c478bd9Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_HBUF_REF) || HBUF_REF_VALID(mmd, pdi));
736*7c478bd9Sstevel@tonic-gate 	ASSERT(!(pdi->flags & PDESC_PBUF_REF) || pbuf_ref_valid(mmd, pdi));
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 	if (err != NULL)
739*7c478bd9Sstevel@tonic-gate 		*err = 0;
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
742*7c478bd9Sstevel@tonic-gate 	/*
743*7c478bd9Sstevel@tonic-gate 	 * Is slab list empty or the last-added slab is full?  If so,
744*7c478bd9Sstevel@tonic-gate 	 * allocate new slab for the descriptor; otherwise, use the
745*7c478bd9Sstevel@tonic-gate 	 * last-added slab instead.
746*7c478bd9Sstevel@tonic-gate 	 */
747*7c478bd9Sstevel@tonic-gate 	slab_last = Q2PDSLAB(mmd->mmd_pd_slab_q.ql_prev);
748*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_pd_slab_q.ql_next == &(mmd->mmd_pd_slab_q) ||
749*7c478bd9Sstevel@tonic-gate 	    slab_last->pds_used == slab_last->pds_sz) {
750*7c478bd9Sstevel@tonic-gate 		slab = kmem_cache_alloc(pd_slab_cache, kmflags);
751*7c478bd9Sstevel@tonic-gate 		if (slab == NULL) {
752*7c478bd9Sstevel@tonic-gate 			if (err != NULL)
753*7c478bd9Sstevel@tonic-gate 				*err = ENOMEM;
754*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(mmd->mmd_pd_slab_lock));
755*7c478bd9Sstevel@tonic-gate 			return (NULL);
756*7c478bd9Sstevel@tonic-gate 		}
757*7c478bd9Sstevel@tonic-gate 		slab->pds_mmd = mmd;
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 		ASSERT(slab->pds_used == 0);
760*7c478bd9Sstevel@tonic-gate 		ASSERT(slab->pds_next == NULL && slab->pds_prev == NULL);
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 		/* insert slab at end of list */
763*7c478bd9Sstevel@tonic-gate 		insque(&(slab->pds_next), mmd->mmd_pd_slab_q.ql_prev);
764*7c478bd9Sstevel@tonic-gate 		mmd->mmd_slab_cnt++;
765*7c478bd9Sstevel@tonic-gate 	} else {
766*7c478bd9Sstevel@tonic-gate 		slab = slab_last;
767*7c478bd9Sstevel@tonic-gate 	}
768*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_used < slab->pds_sz);
769*7c478bd9Sstevel@tonic-gate 	pd = &(slab->pds_free_desc[slab->pds_used++]);
770*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
771*7c478bd9Sstevel@tonic-gate 	pd->pd_next = NULL;
772*7c478bd9Sstevel@tonic-gate 	pd->pd_prev = NULL;
773*7c478bd9Sstevel@tonic-gate 	pd->pd_slab = slab;
774*7c478bd9Sstevel@tonic-gate 	pd->pd_pattbl = NULL;
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
777*7c478bd9Sstevel@tonic-gate 	PDI_COPY(pdi, &(pd->pd_pdi));
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_HBUF_REF)
780*7c478bd9Sstevel@tonic-gate 		mmd->mmd_hbuf_ref++;
781*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_PBUF_REF)
782*7c478bd9Sstevel@tonic-gate 		mmd->mmd_pbuf_ref += pd->pd_pdi.pld_cnt;
783*7c478bd9Sstevel@tonic-gate 	mmd->mmd_pd_cnt++;
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	/* insert descriptor at end of list */
786*7c478bd9Sstevel@tonic-gate 	insque(&(pd->pd_next), mmd->mmd_pd_q.ql_prev);
787*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	return (pd);
790*7c478bd9Sstevel@tonic-gate }
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate /*
793*7c478bd9Sstevel@tonic-gate  * Packet descriptor slab kmem cache constructor routine.
794*7c478bd9Sstevel@tonic-gate  */
795*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
796*7c478bd9Sstevel@tonic-gate static int
797*7c478bd9Sstevel@tonic-gate pdslab_constructor(void *buf, void *cdrarg, int kmflags)
798*7c478bd9Sstevel@tonic-gate {
799*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
800*7c478bd9Sstevel@tonic-gate 	uint_t cnt = (uint_t)(uintptr_t)cdrarg;
801*7c478bd9Sstevel@tonic-gate 	int i;
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	ASSERT(cnt > 0);	/* slab size can't be zero */
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
806*7c478bd9Sstevel@tonic-gate 	slab->pds_next = NULL;
807*7c478bd9Sstevel@tonic-gate 	slab->pds_prev = NULL;
808*7c478bd9Sstevel@tonic-gate 	slab->pds_mmd = NULL;
809*7c478bd9Sstevel@tonic-gate 	slab->pds_used = 0;
810*7c478bd9Sstevel@tonic-gate 	slab->pds_sz = cnt;
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < cnt; i++) {
813*7c478bd9Sstevel@tonic-gate 		pdesc_t *pd = &(slab->pds_free_desc[i]);
814*7c478bd9Sstevel@tonic-gate 		pd->pd_magic = PDESC_MAGIC;
815*7c478bd9Sstevel@tonic-gate 	}
816*7c478bd9Sstevel@tonic-gate 	return (0);
817*7c478bd9Sstevel@tonic-gate }
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate /*
820*7c478bd9Sstevel@tonic-gate  * Packet descriptor slab kmem cache destructor routine.
821*7c478bd9Sstevel@tonic-gate  */
822*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
823*7c478bd9Sstevel@tonic-gate static void
824*7c478bd9Sstevel@tonic-gate pdslab_destructor(void *buf, void *cdrarg)
825*7c478bd9Sstevel@tonic-gate {
826*7c478bd9Sstevel@tonic-gate 	pdesc_slab_t *slab;
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	slab = (pdesc_slab_t *)buf;
829*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_next == NULL);
830*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_prev == NULL);
831*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_mmd == NULL);
832*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_used == 0);
833*7c478bd9Sstevel@tonic-gate 	ASSERT(slab->pds_sz > 0);
834*7c478bd9Sstevel@tonic-gate }
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate /*
837*7c478bd9Sstevel@tonic-gate  * Remove a packet descriptor from the in-use descriptor list,
838*7c478bd9Sstevel@tonic-gate  * called by mmd_rempdesc or during free.
839*7c478bd9Sstevel@tonic-gate  */
840*7c478bd9Sstevel@tonic-gate static pdesc_t *
841*7c478bd9Sstevel@tonic-gate mmd_destroy_pdesc(multidata_t *mmd, pdesc_t *pd)
842*7c478bd9Sstevel@tonic-gate {
843*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd_next;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	pd_next = Q2PD(pd->pd_next);
846*7c478bd9Sstevel@tonic-gate 	remque(&(pd->pd_next));
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 	/* remove all local attributes */
849*7c478bd9Sstevel@tonic-gate 	if (pd->pd_pattbl != NULL)
850*7c478bd9Sstevel@tonic-gate 		mmd_destroy_pattbl(&(pd->pd_pattbl));
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate 	/* don't decrease counts for a removed descriptor */
853*7c478bd9Sstevel@tonic-gate 	if (!(pd->pd_flags & PDESC_REM_DEFER)) {
854*7c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
855*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
856*7c478bd9Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
857*7c478bd9Sstevel@tonic-gate 		}
858*7c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
859*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
860*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
861*7c478bd9Sstevel@tonic-gate 		}
862*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
863*7c478bd9Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
864*7c478bd9Sstevel@tonic-gate 	}
865*7c478bd9Sstevel@tonic-gate 	return (pd_next);
866*7c478bd9Sstevel@tonic-gate }
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate /*
869*7c478bd9Sstevel@tonic-gate  * Remove a packet descriptor from the Multidata.
870*7c478bd9Sstevel@tonic-gate  */
871*7c478bd9Sstevel@tonic-gate void
872*7c478bd9Sstevel@tonic-gate mmd_rempdesc(pdesc_t *pd)
873*7c478bd9Sstevel@tonic-gate {
874*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
877*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
880*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(mmd->mmd_pd_slab_lock));
883*7c478bd9Sstevel@tonic-gate 	/*
884*7c478bd9Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
885*7c478bd9Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
886*7c478bd9Sstevel@tonic-gate 	 * descriptor handle value is held by those threads.  That's why
887*7c478bd9Sstevel@tonic-gate 	 * we simply mark the entry as "removed" and decrement the counts.
888*7c478bd9Sstevel@tonic-gate 	 * If there are no other threads, then we free the descriptor.
889*7c478bd9Sstevel@tonic-gate 	 */
890*7c478bd9Sstevel@tonic-gate 	if (mmd->mmd_dp->db_ref > 1) {
891*7c478bd9Sstevel@tonic-gate 		pd->pd_flags |= PDESC_REM_DEFER;
892*7c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_HBUF_REF) {
893*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_hbuf_ref > 0);
894*7c478bd9Sstevel@tonic-gate 			mmd->mmd_hbuf_ref--;
895*7c478bd9Sstevel@tonic-gate 		}
896*7c478bd9Sstevel@tonic-gate 		if (pd->pd_flags & PDESC_PBUF_REF) {
897*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf_ref > 0);
898*7c478bd9Sstevel@tonic-gate 			mmd->mmd_pbuf_ref -= pd->pd_pdi.pld_cnt;
899*7c478bd9Sstevel@tonic-gate 		}
900*7c478bd9Sstevel@tonic-gate 		ASSERT(mmd->mmd_pd_cnt > 0);
901*7c478bd9Sstevel@tonic-gate 		mmd->mmd_pd_cnt--;
902*7c478bd9Sstevel@tonic-gate 	} else {
903*7c478bd9Sstevel@tonic-gate 		(void) mmd_destroy_pdesc(mmd, pd);
904*7c478bd9Sstevel@tonic-gate 	}
905*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(mmd->mmd_pd_slab_lock));
906*7c478bd9Sstevel@tonic-gate }
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate /*
909*7c478bd9Sstevel@tonic-gate  * A generic routine to traverse the packet descriptor in-use list.
910*7c478bd9Sstevel@tonic-gate  */
911*7c478bd9Sstevel@tonic-gate static pdesc_t *
912*7c478bd9Sstevel@tonic-gate mmd_getpdesc(multidata_t *mmd, pdesc_t *pd, pdescinfo_t *pdi, uint_t forw,
913*7c478bd9Sstevel@tonic-gate     boolean_t mutex_held)
914*7c478bd9Sstevel@tonic-gate {
915*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd_head;
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_slab->pds_mmd == mmd);
918*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
919*7c478bd9Sstevel@tonic-gate 	ASSERT(!mutex_held || MUTEX_HELD(&(mmd->mmd_pd_slab_lock)));
920*7c478bd9Sstevel@tonic-gate 
921*7c478bd9Sstevel@tonic-gate 	if (!mutex_held)
922*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(mmd->mmd_pd_slab_lock));
923*7c478bd9Sstevel@tonic-gate 	pd_head = Q2PD(&(mmd->mmd_pd_q));
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	if (pd == NULL) {
926*7c478bd9Sstevel@tonic-gate 		/*
927*7c478bd9Sstevel@tonic-gate 		 * We're called by mmd_get{first,last}pdesc, and so
928*7c478bd9Sstevel@tonic-gate 		 * return either the first or last list element.
929*7c478bd9Sstevel@tonic-gate 		 */
930*7c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(mmd->mmd_pd_q.ql_next) :
931*7c478bd9Sstevel@tonic-gate 		    Q2PD(mmd->mmd_pd_q.ql_prev);
932*7c478bd9Sstevel@tonic-gate 	} else {
933*7c478bd9Sstevel@tonic-gate 		/*
934*7c478bd9Sstevel@tonic-gate 		 * We're called by mmd_get{next,prev}pdesc, and so
935*7c478bd9Sstevel@tonic-gate 		 * return either the next or previous list element.
936*7c478bd9Sstevel@tonic-gate 		 */
937*7c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
938*7c478bd9Sstevel@tonic-gate 	}
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	while (pd != pd_head) {
941*7c478bd9Sstevel@tonic-gate 		/* skip element if it has been removed */
942*7c478bd9Sstevel@tonic-gate 		if (!(pd->pd_flags & PDESC_REM_DEFER))
943*7c478bd9Sstevel@tonic-gate 			break;
944*7c478bd9Sstevel@tonic-gate 		pd = forw ? Q2PD(pd->pd_next) : Q2PD(pd->pd_prev);
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate 	if (!mutex_held)
947*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(mmd->mmd_pd_slab_lock));
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	/* return NULL if we're back at the beginning */
950*7c478bd9Sstevel@tonic-gate 	if (pd == pd_head)
951*7c478bd9Sstevel@tonic-gate 		pd = NULL;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	/* got an entry; copy descriptor info to caller */
954*7c478bd9Sstevel@tonic-gate 	if (pd != NULL && pdi != NULL)
955*7c478bd9Sstevel@tonic-gate 		PDI_COPY(&(pd->pd_pdi), pdi);
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
958*7c478bd9Sstevel@tonic-gate 	return (pd);
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate }
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate /*
963*7c478bd9Sstevel@tonic-gate  * Return the first packet descriptor in the in-use list.
964*7c478bd9Sstevel@tonic-gate  */
965*7c478bd9Sstevel@tonic-gate pdesc_t *
966*7c478bd9Sstevel@tonic-gate mmd_getfirstpdesc(multidata_t *mmd, pdescinfo_t *pdi)
967*7c478bd9Sstevel@tonic-gate {
968*7c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 1, B_FALSE));
969*7c478bd9Sstevel@tonic-gate }
970*7c478bd9Sstevel@tonic-gate 
971*7c478bd9Sstevel@tonic-gate /*
972*7c478bd9Sstevel@tonic-gate  * Return the last packet descriptor in the in-use list.
973*7c478bd9Sstevel@tonic-gate  */
974*7c478bd9Sstevel@tonic-gate pdesc_t *
975*7c478bd9Sstevel@tonic-gate mmd_getlastpdesc(multidata_t *mmd, pdescinfo_t *pdi)
976*7c478bd9Sstevel@tonic-gate {
977*7c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(mmd, NULL, pdi, 0, B_FALSE));
978*7c478bd9Sstevel@tonic-gate }
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate /*
981*7c478bd9Sstevel@tonic-gate  * Return the next packet descriptor in the in-use list.
982*7c478bd9Sstevel@tonic-gate  */
983*7c478bd9Sstevel@tonic-gate pdesc_t *
984*7c478bd9Sstevel@tonic-gate mmd_getnextpdesc(pdesc_t *pd, pdescinfo_t *pdi)
985*7c478bd9Sstevel@tonic-gate {
986*7c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 1, B_FALSE));
987*7c478bd9Sstevel@tonic-gate }
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate /*
990*7c478bd9Sstevel@tonic-gate  * Return the previous packet descriptor in the in-use list.
991*7c478bd9Sstevel@tonic-gate  */
992*7c478bd9Sstevel@tonic-gate pdesc_t *
993*7c478bd9Sstevel@tonic-gate mmd_getprevpdesc(pdesc_t *pd, pdescinfo_t *pdi)
994*7c478bd9Sstevel@tonic-gate {
995*7c478bd9Sstevel@tonic-gate 	return (mmd_getpdesc(pd->pd_slab->pds_mmd, pd, pdi, 0, B_FALSE));
996*7c478bd9Sstevel@tonic-gate }
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate /*
999*7c478bd9Sstevel@tonic-gate  * Check to see if pdi stretches over c_pdi; used to ensure that a packet
1000*7c478bd9Sstevel@tonic-gate  * descriptor's header and payload span may not be extended beyond the
1001*7c478bd9Sstevel@tonic-gate  * current boundaries.
1002*7c478bd9Sstevel@tonic-gate  */
1003*7c478bd9Sstevel@tonic-gate static boolean_t
1004*7c478bd9Sstevel@tonic-gate pdi_in_range(pdescinfo_t *pdi, pdescinfo_t *c_pdi)
1005*7c478bd9Sstevel@tonic-gate {
1006*7c478bd9Sstevel@tonic-gate 	int i;
1007*7c478bd9Sstevel@tonic-gate 	struct pld_ary_s *pa = &pdi->pld_ary[0];
1008*7c478bd9Sstevel@tonic-gate 	struct pld_ary_s *c_pa = &c_pdi->pld_ary[0];
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	if (pdi->hdr_base < c_pdi->hdr_base || pdi->hdr_lim > c_pdi->hdr_lim)
1011*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate 	/*
1014*7c478bd9Sstevel@tonic-gate 	 * We don't allow the number of span to be reduced, for the sake
1015*7c478bd9Sstevel@tonic-gate 	 * of simplicity.  Instead, we provide PDESC_PLD_SPAN_CLEAR() to
1016*7c478bd9Sstevel@tonic-gate 	 * clear a packet descriptor.  Note that we allow the span count to
1017*7c478bd9Sstevel@tonic-gate 	 * be increased, and the bounds check for the new one happens
1018*7c478bd9Sstevel@tonic-gate 	 * in pbuf_ref_valid.
1019*7c478bd9Sstevel@tonic-gate 	 */
1020*7c478bd9Sstevel@tonic-gate 	if (pdi->pld_cnt < c_pdi->pld_cnt)
1021*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	/* compare only those which are currently defined */
1024*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < c_pdi->pld_cnt; i++, pa++, c_pa++) {
1025*7c478bd9Sstevel@tonic-gate 		if (pa->pld_pbuf_idx != c_pa->pld_pbuf_idx ||
1026*7c478bd9Sstevel@tonic-gate 		    pa->pld_rptr < c_pa->pld_rptr ||
1027*7c478bd9Sstevel@tonic-gate 		    pa->pld_wptr > c_pa->pld_wptr)
1028*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
1031*7c478bd9Sstevel@tonic-gate }
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate /*
1034*7c478bd9Sstevel@tonic-gate  * Modify the layout of a packet descriptor.
1035*7c478bd9Sstevel@tonic-gate  */
1036*7c478bd9Sstevel@tonic-gate pdesc_t *
1037*7c478bd9Sstevel@tonic-gate mmd_adjpdesc(pdesc_t *pd, pdescinfo_t *pdi)
1038*7c478bd9Sstevel@tonic-gate {
1039*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
1040*7c478bd9Sstevel@tonic-gate 	pdescinfo_t *c_pdi;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
1043*7c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
1044*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
1047*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	/* entry has been removed */
1050*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
1051*7c478bd9Sstevel@tonic-gate 		return (NULL);
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	/* caller doesn't intend to specify any buffer reference? */
1054*7c478bd9Sstevel@tonic-gate 	if (!(pdi->flags & PDESC_HAS_REF))
1055*7c478bd9Sstevel@tonic-gate 		return (NULL);
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	/* do the references refer to invalid memory regions? */
1058*7c478bd9Sstevel@tonic-gate 	if (!mmd_speed_over_safety &&
1059*7c478bd9Sstevel@tonic-gate 	    (((pdi->flags & PDESC_HBUF_REF) && !HBUF_REF_VALID(mmd, pdi)) ||
1060*7c478bd9Sstevel@tonic-gate 	    ((pdi->flags & PDESC_PBUF_REF) && !pbuf_ref_valid(mmd, pdi))))
1061*7c478bd9Sstevel@tonic-gate 		return (NULL);
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	/* they're not subsets of current references? */
1064*7c478bd9Sstevel@tonic-gate 	c_pdi = &(pd->pd_pdi);
1065*7c478bd9Sstevel@tonic-gate 	if (!pdi_in_range(pdi, c_pdi))
1066*7c478bd9Sstevel@tonic-gate 		return (NULL);
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate 	/* copy over the descriptor info from caller */
1069*7c478bd9Sstevel@tonic-gate 	PDI_COPY(pdi, c_pdi);
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	return (pd);
1072*7c478bd9Sstevel@tonic-gate }
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate /*
1075*7c478bd9Sstevel@tonic-gate  * Copy the contents of a packet descriptor into a new buffer.  If the
1076*7c478bd9Sstevel@tonic-gate  * descriptor points to more than one buffer fragments, the contents
1077*7c478bd9Sstevel@tonic-gate  * of both fragments will be joined, with the header buffer fragment
1078*7c478bd9Sstevel@tonic-gate  * preceding the payload buffer fragment(s).
1079*7c478bd9Sstevel@tonic-gate  */
1080*7c478bd9Sstevel@tonic-gate mblk_t *
1081*7c478bd9Sstevel@tonic-gate mmd_transform(pdesc_t *pd)
1082*7c478bd9Sstevel@tonic-gate {
1083*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
1084*7c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
1085*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1086*7c478bd9Sstevel@tonic-gate 	int h_size = 0, p_size = 0;
1087*7c478bd9Sstevel@tonic-gate 	int i, len;
1088*7c478bd9Sstevel@tonic-gate 
1089*7c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
1090*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
1093*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	/* entry has been removed */
1096*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
1097*7c478bd9Sstevel@tonic-gate 		return (NULL);
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
1100*7c478bd9Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
1101*7c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_HBUF_REF)
1102*7c478bd9Sstevel@tonic-gate 		h_size = PDESC_HDRL(pdi);
1103*7c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
1104*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++)
1105*7c478bd9Sstevel@tonic-gate 			p_size += PDESC_PLD_SPAN_SIZE(pdi, i);
1106*7c478bd9Sstevel@tonic-gate 	}
1107*7c478bd9Sstevel@tonic-gate 
1108*7c478bd9Sstevel@tonic-gate 	/* allocate space large enough to hold the fragment(s) */
1109*7c478bd9Sstevel@tonic-gate 	ASSERT(h_size + p_size >= 0);
1110*7c478bd9Sstevel@tonic-gate 	if ((mp = allocb(h_size + p_size, BPRI_HI)) == NULL) {
1111*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
1112*7c478bd9Sstevel@tonic-gate 		return (NULL);
1113*7c478bd9Sstevel@tonic-gate 	}
1114*7c478bd9Sstevel@tonic-gate 
1115*7c478bd9Sstevel@tonic-gate 	/* copy over the header fragment */
1116*7c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF) && h_size > 0) {
1117*7c478bd9Sstevel@tonic-gate 		bcopy(pdi->hdr_rptr, mp->b_wptr, h_size);
1118*7c478bd9Sstevel@tonic-gate 		mp->b_wptr += h_size;
1119*7c478bd9Sstevel@tonic-gate 	}
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate 	/* copy over the payload fragment */
1122*7c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_PBUF_REF) && p_size > 0) {
1123*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++) {
1124*7c478bd9Sstevel@tonic-gate 			len = PDESC_PLD_SPAN_SIZE(pdi, i);
1125*7c478bd9Sstevel@tonic-gate 			if (len > 0) {
1126*7c478bd9Sstevel@tonic-gate 				bcopy(pdi->pld_ary[i].pld_rptr,
1127*7c478bd9Sstevel@tonic-gate 				    mp->b_wptr, len);
1128*7c478bd9Sstevel@tonic-gate 				mp->b_wptr += len;
1129*7c478bd9Sstevel@tonic-gate 			}
1130*7c478bd9Sstevel@tonic-gate 		}
1131*7c478bd9Sstevel@tonic-gate 	}
1132*7c478bd9Sstevel@tonic-gate 
1133*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
1134*7c478bd9Sstevel@tonic-gate 	return (mp);
1135*7c478bd9Sstevel@tonic-gate }
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate /*
1138*7c478bd9Sstevel@tonic-gate  * Return a chain of mblks representing the Multidata packet.
1139*7c478bd9Sstevel@tonic-gate  */
1140*7c478bd9Sstevel@tonic-gate mblk_t *
1141*7c478bd9Sstevel@tonic-gate mmd_transform_link(pdesc_t *pd)
1142*7c478bd9Sstevel@tonic-gate {
1143*7c478bd9Sstevel@tonic-gate 	multidata_t *mmd;
1144*7c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
1145*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp = NULL;
1146*7c478bd9Sstevel@tonic-gate 
1147*7c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
1148*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	mmd = pd->pd_slab->pds_mmd;
1151*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	/* entry has been removed */
1154*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
1155*7c478bd9Sstevel@tonic-gate 		return (NULL);
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	pdi = &(pd->pd_pdi);
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 	/* duplicate header buffer */
1160*7c478bd9Sstevel@tonic-gate 	if ((pdi->flags & PDESC_HBUF_REF)) {
1161*7c478bd9Sstevel@tonic-gate 		if ((nmp = dupb(mmd->mmd_hbuf)) == NULL)
1162*7c478bd9Sstevel@tonic-gate 			return (NULL);
1163*7c478bd9Sstevel@tonic-gate 		nmp->b_rptr = pdi->hdr_rptr;
1164*7c478bd9Sstevel@tonic-gate 		nmp->b_wptr = pdi->hdr_wptr;
1165*7c478bd9Sstevel@tonic-gate 	}
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	/* duplicate payload buffer(s) */
1168*7c478bd9Sstevel@tonic-gate 	if (pdi->flags & PDESC_PBUF_REF) {
1169*7c478bd9Sstevel@tonic-gate 		int i;
1170*7c478bd9Sstevel@tonic-gate 		mblk_t *mp;
1171*7c478bd9Sstevel@tonic-gate 		struct pld_ary_s *pa = &pdi->pld_ary[0];
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
1174*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pdi->pld_cnt; i++, pa++) {
1175*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[pa->pld_pbuf_idx] != NULL);
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 			/* skip empty ones */
1178*7c478bd9Sstevel@tonic-gate 			if (PDESC_PLD_SPAN_SIZE(pdi, i) == 0)
1179*7c478bd9Sstevel@tonic-gate 				continue;
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[pa->pld_pbuf_idx]);
1182*7c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
1183*7c478bd9Sstevel@tonic-gate 				if (nmp != NULL)
1184*7c478bd9Sstevel@tonic-gate 					freemsg(nmp);
1185*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
1186*7c478bd9Sstevel@tonic-gate 				return (NULL);
1187*7c478bd9Sstevel@tonic-gate 			}
1188*7c478bd9Sstevel@tonic-gate 			mp->b_rptr = pa->pld_rptr;
1189*7c478bd9Sstevel@tonic-gate 			mp->b_wptr = pa->pld_wptr;
1190*7c478bd9Sstevel@tonic-gate 			if (nmp == NULL)
1191*7c478bd9Sstevel@tonic-gate 				nmp = mp;
1192*7c478bd9Sstevel@tonic-gate 			else
1193*7c478bd9Sstevel@tonic-gate 				linkb(nmp, mp);
1194*7c478bd9Sstevel@tonic-gate 		}
1195*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
1196*7c478bd9Sstevel@tonic-gate 	}
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	return (nmp);
1199*7c478bd9Sstevel@tonic-gate }
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate /*
1202*7c478bd9Sstevel@tonic-gate  * Return duplicate message block(s) of the associated buffer(s).
1203*7c478bd9Sstevel@tonic-gate  */
1204*7c478bd9Sstevel@tonic-gate int
1205*7c478bd9Sstevel@tonic-gate mmd_dupbufs(multidata_t *mmd, mblk_t **hmp, mblk_t **pmp)
1206*7c478bd9Sstevel@tonic-gate {
1207*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
1208*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	if (hmp != NULL) {
1211*7c478bd9Sstevel@tonic-gate 		*hmp = NULL;
1212*7c478bd9Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL &&
1213*7c478bd9Sstevel@tonic-gate 		    (*hmp = dupb(mmd->mmd_hbuf)) == NULL)
1214*7c478bd9Sstevel@tonic-gate 			return (-1);
1215*7c478bd9Sstevel@tonic-gate 	}
1216*7c478bd9Sstevel@tonic-gate 
1217*7c478bd9Sstevel@tonic-gate 	if (pmp != NULL) {
1218*7c478bd9Sstevel@tonic-gate 		int i;
1219*7c478bd9Sstevel@tonic-gate 		mblk_t *mp;
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 		mutex_enter(&mmd->mmd_pd_slab_lock);
1222*7c478bd9Sstevel@tonic-gate 		*pmp = NULL;
1223*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
1224*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
1225*7c478bd9Sstevel@tonic-gate 			mp = dupb(mmd->mmd_pbuf[i]);
1226*7c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
1227*7c478bd9Sstevel@tonic-gate 				if (hmp != NULL && *hmp != NULL)
1228*7c478bd9Sstevel@tonic-gate 					freeb(*hmp);
1229*7c478bd9Sstevel@tonic-gate 				if (*pmp != NULL)
1230*7c478bd9Sstevel@tonic-gate 					freemsg(*pmp);
1231*7c478bd9Sstevel@tonic-gate 				mutex_exit(&mmd->mmd_pd_slab_lock);
1232*7c478bd9Sstevel@tonic-gate 				return (-1);
1233*7c478bd9Sstevel@tonic-gate 			}
1234*7c478bd9Sstevel@tonic-gate 			if (*pmp == NULL)
1235*7c478bd9Sstevel@tonic-gate 				*pmp = mp;
1236*7c478bd9Sstevel@tonic-gate 			else
1237*7c478bd9Sstevel@tonic-gate 				linkb(*pmp, mp);
1238*7c478bd9Sstevel@tonic-gate 		}
1239*7c478bd9Sstevel@tonic-gate 		mutex_exit(&mmd->mmd_pd_slab_lock);
1240*7c478bd9Sstevel@tonic-gate 	}
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	return (0);
1243*7c478bd9Sstevel@tonic-gate }
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate /*
1246*7c478bd9Sstevel@tonic-gate  * Return the layout of a packet descriptor.
1247*7c478bd9Sstevel@tonic-gate  */
1248*7c478bd9Sstevel@tonic-gate int
1249*7c478bd9Sstevel@tonic-gate mmd_getpdescinfo(pdesc_t *pd, pdescinfo_t *pdi)
1250*7c478bd9Sstevel@tonic-gate {
1251*7c478bd9Sstevel@tonic-gate 	ASSERT(pd != NULL);
1252*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_magic == PDESC_MAGIC);
1253*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab != NULL);
1254*7c478bd9Sstevel@tonic-gate 	ASSERT(pd->pd_slab->pds_mmd->mmd_magic == MULTIDATA_MAGIC);
1255*7c478bd9Sstevel@tonic-gate 	ASSERT(pdi != NULL);
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	/* entry has been removed */
1258*7c478bd9Sstevel@tonic-gate 	if (pd->pd_flags & PDESC_REM_DEFER)
1259*7c478bd9Sstevel@tonic-gate 		return (-1);
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 	/* copy descriptor info to caller */
1262*7c478bd9Sstevel@tonic-gate 	PDI_COPY(&(pd->pd_pdi), pdi);
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	return (0);
1265*7c478bd9Sstevel@tonic-gate }
1266*7c478bd9Sstevel@tonic-gate 
1267*7c478bd9Sstevel@tonic-gate /*
1268*7c478bd9Sstevel@tonic-gate  * Add a global or local attribute to a Multidata.  Global attribute
1269*7c478bd9Sstevel@tonic-gate  * association is specified by a NULL packet descriptor.
1270*7c478bd9Sstevel@tonic-gate  */
1271*7c478bd9Sstevel@tonic-gate pattr_t *
1272*7c478bd9Sstevel@tonic-gate mmd_addpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai,
1273*7c478bd9Sstevel@tonic-gate     boolean_t persistent, int kmflags)
1274*7c478bd9Sstevel@tonic-gate {
1275*7c478bd9Sstevel@tonic-gate 	patbkt_t **tbl_p;
1276*7c478bd9Sstevel@tonic-gate 	patbkt_t *tbl, *o_tbl;
1277*7c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
1278*7c478bd9Sstevel@tonic-gate 	pattr_t *pa;
1279*7c478bd9Sstevel@tonic-gate 	uint_t size;
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
1282*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1283*7c478bd9Sstevel@tonic-gate 	ASSERT(pd == NULL || pd->pd_magic == PDESC_MAGIC);
1284*7c478bd9Sstevel@tonic-gate 	ASSERT(pai != NULL);
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	/* pointer to the attribute hash table (local or global) */
1287*7c478bd9Sstevel@tonic-gate 	tbl_p = pd != NULL ? &(pd->pd_pattbl) : &(mmd->mmd_pattbl);
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	/*
1290*7c478bd9Sstevel@tonic-gate 	 * See if the hash table has not yet been created; if so,
1291*7c478bd9Sstevel@tonic-gate 	 * we create the table and store its address atomically.
1292*7c478bd9Sstevel@tonic-gate 	 */
1293*7c478bd9Sstevel@tonic-gate 	if ((tbl = *tbl_p) == NULL) {
1294*7c478bd9Sstevel@tonic-gate 		tbl = kmem_cache_alloc(pattbl_cache, kmflags);
1295*7c478bd9Sstevel@tonic-gate 		if (tbl == NULL)
1296*7c478bd9Sstevel@tonic-gate 			return (NULL);
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 		/* if someone got there first, use his table instead */
1299*7c478bd9Sstevel@tonic-gate 		if ((o_tbl = casptr(tbl_p, NULL, tbl)) != NULL) {
1300*7c478bd9Sstevel@tonic-gate 			kmem_cache_free(pattbl_cache, tbl);
1301*7c478bd9Sstevel@tonic-gate 			tbl = o_tbl;
1302*7c478bd9Sstevel@tonic-gate 		}
1303*7c478bd9Sstevel@tonic-gate 	}
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
1306*7c478bd9Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	/* attribute of the same type already exists? */
1309*7c478bd9Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL)
1310*7c478bd9Sstevel@tonic-gate 		return (NULL);
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	size = sizeof (*pa) + pai->len;
1313*7c478bd9Sstevel@tonic-gate 	if ((pa = kmem_zalloc(size, kmflags)) == NULL)
1314*7c478bd9Sstevel@tonic-gate 		return (NULL);
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 	pa->pat_magic = PATTR_MAGIC;
1317*7c478bd9Sstevel@tonic-gate 	pa->pat_lock = &(bkt->pbkt_lock);
1318*7c478bd9Sstevel@tonic-gate 	pa->pat_mmd = mmd;
1319*7c478bd9Sstevel@tonic-gate 	pa->pat_buflen = size;
1320*7c478bd9Sstevel@tonic-gate 	pa->pat_type = pai->type;
1321*7c478bd9Sstevel@tonic-gate 	pai->buf = pai->len > 0 ? ((uchar_t *)(pa + 1)) : NULL;
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate 	if (persistent)
1324*7c478bd9Sstevel@tonic-gate 		pa->pat_flags = PATTR_PERSIST;
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	/* insert attribute at end of hash chain */
1327*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
1328*7c478bd9Sstevel@tonic-gate 	insque(&(pa->pat_next), bkt->pbkt_pattr_q.ql_prev);
1329*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 	return (pa);
1332*7c478bd9Sstevel@tonic-gate }
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate /*
1335*7c478bd9Sstevel@tonic-gate  * Attribute hash table kmem cache constructor routine.
1336*7c478bd9Sstevel@tonic-gate  */
1337*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1338*7c478bd9Sstevel@tonic-gate static int
1339*7c478bd9Sstevel@tonic-gate pattbl_constructor(void *buf, void *cdrarg, int kmflags)
1340*7c478bd9Sstevel@tonic-gate {
1341*7c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
1342*7c478bd9Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
1343*7c478bd9Sstevel@tonic-gate 	uint_t i;
1344*7c478bd9Sstevel@tonic-gate 
1345*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
1348*7c478bd9Sstevel@tonic-gate 		mutex_init(&(bkt->pbkt_lock), NULL, MUTEX_DRIVER, NULL);
1349*7c478bd9Sstevel@tonic-gate 		QL_INIT(&(bkt->pbkt_pattr_q));
1350*7c478bd9Sstevel@tonic-gate 
1351*7c478bd9Sstevel@tonic-gate 		/* first bucket contains the table size */
1352*7c478bd9Sstevel@tonic-gate 		bkt->pbkt_tbl_sz = i == 0 ? tbl_sz : 0;
1353*7c478bd9Sstevel@tonic-gate 	}
1354*7c478bd9Sstevel@tonic-gate 	return (0);
1355*7c478bd9Sstevel@tonic-gate }
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate /*
1358*7c478bd9Sstevel@tonic-gate  * Attribute hash table kmem cache destructor routine.
1359*7c478bd9Sstevel@tonic-gate  */
1360*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1361*7c478bd9Sstevel@tonic-gate static void
1362*7c478bd9Sstevel@tonic-gate pattbl_destructor(void *buf, void *cdrarg)
1363*7c478bd9Sstevel@tonic-gate {
1364*7c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
1365*7c478bd9Sstevel@tonic-gate 	uint_t tbl_sz = (uint_t)(uintptr_t)cdrarg;
1366*7c478bd9Sstevel@tonic-gate 	uint_t i;
1367*7c478bd9Sstevel@tonic-gate 
1368*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);	/* table size can't be zero */
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	for (i = 0, bkt = (patbkt_t *)buf; i < tbl_sz; i++, bkt++) {
1371*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&(bkt->pbkt_lock));
1372*7c478bd9Sstevel@tonic-gate 		ASSERT(bkt->pbkt_pattr_q.ql_next == &(bkt->pbkt_pattr_q));
1373*7c478bd9Sstevel@tonic-gate 		ASSERT(i > 0 || bkt->pbkt_tbl_sz == tbl_sz);
1374*7c478bd9Sstevel@tonic-gate 	}
1375*7c478bd9Sstevel@tonic-gate }
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate /*
1378*7c478bd9Sstevel@tonic-gate  * Destroy an attribute hash table, called by mmd_rempdesc or during free.
1379*7c478bd9Sstevel@tonic-gate  */
1380*7c478bd9Sstevel@tonic-gate static void
1381*7c478bd9Sstevel@tonic-gate mmd_destroy_pattbl(patbkt_t **tbl)
1382*7c478bd9Sstevel@tonic-gate {
1383*7c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
1384*7c478bd9Sstevel@tonic-gate 	pattr_t *pa, *pa_next;
1385*7c478bd9Sstevel@tonic-gate 	uint_t i, tbl_sz;
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl != NULL);
1388*7c478bd9Sstevel@tonic-gate 	bkt = *tbl;
1389*7c478bd9Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
1392*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
1393*7c478bd9Sstevel@tonic-gate 
1394*7c478bd9Sstevel@tonic-gate 	/* destroy the contents of each bucket */
1395*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
1396*7c478bd9Sstevel@tonic-gate 		/* we ought to be exclusive at this point */
1397*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&(bkt->pbkt_lock)));
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
1400*7c478bd9Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
1401*7c478bd9Sstevel@tonic-gate 			ASSERT(pa->pat_magic == PATTR_MAGIC);
1402*7c478bd9Sstevel@tonic-gate 			pa_next = Q2PATTR(pa->pat_next);
1403*7c478bd9Sstevel@tonic-gate 			remque(&(pa->pat_next));
1404*7c478bd9Sstevel@tonic-gate 			kmem_free(pa, pa->pat_buflen);
1405*7c478bd9Sstevel@tonic-gate 			pa = pa_next;
1406*7c478bd9Sstevel@tonic-gate 		}
1407*7c478bd9Sstevel@tonic-gate 	}
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 	kmem_cache_free(pattbl_cache, *tbl);
1410*7c478bd9Sstevel@tonic-gate 	*tbl = NULL;
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate 	/* commit all previous stores */
1413*7c478bd9Sstevel@tonic-gate 	membar_producer();
1414*7c478bd9Sstevel@tonic-gate }
1415*7c478bd9Sstevel@tonic-gate 
1416*7c478bd9Sstevel@tonic-gate /*
1417*7c478bd9Sstevel@tonic-gate  * Copy the contents of an attribute hash table, called by mmd_copy.
1418*7c478bd9Sstevel@tonic-gate  */
1419*7c478bd9Sstevel@tonic-gate static int
1420*7c478bd9Sstevel@tonic-gate mmd_copy_pattbl(patbkt_t *src_tbl, multidata_t *n_mmd, pdesc_t *n_pd,
1421*7c478bd9Sstevel@tonic-gate     int kmflags)
1422*7c478bd9Sstevel@tonic-gate {
1423*7c478bd9Sstevel@tonic-gate 	patbkt_t *bkt;
1424*7c478bd9Sstevel@tonic-gate 	pattr_t *pa;
1425*7c478bd9Sstevel@tonic-gate 	pattrinfo_t pai;
1426*7c478bd9Sstevel@tonic-gate 	uint_t i, tbl_sz;
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate 	ASSERT(src_tbl != NULL);
1429*7c478bd9Sstevel@tonic-gate 	bkt = src_tbl;
1430*7c478bd9Sstevel@tonic-gate 	tbl_sz = bkt->pbkt_tbl_sz;
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate 	/* make sure caller passes in the first bucket */
1433*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl_sz > 0);
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < tbl_sz; i++, bkt++) {
1436*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(bkt->pbkt_lock));
1437*7c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
1438*7c478bd9Sstevel@tonic-gate 		while (pa != Q2PATTR(&(bkt->pbkt_pattr_q))) {
1439*7c478bd9Sstevel@tonic-gate 			pattr_t *pa_next = Q2PATTR(pa->pat_next);
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate 			/* skip if it's removed */
1442*7c478bd9Sstevel@tonic-gate 			if (pa->pat_flags & PATTR_REM_DEFER) {
1443*7c478bd9Sstevel@tonic-gate 				pa = pa_next;
1444*7c478bd9Sstevel@tonic-gate 				continue;
1445*7c478bd9Sstevel@tonic-gate 			}
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 			pai.type = pa->pat_type;
1448*7c478bd9Sstevel@tonic-gate 			pai.len = pa->pat_buflen - sizeof (*pa);
1449*7c478bd9Sstevel@tonic-gate 			if (mmd_addpattr(n_mmd, n_pd, &pai, (pa->pat_flags &
1450*7c478bd9Sstevel@tonic-gate 			    PATTR_PERSIST) != 0, kmflags) == NULL) {
1451*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(bkt->pbkt_lock));
1452*7c478bd9Sstevel@tonic-gate 				return (-1);
1453*7c478bd9Sstevel@tonic-gate 			}
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 			/* copy over the contents */
1456*7c478bd9Sstevel@tonic-gate 			if (pai.buf != NULL)
1457*7c478bd9Sstevel@tonic-gate 				bcopy(pa + 1, pai.buf, pai.len);
1458*7c478bd9Sstevel@tonic-gate 
1459*7c478bd9Sstevel@tonic-gate 			pa = pa_next;
1460*7c478bd9Sstevel@tonic-gate 		}
1461*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(bkt->pbkt_lock));
1462*7c478bd9Sstevel@tonic-gate 	}
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 	return (0);
1465*7c478bd9Sstevel@tonic-gate }
1466*7c478bd9Sstevel@tonic-gate 
1467*7c478bd9Sstevel@tonic-gate /*
1468*7c478bd9Sstevel@tonic-gate  * Search for an attribute type within an attribute hash bucket.
1469*7c478bd9Sstevel@tonic-gate  */
1470*7c478bd9Sstevel@tonic-gate static pattr_t *
1471*7c478bd9Sstevel@tonic-gate mmd_find_pattr(patbkt_t *bkt, uint_t type)
1472*7c478bd9Sstevel@tonic-gate {
1473*7c478bd9Sstevel@tonic-gate 	pattr_t *pa_head, *pa;
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(bkt->pbkt_lock));
1476*7c478bd9Sstevel@tonic-gate 	pa_head = Q2PATTR(&(bkt->pbkt_pattr_q));
1477*7c478bd9Sstevel@tonic-gate 	pa = Q2PATTR(bkt->pbkt_pattr_q.ql_next);
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 	while (pa != pa_head) {
1480*7c478bd9Sstevel@tonic-gate 		ASSERT(pa->pat_magic == PATTR_MAGIC);
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 		/* return a match; we treat removed entry as non-existent */
1483*7c478bd9Sstevel@tonic-gate 		if (pa->pat_type == type && !(pa->pat_flags & PATTR_REM_DEFER))
1484*7c478bd9Sstevel@tonic-gate 			break;
1485*7c478bd9Sstevel@tonic-gate 		pa = Q2PATTR(pa->pat_next);
1486*7c478bd9Sstevel@tonic-gate 	}
1487*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(bkt->pbkt_lock));
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 	return (pa == pa_head ? NULL : pa);
1490*7c478bd9Sstevel@tonic-gate }
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate /*
1493*7c478bd9Sstevel@tonic-gate  * Remove an attribute from a Multidata.
1494*7c478bd9Sstevel@tonic-gate  */
1495*7c478bd9Sstevel@tonic-gate void
1496*7c478bd9Sstevel@tonic-gate mmd_rempattr(pattr_t *pa)
1497*7c478bd9Sstevel@tonic-gate {
1498*7c478bd9Sstevel@tonic-gate 	kmutex_t *pat_lock = pa->pat_lock;
1499*7c478bd9Sstevel@tonic-gate 
1500*7c478bd9Sstevel@tonic-gate 	ASSERT(pa->pat_magic == PATTR_MAGIC);
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	/* ignore if attribute was marked as persistent */
1503*7c478bd9Sstevel@tonic-gate 	if ((pa->pat_flags & PATTR_PERSIST) != 0)
1504*7c478bd9Sstevel@tonic-gate 		return;
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	mutex_enter(pat_lock);
1507*7c478bd9Sstevel@tonic-gate 	/*
1508*7c478bd9Sstevel@tonic-gate 	 * We can't deallocate the associated resources if the Multidata
1509*7c478bd9Sstevel@tonic-gate 	 * is shared with other threads, because it's possible that the
1510*7c478bd9Sstevel@tonic-gate 	 * attribute handle value is held by those threads.  That's why
1511*7c478bd9Sstevel@tonic-gate 	 * we simply mark the entry as "removed".  If there are no other
1512*7c478bd9Sstevel@tonic-gate 	 * threads, then we free the attribute.
1513*7c478bd9Sstevel@tonic-gate 	 */
1514*7c478bd9Sstevel@tonic-gate 	if (pa->pat_mmd->mmd_dp->db_ref > 1) {
1515*7c478bd9Sstevel@tonic-gate 		pa->pat_flags |= PATTR_REM_DEFER;
1516*7c478bd9Sstevel@tonic-gate 	} else {
1517*7c478bd9Sstevel@tonic-gate 		remque(&(pa->pat_next));
1518*7c478bd9Sstevel@tonic-gate 		kmem_free(pa, pa->pat_buflen);
1519*7c478bd9Sstevel@tonic-gate 	}
1520*7c478bd9Sstevel@tonic-gate 	mutex_exit(pat_lock);
1521*7c478bd9Sstevel@tonic-gate }
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate /*
1524*7c478bd9Sstevel@tonic-gate  * Find an attribute (according to its type) and return its handle.
1525*7c478bd9Sstevel@tonic-gate  */
1526*7c478bd9Sstevel@tonic-gate pattr_t *
1527*7c478bd9Sstevel@tonic-gate mmd_getpattr(multidata_t *mmd, pdesc_t *pd, pattrinfo_t *pai)
1528*7c478bd9Sstevel@tonic-gate {
1529*7c478bd9Sstevel@tonic-gate 	patbkt_t *tbl, *bkt;
1530*7c478bd9Sstevel@tonic-gate 	pattr_t *pa;
1531*7c478bd9Sstevel@tonic-gate 
1532*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
1533*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1534*7c478bd9Sstevel@tonic-gate 	ASSERT(pai != NULL);
1535*7c478bd9Sstevel@tonic-gate 
1536*7c478bd9Sstevel@tonic-gate 	/* get the right attribute hash table (local or global) */
1537*7c478bd9Sstevel@tonic-gate 	tbl = pd != NULL ? pd->pd_pattbl : mmd->mmd_pattbl;
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 	/* attribute hash table doesn't exist? */
1540*7c478bd9Sstevel@tonic-gate 	if (tbl == NULL)
1541*7c478bd9Sstevel@tonic-gate 		return (NULL);
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	ASSERT(tbl->pbkt_tbl_sz > 0);
1544*7c478bd9Sstevel@tonic-gate 	bkt = &(tbl[PATTBL_HASH(pai->type, tbl->pbkt_tbl_sz)]);
1545*7c478bd9Sstevel@tonic-gate 
1546*7c478bd9Sstevel@tonic-gate 	if ((pa = mmd_find_pattr(bkt, pai->type)) != NULL) {
1547*7c478bd9Sstevel@tonic-gate 		ASSERT(pa->pat_buflen >= sizeof (*pa));
1548*7c478bd9Sstevel@tonic-gate 		pai->len = pa->pat_buflen - sizeof (*pa);
1549*7c478bd9Sstevel@tonic-gate 		pai->buf = pai->len > 0 ?
1550*7c478bd9Sstevel@tonic-gate 		    (uchar_t *)pa + sizeof (pattr_t) : NULL;
1551*7c478bd9Sstevel@tonic-gate 	}
1552*7c478bd9Sstevel@tonic-gate 	ASSERT(pa == NULL || pa->pat_magic == PATTR_MAGIC);
1553*7c478bd9Sstevel@tonic-gate 	return (pa);
1554*7c478bd9Sstevel@tonic-gate }
1555*7c478bd9Sstevel@tonic-gate 
1556*7c478bd9Sstevel@tonic-gate /*
1557*7c478bd9Sstevel@tonic-gate  * Return total size of buffers and total size of areas referenced
1558*7c478bd9Sstevel@tonic-gate  * by all in-use (unremoved) packet descriptors.
1559*7c478bd9Sstevel@tonic-gate  */
1560*7c478bd9Sstevel@tonic-gate void
1561*7c478bd9Sstevel@tonic-gate mmd_getsize(multidata_t *mmd, uint_t *ptotal, uint_t *pinuse)
1562*7c478bd9Sstevel@tonic-gate {
1563*7c478bd9Sstevel@tonic-gate 	pdesc_t *pd;
1564*7c478bd9Sstevel@tonic-gate 	pdescinfo_t *pdi;
1565*7c478bd9Sstevel@tonic-gate 	int i;
1566*7c478bd9Sstevel@tonic-gate 
1567*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd != NULL);
1568*7c478bd9Sstevel@tonic-gate 	ASSERT(mmd->mmd_magic == MULTIDATA_MAGIC);
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	mutex_enter(&mmd->mmd_pd_slab_lock);
1571*7c478bd9Sstevel@tonic-gate 	if (ptotal != NULL) {
1572*7c478bd9Sstevel@tonic-gate 		*ptotal = 0;
1573*7c478bd9Sstevel@tonic-gate 
1574*7c478bd9Sstevel@tonic-gate 		if (mmd->mmd_hbuf != NULL)
1575*7c478bd9Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_hbuf);
1576*7c478bd9Sstevel@tonic-gate 
1577*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < mmd->mmd_pbuf_cnt; i++) {
1578*7c478bd9Sstevel@tonic-gate 			ASSERT(mmd->mmd_pbuf[i] != NULL);
1579*7c478bd9Sstevel@tonic-gate 			*ptotal += MBLKL(mmd->mmd_pbuf[i]);
1580*7c478bd9Sstevel@tonic-gate 		}
1581*7c478bd9Sstevel@tonic-gate 	}
1582*7c478bd9Sstevel@tonic-gate 	if (pinuse != NULL) {
1583*7c478bd9Sstevel@tonic-gate 		*pinuse = 0;
1584*7c478bd9Sstevel@tonic-gate 
1585*7c478bd9Sstevel@tonic-gate 		/* first pdesc */
1586*7c478bd9Sstevel@tonic-gate 		pd = mmd_getpdesc(mmd, NULL, NULL, 1, B_TRUE);
1587*7c478bd9Sstevel@tonic-gate 		while (pd != NULL) {
1588*7c478bd9Sstevel@tonic-gate 			pdi = &pd->pd_pdi;
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 			/* next pdesc */
1591*7c478bd9Sstevel@tonic-gate 			pd = mmd_getpdesc(mmd, pd, NULL, 1, B_TRUE);
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 			/* skip over removed descriptor */
1594*7c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_REM_DEFER)
1595*7c478bd9Sstevel@tonic-gate 				continue;
1596*7c478bd9Sstevel@tonic-gate 
1597*7c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_HBUF_REF)
1598*7c478bd9Sstevel@tonic-gate 				*pinuse += PDESC_HDRL(pdi);
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 			if (pdi->flags & PDESC_PBUF_REF) {
1601*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < pdi->pld_cnt; i++)
1602*7c478bd9Sstevel@tonic-gate 					*pinuse += PDESC_PLDL(pdi, i);
1603*7c478bd9Sstevel@tonic-gate 			}
1604*7c478bd9Sstevel@tonic-gate 		}
1605*7c478bd9Sstevel@tonic-gate 	}
1606*7c478bd9Sstevel@tonic-gate 	mutex_exit(&mmd->mmd_pd_slab_lock);
1607*7c478bd9Sstevel@tonic-gate }
1608