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