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