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