1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/param.h> 31*0Sstevel@tonic-gate #include <sys/modctl.h> 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <sys/kmem.h> 34*0Sstevel@tonic-gate #include <sys/cmn_err.h> 35*0Sstevel@tonic-gate #include <sys/ddi.h> 36*0Sstevel@tonic-gate #include <sys/sunddi.h> 37*0Sstevel@tonic-gate #include <sys/spl.h> 38*0Sstevel@tonic-gate #include <sys/time.h> 39*0Sstevel@tonic-gate #include <sys/varargs.h> 40*0Sstevel@tonic-gate #include <ipp/ipp.h> 41*0Sstevel@tonic-gate #include <ipp/ipp_impl.h> 42*0Sstevel@tonic-gate #include <ipp/ipgpc/ipgpc.h> 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate /* 45*0Sstevel@tonic-gate * Debug switch. 46*0Sstevel@tonic-gate */ 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate #if defined(DEBUG) 49*0Sstevel@tonic-gate #define IPP_DBG 50*0Sstevel@tonic-gate #endif 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * Globals 54*0Sstevel@tonic-gate */ 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * ipp_action_count is not static because it is imported by inet/ipp_common.h 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate uint32_t ipp_action_count = 0; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate static kmem_cache_t *ipp_mod_cache = NULL; 62*0Sstevel@tonic-gate static uint32_t ipp_mod_count = 0; 63*0Sstevel@tonic-gate static uint32_t ipp_max_mod = IPP_NMOD; 64*0Sstevel@tonic-gate static ipp_mod_t **ipp_mod_byid; 65*0Sstevel@tonic-gate static krwlock_t ipp_mod_byid_lock[1]; 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate static ipp_mod_id_t ipp_next_mid = IPP_MOD_RESERVED + 1; 68*0Sstevel@tonic-gate static ipp_mod_id_t ipp_mid_limit; 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate static ipp_ref_t *ipp_mod_byname[IPP_NBUCKET]; 71*0Sstevel@tonic-gate static krwlock_t ipp_mod_byname_lock[1]; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static kmem_cache_t *ipp_action_cache = NULL; 74*0Sstevel@tonic-gate static uint32_t ipp_max_action = IPP_NACTION; 75*0Sstevel@tonic-gate static ipp_action_t **ipp_action_byid; 76*0Sstevel@tonic-gate static krwlock_t ipp_action_byid_lock[1]; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate static ipp_action_id_t ipp_next_aid = IPP_ACTION_RESERVED + 1; 79*0Sstevel@tonic-gate static ipp_action_id_t ipp_aid_limit; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate static ipp_ref_t *ipp_action_byname[IPP_NBUCKET]; 82*0Sstevel@tonic-gate static krwlock_t ipp_action_byname_lock[1]; 83*0Sstevel@tonic-gate static ipp_ref_t *ipp_action_noname; 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate static kmem_cache_t *ipp_packet_cache = NULL; 86*0Sstevel@tonic-gate static uint_t ipp_packet_classes = IPP_NCLASS; 87*0Sstevel@tonic-gate static uint_t ipp_packet_logging = 0; 88*0Sstevel@tonic-gate static uint_t ipp_packet_log_entries = IPP_NLOG; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* 91*0Sstevel@tonic-gate * Prototypes 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate void ipp_init(void); 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate int ipp_list_mods(ipp_mod_id_t **, int *); 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate ipp_mod_id_t ipp_mod_lookup(const char *); 99*0Sstevel@tonic-gate int ipp_mod_name(ipp_mod_id_t, char **); 100*0Sstevel@tonic-gate int ipp_mod_register(const char *, ipp_ops_t *); 101*0Sstevel@tonic-gate int ipp_mod_unregister(ipp_mod_id_t); 102*0Sstevel@tonic-gate int ipp_mod_list_actions(ipp_mod_id_t, ipp_action_id_t **, 103*0Sstevel@tonic-gate int *); 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate ipp_action_id_t ipp_action_lookup(const char *); 106*0Sstevel@tonic-gate int ipp_action_name(ipp_action_id_t, char **); 107*0Sstevel@tonic-gate int ipp_action_mod(ipp_action_id_t, ipp_mod_id_t *); 108*0Sstevel@tonic-gate int ipp_action_create(ipp_mod_id_t, const char *, 109*0Sstevel@tonic-gate nvlist_t **, ipp_flags_t, ipp_action_id_t *); 110*0Sstevel@tonic-gate int ipp_action_modify(ipp_action_id_t, nvlist_t **, 111*0Sstevel@tonic-gate ipp_flags_t); 112*0Sstevel@tonic-gate int ipp_action_destroy(ipp_action_id_t, ipp_flags_t); 113*0Sstevel@tonic-gate int ipp_action_info(ipp_action_id_t, int (*)(nvlist_t *, 114*0Sstevel@tonic-gate void *), void *, ipp_flags_t); 115*0Sstevel@tonic-gate void ipp_action_set_ptr(ipp_action_id_t, void *); 116*0Sstevel@tonic-gate void *ipp_action_get_ptr(ipp_action_id_t); 117*0Sstevel@tonic-gate int ipp_action_ref(ipp_action_id_t, ipp_action_id_t, 118*0Sstevel@tonic-gate ipp_flags_t); 119*0Sstevel@tonic-gate int ipp_action_unref(ipp_action_id_t, ipp_action_id_t, 120*0Sstevel@tonic-gate ipp_flags_t); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate int ipp_packet_alloc(ipp_packet_t **, const char *, 123*0Sstevel@tonic-gate ipp_action_id_t); 124*0Sstevel@tonic-gate void ipp_packet_free(ipp_packet_t *); 125*0Sstevel@tonic-gate int ipp_packet_add_class(ipp_packet_t *, const char *, 126*0Sstevel@tonic-gate ipp_action_id_t); 127*0Sstevel@tonic-gate int ipp_packet_process(ipp_packet_t **); 128*0Sstevel@tonic-gate int ipp_packet_next(ipp_packet_t *, ipp_action_id_t); 129*0Sstevel@tonic-gate void ipp_packet_set_data(ipp_packet_t *, mblk_t *); 130*0Sstevel@tonic-gate mblk_t *ipp_packet_get_data(ipp_packet_t *); 131*0Sstevel@tonic-gate void ipp_packet_set_private(ipp_packet_t *, void *, 132*0Sstevel@tonic-gate void (*)(void *)); 133*0Sstevel@tonic-gate void *ipp_packet_get_private(ipp_packet_t *); 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate int ipp_stat_create(ipp_action_id_t, const char *, int, 136*0Sstevel@tonic-gate int (*)(ipp_stat_t *, void *, int), void *, ipp_stat_t **); 137*0Sstevel@tonic-gate void ipp_stat_install(ipp_stat_t *); 138*0Sstevel@tonic-gate void ipp_stat_destroy(ipp_stat_t *); 139*0Sstevel@tonic-gate int ipp_stat_named_init(ipp_stat_t *, const char *, uchar_t, 140*0Sstevel@tonic-gate ipp_named_t *); 141*0Sstevel@tonic-gate int ipp_stat_named_op(ipp_named_t *, void *, int); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static int ref_mod(ipp_action_t *, ipp_mod_t *); 144*0Sstevel@tonic-gate static void unref_mod(ipp_action_t *, ipp_mod_t *); 145*0Sstevel@tonic-gate static int is_mod_busy(ipp_mod_t *); 146*0Sstevel@tonic-gate static int get_mod_ref(ipp_mod_t *, ipp_action_id_t **, int *); 147*0Sstevel@tonic-gate static int get_mods(ipp_mod_id_t **bufp, int *); 148*0Sstevel@tonic-gate static ipp_mod_id_t find_mod(const char *); 149*0Sstevel@tonic-gate static int alloc_mod(const char *, ipp_mod_id_t *); 150*0Sstevel@tonic-gate static void free_mod(ipp_mod_t *); 151*0Sstevel@tonic-gate static ipp_mod_t *hold_mod(ipp_mod_id_t); 152*0Sstevel@tonic-gate static void rele_mod(ipp_mod_t *); 153*0Sstevel@tonic-gate static ipp_mod_id_t get_mid(void); 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate static int condemn_action(ipp_ref_t **, ipp_action_t *); 156*0Sstevel@tonic-gate static int destroy_action(ipp_action_t *, ipp_flags_t); 157*0Sstevel@tonic-gate static int ref_action(ipp_action_t *, ipp_action_t *); 158*0Sstevel@tonic-gate static int unref_action(ipp_action_t *, ipp_action_t *); 159*0Sstevel@tonic-gate static int is_action_refd(ipp_action_t *); 160*0Sstevel@tonic-gate static ipp_action_id_t find_action(const char *); 161*0Sstevel@tonic-gate static int alloc_action(const char *, ipp_action_id_t *); 162*0Sstevel@tonic-gate static void free_action(ipp_action_t *); 163*0Sstevel@tonic-gate static ipp_action_t *hold_action(ipp_action_id_t); 164*0Sstevel@tonic-gate static void rele_action(ipp_action_t *); 165*0Sstevel@tonic-gate static ipp_action_id_t get_aid(void); 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate static int alloc_packet(const char *, ipp_action_id_t, 168*0Sstevel@tonic-gate ipp_packet_t **); 169*0Sstevel@tonic-gate static int realloc_packet(ipp_packet_t *); 170*0Sstevel@tonic-gate static void free_packet(ipp_packet_t *); 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate static int hash(const char *); 173*0Sstevel@tonic-gate static int update_stats(kstat_t *, int); 174*0Sstevel@tonic-gate static void init_mods(void); 175*0Sstevel@tonic-gate static void init_actions(void); 176*0Sstevel@tonic-gate static void init_packets(void); 177*0Sstevel@tonic-gate static int mod_constructor(void *, void *, int); 178*0Sstevel@tonic-gate static void mod_destructor(void *, void *); 179*0Sstevel@tonic-gate static int action_constructor(void *, void *, int); 180*0Sstevel@tonic-gate static void action_destructor(void *, void *); 181*0Sstevel@tonic-gate static int packet_constructor(void *, void *, int); 182*0Sstevel@tonic-gate static void packet_destructor(void *, void *); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * Debug message macros 186*0Sstevel@tonic-gate */ 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate #ifdef IPP_DBG 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate #define DBG_MOD 0x00000001ull 191*0Sstevel@tonic-gate #define DBG_ACTION 0x00000002ull 192*0Sstevel@tonic-gate #define DBG_PACKET 0x00000004ull 193*0Sstevel@tonic-gate #define DBG_STATS 0x00000008ull 194*0Sstevel@tonic-gate #define DBG_LIST 0x00000010ull 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate static uint64_t ipp_debug_flags = 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * DBG_PACKET | 199*0Sstevel@tonic-gate * DBG_STATS | 200*0Sstevel@tonic-gate * DBG_LIST | 201*0Sstevel@tonic-gate * DBG_MOD | 202*0Sstevel@tonic-gate * DBG_ACTION | 203*0Sstevel@tonic-gate */ 204*0Sstevel@tonic-gate 0; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate static kmutex_t debug_mutex[1]; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /*PRINTFLIKE3*/ 209*0Sstevel@tonic-gate static void ipp_debug(uint64_t, const char *, char *, ...) 210*0Sstevel@tonic-gate __KPRINTFLIKE(3); 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate #define DBG0(_type, _fmt) \ 213*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt)); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate #define DBG1(_type, _fmt, _a1) \ 216*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1)); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate #define DBG2(_type, _fmt, _a1, _a2) \ 219*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2)); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate #define DBG3(_type, _fmt, _a1, _a2, _a3) \ 222*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 223*0Sstevel@tonic-gate (_a3)); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \ 226*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 227*0Sstevel@tonic-gate (_a3), (_a4)); 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \ 230*0Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \ 231*0Sstevel@tonic-gate (_a3), (_a4), (_a5)); 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate #else /* IPP_DBG */ 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate #define DBG0(_type, _fmt) 236*0Sstevel@tonic-gate #define DBG1(_type, _fmt, _a1) 237*0Sstevel@tonic-gate #define DBG2(_type, _fmt, _a1, _a2) 238*0Sstevel@tonic-gate #define DBG3(_type, _fmt, _a1, _a2, _a3) 239*0Sstevel@tonic-gate #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) 240*0Sstevel@tonic-gate #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate #endif /* IPP_DBG */ 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate /* 245*0Sstevel@tonic-gate * Lock macros 246*0Sstevel@tonic-gate */ 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate #define LOCK_MOD(_imp, _rw) \ 249*0Sstevel@tonic-gate rw_enter((_imp)->ippm_lock, (_rw)) 250*0Sstevel@tonic-gate #define UNLOCK_MOD(_imp) \ 251*0Sstevel@tonic-gate rw_exit((_imp)->ippm_lock) 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate #define LOCK_ACTION(_ap, _rw) \ 254*0Sstevel@tonic-gate rw_enter((_ap)->ippa_lock, (_rw)) 255*0Sstevel@tonic-gate #define UNLOCK_ACTION(_imp) \ 256*0Sstevel@tonic-gate rw_exit((_imp)->ippa_lock) 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate #define CONFIG_WRITE_START(_ap) \ 259*0Sstevel@tonic-gate CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_WRITE) 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate #define CONFIG_WRITE_END(_ap) \ 262*0Sstevel@tonic-gate CONFIG_LOCK_EXIT((_ap)->ippa_config_lock) 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate #define CONFIG_READ_START(_ap) \ 265*0Sstevel@tonic-gate CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_READ) 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate #define CONFIG_READ_END(_ap) \ 268*0Sstevel@tonic-gate CONFIG_LOCK_EXIT((_ap)->ippa_config_lock) 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* 271*0Sstevel@tonic-gate * Exported functions 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate #define __FN__ "ipp_init" 275*0Sstevel@tonic-gate void 276*0Sstevel@tonic-gate ipp_init( 277*0Sstevel@tonic-gate void) 278*0Sstevel@tonic-gate { 279*0Sstevel@tonic-gate #ifdef IPP_DBG 280*0Sstevel@tonic-gate mutex_init(debug_mutex, NULL, MUTEX_ADAPTIVE, 281*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 282*0Sstevel@tonic-gate #endif /* IPP_DBG */ 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate /* 285*0Sstevel@tonic-gate * Initialize module and action structure caches and associated locks. 286*0Sstevel@tonic-gate */ 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate init_mods(); 289*0Sstevel@tonic-gate init_actions(); 290*0Sstevel@tonic-gate init_packets(); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate #undef __FN__ 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate #define __FN__ "ipp_list_mods" 295*0Sstevel@tonic-gate int 296*0Sstevel@tonic-gate ipp_list_mods( 297*0Sstevel@tonic-gate ipp_mod_id_t **bufp, 298*0Sstevel@tonic-gate int *neltp) 299*0Sstevel@tonic-gate { 300*0Sstevel@tonic-gate ASSERT(bufp != NULL); 301*0Sstevel@tonic-gate ASSERT(neltp != NULL); 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate return (get_mods(bufp, neltp)); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate #undef __FN__ 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate /* 308*0Sstevel@tonic-gate * Module manipulation interface. 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate #define __FN__ "ipp_mod_lookup" 312*0Sstevel@tonic-gate ipp_mod_id_t 313*0Sstevel@tonic-gate ipp_mod_lookup( 314*0Sstevel@tonic-gate const char *modname) 315*0Sstevel@tonic-gate { 316*0Sstevel@tonic-gate ipp_mod_id_t mid; 317*0Sstevel@tonic-gate #define FIRST_TIME 0 318*0Sstevel@tonic-gate int try = FIRST_TIME; 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate /* 321*0Sstevel@tonic-gate * Sanity check the module name. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate if (modname == NULL || strlen(modname) > MAXNAMELEN - 1) 325*0Sstevel@tonic-gate return (IPP_MOD_INVAL); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate try_again: 328*0Sstevel@tonic-gate if ((mid = find_mod(modname)) == IPP_MOD_INVAL) { 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * Module not installed. 332*0Sstevel@tonic-gate */ 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate if (try++ == FIRST_TIME) { 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate /* 337*0Sstevel@tonic-gate * This is the first attempt to find the module so 338*0Sstevel@tonic-gate * try to 'demand load' it. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate DBG1(DBG_MOD, "loading module '%s'\n", modname); 342*0Sstevel@tonic-gate (void) modload("ipp", (char *)modname); 343*0Sstevel@tonic-gate goto try_again; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate return (mid); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate #undef FIRST_TIME 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate #undef __FN__ 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate #define __FN__ "ipp_mod_name" 354*0Sstevel@tonic-gate int 355*0Sstevel@tonic-gate ipp_mod_name( 356*0Sstevel@tonic-gate ipp_mod_id_t mid, 357*0Sstevel@tonic-gate char **modnamep) 358*0Sstevel@tonic-gate { 359*0Sstevel@tonic-gate ipp_mod_t *imp; 360*0Sstevel@tonic-gate char *modname; 361*0Sstevel@tonic-gate char *buf; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate ASSERT(modnamep != NULL); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* 366*0Sstevel@tonic-gate * Translate the module id into the module pointer. 367*0Sstevel@tonic-gate */ 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL) 370*0Sstevel@tonic-gate return (ENOENT); 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 373*0Sstevel@tonic-gate modname = imp->ippm_name; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * Allocate a buffer to pass back to the caller. 377*0Sstevel@tonic-gate */ 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate if ((buf = kmem_zalloc(strlen(modname) + 1, KM_NOSLEEP)) == NULL) { 380*0Sstevel@tonic-gate UNLOCK_MOD(imp); 381*0Sstevel@tonic-gate rele_mod(imp); 382*0Sstevel@tonic-gate return (ENOMEM); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* 386*0Sstevel@tonic-gate * Copy the module name into the buffer. 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate (void) strcpy(buf, modname); 390*0Sstevel@tonic-gate UNLOCK_MOD(imp); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate *modnamep = buf; 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate rele_mod(imp); 395*0Sstevel@tonic-gate return (0); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate #undef __FN__ 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate #define __FN__ "ipp_mod_register" 400*0Sstevel@tonic-gate int 401*0Sstevel@tonic-gate ipp_mod_register( 402*0Sstevel@tonic-gate const char *modname, 403*0Sstevel@tonic-gate ipp_ops_t *ipp_ops) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate ipp_mod_id_t mid; 406*0Sstevel@tonic-gate ipp_mod_t *imp; 407*0Sstevel@tonic-gate int rc; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate ASSERT(ipp_ops != NULL); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * Sanity check the module name. 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate if (modname == NULL || strlen(modname) > MAXNAMELEN - 1) 416*0Sstevel@tonic-gate return (EINVAL); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate /* 419*0Sstevel@tonic-gate * Allocate a module structure. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if ((rc = alloc_mod(modname, &mid)) != 0) 423*0Sstevel@tonic-gate return (rc); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate imp = hold_mod(mid); 426*0Sstevel@tonic-gate ASSERT(imp != NULL); 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * Make module available for use. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 433*0Sstevel@tonic-gate DBG1(DBG_MOD, "registering module '%s'\n", imp->ippm_name); 434*0Sstevel@tonic-gate imp->ippm_ops = ipp_ops; 435*0Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_AVAILABLE; 436*0Sstevel@tonic-gate UNLOCK_MOD(imp); 437*0Sstevel@tonic-gate 438*0Sstevel@tonic-gate rele_mod(imp); 439*0Sstevel@tonic-gate return (0); 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate #undef __FN__ 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate #define __FN__ "ipp_mod_unregister" 444*0Sstevel@tonic-gate int 445*0Sstevel@tonic-gate ipp_mod_unregister( 446*0Sstevel@tonic-gate ipp_mod_id_t mid) 447*0Sstevel@tonic-gate { 448*0Sstevel@tonic-gate ipp_mod_t *imp; 449*0Sstevel@tonic-gate 450*0Sstevel@tonic-gate /* 451*0Sstevel@tonic-gate * Translate the module id into the module pointer. 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL) 455*0Sstevel@tonic-gate return (ENOENT); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 458*0Sstevel@tonic-gate ASSERT(imp->ippm_state == IPP_MODSTATE_AVAILABLE); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate /* 461*0Sstevel@tonic-gate * Check to see if there are any actions that reference the module. 462*0Sstevel@tonic-gate */ 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate if (is_mod_busy(imp)) { 465*0Sstevel@tonic-gate UNLOCK_MOD(imp); 466*0Sstevel@tonic-gate rele_mod(imp); 467*0Sstevel@tonic-gate return (EBUSY); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * Prevent further use of the module. 472*0Sstevel@tonic-gate */ 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate DBG1(DBG_MOD, "unregistering module '%s'\n", imp->ippm_name); 475*0Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_PROTO; 476*0Sstevel@tonic-gate imp->ippm_ops = NULL; 477*0Sstevel@tonic-gate UNLOCK_MOD(imp); 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * Free the module structure. 481*0Sstevel@tonic-gate */ 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate free_mod(imp); 484*0Sstevel@tonic-gate rele_mod(imp); 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate return (0); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate #undef __FN__ 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate #define __FN__ "ipp_mod_list_actions" 491*0Sstevel@tonic-gate int 492*0Sstevel@tonic-gate ipp_mod_list_actions( 493*0Sstevel@tonic-gate ipp_mod_id_t mid, 494*0Sstevel@tonic-gate ipp_action_id_t **bufp, 495*0Sstevel@tonic-gate int *neltp) 496*0Sstevel@tonic-gate { 497*0Sstevel@tonic-gate ipp_mod_t *imp; 498*0Sstevel@tonic-gate int rc; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate ASSERT(bufp != NULL); 501*0Sstevel@tonic-gate ASSERT(neltp != NULL); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * Translate the module id into the module pointer. 505*0Sstevel@tonic-gate */ 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL) 508*0Sstevel@tonic-gate return (ENOENT); 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate /* 511*0Sstevel@tonic-gate * Get the list of actions referencing the module. 512*0Sstevel@tonic-gate */ 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 515*0Sstevel@tonic-gate rc = get_mod_ref(imp, bufp, neltp); 516*0Sstevel@tonic-gate UNLOCK_MOD(imp); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate rele_mod(imp); 519*0Sstevel@tonic-gate return (rc); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate #undef __FN__ 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* 524*0Sstevel@tonic-gate * Action manipulation interface. 525*0Sstevel@tonic-gate */ 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate #define __FN__ "ipp_action_lookup" 528*0Sstevel@tonic-gate ipp_action_id_t 529*0Sstevel@tonic-gate ipp_action_lookup( 530*0Sstevel@tonic-gate const char *aname) 531*0Sstevel@tonic-gate { 532*0Sstevel@tonic-gate if (aname == NULL) 533*0Sstevel@tonic-gate return (IPP_ACTION_INVAL); 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* 536*0Sstevel@tonic-gate * Check for special case 'virtual action' names. 537*0Sstevel@tonic-gate */ 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate if (strcmp(aname, IPP_ANAME_CONT) == 0) 540*0Sstevel@tonic-gate return (IPP_ACTION_CONT); 541*0Sstevel@tonic-gate else if (strcmp(aname, IPP_ANAME_DEFER) == 0) 542*0Sstevel@tonic-gate return (IPP_ACTION_DEFER); 543*0Sstevel@tonic-gate else if (strcmp(aname, IPP_ANAME_DROP) == 0) 544*0Sstevel@tonic-gate return (IPP_ACTION_DROP); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate /* 547*0Sstevel@tonic-gate * Now check real actions. 548*0Sstevel@tonic-gate */ 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate return (find_action(aname)); 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate #undef __FN__ 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate #define __FN__ "ipp_action_name" 555*0Sstevel@tonic-gate int 556*0Sstevel@tonic-gate ipp_action_name( 557*0Sstevel@tonic-gate ipp_action_id_t aid, 558*0Sstevel@tonic-gate char **anamep) 559*0Sstevel@tonic-gate { 560*0Sstevel@tonic-gate ipp_action_t *ap; 561*0Sstevel@tonic-gate char *aname; 562*0Sstevel@tonic-gate char *buf; 563*0Sstevel@tonic-gate int rc; 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate ASSERT(anamep != NULL); 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * Check for special case 'virtual action' ids. 569*0Sstevel@tonic-gate */ 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate switch (aid) { 572*0Sstevel@tonic-gate case IPP_ACTION_CONT: 573*0Sstevel@tonic-gate ap = NULL; 574*0Sstevel@tonic-gate aname = IPP_ANAME_CONT; 575*0Sstevel@tonic-gate break; 576*0Sstevel@tonic-gate case IPP_ACTION_DEFER: 577*0Sstevel@tonic-gate ap = NULL; 578*0Sstevel@tonic-gate aname = IPP_ANAME_DEFER; 579*0Sstevel@tonic-gate break; 580*0Sstevel@tonic-gate case IPP_ACTION_DROP: 581*0Sstevel@tonic-gate ap = NULL; 582*0Sstevel@tonic-gate aname = IPP_ANAME_DROP; 583*0Sstevel@tonic-gate break; 584*0Sstevel@tonic-gate default: 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * Not a special case. Check for a real action. 588*0Sstevel@tonic-gate */ 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 591*0Sstevel@tonic-gate return (ENOENT); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 594*0Sstevel@tonic-gate aname = ap->ippa_name; 595*0Sstevel@tonic-gate break; 596*0Sstevel@tonic-gate } 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate /* 599*0Sstevel@tonic-gate * Allocate a buffer to pass back to the caller. 600*0Sstevel@tonic-gate */ 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate if ((buf = kmem_zalloc(strlen(aname) + 1, KM_NOSLEEP)) == NULL) { 603*0Sstevel@tonic-gate rc = ENOMEM; 604*0Sstevel@tonic-gate goto done; 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate /* 608*0Sstevel@tonic-gate * Copy the action name into the buffer. 609*0Sstevel@tonic-gate */ 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate (void) strcpy(buf, aname); 612*0Sstevel@tonic-gate *anamep = buf; 613*0Sstevel@tonic-gate rc = 0; 614*0Sstevel@tonic-gate done: 615*0Sstevel@tonic-gate /* 616*0Sstevel@tonic-gate * Unlock the action if necessary (i.e. it wasn't a virtual action). 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate if (ap != NULL) { 620*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 621*0Sstevel@tonic-gate rele_action(ap); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate return (rc); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate #undef __FN__ 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate #define __FN__ "ipp_action_mod" 629*0Sstevel@tonic-gate int 630*0Sstevel@tonic-gate ipp_action_mod( 631*0Sstevel@tonic-gate ipp_action_id_t aid, 632*0Sstevel@tonic-gate ipp_mod_id_t *midp) 633*0Sstevel@tonic-gate { 634*0Sstevel@tonic-gate ipp_action_t *ap; 635*0Sstevel@tonic-gate ipp_mod_t *imp; 636*0Sstevel@tonic-gate 637*0Sstevel@tonic-gate ASSERT(midp != NULL); 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* 640*0Sstevel@tonic-gate * Return an error for 'virtual action' ids. 641*0Sstevel@tonic-gate */ 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate switch (aid) { 644*0Sstevel@tonic-gate case IPP_ACTION_CONT: 645*0Sstevel@tonic-gate /*FALLTHRU*/ 646*0Sstevel@tonic-gate case IPP_ACTION_DEFER: 647*0Sstevel@tonic-gate /*FALLTHRU*/ 648*0Sstevel@tonic-gate case IPP_ACTION_DROP: 649*0Sstevel@tonic-gate return (EINVAL); 650*0Sstevel@tonic-gate default: 651*0Sstevel@tonic-gate break; 652*0Sstevel@tonic-gate } 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate /* 655*0Sstevel@tonic-gate * This is a real action. 656*0Sstevel@tonic-gate */ 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 659*0Sstevel@tonic-gate return (ENOENT); 660*0Sstevel@tonic-gate 661*0Sstevel@tonic-gate /* 662*0Sstevel@tonic-gate * Check that the action is not in prototype state. 663*0Sstevel@tonic-gate */ 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 666*0Sstevel@tonic-gate if (ap->ippa_state == IPP_ASTATE_PROTO) { 667*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 668*0Sstevel@tonic-gate rele_action(ap); 669*0Sstevel@tonic-gate return (ENOENT); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate imp = ap->ippa_mod; 673*0Sstevel@tonic-gate ASSERT(imp != NULL); 674*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate *midp = imp->ippm_id; 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate rele_action(ap); 679*0Sstevel@tonic-gate return (0); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate #undef __FN__ 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate #define __FN__ "ipp_action_create" 684*0Sstevel@tonic-gate int 685*0Sstevel@tonic-gate ipp_action_create( 686*0Sstevel@tonic-gate ipp_mod_id_t mid, 687*0Sstevel@tonic-gate const char *aname, 688*0Sstevel@tonic-gate nvlist_t **nvlpp, 689*0Sstevel@tonic-gate ipp_flags_t flags, 690*0Sstevel@tonic-gate ipp_action_id_t *aidp) 691*0Sstevel@tonic-gate { 692*0Sstevel@tonic-gate ipp_ops_t *ippo; 693*0Sstevel@tonic-gate ipp_mod_t *imp; 694*0Sstevel@tonic-gate ipp_action_id_t aid; 695*0Sstevel@tonic-gate ipp_action_t *ap; 696*0Sstevel@tonic-gate int rc; 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate ASSERT(nvlpp != NULL); 699*0Sstevel@tonic-gate ASSERT(*nvlpp != NULL); 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate /* 702*0Sstevel@tonic-gate * Sanity check the action name (NULL means the framework chooses the 703*0Sstevel@tonic-gate * name). 704*0Sstevel@tonic-gate */ 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate if (aname != NULL && strlen(aname) > MAXNAMELEN - 1) 707*0Sstevel@tonic-gate return (EINVAL); 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate /* 710*0Sstevel@tonic-gate * Translate the module id into the module pointer. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL) 714*0Sstevel@tonic-gate return (ENOENT); 715*0Sstevel@tonic-gate 716*0Sstevel@tonic-gate /* 717*0Sstevel@tonic-gate * Allocate an action. 718*0Sstevel@tonic-gate */ 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate if ((rc = alloc_action(aname, &aid)) != 0) { 721*0Sstevel@tonic-gate rele_mod(imp); 722*0Sstevel@tonic-gate return (rc); 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate 725*0Sstevel@tonic-gate ap = hold_action(aid); 726*0Sstevel@tonic-gate ASSERT(ap != NULL); 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate /* 729*0Sstevel@tonic-gate * Note that the action is in the process of creation/destruction. 730*0Sstevel@tonic-gate */ 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 733*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_CONFIG_PENDING; 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * Reference the module for which the action is being created. 737*0Sstevel@tonic-gate */ 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 740*0Sstevel@tonic-gate if ((rc = ref_mod(ap, imp)) != 0) { 741*0Sstevel@tonic-gate UNLOCK_MOD(imp); 742*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO; 743*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate free_action(ap); 746*0Sstevel@tonic-gate rele_action(ap); 747*0Sstevel@tonic-gate rele_mod(imp); 748*0Sstevel@tonic-gate return (rc); 749*0Sstevel@tonic-gate } 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate ippo = imp->ippm_ops; 754*0Sstevel@tonic-gate ASSERT(ippo != NULL); 755*0Sstevel@tonic-gate UNLOCK_MOD(imp); 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* 758*0Sstevel@tonic-gate * Call into the module to create the action context. 759*0Sstevel@tonic-gate */ 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate CONFIG_WRITE_START(ap); 762*0Sstevel@tonic-gate DBG2(DBG_ACTION, "creating action '%s' in module '%s'\n", 763*0Sstevel@tonic-gate ap->ippa_name, imp->ippm_name); 764*0Sstevel@tonic-gate if ((rc = ippo->ippo_action_create(ap->ippa_id, nvlpp, flags)) != 0) { 765*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 766*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 767*0Sstevel@tonic-gate unref_mod(ap, imp); 768*0Sstevel@tonic-gate UNLOCK_MOD(imp); 769*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO; 770*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate CONFIG_WRITE_END(ap); 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate free_action(ap); 775*0Sstevel@tonic-gate rele_action(ap); 776*0Sstevel@tonic-gate rele_mod(imp); 777*0Sstevel@tonic-gate return (rc); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate CONFIG_WRITE_END(ap); 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate /* 782*0Sstevel@tonic-gate * Make the action available for use. 783*0Sstevel@tonic-gate */ 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 786*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE; 787*0Sstevel@tonic-gate if (aidp != NULL) 788*0Sstevel@tonic-gate *aidp = ap->ippa_id; 789*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate rele_action(ap); 792*0Sstevel@tonic-gate rele_mod(imp); 793*0Sstevel@tonic-gate return (0); 794*0Sstevel@tonic-gate } 795*0Sstevel@tonic-gate #undef __FN__ 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate #define __FN__ "ipp_action_destroy" 798*0Sstevel@tonic-gate int 799*0Sstevel@tonic-gate ipp_action_destroy( 800*0Sstevel@tonic-gate ipp_action_id_t aid, 801*0Sstevel@tonic-gate ipp_flags_t flags) 802*0Sstevel@tonic-gate { 803*0Sstevel@tonic-gate ipp_ref_t *rp = NULL; 804*0Sstevel@tonic-gate ipp_ref_t *tmp; 805*0Sstevel@tonic-gate ipp_action_t *ap; 806*0Sstevel@tonic-gate int rc; 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate /* 809*0Sstevel@tonic-gate * Translate the action id into the action pointer. 810*0Sstevel@tonic-gate */ 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 813*0Sstevel@tonic-gate return (ENOENT); 814*0Sstevel@tonic-gate 815*0Sstevel@tonic-gate /* 816*0Sstevel@tonic-gate * Set the condemned action list pointer and destroy the action. 817*0Sstevel@tonic-gate */ 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate ap->ippa_condemned = &rp; 820*0Sstevel@tonic-gate if ((rc = destroy_action(ap, flags)) == 0) { 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate /* 823*0Sstevel@tonic-gate * Destroy any other actions condemned by the destruction of 824*0Sstevel@tonic-gate * the first action. 825*0Sstevel@tonic-gate */ 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) { 828*0Sstevel@tonic-gate ap = tmp->ippr_action; 829*0Sstevel@tonic-gate ap->ippa_condemned = &rp; 830*0Sstevel@tonic-gate (void) destroy_action(ap, flags); 831*0Sstevel@tonic-gate } 832*0Sstevel@tonic-gate } else { 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate /* 835*0Sstevel@tonic-gate * Unreference any condemned actions since the destruction of 836*0Sstevel@tonic-gate * the first action failed. 837*0Sstevel@tonic-gate */ 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) { 840*0Sstevel@tonic-gate ap = tmp->ippr_action; 841*0Sstevel@tonic-gate rele_action(ap); 842*0Sstevel@tonic-gate } 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate /* 846*0Sstevel@tonic-gate * Clean up the condemned list. 847*0Sstevel@tonic-gate */ 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate while (rp != NULL) { 850*0Sstevel@tonic-gate tmp = rp; 851*0Sstevel@tonic-gate rp = rp->ippr_nextp; 852*0Sstevel@tonic-gate kmem_free(tmp, sizeof (ipp_ref_t)); 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate return (rc); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate #undef __FN__ 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate #define __FN__ "ipp_action_modify" 860*0Sstevel@tonic-gate int 861*0Sstevel@tonic-gate ipp_action_modify( 862*0Sstevel@tonic-gate ipp_action_id_t aid, 863*0Sstevel@tonic-gate nvlist_t **nvlpp, 864*0Sstevel@tonic-gate ipp_flags_t flags) 865*0Sstevel@tonic-gate { 866*0Sstevel@tonic-gate ipp_action_t *ap; 867*0Sstevel@tonic-gate ipp_ops_t *ippo; 868*0Sstevel@tonic-gate ipp_mod_t *imp; 869*0Sstevel@tonic-gate int rc; 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate ASSERT(nvlpp != NULL); 872*0Sstevel@tonic-gate ASSERT(*nvlpp != NULL); 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate /* 875*0Sstevel@tonic-gate * Translate the action id into the action pointer. 876*0Sstevel@tonic-gate */ 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 879*0Sstevel@tonic-gate return (ENOENT); 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate /* 882*0Sstevel@tonic-gate * Check that the action is either available for use or is in the 883*0Sstevel@tonic-gate * process of creation/destruction. 884*0Sstevel@tonic-gate * 885*0Sstevel@tonic-gate * NOTE: It is up to the module to lock multiple configuration 886*0Sstevel@tonic-gate * operations against each other if necessary. 887*0Sstevel@tonic-gate */ 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 890*0Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE && 891*0Sstevel@tonic-gate ap->ippa_state != IPP_ASTATE_CONFIG_PENDING) { 892*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 893*0Sstevel@tonic-gate rele_action(ap); 894*0Sstevel@tonic-gate return (EPROTO); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate imp = ap->ippa_mod; 898*0Sstevel@tonic-gate ASSERT(imp != NULL); 899*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate ippo = imp->ippm_ops; 902*0Sstevel@tonic-gate ASSERT(ippo != NULL); 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate /* 905*0Sstevel@tonic-gate * Call into the module to modify the action context. 906*0Sstevel@tonic-gate */ 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate DBG1(DBG_ACTION, "modifying action '%s'\n", ap->ippa_name); 909*0Sstevel@tonic-gate CONFIG_WRITE_START(ap); 910*0Sstevel@tonic-gate rc = ippo->ippo_action_modify(aid, nvlpp, flags); 911*0Sstevel@tonic-gate CONFIG_WRITE_END(ap); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate rele_action(ap); 914*0Sstevel@tonic-gate return (rc); 915*0Sstevel@tonic-gate } 916*0Sstevel@tonic-gate #undef __FN__ 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate #define __FN__ "ipp_action_info" 919*0Sstevel@tonic-gate int 920*0Sstevel@tonic-gate ipp_action_info( 921*0Sstevel@tonic-gate ipp_action_id_t aid, 922*0Sstevel@tonic-gate int (*fn)(nvlist_t *, void *), 923*0Sstevel@tonic-gate void *arg, 924*0Sstevel@tonic-gate ipp_flags_t flags) 925*0Sstevel@tonic-gate { 926*0Sstevel@tonic-gate ipp_action_t *ap; 927*0Sstevel@tonic-gate ipp_mod_t *imp; 928*0Sstevel@tonic-gate ipp_ops_t *ippo; 929*0Sstevel@tonic-gate int rc; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate /* 932*0Sstevel@tonic-gate * Translate the action id into the action pointer. 933*0Sstevel@tonic-gate */ 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 936*0Sstevel@tonic-gate return (ENOENT); 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate /* 939*0Sstevel@tonic-gate * Check that the action is available for use. We don't want to 940*0Sstevel@tonic-gate * read back parameters while the action is in the process of 941*0Sstevel@tonic-gate * creation/destruction. 942*0Sstevel@tonic-gate */ 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 945*0Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) { 946*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 947*0Sstevel@tonic-gate rele_action(ap); 948*0Sstevel@tonic-gate return (EPROTO); 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate imp = ap->ippa_mod; 952*0Sstevel@tonic-gate ASSERT(imp != NULL); 953*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate ippo = imp->ippm_ops; 956*0Sstevel@tonic-gate ASSERT(ippo != NULL); 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate /* 959*0Sstevel@tonic-gate * Call into the module to get the action configuration information. 960*0Sstevel@tonic-gate */ 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate DBG1(DBG_ACTION, 963*0Sstevel@tonic-gate "getting configuration information from action '%s'\n", 964*0Sstevel@tonic-gate ap->ippa_name); 965*0Sstevel@tonic-gate CONFIG_READ_START(ap); 966*0Sstevel@tonic-gate if ((rc = ippo->ippo_action_info(aid, fn, arg, flags)) != 0) { 967*0Sstevel@tonic-gate CONFIG_READ_END(ap); 968*0Sstevel@tonic-gate rele_action(ap); 969*0Sstevel@tonic-gate return (rc); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate CONFIG_READ_END(ap); 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate rele_action(ap); 974*0Sstevel@tonic-gate return (0); 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate #undef __FN__ 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate #define __FN__ "ipp_action_set_ptr" 979*0Sstevel@tonic-gate void 980*0Sstevel@tonic-gate ipp_action_set_ptr( 981*0Sstevel@tonic-gate ipp_action_id_t aid, 982*0Sstevel@tonic-gate void *ptr) 983*0Sstevel@tonic-gate { 984*0Sstevel@tonic-gate ipp_action_t *ap; 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * Translate the action id into the action pointer. 988*0Sstevel@tonic-gate */ 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate ap = hold_action(aid); 991*0Sstevel@tonic-gate ASSERT(ap != NULL); 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate /* 994*0Sstevel@tonic-gate * Set the private data pointer. 995*0Sstevel@tonic-gate */ 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate ap->ippa_ptr = ptr; 998*0Sstevel@tonic-gate rele_action(ap); 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate #undef __FN__ 1001*0Sstevel@tonic-gate 1002*0Sstevel@tonic-gate #define __FN__ "ipp_action_get_ptr" 1003*0Sstevel@tonic-gate void * 1004*0Sstevel@tonic-gate ipp_action_get_ptr( 1005*0Sstevel@tonic-gate ipp_action_id_t aid) 1006*0Sstevel@tonic-gate { 1007*0Sstevel@tonic-gate ipp_action_t *ap; 1008*0Sstevel@tonic-gate void *ptr; 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Translate the action id into the action pointer. 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate ap = hold_action(aid); 1015*0Sstevel@tonic-gate ASSERT(ap != NULL); 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate /* 1018*0Sstevel@tonic-gate * Return the private data pointer. 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate ptr = ap->ippa_ptr; 1022*0Sstevel@tonic-gate rele_action(ap); 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate return (ptr); 1025*0Sstevel@tonic-gate } 1026*0Sstevel@tonic-gate #undef __FN__ 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate #define __FN__ "ipp_action_ref" 1029*0Sstevel@tonic-gate /*ARGSUSED*/ 1030*0Sstevel@tonic-gate int 1031*0Sstevel@tonic-gate ipp_action_ref( 1032*0Sstevel@tonic-gate ipp_action_id_t aid, 1033*0Sstevel@tonic-gate ipp_action_id_t ref_aid, 1034*0Sstevel@tonic-gate ipp_flags_t flags) 1035*0Sstevel@tonic-gate { 1036*0Sstevel@tonic-gate ipp_action_t *ap; 1037*0Sstevel@tonic-gate ipp_action_t *ref_ap; 1038*0Sstevel@tonic-gate int rc; 1039*0Sstevel@tonic-gate 1040*0Sstevel@tonic-gate /* 1041*0Sstevel@tonic-gate * Actions are not allowed to reference themselves. 1042*0Sstevel@tonic-gate */ 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate if (aid == ref_aid) 1045*0Sstevel@tonic-gate return (EINVAL); 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* 1048*0Sstevel@tonic-gate * Check for a special case 'virtual action' id. 1049*0Sstevel@tonic-gate */ 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate switch (ref_aid) { 1052*0Sstevel@tonic-gate case IPP_ACTION_CONT: 1053*0Sstevel@tonic-gate /*FALLTHRU*/ 1054*0Sstevel@tonic-gate case IPP_ACTION_DEFER: 1055*0Sstevel@tonic-gate /*FALLTHRU*/ 1056*0Sstevel@tonic-gate case IPP_ACTION_DROP: 1057*0Sstevel@tonic-gate return (0); 1058*0Sstevel@tonic-gate default: 1059*0Sstevel@tonic-gate break; 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate /* 1063*0Sstevel@tonic-gate * Translate the action ids into action pointers. 1064*0Sstevel@tonic-gate */ 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 1067*0Sstevel@tonic-gate return (ENOENT); 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate if ((ref_ap = hold_action(ref_aid)) == NULL) { 1070*0Sstevel@tonic-gate rele_action(ap); 1071*0Sstevel@tonic-gate return (ENOENT); 1072*0Sstevel@tonic-gate } 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 1075*0Sstevel@tonic-gate LOCK_ACTION(ref_ap, RW_WRITER); 1076*0Sstevel@tonic-gate 1077*0Sstevel@tonic-gate if (ref_ap->ippa_state != IPP_ASTATE_AVAILABLE) { 1078*0Sstevel@tonic-gate UNLOCK_ACTION(ref_ap); 1079*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate rele_action(ref_ap); 1082*0Sstevel@tonic-gate rele_action(ap); 1083*0Sstevel@tonic-gate return (EPROTO); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate /* 1087*0Sstevel@tonic-gate * Create references between the two actions. 1088*0Sstevel@tonic-gate */ 1089*0Sstevel@tonic-gate 1090*0Sstevel@tonic-gate rc = ref_action(ap, ref_ap); 1091*0Sstevel@tonic-gate UNLOCK_ACTION(ref_ap); 1092*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate rele_action(ref_ap); 1095*0Sstevel@tonic-gate rele_action(ap); 1096*0Sstevel@tonic-gate return (rc); 1097*0Sstevel@tonic-gate } 1098*0Sstevel@tonic-gate #undef __FN__ 1099*0Sstevel@tonic-gate 1100*0Sstevel@tonic-gate #define __FN__ "ipp_action_unref" 1101*0Sstevel@tonic-gate int 1102*0Sstevel@tonic-gate ipp_action_unref( 1103*0Sstevel@tonic-gate ipp_action_id_t aid, 1104*0Sstevel@tonic-gate ipp_action_id_t ref_aid, 1105*0Sstevel@tonic-gate ipp_flags_t flags) 1106*0Sstevel@tonic-gate { 1107*0Sstevel@tonic-gate ipp_action_t *ap; 1108*0Sstevel@tonic-gate ipp_action_t *ref_ap; 1109*0Sstevel@tonic-gate int ref_is_busy; 1110*0Sstevel@tonic-gate int rc; 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate if (aid == ref_aid) 1113*0Sstevel@tonic-gate return (EINVAL); 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate /* 1116*0Sstevel@tonic-gate * Check for a special case 'virtual action' id. 1117*0Sstevel@tonic-gate */ 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate switch (ref_aid) { 1120*0Sstevel@tonic-gate case IPP_ACTION_CONT: 1121*0Sstevel@tonic-gate /*FALLTHRU*/ 1122*0Sstevel@tonic-gate case IPP_ACTION_DEFER: 1123*0Sstevel@tonic-gate /*FALLTHRU*/ 1124*0Sstevel@tonic-gate case IPP_ACTION_DROP: 1125*0Sstevel@tonic-gate return (0); 1126*0Sstevel@tonic-gate default: 1127*0Sstevel@tonic-gate break; 1128*0Sstevel@tonic-gate } 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate /* 1131*0Sstevel@tonic-gate * Translate the action ids into action pointers. 1132*0Sstevel@tonic-gate */ 1133*0Sstevel@tonic-gate 1134*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 1135*0Sstevel@tonic-gate return (ENOENT); 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate if ((ref_ap = hold_action(ref_aid)) == NULL) { 1138*0Sstevel@tonic-gate rele_action(ap); 1139*0Sstevel@tonic-gate return (ENOENT); 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 1143*0Sstevel@tonic-gate LOCK_ACTION(ref_ap, RW_WRITER); 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Remove the reference between the actions. 1147*0Sstevel@tonic-gate */ 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate if ((rc = unref_action(ap, ref_ap)) != 0) { 1150*0Sstevel@tonic-gate UNLOCK_ACTION(ref_ap); 1151*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1152*0Sstevel@tonic-gate rele_action(ref_ap); 1153*0Sstevel@tonic-gate rele_action(ap); 1154*0Sstevel@tonic-gate return (rc); 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate ref_is_busy = is_action_refd(ref_ap); 1158*0Sstevel@tonic-gate 1159*0Sstevel@tonic-gate UNLOCK_ACTION(ref_ap); 1160*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate if (flags & IPP_DESTROY_REF) { 1163*0Sstevel@tonic-gate if (!ref_is_busy) { 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate /* 1166*0Sstevel@tonic-gate * Condemn the action so that it will be destroyed. 1167*0Sstevel@tonic-gate */ 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate (void) condemn_action(ap->ippa_condemned, ref_ap); 1170*0Sstevel@tonic-gate return (0); 1171*0Sstevel@tonic-gate } 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate rele_action(ref_ap); 1175*0Sstevel@tonic-gate rele_action(ap); 1176*0Sstevel@tonic-gate return (0); 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate #undef __FN__ 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* 1181*0Sstevel@tonic-gate * Packet manipulation interface. 1182*0Sstevel@tonic-gate */ 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate #define __FN__ "ipp_packet_alloc" 1185*0Sstevel@tonic-gate int 1186*0Sstevel@tonic-gate ipp_packet_alloc( 1187*0Sstevel@tonic-gate ipp_packet_t **ppp, 1188*0Sstevel@tonic-gate const char *name, 1189*0Sstevel@tonic-gate ipp_action_id_t aid) 1190*0Sstevel@tonic-gate { 1191*0Sstevel@tonic-gate ipp_packet_t *pp; 1192*0Sstevel@tonic-gate int rc; 1193*0Sstevel@tonic-gate 1194*0Sstevel@tonic-gate ASSERT(ppp != NULL); 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate /* 1197*0Sstevel@tonic-gate * A name is required. 1198*0Sstevel@tonic-gate */ 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate if (name == NULL || strlen(name) > MAXNAMELEN - 1) 1201*0Sstevel@tonic-gate return (EINVAL); 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate /* 1204*0Sstevel@tonic-gate * Allocate a packet structure from the cache. 1205*0Sstevel@tonic-gate */ 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate if ((rc = alloc_packet(name, aid, &pp)) != 0) 1208*0Sstevel@tonic-gate return (rc); 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gate if (ipp_packet_logging != 0 && pp->ippp_log == NULL) { 1211*0Sstevel@tonic-gate 1212*0Sstevel@tonic-gate /* 1213*0Sstevel@tonic-gate * Logging is turned on but there's no log buffer. We need 1214*0Sstevel@tonic-gate * to allocate one. 1215*0Sstevel@tonic-gate */ 1216*0Sstevel@tonic-gate if ((pp->ippp_log = kmem_alloc( 1217*0Sstevel@tonic-gate ipp_packet_log_entries * sizeof (ipp_log_t), 1218*0Sstevel@tonic-gate KM_NOSLEEP)) != NULL) { 1219*0Sstevel@tonic-gate pp->ippp_log_limit = ipp_packet_log_entries - 1; 1220*0Sstevel@tonic-gate pp->ippp_log_windex = 0; 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate } else if (ipp_packet_logging == 0 && pp->ippp_log != NULL) { 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate /* 1225*0Sstevel@tonic-gate * A log buffer is present but logging has been turned off. 1226*0Sstevel@tonic-gate * Free the buffer now, 1227*0Sstevel@tonic-gate */ 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate kmem_free(pp->ippp_log, 1230*0Sstevel@tonic-gate (pp->ippp_log_limit + 1) * sizeof (ipp_log_t)); 1231*0Sstevel@tonic-gate pp->ippp_log = NULL; 1232*0Sstevel@tonic-gate pp->ippp_log_limit = 0; 1233*0Sstevel@tonic-gate pp->ippp_log_windex = 0; 1234*0Sstevel@tonic-gate } 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate *ppp = pp; 1237*0Sstevel@tonic-gate return (0); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate #undef __FN__ 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate #define __FN__ "ipp_packet_free" 1242*0Sstevel@tonic-gate void 1243*0Sstevel@tonic-gate ipp_packet_free( 1244*0Sstevel@tonic-gate ipp_packet_t *pp) 1245*0Sstevel@tonic-gate { 1246*0Sstevel@tonic-gate 1247*0Sstevel@tonic-gate ASSERT(pp != NULL); 1248*0Sstevel@tonic-gate 1249*0Sstevel@tonic-gate /* 1250*0Sstevel@tonic-gate * If there is a private structure pointer set, call its free 1251*0Sstevel@tonic-gate * function. 1252*0Sstevel@tonic-gate */ 1253*0Sstevel@tonic-gate 1254*0Sstevel@tonic-gate if (pp->ippp_private) { 1255*0Sstevel@tonic-gate pp->ippp_private_free(pp->ippp_private); 1256*0Sstevel@tonic-gate pp->ippp_private = NULL; 1257*0Sstevel@tonic-gate pp->ippp_private_free = NULL; 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate 1260*0Sstevel@tonic-gate /* 1261*0Sstevel@tonic-gate * Free the packet structure back to the cache. 1262*0Sstevel@tonic-gate */ 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate free_packet(pp); 1265*0Sstevel@tonic-gate } 1266*0Sstevel@tonic-gate #undef __FN__ 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate #define __FN__ "ipp_packet_add_class" 1269*0Sstevel@tonic-gate int 1270*0Sstevel@tonic-gate ipp_packet_add_class( 1271*0Sstevel@tonic-gate ipp_packet_t *pp, 1272*0Sstevel@tonic-gate const char *name, 1273*0Sstevel@tonic-gate ipp_action_id_t aid) 1274*0Sstevel@tonic-gate { 1275*0Sstevel@tonic-gate ipp_class_t *cp; 1276*0Sstevel@tonic-gate int rc; 1277*0Sstevel@tonic-gate 1278*0Sstevel@tonic-gate ASSERT(pp != NULL); 1279*0Sstevel@tonic-gate 1280*0Sstevel@tonic-gate /* 1281*0Sstevel@tonic-gate * A name is required. 1282*0Sstevel@tonic-gate */ 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate if (name == NULL || strlen(name) > MAXNAMELEN - 1) 1285*0Sstevel@tonic-gate return (EINVAL); 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate /* 1288*0Sstevel@tonic-gate * Check if there is an available class structure. 1289*0Sstevel@tonic-gate */ 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate if (pp->ippp_class_windex == pp->ippp_class_limit) { 1292*0Sstevel@tonic-gate 1293*0Sstevel@tonic-gate /* 1294*0Sstevel@tonic-gate * No more structures. Re-allocate the array. 1295*0Sstevel@tonic-gate */ 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate if ((rc = realloc_packet(pp)) != 0) 1298*0Sstevel@tonic-gate return (rc); 1299*0Sstevel@tonic-gate } 1300*0Sstevel@tonic-gate ASSERT(pp->ippp_class_windex < pp->ippp_class_limit); 1301*0Sstevel@tonic-gate 1302*0Sstevel@tonic-gate /* 1303*0Sstevel@tonic-gate * Set up a new class structure. 1304*0Sstevel@tonic-gate */ 1305*0Sstevel@tonic-gate 1306*0Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_windex++]); 1307*0Sstevel@tonic-gate (void) strcpy(cp->ippc_name, name); 1308*0Sstevel@tonic-gate cp->ippc_aid = aid; 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate return (0); 1311*0Sstevel@tonic-gate } 1312*0Sstevel@tonic-gate #undef __FN__ 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate #define __FN__ "ipp_packet_process" 1315*0Sstevel@tonic-gate int 1316*0Sstevel@tonic-gate ipp_packet_process( 1317*0Sstevel@tonic-gate ipp_packet_t **ppp) 1318*0Sstevel@tonic-gate { 1319*0Sstevel@tonic-gate ipp_packet_t *pp; 1320*0Sstevel@tonic-gate ipp_action_id_t aid; 1321*0Sstevel@tonic-gate ipp_class_t *cp; 1322*0Sstevel@tonic-gate ipp_log_t *lp; 1323*0Sstevel@tonic-gate ipp_action_t *ap; 1324*0Sstevel@tonic-gate ipp_mod_t *imp; 1325*0Sstevel@tonic-gate ipp_ops_t *ippo; 1326*0Sstevel@tonic-gate int rc; 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate ASSERT(ppp != NULL); 1329*0Sstevel@tonic-gate pp = *ppp; 1330*0Sstevel@tonic-gate ASSERT(pp != NULL); 1331*0Sstevel@tonic-gate 1332*0Sstevel@tonic-gate /* 1333*0Sstevel@tonic-gate * Walk the class list. 1334*0Sstevel@tonic-gate */ 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate while (pp->ippp_class_rindex < pp->ippp_class_windex) { 1337*0Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_rindex]); 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate /* 1340*0Sstevel@tonic-gate * While there is a real action to invoke... 1341*0Sstevel@tonic-gate */ 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate aid = cp->ippc_aid; 1344*0Sstevel@tonic-gate while (aid != IPP_ACTION_CONT && 1345*0Sstevel@tonic-gate aid != IPP_ACTION_DEFER && 1346*0Sstevel@tonic-gate aid != IPP_ACTION_DROP) { 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate ASSERT(aid != IPP_ACTION_INVAL); 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate /* 1351*0Sstevel@tonic-gate * Translate the action id to the action pointer. 1352*0Sstevel@tonic-gate */ 1353*0Sstevel@tonic-gate 1354*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) { 1355*0Sstevel@tonic-gate DBG1(DBG_PACKET, 1356*0Sstevel@tonic-gate "action id '%d' not found\n", aid); 1357*0Sstevel@tonic-gate return (ENOENT); 1358*0Sstevel@tonic-gate } 1359*0Sstevel@tonic-gate 1360*0Sstevel@tonic-gate /* 1361*0Sstevel@tonic-gate * Check that the action is available for use... 1362*0Sstevel@tonic-gate */ 1363*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 1364*0Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) { 1365*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1366*0Sstevel@tonic-gate rele_action(ap); 1367*0Sstevel@tonic-gate return (EPROTO); 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate /* 1371*0Sstevel@tonic-gate * Increment the action's packet count to note that 1372*0Sstevel@tonic-gate * it's being used. 1373*0Sstevel@tonic-gate * 1374*0Sstevel@tonic-gate * NOTE: We only have a read lock, so we need to use 1375*0Sstevel@tonic-gate * atomic_add_32(). The read lock is still 1376*0Sstevel@tonic-gate * important though as it is crucial to block 1377*0Sstevel@tonic-gate * out a destroy operation between the action 1378*0Sstevel@tonic-gate * state being checked and the packet count 1379*0Sstevel@tonic-gate * being incremented. 1380*0Sstevel@tonic-gate */ 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate atomic_add_32(&(ap->ippa_packets), 1); 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gate imp = ap->ippa_mod; 1385*0Sstevel@tonic-gate ASSERT(imp != NULL); 1386*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate ippo = imp->ippm_ops; 1389*0Sstevel@tonic-gate ASSERT(ippo != NULL); 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate /* 1392*0Sstevel@tonic-gate * If there's a log, grab the next entry and fill it 1393*0Sstevel@tonic-gate * in. 1394*0Sstevel@tonic-gate */ 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate if (pp->ippp_log != NULL && 1397*0Sstevel@tonic-gate pp->ippp_log_windex <= pp->ippp_log_limit) { 1398*0Sstevel@tonic-gate lp = &(pp->ippp_log[pp->ippp_log_windex++]); 1399*0Sstevel@tonic-gate lp->ippl_aid = aid; 1400*0Sstevel@tonic-gate (void) strcpy(lp->ippl_name, cp->ippc_name); 1401*0Sstevel@tonic-gate gethrestime(&lp->ippl_begin); 1402*0Sstevel@tonic-gate } else { 1403*0Sstevel@tonic-gate lp = NULL; 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate /* 1407*0Sstevel@tonic-gate * Invoke the action. 1408*0Sstevel@tonic-gate */ 1409*0Sstevel@tonic-gate 1410*0Sstevel@tonic-gate rc = ippo->ippo_action_invoke(aid, pp); 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate /* 1413*0Sstevel@tonic-gate * Also log the time that the action finished 1414*0Sstevel@tonic-gate * processing. 1415*0Sstevel@tonic-gate */ 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate if (lp != NULL) 1418*0Sstevel@tonic-gate gethrestime(&lp->ippl_end); 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate /* 1421*0Sstevel@tonic-gate * Decrement the packet count. 1422*0Sstevel@tonic-gate */ 1423*0Sstevel@tonic-gate 1424*0Sstevel@tonic-gate atomic_add_32(&(ap->ippa_packets), -1); 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate /* 1427*0Sstevel@tonic-gate * If the class' action id is the same now as it was 1428*0Sstevel@tonic-gate * before then clearly no 'next action' has been set. 1429*0Sstevel@tonic-gate * This is a protocol error. 1430*0Sstevel@tonic-gate */ 1431*0Sstevel@tonic-gate 1432*0Sstevel@tonic-gate if (cp->ippc_aid == aid) { 1433*0Sstevel@tonic-gate DBG1(DBG_PACKET, 1434*0Sstevel@tonic-gate "action '%s' did not set next action\n", 1435*0Sstevel@tonic-gate ap->ippa_name); 1436*0Sstevel@tonic-gate rele_action(ap); 1437*0Sstevel@tonic-gate return (EPROTO); 1438*0Sstevel@tonic-gate } 1439*0Sstevel@tonic-gate 1440*0Sstevel@tonic-gate /* 1441*0Sstevel@tonic-gate * The action did not complete successfully. Terminate 1442*0Sstevel@tonic-gate * packet processing. 1443*0Sstevel@tonic-gate */ 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate if (rc != 0) { 1446*0Sstevel@tonic-gate DBG2(DBG_PACKET, 1447*0Sstevel@tonic-gate "action error '%d' from action '%s'\n", 1448*0Sstevel@tonic-gate rc, ap->ippa_name); 1449*0Sstevel@tonic-gate rele_action(ap); 1450*0Sstevel@tonic-gate return (rc); 1451*0Sstevel@tonic-gate } 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate rele_action(ap); 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate /* 1456*0Sstevel@tonic-gate * Look at the next action. 1457*0Sstevel@tonic-gate */ 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate aid = cp->ippc_aid; 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate /* 1463*0Sstevel@tonic-gate * No more real actions to invoke, check for 'virtual' ones. 1464*0Sstevel@tonic-gate */ 1465*0Sstevel@tonic-gate 1466*0Sstevel@tonic-gate /* 1467*0Sstevel@tonic-gate * Packet deferred: module has held onto packet for processing 1468*0Sstevel@tonic-gate * later. 1469*0Sstevel@tonic-gate */ 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate if (cp->ippc_aid == IPP_ACTION_DEFER) { 1472*0Sstevel@tonic-gate *ppp = NULL; 1473*0Sstevel@tonic-gate return (0); 1474*0Sstevel@tonic-gate } 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate /* 1477*0Sstevel@tonic-gate * Packet dropped: free the packet and discontinue processing. 1478*0Sstevel@tonic-gate */ 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate if (cp->ippc_aid == IPP_ACTION_DROP) { 1481*0Sstevel@tonic-gate freemsg(pp->ippp_data); 1482*0Sstevel@tonic-gate ipp_packet_free(pp); 1483*0Sstevel@tonic-gate *ppp = NULL; 1484*0Sstevel@tonic-gate return (0); 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate /* 1488*0Sstevel@tonic-gate * Must be 'continue processing': move onto the next class. 1489*0Sstevel@tonic-gate */ 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate ASSERT(cp->ippc_aid == IPP_ACTION_CONT); 1492*0Sstevel@tonic-gate pp->ippp_class_rindex++; 1493*0Sstevel@tonic-gate } 1494*0Sstevel@tonic-gate 1495*0Sstevel@tonic-gate return (0); 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate #undef __FN__ 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate #define __FN__ "ipp_packet_next" 1500*0Sstevel@tonic-gate int 1501*0Sstevel@tonic-gate ipp_packet_next( 1502*0Sstevel@tonic-gate ipp_packet_t *pp, 1503*0Sstevel@tonic-gate ipp_action_id_t aid) 1504*0Sstevel@tonic-gate { 1505*0Sstevel@tonic-gate ipp_action_t *ap; 1506*0Sstevel@tonic-gate ipp_class_t *cp; 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate ASSERT(pp != NULL); 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_rindex]); 1511*0Sstevel@tonic-gate ASSERT(cp != NULL); 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate /* 1514*0Sstevel@tonic-gate * Check for a special case 'virtual action' id. 1515*0Sstevel@tonic-gate */ 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate switch (aid) { 1518*0Sstevel@tonic-gate case IPP_ACTION_INVAL: 1519*0Sstevel@tonic-gate return (EINVAL); 1520*0Sstevel@tonic-gate case IPP_ACTION_DEFER: 1521*0Sstevel@tonic-gate /*FALLTHRU*/ 1522*0Sstevel@tonic-gate case IPP_ACTION_CONT: 1523*0Sstevel@tonic-gate /*FALLTHRU*/ 1524*0Sstevel@tonic-gate case IPP_ACTION_DROP: 1525*0Sstevel@tonic-gate break; 1526*0Sstevel@tonic-gate default: 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate /* 1529*0Sstevel@tonic-gate * Not a virtual action so try to translate the action id 1530*0Sstevel@tonic-gate * into the action pointer to confirm the actions existence. 1531*0Sstevel@tonic-gate */ 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) { 1534*0Sstevel@tonic-gate DBG0(DBG_PACKET, "invalid action\n"); 1535*0Sstevel@tonic-gate return (ENOENT); 1536*0Sstevel@tonic-gate } 1537*0Sstevel@tonic-gate rele_action(ap); 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate break; 1540*0Sstevel@tonic-gate } 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate /* 1543*0Sstevel@tonic-gate * Set the class' new action id. 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate cp->ippc_aid = aid; 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate return (0); 1549*0Sstevel@tonic-gate } 1550*0Sstevel@tonic-gate #undef __FN__ 1551*0Sstevel@tonic-gate 1552*0Sstevel@tonic-gate #define __FN__ "ipp_packet_set_data" 1553*0Sstevel@tonic-gate void 1554*0Sstevel@tonic-gate ipp_packet_set_data( 1555*0Sstevel@tonic-gate ipp_packet_t *pp, 1556*0Sstevel@tonic-gate mblk_t *data) 1557*0Sstevel@tonic-gate { 1558*0Sstevel@tonic-gate ASSERT(pp != NULL); 1559*0Sstevel@tonic-gate pp->ippp_data = data; 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate #undef __FN__ 1562*0Sstevel@tonic-gate 1563*0Sstevel@tonic-gate #define __FN__ "ipp_packet_get_data" 1564*0Sstevel@tonic-gate mblk_t * 1565*0Sstevel@tonic-gate ipp_packet_get_data( 1566*0Sstevel@tonic-gate ipp_packet_t *pp) 1567*0Sstevel@tonic-gate { 1568*0Sstevel@tonic-gate ASSERT(pp != NULL); 1569*0Sstevel@tonic-gate return (pp->ippp_data); 1570*0Sstevel@tonic-gate } 1571*0Sstevel@tonic-gate #undef __FN__ 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate #define __FN__ "ipp_packet_set_private" 1574*0Sstevel@tonic-gate void 1575*0Sstevel@tonic-gate ipp_packet_set_private( 1576*0Sstevel@tonic-gate ipp_packet_t *pp, 1577*0Sstevel@tonic-gate void *buf, 1578*0Sstevel@tonic-gate void (*free_func)(void *)) 1579*0Sstevel@tonic-gate { 1580*0Sstevel@tonic-gate ASSERT(pp != NULL); 1581*0Sstevel@tonic-gate ASSERT(free_func != NULL); 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate pp->ippp_private = buf; 1584*0Sstevel@tonic-gate pp->ippp_private_free = free_func; 1585*0Sstevel@tonic-gate } 1586*0Sstevel@tonic-gate #undef __FN__ 1587*0Sstevel@tonic-gate 1588*0Sstevel@tonic-gate #define __FN__ "ipp_packet_get_private" 1589*0Sstevel@tonic-gate void * 1590*0Sstevel@tonic-gate ipp_packet_get_private( 1591*0Sstevel@tonic-gate ipp_packet_t *pp) 1592*0Sstevel@tonic-gate { 1593*0Sstevel@tonic-gate ASSERT(pp != NULL); 1594*0Sstevel@tonic-gate return (pp->ippp_private); 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate #undef __FN__ 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate /* 1599*0Sstevel@tonic-gate * Statistics interface. 1600*0Sstevel@tonic-gate */ 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate #define __FN__ "ipp_stat_create" 1603*0Sstevel@tonic-gate int 1604*0Sstevel@tonic-gate ipp_stat_create( 1605*0Sstevel@tonic-gate ipp_action_id_t aid, 1606*0Sstevel@tonic-gate const char *name, 1607*0Sstevel@tonic-gate int nstat, 1608*0Sstevel@tonic-gate int (*update)(ipp_stat_t *, void *, int), 1609*0Sstevel@tonic-gate void *arg, 1610*0Sstevel@tonic-gate ipp_stat_t **spp) 1611*0Sstevel@tonic-gate { 1612*0Sstevel@tonic-gate ipp_action_t *ap; 1613*0Sstevel@tonic-gate ipp_mod_t *imp; 1614*0Sstevel@tonic-gate ipp_stat_impl_t *sip; 1615*0Sstevel@tonic-gate ipp_stat_t *sp; 1616*0Sstevel@tonic-gate kstat_t *ksp; 1617*0Sstevel@tonic-gate char *class; 1618*0Sstevel@tonic-gate char *modname; 1619*0Sstevel@tonic-gate int instance; 1620*0Sstevel@tonic-gate 1621*0Sstevel@tonic-gate ASSERT(spp != NULL); 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate /* 1624*0Sstevel@tonic-gate * Sanity check the arguments. 1625*0Sstevel@tonic-gate */ 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate if (name == NULL || nstat <= 0 || update == NULL) 1628*0Sstevel@tonic-gate return (EINVAL); 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gate /* 1631*0Sstevel@tonic-gate * Translate the action id into the action pointer. 1632*0Sstevel@tonic-gate */ 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) 1635*0Sstevel@tonic-gate return (ENOENT); 1636*0Sstevel@tonic-gate 1637*0Sstevel@tonic-gate /* 1638*0Sstevel@tonic-gate * Grab relevant action and module information. 1639*0Sstevel@tonic-gate */ 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 1642*0Sstevel@tonic-gate class = ap->ippa_name; 1643*0Sstevel@tonic-gate instance = (int)ap->ippa_id; 1644*0Sstevel@tonic-gate 1645*0Sstevel@tonic-gate imp = ap->ippa_mod; 1646*0Sstevel@tonic-gate ASSERT(imp != NULL); 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 1649*0Sstevel@tonic-gate modname = imp->ippm_name; 1650*0Sstevel@tonic-gate 1651*0Sstevel@tonic-gate /* 1652*0Sstevel@tonic-gate * Allocate a stats info structure. 1653*0Sstevel@tonic-gate */ 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate if ((sip = kmem_alloc(sizeof (ipp_stat_impl_t), KM_NOSLEEP)) == NULL) 1656*0Sstevel@tonic-gate return (ENOMEM); 1657*0Sstevel@tonic-gate 1658*0Sstevel@tonic-gate /* 1659*0Sstevel@tonic-gate * Create a set of kstats. 1660*0Sstevel@tonic-gate */ 1661*0Sstevel@tonic-gate 1662*0Sstevel@tonic-gate DBG2(DBG_STATS, "creating stat set '%s' for action '%s'\n", 1663*0Sstevel@tonic-gate name, class); 1664*0Sstevel@tonic-gate if ((ksp = kstat_create(modname, instance, (char *)name, class, 1665*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_WRITABLE)) == NULL) { 1666*0Sstevel@tonic-gate kmem_free(sip, sizeof (ipp_stat_impl_t)); 1667*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1668*0Sstevel@tonic-gate UNLOCK_MOD(imp); 1669*0Sstevel@tonic-gate return (EINVAL); /* Assume EINVAL was the cause */ 1670*0Sstevel@tonic-gate } 1671*0Sstevel@tonic-gate 1672*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 1673*0Sstevel@tonic-gate UNLOCK_MOD(imp); 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate DBG1(DBG_STATS, "ks_data = %p\n", ksp->ks_data); 1676*0Sstevel@tonic-gate 1677*0Sstevel@tonic-gate /* 1678*0Sstevel@tonic-gate * Set up the kstats structure with a private data pointer and an 1679*0Sstevel@tonic-gate * 'update' function. 1680*0Sstevel@tonic-gate */ 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate ksp->ks_update = update_stats; 1683*0Sstevel@tonic-gate ksp->ks_private = (void *)sip; 1684*0Sstevel@tonic-gate 1685*0Sstevel@tonic-gate /* 1686*0Sstevel@tonic-gate * Keep a reference to the kstats structure in our own stats info 1687*0Sstevel@tonic-gate * structure. 1688*0Sstevel@tonic-gate */ 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate sip->ippsi_ksp = ksp; 1691*0Sstevel@tonic-gate sip->ippsi_data = ksp->ks_data; 1692*0Sstevel@tonic-gate 1693*0Sstevel@tonic-gate /* 1694*0Sstevel@tonic-gate * Fill in the rest of the stats info structure. 1695*0Sstevel@tonic-gate */ 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate (void) strcpy(sip->ippsi_name, name); 1698*0Sstevel@tonic-gate sip->ippsi_arg = arg; 1699*0Sstevel@tonic-gate sip->ippsi_update = update; 1700*0Sstevel@tonic-gate sip->ippsi_limit = nstat; 1701*0Sstevel@tonic-gate sip->ippsi_count = 0; 1702*0Sstevel@tonic-gate mutex_init(sip->ippsi_lock, NULL, MUTEX_ADAPTIVE, 1703*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 1704*0Sstevel@tonic-gate 1705*0Sstevel@tonic-gate /* 1706*0Sstevel@tonic-gate * Case the stats info structure to a semi-opaque structure that 1707*0Sstevel@tonic-gate * we pass back to the caller. 1708*0Sstevel@tonic-gate */ 1709*0Sstevel@tonic-gate 1710*0Sstevel@tonic-gate sp = (ipp_stat_t *)sip; 1711*0Sstevel@tonic-gate ASSERT(sp->ipps_data == sip->ippsi_data); 1712*0Sstevel@tonic-gate *spp = sp; 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate rele_action(ap); 1715*0Sstevel@tonic-gate return (0); 1716*0Sstevel@tonic-gate } 1717*0Sstevel@tonic-gate #undef __FN__ 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gate #define __FN__ "ipp_stat_install" 1720*0Sstevel@tonic-gate void 1721*0Sstevel@tonic-gate ipp_stat_install( 1722*0Sstevel@tonic-gate ipp_stat_t *sp) 1723*0Sstevel@tonic-gate { 1724*0Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp; 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate ASSERT(sp != NULL); 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate /* 1729*0Sstevel@tonic-gate * Install the set of kstats referenced by the stats info structure. 1730*0Sstevel@tonic-gate */ 1731*0Sstevel@tonic-gate 1732*0Sstevel@tonic-gate DBG1(DBG_STATS, "installing stat set '%s'\n", sip->ippsi_name); 1733*0Sstevel@tonic-gate kstat_install(sip->ippsi_ksp); 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate #undef __FN__ 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate #define __FN__ "ipp_stat_destroy" 1738*0Sstevel@tonic-gate void 1739*0Sstevel@tonic-gate ipp_stat_destroy( 1740*0Sstevel@tonic-gate ipp_stat_t *sp) 1741*0Sstevel@tonic-gate { 1742*0Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp; 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate ASSERT(sp != NULL); 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate /* 1747*0Sstevel@tonic-gate * Destroy the set of kstats referenced by the stats info structure. 1748*0Sstevel@tonic-gate */ 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate DBG1(DBG_STATS, "destroying stat set '%s'\n", sip->ippsi_name); 1751*0Sstevel@tonic-gate kstat_delete(sip->ippsi_ksp); 1752*0Sstevel@tonic-gate 1753*0Sstevel@tonic-gate /* 1754*0Sstevel@tonic-gate * Destroy the stats info structure itself. 1755*0Sstevel@tonic-gate */ 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate mutex_destroy(sip->ippsi_lock); 1758*0Sstevel@tonic-gate kmem_free(sip, sizeof (ipp_stat_impl_t)); 1759*0Sstevel@tonic-gate } 1760*0Sstevel@tonic-gate #undef __FN__ 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate #define __FN__ "ipp_stat_named_init" 1763*0Sstevel@tonic-gate int 1764*0Sstevel@tonic-gate ipp_stat_named_init( 1765*0Sstevel@tonic-gate ipp_stat_t *sp, 1766*0Sstevel@tonic-gate const char *name, 1767*0Sstevel@tonic-gate uchar_t type, 1768*0Sstevel@tonic-gate ipp_named_t *np) 1769*0Sstevel@tonic-gate { 1770*0Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp; 1771*0Sstevel@tonic-gate uchar_t ktype; 1772*0Sstevel@tonic-gate 1773*0Sstevel@tonic-gate ASSERT(sp != NULL); 1774*0Sstevel@tonic-gate ASSERT(np != NULL); 1775*0Sstevel@tonic-gate 1776*0Sstevel@tonic-gate if (name == NULL) 1777*0Sstevel@tonic-gate return (EINVAL); 1778*0Sstevel@tonic-gate 1779*0Sstevel@tonic-gate if ((type & IPP_STAT_TAG) == 0) 1780*0Sstevel@tonic-gate return (EINVAL); 1781*0Sstevel@tonic-gate ktype = type & ~IPP_STAT_TAG; 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate /* 1784*0Sstevel@tonic-gate * Check we will not exceed the maximum number of a stats that was 1785*0Sstevel@tonic-gate * indicated during set creation. 1786*0Sstevel@tonic-gate */ 1787*0Sstevel@tonic-gate 1788*0Sstevel@tonic-gate mutex_enter(sip->ippsi_lock); 1789*0Sstevel@tonic-gate if (sip->ippsi_count >= sip->ippsi_limit) { 1790*0Sstevel@tonic-gate mutex_exit(sip->ippsi_lock); 1791*0Sstevel@tonic-gate return (ENOSPC); 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate /* 1795*0Sstevel@tonic-gate * Bump the count. 1796*0Sstevel@tonic-gate */ 1797*0Sstevel@tonic-gate 1798*0Sstevel@tonic-gate sip->ippsi_count++; 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate /* 1801*0Sstevel@tonic-gate * Create a new named kstat. 1802*0Sstevel@tonic-gate */ 1803*0Sstevel@tonic-gate 1804*0Sstevel@tonic-gate DBG3(DBG_STATS, "%s.%s: knp = %p\n", sip->ippsi_name, name, np); 1805*0Sstevel@tonic-gate kstat_named_init(np, (char *)name, ktype); 1806*0Sstevel@tonic-gate mutex_exit(sip->ippsi_lock); 1807*0Sstevel@tonic-gate 1808*0Sstevel@tonic-gate return (0); 1809*0Sstevel@tonic-gate } 1810*0Sstevel@tonic-gate #undef __FN__ 1811*0Sstevel@tonic-gate 1812*0Sstevel@tonic-gate #define __FN__ "ipp_stat_named_op" 1813*0Sstevel@tonic-gate int 1814*0Sstevel@tonic-gate ipp_stat_named_op( 1815*0Sstevel@tonic-gate ipp_named_t *np, 1816*0Sstevel@tonic-gate void *valp, 1817*0Sstevel@tonic-gate int rw) 1818*0Sstevel@tonic-gate { 1819*0Sstevel@tonic-gate kstat_named_t *knp; 1820*0Sstevel@tonic-gate uchar_t type; 1821*0Sstevel@tonic-gate int rc = 0; 1822*0Sstevel@tonic-gate 1823*0Sstevel@tonic-gate ASSERT(np != NULL); 1824*0Sstevel@tonic-gate ASSERT(valp != NULL); 1825*0Sstevel@tonic-gate 1826*0Sstevel@tonic-gate knp = np; 1827*0Sstevel@tonic-gate type = knp->data_type | IPP_STAT_TAG; 1828*0Sstevel@tonic-gate 1829*0Sstevel@tonic-gate /* 1830*0Sstevel@tonic-gate * Copy data to or from the named kstat, depending on the specified 1831*0Sstevel@tonic-gate * opcode. 1832*0Sstevel@tonic-gate */ 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate switch (rw) { 1835*0Sstevel@tonic-gate case IPP_STAT_WRITE: 1836*0Sstevel@tonic-gate switch (type) { 1837*0Sstevel@tonic-gate case IPP_STAT_INT32: 1838*0Sstevel@tonic-gate *(int32_t *)valp = knp->value.i32; 1839*0Sstevel@tonic-gate break; 1840*0Sstevel@tonic-gate case IPP_STAT_UINT32: 1841*0Sstevel@tonic-gate *(uint32_t *)valp = knp->value.ui32; 1842*0Sstevel@tonic-gate break; 1843*0Sstevel@tonic-gate case IPP_STAT_INT64: 1844*0Sstevel@tonic-gate *(int64_t *)valp = knp->value.i64; 1845*0Sstevel@tonic-gate break; 1846*0Sstevel@tonic-gate case IPP_STAT_UINT64: 1847*0Sstevel@tonic-gate *(uint64_t *)valp = knp->value.ui64; 1848*0Sstevel@tonic-gate break; 1849*0Sstevel@tonic-gate case IPP_STAT_STRING: 1850*0Sstevel@tonic-gate (void) strncpy(valp, knp->value.c, 16); 1851*0Sstevel@tonic-gate break; 1852*0Sstevel@tonic-gate default: 1853*0Sstevel@tonic-gate ASSERT(0); /* should not reach here */ 1854*0Sstevel@tonic-gate break; 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate break; 1858*0Sstevel@tonic-gate case IPP_STAT_READ: 1859*0Sstevel@tonic-gate switch (type) { 1860*0Sstevel@tonic-gate case IPP_STAT_INT32: 1861*0Sstevel@tonic-gate knp->value.i32 = *(int32_t *)valp; 1862*0Sstevel@tonic-gate break; 1863*0Sstevel@tonic-gate case IPP_STAT_UINT32: 1864*0Sstevel@tonic-gate knp->value.ui32 = *(uint32_t *)valp; 1865*0Sstevel@tonic-gate break; 1866*0Sstevel@tonic-gate case IPP_STAT_INT64: 1867*0Sstevel@tonic-gate knp->value.i64 = *(int64_t *)valp; 1868*0Sstevel@tonic-gate break; 1869*0Sstevel@tonic-gate case IPP_STAT_UINT64: 1870*0Sstevel@tonic-gate knp->value.ui64 = *(uint64_t *)valp; 1871*0Sstevel@tonic-gate break; 1872*0Sstevel@tonic-gate case IPP_STAT_STRING: 1873*0Sstevel@tonic-gate (void) strncpy(knp->value.c, valp, 16); 1874*0Sstevel@tonic-gate break; 1875*0Sstevel@tonic-gate default: 1876*0Sstevel@tonic-gate ASSERT(0); /* should not reach here */ 1877*0Sstevel@tonic-gate break; 1878*0Sstevel@tonic-gate } 1879*0Sstevel@tonic-gate 1880*0Sstevel@tonic-gate break; 1881*0Sstevel@tonic-gate default: 1882*0Sstevel@tonic-gate rc = EINVAL; 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate 1885*0Sstevel@tonic-gate return (rc); 1886*0Sstevel@tonic-gate } 1887*0Sstevel@tonic-gate #undef __FN__ 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gate /* 1890*0Sstevel@tonic-gate * Local functions (for local people. There's nothing for you here!) 1891*0Sstevel@tonic-gate */ 1892*0Sstevel@tonic-gate 1893*0Sstevel@tonic-gate #define __FN__ "ref_mod" 1894*0Sstevel@tonic-gate static int 1895*0Sstevel@tonic-gate ref_mod( 1896*0Sstevel@tonic-gate ipp_action_t *ap, 1897*0Sstevel@tonic-gate ipp_mod_t *imp) 1898*0Sstevel@tonic-gate { 1899*0Sstevel@tonic-gate ipp_ref_t **rpp; 1900*0Sstevel@tonic-gate ipp_ref_t *rp; 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate ASSERT(rw_write_held(ap->ippa_lock)); 1903*0Sstevel@tonic-gate ASSERT(rw_write_held(imp->ippm_lock)); 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate /* 1906*0Sstevel@tonic-gate * Add the new reference at the end of the module's list. 1907*0Sstevel@tonic-gate */ 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate rpp = &(imp->ippm_action); 1910*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 1911*0Sstevel@tonic-gate ASSERT(rp->ippr_action != ap); 1912*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 1913*0Sstevel@tonic-gate } 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gate /* 1916*0Sstevel@tonic-gate * Allocate a reference structure. 1917*0Sstevel@tonic-gate */ 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) 1920*0Sstevel@tonic-gate return (ENOMEM); 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate /* 1923*0Sstevel@tonic-gate * Set the reference to the action and link it onto the module's list. 1924*0Sstevel@tonic-gate */ 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate rp->ippr_action = ap; 1927*0Sstevel@tonic-gate *rpp = rp; 1928*0Sstevel@tonic-gate 1929*0Sstevel@tonic-gate /* 1930*0Sstevel@tonic-gate * Keep a 'back pointer' from the action structure to the module 1931*0Sstevel@tonic-gate * structure. 1932*0Sstevel@tonic-gate */ 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate ap->ippa_mod = imp; 1935*0Sstevel@tonic-gate 1936*0Sstevel@tonic-gate return (0); 1937*0Sstevel@tonic-gate } 1938*0Sstevel@tonic-gate #undef __FN__ 1939*0Sstevel@tonic-gate 1940*0Sstevel@tonic-gate #define __FN__ "unref_mod" 1941*0Sstevel@tonic-gate static void 1942*0Sstevel@tonic-gate unref_mod( 1943*0Sstevel@tonic-gate ipp_action_t *ap, 1944*0Sstevel@tonic-gate ipp_mod_t *imp) 1945*0Sstevel@tonic-gate { 1946*0Sstevel@tonic-gate ipp_ref_t **rpp; 1947*0Sstevel@tonic-gate ipp_ref_t *rp; 1948*0Sstevel@tonic-gate 1949*0Sstevel@tonic-gate ASSERT(rw_write_held(ap->ippa_lock)); 1950*0Sstevel@tonic-gate ASSERT(rw_write_held(imp->ippm_lock)); 1951*0Sstevel@tonic-gate 1952*0Sstevel@tonic-gate /* 1953*0Sstevel@tonic-gate * Scan the module's list for the reference to the action. 1954*0Sstevel@tonic-gate */ 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate rpp = &(imp->ippm_action); 1957*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 1958*0Sstevel@tonic-gate if (rp->ippr_action == ap) 1959*0Sstevel@tonic-gate break; 1960*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 1961*0Sstevel@tonic-gate } 1962*0Sstevel@tonic-gate ASSERT(rp != NULL); 1963*0Sstevel@tonic-gate 1964*0Sstevel@tonic-gate /* 1965*0Sstevel@tonic-gate * Unlink the reference structure and free it. 1966*0Sstevel@tonic-gate */ 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate *rpp = rp->ippr_nextp; 1969*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 1970*0Sstevel@tonic-gate 1971*0Sstevel@tonic-gate /* 1972*0Sstevel@tonic-gate * NULL the 'back pointer'. 1973*0Sstevel@tonic-gate */ 1974*0Sstevel@tonic-gate 1975*0Sstevel@tonic-gate ap->ippa_mod = NULL; 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate #undef __FN__ 1978*0Sstevel@tonic-gate 1979*0Sstevel@tonic-gate #define __FN__ "is_mod_busy" 1980*0Sstevel@tonic-gate static int 1981*0Sstevel@tonic-gate is_mod_busy( 1982*0Sstevel@tonic-gate ipp_mod_t *imp) 1983*0Sstevel@tonic-gate { 1984*0Sstevel@tonic-gate /* 1985*0Sstevel@tonic-gate * Return a value which is true (non-zero) iff the module refers 1986*0Sstevel@tonic-gate * to no actions. 1987*0Sstevel@tonic-gate */ 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate return (imp->ippm_action != NULL); 1990*0Sstevel@tonic-gate } 1991*0Sstevel@tonic-gate #undef __FN__ 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate #define __FN__ "get_mod_ref" 1994*0Sstevel@tonic-gate static int 1995*0Sstevel@tonic-gate get_mod_ref( 1996*0Sstevel@tonic-gate ipp_mod_t *imp, 1997*0Sstevel@tonic-gate ipp_action_id_t **bufp, 1998*0Sstevel@tonic-gate int *neltp) 1999*0Sstevel@tonic-gate { 2000*0Sstevel@tonic-gate ipp_ref_t *rp; 2001*0Sstevel@tonic-gate int nelt; 2002*0Sstevel@tonic-gate ipp_action_t *ap; 2003*0Sstevel@tonic-gate ipp_action_id_t *buf; 2004*0Sstevel@tonic-gate int length; 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate ASSERT(rw_lock_held(imp->ippm_lock)); 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate /* 2009*0Sstevel@tonic-gate * Count the number of actions referred to from the module structure. 2010*0Sstevel@tonic-gate */ 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate nelt = 0; 2013*0Sstevel@tonic-gate for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) { 2014*0Sstevel@tonic-gate nelt++; 2015*0Sstevel@tonic-gate } 2016*0Sstevel@tonic-gate DBG1(DBG_LIST, "%d actions found\n", nelt); 2017*0Sstevel@tonic-gate 2018*0Sstevel@tonic-gate /* 2019*0Sstevel@tonic-gate * If there are no actions referred to then there's nothing to do. 2020*0Sstevel@tonic-gate */ 2021*0Sstevel@tonic-gate 2022*0Sstevel@tonic-gate if (nelt == 0) { 2023*0Sstevel@tonic-gate *bufp = NULL; 2024*0Sstevel@tonic-gate *neltp = 0; 2025*0Sstevel@tonic-gate return (0); 2026*0Sstevel@tonic-gate } 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate /* 2029*0Sstevel@tonic-gate * Allocate a buffer to pass back to the caller. 2030*0Sstevel@tonic-gate */ 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate length = nelt * sizeof (ipp_action_id_t); 2033*0Sstevel@tonic-gate if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) 2034*0Sstevel@tonic-gate return (ENOMEM); 2035*0Sstevel@tonic-gate 2036*0Sstevel@tonic-gate /* 2037*0Sstevel@tonic-gate * Fill the buffer with an array of action ids. 2038*0Sstevel@tonic-gate */ 2039*0Sstevel@tonic-gate 2040*0Sstevel@tonic-gate *bufp = buf; 2041*0Sstevel@tonic-gate *neltp = nelt; 2042*0Sstevel@tonic-gate 2043*0Sstevel@tonic-gate for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) { 2044*0Sstevel@tonic-gate ap = rp->ippr_action; 2045*0Sstevel@tonic-gate *buf++ = ap->ippa_id; 2046*0Sstevel@tonic-gate } 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length); 2049*0Sstevel@tonic-gate return (0); 2050*0Sstevel@tonic-gate } 2051*0Sstevel@tonic-gate #undef __FN__ 2052*0Sstevel@tonic-gate 2053*0Sstevel@tonic-gate #define __FN__ "get_mods" 2054*0Sstevel@tonic-gate static int 2055*0Sstevel@tonic-gate get_mods( 2056*0Sstevel@tonic-gate ipp_mod_id_t **bufp, 2057*0Sstevel@tonic-gate int *neltp) 2058*0Sstevel@tonic-gate { 2059*0Sstevel@tonic-gate ipp_mod_id_t *buf; 2060*0Sstevel@tonic-gate int length; 2061*0Sstevel@tonic-gate ipp_mod_id_t mid; 2062*0Sstevel@tonic-gate ipp_mod_t *imp; 2063*0Sstevel@tonic-gate 2064*0Sstevel@tonic-gate 2065*0Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_READER); 2066*0Sstevel@tonic-gate 2067*0Sstevel@tonic-gate /* 2068*0Sstevel@tonic-gate * If there are no modules registered then there's nothing to do. 2069*0Sstevel@tonic-gate */ 2070*0Sstevel@tonic-gate 2071*0Sstevel@tonic-gate if (ipp_mod_count == 0) { 2072*0Sstevel@tonic-gate DBG0(DBG_LIST, "no modules registered\n"); 2073*0Sstevel@tonic-gate *bufp = NULL; 2074*0Sstevel@tonic-gate *neltp = 0; 2075*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2076*0Sstevel@tonic-gate return (0); 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate 2079*0Sstevel@tonic-gate /* 2080*0Sstevel@tonic-gate * Allocate a buffer to pass back to the caller. 2081*0Sstevel@tonic-gate */ 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate DBG1(DBG_LIST, "%d modules registered\n", ipp_mod_count); 2084*0Sstevel@tonic-gate length = ipp_mod_count * sizeof (ipp_mod_id_t); 2085*0Sstevel@tonic-gate if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) { 2086*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2087*0Sstevel@tonic-gate return (ENOMEM); 2088*0Sstevel@tonic-gate } 2089*0Sstevel@tonic-gate 2090*0Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_READER); 2091*0Sstevel@tonic-gate 2092*0Sstevel@tonic-gate /* 2093*0Sstevel@tonic-gate * Search the array of all modules. 2094*0Sstevel@tonic-gate */ 2095*0Sstevel@tonic-gate 2096*0Sstevel@tonic-gate *bufp = buf; 2097*0Sstevel@tonic-gate *neltp = ipp_mod_count; 2098*0Sstevel@tonic-gate 2099*0Sstevel@tonic-gate for (mid = IPP_MOD_RESERVED + 1; mid <= ipp_mid_limit; mid++) { 2100*0Sstevel@tonic-gate if ((imp = ipp_mod_byid[mid]) == NULL) 2101*0Sstevel@tonic-gate continue; 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gate /* 2104*0Sstevel@tonic-gate * If the module has 'destruct pending' set then it means it 2105*0Sstevel@tonic-gate * is either still in the cache (i.e not allocated) or in the 2106*0Sstevel@tonic-gate * process of being set up by alloc_mod(). 2107*0Sstevel@tonic-gate */ 2108*0Sstevel@tonic-gate 2109*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 2110*0Sstevel@tonic-gate ASSERT(imp->ippm_id == mid); 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate if (imp->ippm_destruct_pending) { 2113*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2114*0Sstevel@tonic-gate continue; 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2117*0Sstevel@tonic-gate 2118*0Sstevel@tonic-gate *buf++ = mid; 2119*0Sstevel@tonic-gate } 2120*0Sstevel@tonic-gate 2121*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 2122*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length); 2125*0Sstevel@tonic-gate return (0); 2126*0Sstevel@tonic-gate } 2127*0Sstevel@tonic-gate #undef __FN__ 2128*0Sstevel@tonic-gate 2129*0Sstevel@tonic-gate #define __FN__ "find_mod" 2130*0Sstevel@tonic-gate static ipp_mod_id_t 2131*0Sstevel@tonic-gate find_mod( 2132*0Sstevel@tonic-gate const char *modname) 2133*0Sstevel@tonic-gate { 2134*0Sstevel@tonic-gate ipp_mod_id_t mid; 2135*0Sstevel@tonic-gate ipp_mod_t *imp; 2136*0Sstevel@tonic-gate ipp_ref_t *rp; 2137*0Sstevel@tonic-gate int hb; 2138*0Sstevel@tonic-gate 2139*0Sstevel@tonic-gate ASSERT(modname != NULL); 2140*0Sstevel@tonic-gate 2141*0Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_READER); 2142*0Sstevel@tonic-gate 2143*0Sstevel@tonic-gate /* 2144*0Sstevel@tonic-gate * Quick return if no modules are registered. 2145*0Sstevel@tonic-gate */ 2146*0Sstevel@tonic-gate 2147*0Sstevel@tonic-gate if (ipp_mod_count == 0) { 2148*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2149*0Sstevel@tonic-gate return (IPP_MOD_INVAL); 2150*0Sstevel@tonic-gate } 2151*0Sstevel@tonic-gate 2152*0Sstevel@tonic-gate /* 2153*0Sstevel@tonic-gate * Find the hash bucket where the module structure should be. 2154*0Sstevel@tonic-gate */ 2155*0Sstevel@tonic-gate 2156*0Sstevel@tonic-gate hb = hash(modname); 2157*0Sstevel@tonic-gate rp = ipp_mod_byname[hb]; 2158*0Sstevel@tonic-gate 2159*0Sstevel@tonic-gate /* 2160*0Sstevel@tonic-gate * Scan the bucket for a match. 2161*0Sstevel@tonic-gate */ 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate while (rp != NULL) { 2164*0Sstevel@tonic-gate imp = rp->ippr_mod; 2165*0Sstevel@tonic-gate if (strcmp(imp->ippm_name, modname) == 0) 2166*0Sstevel@tonic-gate break; 2167*0Sstevel@tonic-gate rp = rp->ippr_nextp; 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate 2170*0Sstevel@tonic-gate if (rp == NULL) { 2171*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2172*0Sstevel@tonic-gate return (IPP_MOD_INVAL); 2173*0Sstevel@tonic-gate } 2174*0Sstevel@tonic-gate 2175*0Sstevel@tonic-gate if (imp->ippm_state == IPP_MODSTATE_PROTO) { 2176*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2177*0Sstevel@tonic-gate return (IPP_MOD_INVAL); 2178*0Sstevel@tonic-gate } 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate mid = imp->ippm_id; 2181*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate return (mid); 2184*0Sstevel@tonic-gate } 2185*0Sstevel@tonic-gate #undef __FN__ 2186*0Sstevel@tonic-gate 2187*0Sstevel@tonic-gate #define __FN__ "alloc_mod" 2188*0Sstevel@tonic-gate static int 2189*0Sstevel@tonic-gate alloc_mod( 2190*0Sstevel@tonic-gate const char *modname, 2191*0Sstevel@tonic-gate ipp_mod_id_t *midp) 2192*0Sstevel@tonic-gate { 2193*0Sstevel@tonic-gate ipp_mod_t *imp; 2194*0Sstevel@tonic-gate ipp_ref_t **rpp; 2195*0Sstevel@tonic-gate ipp_ref_t *rp; 2196*0Sstevel@tonic-gate int hb; 2197*0Sstevel@tonic-gate 2198*0Sstevel@tonic-gate ASSERT(modname != NULL); 2199*0Sstevel@tonic-gate ASSERT(midp != NULL); 2200*0Sstevel@tonic-gate 2201*0Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_WRITER); 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate /* 2204*0Sstevel@tonic-gate * Find the right hash bucket for a module of the given name. 2205*0Sstevel@tonic-gate */ 2206*0Sstevel@tonic-gate 2207*0Sstevel@tonic-gate hb = hash(modname); 2208*0Sstevel@tonic-gate rpp = &ipp_mod_byname[hb]; 2209*0Sstevel@tonic-gate 2210*0Sstevel@tonic-gate /* 2211*0Sstevel@tonic-gate * Scan the bucket making sure the module isn't already 2212*0Sstevel@tonic-gate * registered. 2213*0Sstevel@tonic-gate */ 2214*0Sstevel@tonic-gate 2215*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2216*0Sstevel@tonic-gate imp = rp->ippr_mod; 2217*0Sstevel@tonic-gate if (strcmp(imp->ippm_name, modname) == 0) { 2218*0Sstevel@tonic-gate DBG1(DBG_MOD, "module '%s' already exists\n", modname); 2219*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2220*0Sstevel@tonic-gate return (EEXIST); 2221*0Sstevel@tonic-gate } 2222*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2223*0Sstevel@tonic-gate } 2224*0Sstevel@tonic-gate 2225*0Sstevel@tonic-gate /* 2226*0Sstevel@tonic-gate * Allocate a new reference structure and a new module structure. 2227*0Sstevel@tonic-gate */ 2228*0Sstevel@tonic-gate 2229*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) { 2230*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2231*0Sstevel@tonic-gate return (ENOMEM); 2232*0Sstevel@tonic-gate } 2233*0Sstevel@tonic-gate 2234*0Sstevel@tonic-gate if ((imp = kmem_cache_alloc(ipp_mod_cache, KM_NOSLEEP)) == NULL) { 2235*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2236*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2237*0Sstevel@tonic-gate return (ENOMEM); 2238*0Sstevel@tonic-gate } 2239*0Sstevel@tonic-gate 2240*0Sstevel@tonic-gate /* 2241*0Sstevel@tonic-gate * Set up the name of the new structure. 2242*0Sstevel@tonic-gate */ 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gate (void) strcpy(imp->ippm_name, modname); 2245*0Sstevel@tonic-gate 2246*0Sstevel@tonic-gate /* 2247*0Sstevel@tonic-gate * Make sure the 'destruct pending' flag is clear. This indicates 2248*0Sstevel@tonic-gate * that the structure is no longer part of the cache. 2249*0Sstevel@tonic-gate */ 2250*0Sstevel@tonic-gate 2251*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 2252*0Sstevel@tonic-gate imp->ippm_destruct_pending = B_FALSE; 2253*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2254*0Sstevel@tonic-gate 2255*0Sstevel@tonic-gate /* 2256*0Sstevel@tonic-gate * Set the reference and link it into the hash bucket. 2257*0Sstevel@tonic-gate */ 2258*0Sstevel@tonic-gate 2259*0Sstevel@tonic-gate rp->ippr_mod = imp; 2260*0Sstevel@tonic-gate *rpp = rp; 2261*0Sstevel@tonic-gate 2262*0Sstevel@tonic-gate /* 2263*0Sstevel@tonic-gate * Increment the module count. 2264*0Sstevel@tonic-gate */ 2265*0Sstevel@tonic-gate 2266*0Sstevel@tonic-gate ipp_mod_count++; 2267*0Sstevel@tonic-gate 2268*0Sstevel@tonic-gate *midp = imp->ippm_id; 2269*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2270*0Sstevel@tonic-gate return (0); 2271*0Sstevel@tonic-gate } 2272*0Sstevel@tonic-gate #undef __FN__ 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate #define __FN__ "free_mod" 2275*0Sstevel@tonic-gate static void 2276*0Sstevel@tonic-gate free_mod( 2277*0Sstevel@tonic-gate ipp_mod_t *imp) 2278*0Sstevel@tonic-gate { 2279*0Sstevel@tonic-gate ipp_ref_t **rpp; 2280*0Sstevel@tonic-gate ipp_ref_t *rp; 2281*0Sstevel@tonic-gate int hb; 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_WRITER); 2284*0Sstevel@tonic-gate 2285*0Sstevel@tonic-gate /* 2286*0Sstevel@tonic-gate * Find the hash bucket where the module structure should be. 2287*0Sstevel@tonic-gate */ 2288*0Sstevel@tonic-gate 2289*0Sstevel@tonic-gate hb = hash(imp->ippm_name); 2290*0Sstevel@tonic-gate rpp = &ipp_mod_byname[hb]; 2291*0Sstevel@tonic-gate 2292*0Sstevel@tonic-gate /* 2293*0Sstevel@tonic-gate * Scan the bucket for a match. 2294*0Sstevel@tonic-gate */ 2295*0Sstevel@tonic-gate 2296*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2297*0Sstevel@tonic-gate if (rp->ippr_mod == imp) 2298*0Sstevel@tonic-gate break; 2299*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2300*0Sstevel@tonic-gate } 2301*0Sstevel@tonic-gate ASSERT(rp != NULL); 2302*0Sstevel@tonic-gate 2303*0Sstevel@tonic-gate /* 2304*0Sstevel@tonic-gate * Unlink the reference structure and free it. 2305*0Sstevel@tonic-gate */ 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate *rpp = rp->ippr_nextp; 2308*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2309*0Sstevel@tonic-gate 2310*0Sstevel@tonic-gate /* 2311*0Sstevel@tonic-gate * Decrement the module count. 2312*0Sstevel@tonic-gate */ 2313*0Sstevel@tonic-gate 2314*0Sstevel@tonic-gate ipp_mod_count--; 2315*0Sstevel@tonic-gate 2316*0Sstevel@tonic-gate /* 2317*0Sstevel@tonic-gate * Empty the name. 2318*0Sstevel@tonic-gate */ 2319*0Sstevel@tonic-gate 2320*0Sstevel@tonic-gate *imp->ippm_name = '\0'; 2321*0Sstevel@tonic-gate 2322*0Sstevel@tonic-gate /* 2323*0Sstevel@tonic-gate * If the hold count is zero then we can free the structure 2324*0Sstevel@tonic-gate * immediately, otherwise we defer to rele_mod(). 2325*0Sstevel@tonic-gate */ 2326*0Sstevel@tonic-gate 2327*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 2328*0Sstevel@tonic-gate imp->ippm_destruct_pending = B_TRUE; 2329*0Sstevel@tonic-gate if (imp->ippm_hold_count == 0) { 2330*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2331*0Sstevel@tonic-gate kmem_cache_free(ipp_mod_cache, imp); 2332*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2333*0Sstevel@tonic-gate return; 2334*0Sstevel@tonic-gate } 2335*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2336*0Sstevel@tonic-gate 2337*0Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock); 2338*0Sstevel@tonic-gate } 2339*0Sstevel@tonic-gate #undef __FN__ 2340*0Sstevel@tonic-gate 2341*0Sstevel@tonic-gate #define __FN__ "hold_mod" 2342*0Sstevel@tonic-gate static ipp_mod_t * 2343*0Sstevel@tonic-gate hold_mod( 2344*0Sstevel@tonic-gate ipp_mod_id_t mid) 2345*0Sstevel@tonic-gate { 2346*0Sstevel@tonic-gate ipp_mod_t *imp; 2347*0Sstevel@tonic-gate 2348*0Sstevel@tonic-gate if (mid < 0) 2349*0Sstevel@tonic-gate return (NULL); 2350*0Sstevel@tonic-gate 2351*0Sstevel@tonic-gate /* 2352*0Sstevel@tonic-gate * Use the module id as an index into the array of all module 2353*0Sstevel@tonic-gate * structures. 2354*0Sstevel@tonic-gate */ 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_READER); 2357*0Sstevel@tonic-gate if ((imp = ipp_mod_byid[mid]) == NULL) { 2358*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 2359*0Sstevel@tonic-gate return (NULL); 2360*0Sstevel@tonic-gate } 2361*0Sstevel@tonic-gate 2362*0Sstevel@tonic-gate ASSERT(imp->ippm_id == mid); 2363*0Sstevel@tonic-gate 2364*0Sstevel@tonic-gate /* 2365*0Sstevel@tonic-gate * If the modul has 'destruct pending' set then it means it is either 2366*0Sstevel@tonic-gate * still in the cache (i.e not allocated) or in the process of 2367*0Sstevel@tonic-gate * being set up by alloc_mod(). 2368*0Sstevel@tonic-gate */ 2369*0Sstevel@tonic-gate 2370*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 2371*0Sstevel@tonic-gate if (imp->ippm_destruct_pending) { 2372*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2373*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 2374*0Sstevel@tonic-gate return (NULL); 2375*0Sstevel@tonic-gate } 2376*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate /* 2379*0Sstevel@tonic-gate * Increment the hold count to prevent the structure from being 2380*0Sstevel@tonic-gate * freed. 2381*0Sstevel@tonic-gate */ 2382*0Sstevel@tonic-gate 2383*0Sstevel@tonic-gate atomic_add_32(&(imp->ippm_hold_count), 1); 2384*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 2385*0Sstevel@tonic-gate 2386*0Sstevel@tonic-gate return (imp); 2387*0Sstevel@tonic-gate } 2388*0Sstevel@tonic-gate #undef __FN__ 2389*0Sstevel@tonic-gate 2390*0Sstevel@tonic-gate #define __FN__ "rele_mod" 2391*0Sstevel@tonic-gate static void 2392*0Sstevel@tonic-gate rele_mod( 2393*0Sstevel@tonic-gate ipp_mod_t *imp) 2394*0Sstevel@tonic-gate { 2395*0Sstevel@tonic-gate /* 2396*0Sstevel@tonic-gate * This call means we're done with the pointer so we can drop the 2397*0Sstevel@tonic-gate * hold count. 2398*0Sstevel@tonic-gate */ 2399*0Sstevel@tonic-gate 2400*0Sstevel@tonic-gate ASSERT(imp->ippm_hold_count != 0); 2401*0Sstevel@tonic-gate atomic_add_32(&(imp->ippm_hold_count), -1); 2402*0Sstevel@tonic-gate 2403*0Sstevel@tonic-gate /* 2404*0Sstevel@tonic-gate * If the structure has 'destruct pending' set then we tried to free 2405*0Sstevel@tonic-gate * it but couldn't, so do it now. 2406*0Sstevel@tonic-gate */ 2407*0Sstevel@tonic-gate 2408*0Sstevel@tonic-gate LOCK_MOD(imp, RW_READER); 2409*0Sstevel@tonic-gate if (imp->ippm_destruct_pending && imp->ippm_hold_count == 0) { 2410*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2411*0Sstevel@tonic-gate kmem_cache_free(ipp_mod_cache, imp); 2412*0Sstevel@tonic-gate return; 2413*0Sstevel@tonic-gate } 2414*0Sstevel@tonic-gate 2415*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2416*0Sstevel@tonic-gate } 2417*0Sstevel@tonic-gate #undef __FN__ 2418*0Sstevel@tonic-gate 2419*0Sstevel@tonic-gate #define __FN__ "get_mid" 2420*0Sstevel@tonic-gate static ipp_mod_id_t 2421*0Sstevel@tonic-gate get_mid( 2422*0Sstevel@tonic-gate void) 2423*0Sstevel@tonic-gate { 2424*0Sstevel@tonic-gate int index; 2425*0Sstevel@tonic-gate int start; 2426*0Sstevel@tonic-gate int limit; 2427*0Sstevel@tonic-gate 2428*0Sstevel@tonic-gate ASSERT(rw_write_held(ipp_mod_byid_lock)); 2429*0Sstevel@tonic-gate 2430*0Sstevel@tonic-gate /* 2431*0Sstevel@tonic-gate * Start searching after the last module id we allocated. 2432*0Sstevel@tonic-gate */ 2433*0Sstevel@tonic-gate 2434*0Sstevel@tonic-gate start = (int)ipp_next_mid; 2435*0Sstevel@tonic-gate limit = (int)ipp_mid_limit; 2436*0Sstevel@tonic-gate 2437*0Sstevel@tonic-gate /* 2438*0Sstevel@tonic-gate * Look for a spare slot in the array. 2439*0Sstevel@tonic-gate */ 2440*0Sstevel@tonic-gate 2441*0Sstevel@tonic-gate index = start; 2442*0Sstevel@tonic-gate while (ipp_mod_byid[index] != NULL) { 2443*0Sstevel@tonic-gate index++; 2444*0Sstevel@tonic-gate if (index > limit) 2445*0Sstevel@tonic-gate index = IPP_MOD_RESERVED + 1; 2446*0Sstevel@tonic-gate if (index == start) 2447*0Sstevel@tonic-gate return (IPP_MOD_INVAL); 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate 2450*0Sstevel@tonic-gate /* 2451*0Sstevel@tonic-gate * Note that we've just allocated a new module id so that we can 2452*0Sstevel@tonic-gate * start our search there next time. 2453*0Sstevel@tonic-gate */ 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate index++; 2456*0Sstevel@tonic-gate if (index > limit) { 2457*0Sstevel@tonic-gate ipp_next_mid = IPP_MOD_RESERVED + 1; 2458*0Sstevel@tonic-gate } else 2459*0Sstevel@tonic-gate ipp_next_mid = (ipp_mod_id_t)index; 2460*0Sstevel@tonic-gate 2461*0Sstevel@tonic-gate return ((ipp_mod_id_t)(--index)); 2462*0Sstevel@tonic-gate } 2463*0Sstevel@tonic-gate #undef __FN__ 2464*0Sstevel@tonic-gate 2465*0Sstevel@tonic-gate #define __FN__ "condemn_action" 2466*0Sstevel@tonic-gate static int 2467*0Sstevel@tonic-gate condemn_action( 2468*0Sstevel@tonic-gate ipp_ref_t **rpp, 2469*0Sstevel@tonic-gate ipp_action_t *ap) 2470*0Sstevel@tonic-gate { 2471*0Sstevel@tonic-gate ipp_ref_t *rp; 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate DBG1(DBG_ACTION, "condemning action '%s'\n", ap->ippa_name); 2474*0Sstevel@tonic-gate 2475*0Sstevel@tonic-gate /* 2476*0Sstevel@tonic-gate * Check to see if the action is already condemned. 2477*0Sstevel@tonic-gate */ 2478*0Sstevel@tonic-gate 2479*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2480*0Sstevel@tonic-gate if (rp->ippr_action == ap) 2481*0Sstevel@tonic-gate break; 2482*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2483*0Sstevel@tonic-gate } 2484*0Sstevel@tonic-gate 2485*0Sstevel@tonic-gate /* 2486*0Sstevel@tonic-gate * Create a new entry for the action. 2487*0Sstevel@tonic-gate */ 2488*0Sstevel@tonic-gate 2489*0Sstevel@tonic-gate if (rp == NULL) { 2490*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) 2491*0Sstevel@tonic-gate return (ENOMEM); 2492*0Sstevel@tonic-gate 2493*0Sstevel@tonic-gate rp->ippr_action = ap; 2494*0Sstevel@tonic-gate *rpp = rp; 2495*0Sstevel@tonic-gate } 2496*0Sstevel@tonic-gate 2497*0Sstevel@tonic-gate return (0); 2498*0Sstevel@tonic-gate } 2499*0Sstevel@tonic-gate #undef __FN__ 2500*0Sstevel@tonic-gate 2501*0Sstevel@tonic-gate #define __FN__ "destroy_action" 2502*0Sstevel@tonic-gate static int 2503*0Sstevel@tonic-gate destroy_action( 2504*0Sstevel@tonic-gate ipp_action_t *ap, 2505*0Sstevel@tonic-gate ipp_flags_t flags) 2506*0Sstevel@tonic-gate { 2507*0Sstevel@tonic-gate ipp_ops_t *ippo; 2508*0Sstevel@tonic-gate ipp_mod_t *imp; 2509*0Sstevel@tonic-gate #define MAXWAIT 10 2510*0Sstevel@tonic-gate uint32_t wait; 2511*0Sstevel@tonic-gate int rc; 2512*0Sstevel@tonic-gate 2513*0Sstevel@tonic-gate /* 2514*0Sstevel@tonic-gate * Check that the action is available. 2515*0Sstevel@tonic-gate */ 2516*0Sstevel@tonic-gate 2517*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 2518*0Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) { 2519*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2520*0Sstevel@tonic-gate rele_action(ap); 2521*0Sstevel@tonic-gate return (EPROTO); 2522*0Sstevel@tonic-gate } 2523*0Sstevel@tonic-gate 2524*0Sstevel@tonic-gate /* 2525*0Sstevel@tonic-gate * Note that the action is in the process of creation/destruction. 2526*0Sstevel@tonic-gate */ 2527*0Sstevel@tonic-gate 2528*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_CONFIG_PENDING; 2529*0Sstevel@tonic-gate 2530*0Sstevel@tonic-gate /* 2531*0Sstevel@tonic-gate * Wait for the in-transit packet count for this action to fall to 2532*0Sstevel@tonic-gate * zero (checking at millisecond intervals). 2533*0Sstevel@tonic-gate * 2534*0Sstevel@tonic-gate * NOTE: no new packets will enter the action now that the 2535*0Sstevel@tonic-gate * state has been changed. 2536*0Sstevel@tonic-gate */ 2537*0Sstevel@tonic-gate 2538*0Sstevel@tonic-gate for (wait = 0; ap->ippa_packets > 0 && wait < (MAXWAIT * 1000000); 2539*0Sstevel@tonic-gate wait += 1000) { 2540*0Sstevel@tonic-gate 2541*0Sstevel@tonic-gate /* 2542*0Sstevel@tonic-gate * NOTE: We can hang onto the lock because the packet count is 2543*0Sstevel@tonic-gate * decremented without needing to take the lock. 2544*0Sstevel@tonic-gate */ 2545*0Sstevel@tonic-gate 2546*0Sstevel@tonic-gate drv_usecwait(1000); 2547*0Sstevel@tonic-gate } 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate /* 2550*0Sstevel@tonic-gate * The packet count did not fall to zero. 2551*0Sstevel@tonic-gate */ 2552*0Sstevel@tonic-gate if (ap->ippa_packets > 0) { 2553*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE; 2554*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2555*0Sstevel@tonic-gate rele_action(ap); 2556*0Sstevel@tonic-gate return (EAGAIN); 2557*0Sstevel@tonic-gate } 2558*0Sstevel@tonic-gate 2559*0Sstevel@tonic-gate /* 2560*0Sstevel@tonic-gate * Check to see if any other action has a dependency on this one. 2561*0Sstevel@tonic-gate */ 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate if (is_action_refd(ap)) { 2564*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE; 2565*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2566*0Sstevel@tonic-gate rele_action(ap); 2567*0Sstevel@tonic-gate return (EBUSY); 2568*0Sstevel@tonic-gate } 2569*0Sstevel@tonic-gate 2570*0Sstevel@tonic-gate imp = ap->ippa_mod; 2571*0Sstevel@tonic-gate ASSERT(imp != NULL); 2572*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2573*0Sstevel@tonic-gate 2574*0Sstevel@tonic-gate ippo = imp->ippm_ops; 2575*0Sstevel@tonic-gate ASSERT(ippo != NULL); 2576*0Sstevel@tonic-gate 2577*0Sstevel@tonic-gate /* 2578*0Sstevel@tonic-gate * Call into the module to destroy the action context. 2579*0Sstevel@tonic-gate */ 2580*0Sstevel@tonic-gate 2581*0Sstevel@tonic-gate CONFIG_WRITE_START(ap); 2582*0Sstevel@tonic-gate DBG1(DBG_ACTION, "destroying action '%s'\n", ap->ippa_name); 2583*0Sstevel@tonic-gate if ((rc = ippo->ippo_action_destroy(ap->ippa_id, flags)) != 0) { 2584*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 2585*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE; 2586*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2587*0Sstevel@tonic-gate 2588*0Sstevel@tonic-gate CONFIG_WRITE_END(ap); 2589*0Sstevel@tonic-gate 2590*0Sstevel@tonic-gate rele_action(ap); 2591*0Sstevel@tonic-gate return (rc); 2592*0Sstevel@tonic-gate } 2593*0Sstevel@tonic-gate CONFIG_WRITE_END(ap); 2594*0Sstevel@tonic-gate 2595*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 2596*0Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER); 2597*0Sstevel@tonic-gate unref_mod(ap, imp); 2598*0Sstevel@tonic-gate UNLOCK_MOD(imp); 2599*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO; 2600*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2601*0Sstevel@tonic-gate 2602*0Sstevel@tonic-gate /* 2603*0Sstevel@tonic-gate * Free the action structure. 2604*0Sstevel@tonic-gate */ 2605*0Sstevel@tonic-gate 2606*0Sstevel@tonic-gate ASSERT(ap->ippa_ref == NULL); 2607*0Sstevel@tonic-gate free_action(ap); 2608*0Sstevel@tonic-gate rele_action(ap); 2609*0Sstevel@tonic-gate return (0); 2610*0Sstevel@tonic-gate #undef MAXWAIT 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate #undef __FN__ 2613*0Sstevel@tonic-gate 2614*0Sstevel@tonic-gate #define __FN__ "ref_action" 2615*0Sstevel@tonic-gate static int 2616*0Sstevel@tonic-gate ref_action( 2617*0Sstevel@tonic-gate ipp_action_t *refby_ap, 2618*0Sstevel@tonic-gate ipp_action_t *ref_ap) 2619*0Sstevel@tonic-gate { 2620*0Sstevel@tonic-gate ipp_ref_t **rpp; 2621*0Sstevel@tonic-gate ipp_ref_t **save_rpp; 2622*0Sstevel@tonic-gate ipp_ref_t *rp; 2623*0Sstevel@tonic-gate 2624*0Sstevel@tonic-gate ASSERT(rw_write_held(refby_ap->ippa_lock)); 2625*0Sstevel@tonic-gate ASSERT(rw_write_held(ref_ap->ippa_lock)); 2626*0Sstevel@tonic-gate 2627*0Sstevel@tonic-gate /* 2628*0Sstevel@tonic-gate * We want to add the new reference at the end of the refering 2629*0Sstevel@tonic-gate * action's list. 2630*0Sstevel@tonic-gate */ 2631*0Sstevel@tonic-gate 2632*0Sstevel@tonic-gate rpp = &(refby_ap->ippa_ref); 2633*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2634*0Sstevel@tonic-gate if (rp->ippr_action == ref_ap) 2635*0Sstevel@tonic-gate break; 2636*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2637*0Sstevel@tonic-gate } 2638*0Sstevel@tonic-gate 2639*0Sstevel@tonic-gate if ((rp = *rpp) != NULL) { 2640*0Sstevel@tonic-gate 2641*0Sstevel@tonic-gate /* 2642*0Sstevel@tonic-gate * There is an existing reference so increment its counter. 2643*0Sstevel@tonic-gate */ 2644*0Sstevel@tonic-gate 2645*0Sstevel@tonic-gate rp->ippr_count++; 2646*0Sstevel@tonic-gate 2647*0Sstevel@tonic-gate /* 2648*0Sstevel@tonic-gate * Find the 'back pointer' and increment its counter too. 2649*0Sstevel@tonic-gate */ 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gate rp = ref_ap->ippa_refby; 2652*0Sstevel@tonic-gate while (rp != NULL) { 2653*0Sstevel@tonic-gate if (rp->ippr_action == refby_ap) 2654*0Sstevel@tonic-gate break; 2655*0Sstevel@tonic-gate rp = rp->ippr_nextp; 2656*0Sstevel@tonic-gate } 2657*0Sstevel@tonic-gate ASSERT(rp != NULL); 2658*0Sstevel@tonic-gate 2659*0Sstevel@tonic-gate rp->ippr_count++; 2660*0Sstevel@tonic-gate } else { 2661*0Sstevel@tonic-gate 2662*0Sstevel@tonic-gate /* 2663*0Sstevel@tonic-gate * Allocate, fill in and link a new reference structure. 2664*0Sstevel@tonic-gate */ 2665*0Sstevel@tonic-gate 2666*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) 2667*0Sstevel@tonic-gate return (ENOMEM); 2668*0Sstevel@tonic-gate 2669*0Sstevel@tonic-gate rp->ippr_action = ref_ap; 2670*0Sstevel@tonic-gate rp->ippr_count = 1; 2671*0Sstevel@tonic-gate *rpp = rp; 2672*0Sstevel@tonic-gate save_rpp = rpp; 2673*0Sstevel@tonic-gate 2674*0Sstevel@tonic-gate /* 2675*0Sstevel@tonic-gate * We keep a 'back pointer' which we want to add at the end of 2676*0Sstevel@tonic-gate * a list in the referred action's structure. 2677*0Sstevel@tonic-gate */ 2678*0Sstevel@tonic-gate 2679*0Sstevel@tonic-gate rpp = &(ref_ap->ippa_refby); 2680*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2681*0Sstevel@tonic-gate ASSERT(rp->ippr_action != refby_ap); 2682*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2683*0Sstevel@tonic-gate } 2684*0Sstevel@tonic-gate 2685*0Sstevel@tonic-gate /* 2686*0Sstevel@tonic-gate * Allocate another reference structure and, if this fails, 2687*0Sstevel@tonic-gate * remember to clean up the first reference structure we 2688*0Sstevel@tonic-gate * allocated. 2689*0Sstevel@tonic-gate */ 2690*0Sstevel@tonic-gate 2691*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), 2692*0Sstevel@tonic-gate KM_NOSLEEP)) == NULL) { 2693*0Sstevel@tonic-gate rpp = save_rpp; 2694*0Sstevel@tonic-gate rp = *rpp; 2695*0Sstevel@tonic-gate *rpp = NULL; 2696*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2697*0Sstevel@tonic-gate 2698*0Sstevel@tonic-gate return (ENOMEM); 2699*0Sstevel@tonic-gate } 2700*0Sstevel@tonic-gate 2701*0Sstevel@tonic-gate /* 2702*0Sstevel@tonic-gate * Fill in the reference structure with the 'back pointer' and 2703*0Sstevel@tonic-gate * link it into the list. 2704*0Sstevel@tonic-gate */ 2705*0Sstevel@tonic-gate 2706*0Sstevel@tonic-gate rp->ippr_action = refby_ap; 2707*0Sstevel@tonic-gate rp->ippr_count = 1; 2708*0Sstevel@tonic-gate *rpp = rp; 2709*0Sstevel@tonic-gate } 2710*0Sstevel@tonic-gate 2711*0Sstevel@tonic-gate return (0); 2712*0Sstevel@tonic-gate } 2713*0Sstevel@tonic-gate #undef __FN__ 2714*0Sstevel@tonic-gate 2715*0Sstevel@tonic-gate #define __FN__ "unref_action" 2716*0Sstevel@tonic-gate static int 2717*0Sstevel@tonic-gate unref_action( 2718*0Sstevel@tonic-gate ipp_action_t *refby_ap, 2719*0Sstevel@tonic-gate ipp_action_t *ref_ap) 2720*0Sstevel@tonic-gate { 2721*0Sstevel@tonic-gate ipp_ref_t **rpp; 2722*0Sstevel@tonic-gate ipp_ref_t *rp; 2723*0Sstevel@tonic-gate 2724*0Sstevel@tonic-gate ASSERT(rw_write_held(refby_ap->ippa_lock)); 2725*0Sstevel@tonic-gate ASSERT(rw_write_held(ref_ap->ippa_lock)); 2726*0Sstevel@tonic-gate 2727*0Sstevel@tonic-gate /* 2728*0Sstevel@tonic-gate * Scan for the reference in the referring action's list. 2729*0Sstevel@tonic-gate */ 2730*0Sstevel@tonic-gate 2731*0Sstevel@tonic-gate rpp = &(refby_ap->ippa_ref); 2732*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2733*0Sstevel@tonic-gate if (rp->ippr_action == ref_ap) 2734*0Sstevel@tonic-gate break; 2735*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2736*0Sstevel@tonic-gate } 2737*0Sstevel@tonic-gate 2738*0Sstevel@tonic-gate if (rp == NULL) 2739*0Sstevel@tonic-gate return (ENOENT); 2740*0Sstevel@tonic-gate 2741*0Sstevel@tonic-gate if (rp->ippr_count > 1) { 2742*0Sstevel@tonic-gate 2743*0Sstevel@tonic-gate /* 2744*0Sstevel@tonic-gate * There are currently multiple references so decrement the 2745*0Sstevel@tonic-gate * count. 2746*0Sstevel@tonic-gate */ 2747*0Sstevel@tonic-gate 2748*0Sstevel@tonic-gate rp->ippr_count--; 2749*0Sstevel@tonic-gate 2750*0Sstevel@tonic-gate /* 2751*0Sstevel@tonic-gate * Find the 'back pointer' and decrement its counter too. 2752*0Sstevel@tonic-gate */ 2753*0Sstevel@tonic-gate 2754*0Sstevel@tonic-gate rp = ref_ap->ippa_refby; 2755*0Sstevel@tonic-gate while (rp != NULL) { 2756*0Sstevel@tonic-gate if (rp->ippr_action == refby_ap) 2757*0Sstevel@tonic-gate break; 2758*0Sstevel@tonic-gate rp = rp->ippr_nextp; 2759*0Sstevel@tonic-gate } 2760*0Sstevel@tonic-gate ASSERT(rp != NULL); 2761*0Sstevel@tonic-gate 2762*0Sstevel@tonic-gate rp->ippr_count--; 2763*0Sstevel@tonic-gate } else { 2764*0Sstevel@tonic-gate 2765*0Sstevel@tonic-gate /* 2766*0Sstevel@tonic-gate * There is currently only a single reference, so unlink and 2767*0Sstevel@tonic-gate * free the reference structure. 2768*0Sstevel@tonic-gate */ 2769*0Sstevel@tonic-gate 2770*0Sstevel@tonic-gate *rpp = rp->ippr_nextp; 2771*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2772*0Sstevel@tonic-gate 2773*0Sstevel@tonic-gate /* 2774*0Sstevel@tonic-gate * Scan for the 'back pointer' in the referred action's list. 2775*0Sstevel@tonic-gate */ 2776*0Sstevel@tonic-gate 2777*0Sstevel@tonic-gate rpp = &(ref_ap->ippa_refby); 2778*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2779*0Sstevel@tonic-gate if (rp->ippr_action == refby_ap) 2780*0Sstevel@tonic-gate break; 2781*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2782*0Sstevel@tonic-gate } 2783*0Sstevel@tonic-gate ASSERT(rp != NULL); 2784*0Sstevel@tonic-gate 2785*0Sstevel@tonic-gate /* 2786*0Sstevel@tonic-gate * Unlink and free this reference structure too. 2787*0Sstevel@tonic-gate */ 2788*0Sstevel@tonic-gate 2789*0Sstevel@tonic-gate *rpp = rp->ippr_nextp; 2790*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2791*0Sstevel@tonic-gate } 2792*0Sstevel@tonic-gate 2793*0Sstevel@tonic-gate return (0); 2794*0Sstevel@tonic-gate } 2795*0Sstevel@tonic-gate #undef __FN__ 2796*0Sstevel@tonic-gate 2797*0Sstevel@tonic-gate #define __FN__ "is_action_refd" 2798*0Sstevel@tonic-gate static int 2799*0Sstevel@tonic-gate is_action_refd( 2800*0Sstevel@tonic-gate ipp_action_t *ap) 2801*0Sstevel@tonic-gate { 2802*0Sstevel@tonic-gate /* 2803*0Sstevel@tonic-gate * Return a value which is true (non-zero) iff the action is not 2804*0Sstevel@tonic-gate * referred to by any other actions. 2805*0Sstevel@tonic-gate */ 2806*0Sstevel@tonic-gate 2807*0Sstevel@tonic-gate return (ap->ippa_refby != NULL); 2808*0Sstevel@tonic-gate } 2809*0Sstevel@tonic-gate #undef __FN__ 2810*0Sstevel@tonic-gate 2811*0Sstevel@tonic-gate #define __FN__ "find_action" 2812*0Sstevel@tonic-gate static ipp_action_id_t 2813*0Sstevel@tonic-gate find_action( 2814*0Sstevel@tonic-gate const char *aname) 2815*0Sstevel@tonic-gate { 2816*0Sstevel@tonic-gate ipp_action_id_t aid; 2817*0Sstevel@tonic-gate ipp_action_t *ap; 2818*0Sstevel@tonic-gate ipp_ref_t *rp; 2819*0Sstevel@tonic-gate int hb; 2820*0Sstevel@tonic-gate 2821*0Sstevel@tonic-gate ASSERT(aname != NULL); 2822*0Sstevel@tonic-gate 2823*0Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_READER); 2824*0Sstevel@tonic-gate 2825*0Sstevel@tonic-gate /* 2826*0Sstevel@tonic-gate * Quick return if there are no actions defined at all. 2827*0Sstevel@tonic-gate */ 2828*0Sstevel@tonic-gate 2829*0Sstevel@tonic-gate if (ipp_action_count == 0) { 2830*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2831*0Sstevel@tonic-gate return (IPP_ACTION_INVAL); 2832*0Sstevel@tonic-gate } 2833*0Sstevel@tonic-gate 2834*0Sstevel@tonic-gate /* 2835*0Sstevel@tonic-gate * Find the hash bucket where the action structure should be. 2836*0Sstevel@tonic-gate */ 2837*0Sstevel@tonic-gate 2838*0Sstevel@tonic-gate hb = hash(aname); 2839*0Sstevel@tonic-gate rp = ipp_action_byname[hb]; 2840*0Sstevel@tonic-gate 2841*0Sstevel@tonic-gate /* 2842*0Sstevel@tonic-gate * Scan the bucket looking for a match. 2843*0Sstevel@tonic-gate */ 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate while (rp != NULL) { 2846*0Sstevel@tonic-gate ap = rp->ippr_action; 2847*0Sstevel@tonic-gate if (strcmp(ap->ippa_name, aname) == 0) 2848*0Sstevel@tonic-gate break; 2849*0Sstevel@tonic-gate rp = rp->ippr_nextp; 2850*0Sstevel@tonic-gate } 2851*0Sstevel@tonic-gate 2852*0Sstevel@tonic-gate if (rp == NULL) { 2853*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2854*0Sstevel@tonic-gate return (IPP_ACTION_INVAL); 2855*0Sstevel@tonic-gate } 2856*0Sstevel@tonic-gate 2857*0Sstevel@tonic-gate if (ap->ippa_state == IPP_ASTATE_PROTO) { 2858*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2859*0Sstevel@tonic-gate return (IPP_ACTION_INVAL); 2860*0Sstevel@tonic-gate } 2861*0Sstevel@tonic-gate 2862*0Sstevel@tonic-gate aid = ap->ippa_id; 2863*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2864*0Sstevel@tonic-gate 2865*0Sstevel@tonic-gate return (aid); 2866*0Sstevel@tonic-gate } 2867*0Sstevel@tonic-gate #undef __FN__ 2868*0Sstevel@tonic-gate 2869*0Sstevel@tonic-gate #define __FN__ "alloc_action" 2870*0Sstevel@tonic-gate static int 2871*0Sstevel@tonic-gate alloc_action( 2872*0Sstevel@tonic-gate const char *aname, 2873*0Sstevel@tonic-gate ipp_action_id_t *aidp) 2874*0Sstevel@tonic-gate { 2875*0Sstevel@tonic-gate ipp_action_t *ap; 2876*0Sstevel@tonic-gate ipp_ref_t **rpp; 2877*0Sstevel@tonic-gate ipp_ref_t *rp; 2878*0Sstevel@tonic-gate int hb; 2879*0Sstevel@tonic-gate 2880*0Sstevel@tonic-gate ASSERT(aidp != NULL); 2881*0Sstevel@tonic-gate 2882*0Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_WRITER); 2883*0Sstevel@tonic-gate 2884*0Sstevel@tonic-gate /* 2885*0Sstevel@tonic-gate * Find the right hash bucket for an action of the given name. 2886*0Sstevel@tonic-gate * (Nameless actions always go in a special bucket). 2887*0Sstevel@tonic-gate */ 2888*0Sstevel@tonic-gate 2889*0Sstevel@tonic-gate if (aname != NULL) { 2890*0Sstevel@tonic-gate hb = hash(aname); 2891*0Sstevel@tonic-gate rpp = &ipp_action_byname[hb]; 2892*0Sstevel@tonic-gate } else 2893*0Sstevel@tonic-gate rpp = &ipp_action_noname; 2894*0Sstevel@tonic-gate 2895*0Sstevel@tonic-gate /* 2896*0Sstevel@tonic-gate * Scan the bucket to make sure that an action with the given name 2897*0Sstevel@tonic-gate * does not already exist. 2898*0Sstevel@tonic-gate */ 2899*0Sstevel@tonic-gate 2900*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2901*0Sstevel@tonic-gate ap = rp->ippr_action; 2902*0Sstevel@tonic-gate if (aname != NULL && strcmp(ap->ippa_name, aname) == 0) { 2903*0Sstevel@tonic-gate DBG1(DBG_ACTION, "action '%s' already exists\n", 2904*0Sstevel@tonic-gate aname); 2905*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2906*0Sstevel@tonic-gate return (EEXIST); 2907*0Sstevel@tonic-gate } 2908*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2909*0Sstevel@tonic-gate } 2910*0Sstevel@tonic-gate 2911*0Sstevel@tonic-gate /* 2912*0Sstevel@tonic-gate * Allocate a new reference structure and a new action structure. 2913*0Sstevel@tonic-gate */ 2914*0Sstevel@tonic-gate 2915*0Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) { 2916*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2917*0Sstevel@tonic-gate return (ENOMEM); 2918*0Sstevel@tonic-gate } 2919*0Sstevel@tonic-gate 2920*0Sstevel@tonic-gate if ((ap = kmem_cache_alloc(ipp_action_cache, KM_NOSLEEP)) == NULL) { 2921*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 2922*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2923*0Sstevel@tonic-gate return (ENOMEM); 2924*0Sstevel@tonic-gate } 2925*0Sstevel@tonic-gate 2926*0Sstevel@tonic-gate /* 2927*0Sstevel@tonic-gate * Dream up a name if there isn't a real one and note that the action is 2928*0Sstevel@tonic-gate * really nameless. 2929*0Sstevel@tonic-gate */ 2930*0Sstevel@tonic-gate 2931*0Sstevel@tonic-gate if (aname == NULL) { 2932*0Sstevel@tonic-gate (void) sprintf(ap->ippa_name, "$%08X", ap->ippa_id); 2933*0Sstevel@tonic-gate ap->ippa_nameless = B_TRUE; 2934*0Sstevel@tonic-gate } else 2935*0Sstevel@tonic-gate (void) strcpy(ap->ippa_name, aname); 2936*0Sstevel@tonic-gate 2937*0Sstevel@tonic-gate /* 2938*0Sstevel@tonic-gate * Make sure the 'destruct pending' flag is clear. This indicates that 2939*0Sstevel@tonic-gate * the structure is no longer part of the cache. 2940*0Sstevel@tonic-gate */ 2941*0Sstevel@tonic-gate 2942*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 2943*0Sstevel@tonic-gate ap->ippa_destruct_pending = B_FALSE; 2944*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 2945*0Sstevel@tonic-gate 2946*0Sstevel@tonic-gate /* 2947*0Sstevel@tonic-gate * Fill in the reference structure and lint it onto the list. 2948*0Sstevel@tonic-gate */ 2949*0Sstevel@tonic-gate 2950*0Sstevel@tonic-gate rp->ippr_action = ap; 2951*0Sstevel@tonic-gate *rpp = rp; 2952*0Sstevel@tonic-gate 2953*0Sstevel@tonic-gate /* 2954*0Sstevel@tonic-gate * Increment the action count. 2955*0Sstevel@tonic-gate */ 2956*0Sstevel@tonic-gate 2957*0Sstevel@tonic-gate ipp_action_count++; 2958*0Sstevel@tonic-gate 2959*0Sstevel@tonic-gate *aidp = ap->ippa_id; 2960*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 2961*0Sstevel@tonic-gate return (0); 2962*0Sstevel@tonic-gate } 2963*0Sstevel@tonic-gate #undef __FN__ 2964*0Sstevel@tonic-gate 2965*0Sstevel@tonic-gate #define __FN__ "free_action" 2966*0Sstevel@tonic-gate static void 2967*0Sstevel@tonic-gate free_action( 2968*0Sstevel@tonic-gate ipp_action_t *ap) 2969*0Sstevel@tonic-gate { 2970*0Sstevel@tonic-gate ipp_ref_t **rpp; 2971*0Sstevel@tonic-gate ipp_ref_t *rp; 2972*0Sstevel@tonic-gate int hb; 2973*0Sstevel@tonic-gate 2974*0Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_WRITER); 2975*0Sstevel@tonic-gate 2976*0Sstevel@tonic-gate /* 2977*0Sstevel@tonic-gate * Find the hash bucket where the action structure should be. 2978*0Sstevel@tonic-gate */ 2979*0Sstevel@tonic-gate 2980*0Sstevel@tonic-gate if (!ap->ippa_nameless) { 2981*0Sstevel@tonic-gate hb = hash(ap->ippa_name); 2982*0Sstevel@tonic-gate rpp = &ipp_action_byname[hb]; 2983*0Sstevel@tonic-gate } else 2984*0Sstevel@tonic-gate rpp = &ipp_action_noname; 2985*0Sstevel@tonic-gate 2986*0Sstevel@tonic-gate /* 2987*0Sstevel@tonic-gate * Scan the bucket for a match. 2988*0Sstevel@tonic-gate */ 2989*0Sstevel@tonic-gate 2990*0Sstevel@tonic-gate while ((rp = *rpp) != NULL) { 2991*0Sstevel@tonic-gate if (rp->ippr_action == ap) 2992*0Sstevel@tonic-gate break; 2993*0Sstevel@tonic-gate rpp = &(rp->ippr_nextp); 2994*0Sstevel@tonic-gate } 2995*0Sstevel@tonic-gate ASSERT(rp != NULL); 2996*0Sstevel@tonic-gate 2997*0Sstevel@tonic-gate /* 2998*0Sstevel@tonic-gate * Unlink and free the reference structure. 2999*0Sstevel@tonic-gate */ 3000*0Sstevel@tonic-gate 3001*0Sstevel@tonic-gate *rpp = rp->ippr_nextp; 3002*0Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t)); 3003*0Sstevel@tonic-gate 3004*0Sstevel@tonic-gate /* 3005*0Sstevel@tonic-gate * Decrement the action count. 3006*0Sstevel@tonic-gate */ 3007*0Sstevel@tonic-gate 3008*0Sstevel@tonic-gate ipp_action_count--; 3009*0Sstevel@tonic-gate 3010*0Sstevel@tonic-gate /* 3011*0Sstevel@tonic-gate * Empty the name. 3012*0Sstevel@tonic-gate */ 3013*0Sstevel@tonic-gate 3014*0Sstevel@tonic-gate *ap->ippa_name = '\0'; 3015*0Sstevel@tonic-gate 3016*0Sstevel@tonic-gate /* 3017*0Sstevel@tonic-gate * If the hold count is zero then we can free the structure 3018*0Sstevel@tonic-gate * immediately, otherwise we defer to rele_action(). 3019*0Sstevel@tonic-gate */ 3020*0Sstevel@tonic-gate 3021*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER); 3022*0Sstevel@tonic-gate ap->ippa_destruct_pending = B_TRUE; 3023*0Sstevel@tonic-gate if (ap->ippa_hold_count == 0) { 3024*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3025*0Sstevel@tonic-gate kmem_cache_free(ipp_action_cache, ap); 3026*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 3027*0Sstevel@tonic-gate return; 3028*0Sstevel@tonic-gate } 3029*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3030*0Sstevel@tonic-gate 3031*0Sstevel@tonic-gate rw_exit(ipp_action_byname_lock); 3032*0Sstevel@tonic-gate } 3033*0Sstevel@tonic-gate #undef __FN__ 3034*0Sstevel@tonic-gate 3035*0Sstevel@tonic-gate #define __FN__ "hold_action" 3036*0Sstevel@tonic-gate static ipp_action_t * 3037*0Sstevel@tonic-gate hold_action( 3038*0Sstevel@tonic-gate ipp_action_id_t aid) 3039*0Sstevel@tonic-gate { 3040*0Sstevel@tonic-gate ipp_action_t *ap; 3041*0Sstevel@tonic-gate 3042*0Sstevel@tonic-gate if (aid < 0) 3043*0Sstevel@tonic-gate return (NULL); 3044*0Sstevel@tonic-gate 3045*0Sstevel@tonic-gate /* 3046*0Sstevel@tonic-gate * Use the action id as an index into the array of all action 3047*0Sstevel@tonic-gate * structures. 3048*0Sstevel@tonic-gate */ 3049*0Sstevel@tonic-gate 3050*0Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_READER); 3051*0Sstevel@tonic-gate if ((ap = ipp_action_byid[aid]) == NULL) { 3052*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3053*0Sstevel@tonic-gate return (NULL); 3054*0Sstevel@tonic-gate } 3055*0Sstevel@tonic-gate 3056*0Sstevel@tonic-gate /* 3057*0Sstevel@tonic-gate * If the action has 'destruct pending' set then it means it is either 3058*0Sstevel@tonic-gate * still in the cache (i.e not allocated) or in the process of 3059*0Sstevel@tonic-gate * being set up by alloc_action(). 3060*0Sstevel@tonic-gate */ 3061*0Sstevel@tonic-gate 3062*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 3063*0Sstevel@tonic-gate if (ap->ippa_destruct_pending) { 3064*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3065*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3066*0Sstevel@tonic-gate return (NULL); 3067*0Sstevel@tonic-gate } 3068*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3069*0Sstevel@tonic-gate 3070*0Sstevel@tonic-gate /* 3071*0Sstevel@tonic-gate * Increment the hold count to prevent the structure from being 3072*0Sstevel@tonic-gate * freed. 3073*0Sstevel@tonic-gate */ 3074*0Sstevel@tonic-gate 3075*0Sstevel@tonic-gate atomic_add_32(&(ap->ippa_hold_count), 1); 3076*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3077*0Sstevel@tonic-gate 3078*0Sstevel@tonic-gate return (ap); 3079*0Sstevel@tonic-gate } 3080*0Sstevel@tonic-gate #undef __FN__ 3081*0Sstevel@tonic-gate 3082*0Sstevel@tonic-gate #define __FN__ "rele_action" 3083*0Sstevel@tonic-gate static void 3084*0Sstevel@tonic-gate rele_action( 3085*0Sstevel@tonic-gate ipp_action_t *ap) 3086*0Sstevel@tonic-gate { 3087*0Sstevel@tonic-gate /* 3088*0Sstevel@tonic-gate * This call means we're done with the pointer so we can drop the 3089*0Sstevel@tonic-gate * hold count. 3090*0Sstevel@tonic-gate */ 3091*0Sstevel@tonic-gate 3092*0Sstevel@tonic-gate ASSERT(ap->ippa_hold_count != 0); 3093*0Sstevel@tonic-gate atomic_add_32(&(ap->ippa_hold_count), -1); 3094*0Sstevel@tonic-gate 3095*0Sstevel@tonic-gate /* 3096*0Sstevel@tonic-gate * If the structure has 'destruct pending' set then we tried to free 3097*0Sstevel@tonic-gate * it but couldn't, so do it now. 3098*0Sstevel@tonic-gate */ 3099*0Sstevel@tonic-gate 3100*0Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER); 3101*0Sstevel@tonic-gate if (ap->ippa_destruct_pending && ap->ippa_hold_count == 0) { 3102*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3103*0Sstevel@tonic-gate kmem_cache_free(ipp_action_cache, ap); 3104*0Sstevel@tonic-gate return; 3105*0Sstevel@tonic-gate } 3106*0Sstevel@tonic-gate UNLOCK_ACTION(ap); 3107*0Sstevel@tonic-gate } 3108*0Sstevel@tonic-gate #undef __FN__ 3109*0Sstevel@tonic-gate 3110*0Sstevel@tonic-gate #define __FN__ "get_aid" 3111*0Sstevel@tonic-gate static ipp_action_id_t 3112*0Sstevel@tonic-gate get_aid( 3113*0Sstevel@tonic-gate void) 3114*0Sstevel@tonic-gate { 3115*0Sstevel@tonic-gate int index; 3116*0Sstevel@tonic-gate int start; 3117*0Sstevel@tonic-gate int limit; 3118*0Sstevel@tonic-gate 3119*0Sstevel@tonic-gate ASSERT(rw_write_held(ipp_action_byid_lock)); 3120*0Sstevel@tonic-gate 3121*0Sstevel@tonic-gate /* 3122*0Sstevel@tonic-gate * Start searching after the last action id that we allocated. 3123*0Sstevel@tonic-gate */ 3124*0Sstevel@tonic-gate 3125*0Sstevel@tonic-gate start = (int)ipp_next_aid; 3126*0Sstevel@tonic-gate limit = (int)ipp_aid_limit; 3127*0Sstevel@tonic-gate 3128*0Sstevel@tonic-gate /* 3129*0Sstevel@tonic-gate * Look for a spare slot in the array. 3130*0Sstevel@tonic-gate */ 3131*0Sstevel@tonic-gate 3132*0Sstevel@tonic-gate index = start; 3133*0Sstevel@tonic-gate while (ipp_action_byid[index] != NULL) { 3134*0Sstevel@tonic-gate index++; 3135*0Sstevel@tonic-gate if (index > limit) 3136*0Sstevel@tonic-gate index = IPP_ACTION_RESERVED + 1; 3137*0Sstevel@tonic-gate if (index == start) 3138*0Sstevel@tonic-gate return (IPP_ACTION_INVAL); 3139*0Sstevel@tonic-gate } 3140*0Sstevel@tonic-gate 3141*0Sstevel@tonic-gate /* 3142*0Sstevel@tonic-gate * Note that we've just allocated a new action id so that we can 3143*0Sstevel@tonic-gate * start our search there next time. 3144*0Sstevel@tonic-gate */ 3145*0Sstevel@tonic-gate 3146*0Sstevel@tonic-gate index++; 3147*0Sstevel@tonic-gate if (index > limit) 3148*0Sstevel@tonic-gate ipp_next_aid = IPP_ACTION_RESERVED + 1; 3149*0Sstevel@tonic-gate else 3150*0Sstevel@tonic-gate ipp_next_aid = (ipp_action_id_t)index; 3151*0Sstevel@tonic-gate 3152*0Sstevel@tonic-gate return ((ipp_action_id_t)(--index)); 3153*0Sstevel@tonic-gate } 3154*0Sstevel@tonic-gate #undef __FN__ 3155*0Sstevel@tonic-gate 3156*0Sstevel@tonic-gate #define __FN__ "alloc_packet" 3157*0Sstevel@tonic-gate static int 3158*0Sstevel@tonic-gate alloc_packet( 3159*0Sstevel@tonic-gate const char *name, 3160*0Sstevel@tonic-gate ipp_action_id_t aid, 3161*0Sstevel@tonic-gate ipp_packet_t **ppp) 3162*0Sstevel@tonic-gate { 3163*0Sstevel@tonic-gate ipp_packet_t *pp; 3164*0Sstevel@tonic-gate ipp_class_t *cp; 3165*0Sstevel@tonic-gate 3166*0Sstevel@tonic-gate if ((pp = kmem_cache_alloc(ipp_packet_cache, KM_NOSLEEP)) == NULL) 3167*0Sstevel@tonic-gate return (ENOMEM); 3168*0Sstevel@tonic-gate 3169*0Sstevel@tonic-gate /* 3170*0Sstevel@tonic-gate * Set the packet up with a single class. 3171*0Sstevel@tonic-gate */ 3172*0Sstevel@tonic-gate 3173*0Sstevel@tonic-gate cp = &(pp->ippp_class_array[0]); 3174*0Sstevel@tonic-gate pp->ippp_class_windex = 1; 3175*0Sstevel@tonic-gate 3176*0Sstevel@tonic-gate (void) strcpy(cp->ippc_name, name); 3177*0Sstevel@tonic-gate cp->ippc_aid = aid; 3178*0Sstevel@tonic-gate 3179*0Sstevel@tonic-gate *ppp = pp; 3180*0Sstevel@tonic-gate return (0); 3181*0Sstevel@tonic-gate } 3182*0Sstevel@tonic-gate #undef __FN__ 3183*0Sstevel@tonic-gate 3184*0Sstevel@tonic-gate #define __FN__ "realloc_packet" 3185*0Sstevel@tonic-gate static int 3186*0Sstevel@tonic-gate realloc_packet( 3187*0Sstevel@tonic-gate ipp_packet_t *pp) 3188*0Sstevel@tonic-gate { 3189*0Sstevel@tonic-gate uint_t length; 3190*0Sstevel@tonic-gate ipp_class_t *array; 3191*0Sstevel@tonic-gate 3192*0Sstevel@tonic-gate length = (pp->ippp_class_limit + 1) << 1; 3193*0Sstevel@tonic-gate if ((array = kmem_alloc(length * sizeof (ipp_class_t), 3194*0Sstevel@tonic-gate KM_NOSLEEP)) == NULL) 3195*0Sstevel@tonic-gate return (ENOMEM); 3196*0Sstevel@tonic-gate 3197*0Sstevel@tonic-gate bcopy(pp->ippp_class_array, array, 3198*0Sstevel@tonic-gate (length >> 1) * sizeof (ipp_class_t)); 3199*0Sstevel@tonic-gate 3200*0Sstevel@tonic-gate kmem_free(pp->ippp_class_array, 3201*0Sstevel@tonic-gate (length >> 1) * sizeof (ipp_class_t)); 3202*0Sstevel@tonic-gate 3203*0Sstevel@tonic-gate pp->ippp_class_array = array; 3204*0Sstevel@tonic-gate pp->ippp_class_limit = length - 1; 3205*0Sstevel@tonic-gate 3206*0Sstevel@tonic-gate return (0); 3207*0Sstevel@tonic-gate } 3208*0Sstevel@tonic-gate #undef __FN__ 3209*0Sstevel@tonic-gate 3210*0Sstevel@tonic-gate #define __FN__ "free_packet" 3211*0Sstevel@tonic-gate static void 3212*0Sstevel@tonic-gate free_packet( 3213*0Sstevel@tonic-gate ipp_packet_t *pp) 3214*0Sstevel@tonic-gate { 3215*0Sstevel@tonic-gate pp->ippp_class_windex = 0; 3216*0Sstevel@tonic-gate pp->ippp_class_rindex = 0; 3217*0Sstevel@tonic-gate 3218*0Sstevel@tonic-gate pp->ippp_data = NULL; 3219*0Sstevel@tonic-gate pp->ippp_private = NULL; 3220*0Sstevel@tonic-gate 3221*0Sstevel@tonic-gate kmem_cache_free(ipp_packet_cache, pp); 3222*0Sstevel@tonic-gate } 3223*0Sstevel@tonic-gate #undef __FN__ 3224*0Sstevel@tonic-gate 3225*0Sstevel@tonic-gate #define __FN__ "hash" 3226*0Sstevel@tonic-gate static int 3227*0Sstevel@tonic-gate hash( 3228*0Sstevel@tonic-gate const char *name) 3229*0Sstevel@tonic-gate { 3230*0Sstevel@tonic-gate int val = 0; 3231*0Sstevel@tonic-gate char *ptr; 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate /* 3234*0Sstevel@tonic-gate * Make a hash value by XORing all the ascii codes in the text string. 3235*0Sstevel@tonic-gate */ 3236*0Sstevel@tonic-gate 3237*0Sstevel@tonic-gate for (ptr = (char *)name; *ptr != NULL; ptr++) { 3238*0Sstevel@tonic-gate val ^= *ptr; 3239*0Sstevel@tonic-gate } 3240*0Sstevel@tonic-gate 3241*0Sstevel@tonic-gate /* 3242*0Sstevel@tonic-gate * Return the value modulo the number of hash buckets we allow. 3243*0Sstevel@tonic-gate */ 3244*0Sstevel@tonic-gate 3245*0Sstevel@tonic-gate return (val % IPP_NBUCKET); 3246*0Sstevel@tonic-gate } 3247*0Sstevel@tonic-gate #undef __FN__ 3248*0Sstevel@tonic-gate 3249*0Sstevel@tonic-gate #define __FN__ "update_stats" 3250*0Sstevel@tonic-gate static int 3251*0Sstevel@tonic-gate update_stats( 3252*0Sstevel@tonic-gate kstat_t *ksp, 3253*0Sstevel@tonic-gate int rw) 3254*0Sstevel@tonic-gate { 3255*0Sstevel@tonic-gate ipp_stat_impl_t *sip; 3256*0Sstevel@tonic-gate 3257*0Sstevel@tonic-gate ASSERT(ksp->ks_private != NULL); 3258*0Sstevel@tonic-gate sip = (ipp_stat_impl_t *)ksp->ks_private; 3259*0Sstevel@tonic-gate 3260*0Sstevel@tonic-gate /* 3261*0Sstevel@tonic-gate * Call the update function passed to ipp_stat_create() for the given 3262*0Sstevel@tonic-gate * set of kstats. 3263*0Sstevel@tonic-gate */ 3264*0Sstevel@tonic-gate 3265*0Sstevel@tonic-gate return (sip->ippsi_update((ipp_stat_t *)sip, sip->ippsi_arg, rw)); 3266*0Sstevel@tonic-gate } 3267*0Sstevel@tonic-gate #undef __FN__ 3268*0Sstevel@tonic-gate 3269*0Sstevel@tonic-gate #define __FN__ "init_mods" 3270*0Sstevel@tonic-gate static void 3271*0Sstevel@tonic-gate init_mods( 3272*0Sstevel@tonic-gate void) 3273*0Sstevel@tonic-gate { 3274*0Sstevel@tonic-gate /* 3275*0Sstevel@tonic-gate * Initialise the array of all module structures and the module 3276*0Sstevel@tonic-gate * structure kmem cache. 3277*0Sstevel@tonic-gate */ 3278*0Sstevel@tonic-gate 3279*0Sstevel@tonic-gate rw_init(ipp_mod_byid_lock, NULL, RW_DEFAULT, 3280*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3281*0Sstevel@tonic-gate ipp_mod_byid = kmem_zalloc(sizeof (ipp_mod_t *) * (ipp_max_mod + 1), 3282*0Sstevel@tonic-gate KM_SLEEP); 3283*0Sstevel@tonic-gate ipp_mod_byid[ipp_max_mod] = (ipp_mod_t *)-1; 3284*0Sstevel@tonic-gate ipp_mid_limit = (ipp_mod_id_t)(ipp_max_mod - 1); 3285*0Sstevel@tonic-gate 3286*0Sstevel@tonic-gate ipp_mod_cache = kmem_cache_create("ipp_mod", sizeof (ipp_mod_t), 3287*0Sstevel@tonic-gate IPP_ALIGN, mod_constructor, mod_destructor, NULL, NULL, NULL, 0); 3288*0Sstevel@tonic-gate ASSERT(ipp_mod_cache != NULL); 3289*0Sstevel@tonic-gate 3290*0Sstevel@tonic-gate /* 3291*0Sstevel@tonic-gate * Initialize the 'module by name' hash bucket array. 3292*0Sstevel@tonic-gate */ 3293*0Sstevel@tonic-gate 3294*0Sstevel@tonic-gate rw_init(ipp_mod_byname_lock, NULL, RW_DEFAULT, 3295*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3296*0Sstevel@tonic-gate bzero(ipp_mod_byname, IPP_NBUCKET * sizeof (ipp_ref_t *)); 3297*0Sstevel@tonic-gate } 3298*0Sstevel@tonic-gate #undef __FN__ 3299*0Sstevel@tonic-gate 3300*0Sstevel@tonic-gate #define __FN__ "init_actions" 3301*0Sstevel@tonic-gate static void 3302*0Sstevel@tonic-gate init_actions( 3303*0Sstevel@tonic-gate void) 3304*0Sstevel@tonic-gate { 3305*0Sstevel@tonic-gate /* 3306*0Sstevel@tonic-gate * Initialise the array of all action structures and the action 3307*0Sstevel@tonic-gate * structure cache. 3308*0Sstevel@tonic-gate */ 3309*0Sstevel@tonic-gate 3310*0Sstevel@tonic-gate rw_init(ipp_action_byid_lock, NULL, RW_DEFAULT, 3311*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3312*0Sstevel@tonic-gate ipp_action_byid = kmem_zalloc(sizeof (ipp_action_t *) * 3313*0Sstevel@tonic-gate (ipp_max_action + 1), KM_SLEEP); 3314*0Sstevel@tonic-gate ipp_action_byid[ipp_max_action] = (ipp_action_t *)-1; 3315*0Sstevel@tonic-gate ipp_aid_limit = (ipp_action_id_t)(ipp_max_action - 1); 3316*0Sstevel@tonic-gate 3317*0Sstevel@tonic-gate ipp_action_cache = kmem_cache_create("ipp_action", 3318*0Sstevel@tonic-gate sizeof (ipp_action_t), IPP_ALIGN, action_constructor, 3319*0Sstevel@tonic-gate action_destructor, NULL, NULL, NULL, 0); 3320*0Sstevel@tonic-gate ASSERT(ipp_action_cache != NULL); 3321*0Sstevel@tonic-gate 3322*0Sstevel@tonic-gate /* 3323*0Sstevel@tonic-gate * Initialize the 'action by name' hash bucket array (and the special 3324*0Sstevel@tonic-gate * 'hash' bucket for nameless actions). 3325*0Sstevel@tonic-gate */ 3326*0Sstevel@tonic-gate 3327*0Sstevel@tonic-gate rw_init(ipp_action_byname_lock, NULL, RW_DEFAULT, 3328*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3329*0Sstevel@tonic-gate bzero(ipp_action_byname, IPP_NBUCKET * sizeof (ipp_ref_t *)); 3330*0Sstevel@tonic-gate ipp_action_noname = NULL; 3331*0Sstevel@tonic-gate } 3332*0Sstevel@tonic-gate #undef __FN__ 3333*0Sstevel@tonic-gate 3334*0Sstevel@tonic-gate #define __FN__ "init_packets" 3335*0Sstevel@tonic-gate static void 3336*0Sstevel@tonic-gate init_packets( 3337*0Sstevel@tonic-gate void) 3338*0Sstevel@tonic-gate { 3339*0Sstevel@tonic-gate /* 3340*0Sstevel@tonic-gate * Initialise the packet structure cache. 3341*0Sstevel@tonic-gate */ 3342*0Sstevel@tonic-gate 3343*0Sstevel@tonic-gate ipp_packet_cache = kmem_cache_create("ipp_packet", 3344*0Sstevel@tonic-gate sizeof (ipp_packet_t), IPP_ALIGN, packet_constructor, 3345*0Sstevel@tonic-gate packet_destructor, NULL, NULL, NULL, 0); 3346*0Sstevel@tonic-gate ASSERT(ipp_packet_cache != NULL); 3347*0Sstevel@tonic-gate } 3348*0Sstevel@tonic-gate #undef __FN__ 3349*0Sstevel@tonic-gate 3350*0Sstevel@tonic-gate /* 3351*0Sstevel@tonic-gate * Kmem cache constructor/destructor functions. 3352*0Sstevel@tonic-gate */ 3353*0Sstevel@tonic-gate 3354*0Sstevel@tonic-gate #define __FN__ "mod_constructor" 3355*0Sstevel@tonic-gate /*ARGSUSED*/ 3356*0Sstevel@tonic-gate static int 3357*0Sstevel@tonic-gate mod_constructor( 3358*0Sstevel@tonic-gate void *buf, 3359*0Sstevel@tonic-gate void *cdrarg, 3360*0Sstevel@tonic-gate int kmflags) 3361*0Sstevel@tonic-gate { 3362*0Sstevel@tonic-gate ipp_mod_t *imp; 3363*0Sstevel@tonic-gate ipp_mod_id_t mid; 3364*0Sstevel@tonic-gate 3365*0Sstevel@tonic-gate ASSERT(buf != NULL); 3366*0Sstevel@tonic-gate bzero(buf, sizeof (ipp_mod_t)); 3367*0Sstevel@tonic-gate imp = (ipp_mod_t *)buf; 3368*0Sstevel@tonic-gate 3369*0Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_WRITER); 3370*0Sstevel@tonic-gate 3371*0Sstevel@tonic-gate /* 3372*0Sstevel@tonic-gate * Get a new module id. 3373*0Sstevel@tonic-gate */ 3374*0Sstevel@tonic-gate 3375*0Sstevel@tonic-gate if ((mid = get_mid()) <= IPP_MOD_RESERVED) { 3376*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 3377*0Sstevel@tonic-gate return (-1); 3378*0Sstevel@tonic-gate } 3379*0Sstevel@tonic-gate 3380*0Sstevel@tonic-gate /* 3381*0Sstevel@tonic-gate * Initialize the buffer as a module structure in PROTO form. 3382*0Sstevel@tonic-gate */ 3383*0Sstevel@tonic-gate 3384*0Sstevel@tonic-gate imp->ippm_destruct_pending = B_TRUE; 3385*0Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_PROTO; 3386*0Sstevel@tonic-gate rw_init(imp->ippm_lock, NULL, RW_DEFAULT, 3387*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3388*0Sstevel@tonic-gate 3389*0Sstevel@tonic-gate /* 3390*0Sstevel@tonic-gate * Insert it into the array of all module structures. 3391*0Sstevel@tonic-gate */ 3392*0Sstevel@tonic-gate 3393*0Sstevel@tonic-gate imp->ippm_id = mid; 3394*0Sstevel@tonic-gate ipp_mod_byid[mid] = imp; 3395*0Sstevel@tonic-gate 3396*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 3397*0Sstevel@tonic-gate 3398*0Sstevel@tonic-gate return (0); 3399*0Sstevel@tonic-gate } 3400*0Sstevel@tonic-gate #undef __FN__ 3401*0Sstevel@tonic-gate 3402*0Sstevel@tonic-gate #define __FN__ "mod_destructor" 3403*0Sstevel@tonic-gate /*ARGSUSED*/ 3404*0Sstevel@tonic-gate static void 3405*0Sstevel@tonic-gate mod_destructor( 3406*0Sstevel@tonic-gate void *buf, 3407*0Sstevel@tonic-gate void *cdrarg) 3408*0Sstevel@tonic-gate { 3409*0Sstevel@tonic-gate ipp_mod_t *imp; 3410*0Sstevel@tonic-gate 3411*0Sstevel@tonic-gate ASSERT(buf != NULL); 3412*0Sstevel@tonic-gate imp = (ipp_mod_t *)buf; 3413*0Sstevel@tonic-gate 3414*0Sstevel@tonic-gate ASSERT(imp->ippm_state == IPP_MODSTATE_PROTO); 3415*0Sstevel@tonic-gate ASSERT(imp->ippm_action == NULL); 3416*0Sstevel@tonic-gate ASSERT(*imp->ippm_name == '\0'); 3417*0Sstevel@tonic-gate ASSERT(imp->ippm_destruct_pending); 3418*0Sstevel@tonic-gate 3419*0Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_WRITER); 3420*0Sstevel@tonic-gate ASSERT(imp->ippm_hold_count == 0); 3421*0Sstevel@tonic-gate 3422*0Sstevel@tonic-gate /* 3423*0Sstevel@tonic-gate * NULL the entry in the array of all module structures. 3424*0Sstevel@tonic-gate */ 3425*0Sstevel@tonic-gate 3426*0Sstevel@tonic-gate ipp_mod_byid[imp->ippm_id] = NULL; 3427*0Sstevel@tonic-gate 3428*0Sstevel@tonic-gate /* 3429*0Sstevel@tonic-gate * Clean up any remnants of the module structure as the buffer is 3430*0Sstevel@tonic-gate * about to disappear. 3431*0Sstevel@tonic-gate */ 3432*0Sstevel@tonic-gate 3433*0Sstevel@tonic-gate rw_destroy(imp->ippm_lock); 3434*0Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock); 3435*0Sstevel@tonic-gate } 3436*0Sstevel@tonic-gate #undef __FN__ 3437*0Sstevel@tonic-gate 3438*0Sstevel@tonic-gate #define __FN__ "action_constructor" 3439*0Sstevel@tonic-gate /*ARGSUSED*/ 3440*0Sstevel@tonic-gate static int 3441*0Sstevel@tonic-gate action_constructor( 3442*0Sstevel@tonic-gate void *buf, 3443*0Sstevel@tonic-gate void *cdrarg, 3444*0Sstevel@tonic-gate int kmflags) 3445*0Sstevel@tonic-gate { 3446*0Sstevel@tonic-gate ipp_action_t *ap; 3447*0Sstevel@tonic-gate ipp_action_id_t aid; 3448*0Sstevel@tonic-gate 3449*0Sstevel@tonic-gate ASSERT(buf != NULL); 3450*0Sstevel@tonic-gate bzero(buf, sizeof (ipp_action_t)); 3451*0Sstevel@tonic-gate ap = (ipp_action_t *)buf; 3452*0Sstevel@tonic-gate 3453*0Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_WRITER); 3454*0Sstevel@tonic-gate 3455*0Sstevel@tonic-gate /* 3456*0Sstevel@tonic-gate * Get a new action id. 3457*0Sstevel@tonic-gate */ 3458*0Sstevel@tonic-gate 3459*0Sstevel@tonic-gate if ((aid = get_aid()) <= IPP_ACTION_RESERVED) { 3460*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3461*0Sstevel@tonic-gate return (-1); 3462*0Sstevel@tonic-gate } 3463*0Sstevel@tonic-gate 3464*0Sstevel@tonic-gate /* 3465*0Sstevel@tonic-gate * Initialize the buffer as an action structure in PROTO form. 3466*0Sstevel@tonic-gate */ 3467*0Sstevel@tonic-gate 3468*0Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO; 3469*0Sstevel@tonic-gate ap->ippa_destruct_pending = B_TRUE; 3470*0Sstevel@tonic-gate rw_init(ap->ippa_lock, NULL, RW_DEFAULT, 3471*0Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL)); 3472*0Sstevel@tonic-gate CONFIG_LOCK_INIT(ap->ippa_config_lock); 3473*0Sstevel@tonic-gate 3474*0Sstevel@tonic-gate /* 3475*0Sstevel@tonic-gate * Insert it into the array of all action structures. 3476*0Sstevel@tonic-gate */ 3477*0Sstevel@tonic-gate 3478*0Sstevel@tonic-gate ap->ippa_id = aid; 3479*0Sstevel@tonic-gate ipp_action_byid[aid] = ap; 3480*0Sstevel@tonic-gate 3481*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3482*0Sstevel@tonic-gate return (0); 3483*0Sstevel@tonic-gate } 3484*0Sstevel@tonic-gate #undef __FN__ 3485*0Sstevel@tonic-gate 3486*0Sstevel@tonic-gate #define __FN__ "action_destructor" 3487*0Sstevel@tonic-gate /*ARGSUSED*/ 3488*0Sstevel@tonic-gate static void 3489*0Sstevel@tonic-gate action_destructor( 3490*0Sstevel@tonic-gate void *buf, 3491*0Sstevel@tonic-gate void *cdrarg) 3492*0Sstevel@tonic-gate { 3493*0Sstevel@tonic-gate ipp_action_t *ap; 3494*0Sstevel@tonic-gate 3495*0Sstevel@tonic-gate ASSERT(buf != NULL); 3496*0Sstevel@tonic-gate ap = (ipp_action_t *)buf; 3497*0Sstevel@tonic-gate 3498*0Sstevel@tonic-gate ASSERT(ap->ippa_state == IPP_ASTATE_PROTO); 3499*0Sstevel@tonic-gate ASSERT(ap->ippa_ref == NULL); 3500*0Sstevel@tonic-gate ASSERT(ap->ippa_refby == NULL); 3501*0Sstevel@tonic-gate ASSERT(ap->ippa_packets == 0); 3502*0Sstevel@tonic-gate ASSERT(*ap->ippa_name == '\0'); 3503*0Sstevel@tonic-gate ASSERT(ap->ippa_destruct_pending); 3504*0Sstevel@tonic-gate 3505*0Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_WRITER); 3506*0Sstevel@tonic-gate ASSERT(ap->ippa_hold_count == 0); 3507*0Sstevel@tonic-gate 3508*0Sstevel@tonic-gate /* 3509*0Sstevel@tonic-gate * NULL the entry in the array of all action structures. 3510*0Sstevel@tonic-gate */ 3511*0Sstevel@tonic-gate 3512*0Sstevel@tonic-gate ipp_action_byid[ap->ippa_id] = NULL; 3513*0Sstevel@tonic-gate 3514*0Sstevel@tonic-gate /* 3515*0Sstevel@tonic-gate * Clean up any remnants of the action structure as the buffer is 3516*0Sstevel@tonic-gate * about to disappear. 3517*0Sstevel@tonic-gate */ 3518*0Sstevel@tonic-gate 3519*0Sstevel@tonic-gate CONFIG_LOCK_FINI(ap->ippa_config_lock); 3520*0Sstevel@tonic-gate rw_destroy(ap->ippa_lock); 3521*0Sstevel@tonic-gate 3522*0Sstevel@tonic-gate rw_exit(ipp_action_byid_lock); 3523*0Sstevel@tonic-gate } 3524*0Sstevel@tonic-gate #undef __FN__ 3525*0Sstevel@tonic-gate 3526*0Sstevel@tonic-gate #define __FN__ "packet_constructor" 3527*0Sstevel@tonic-gate /*ARGSUSED*/ 3528*0Sstevel@tonic-gate static int 3529*0Sstevel@tonic-gate packet_constructor( 3530*0Sstevel@tonic-gate void *buf, 3531*0Sstevel@tonic-gate void *cdrarg, 3532*0Sstevel@tonic-gate int kmflags) 3533*0Sstevel@tonic-gate { 3534*0Sstevel@tonic-gate ipp_packet_t *pp; 3535*0Sstevel@tonic-gate ipp_class_t *cp; 3536*0Sstevel@tonic-gate 3537*0Sstevel@tonic-gate ASSERT(buf != NULL); 3538*0Sstevel@tonic-gate bzero(buf, sizeof (ipp_packet_t)); 3539*0Sstevel@tonic-gate pp = (ipp_packet_t *)buf; 3540*0Sstevel@tonic-gate 3541*0Sstevel@tonic-gate if ((cp = kmem_alloc(ipp_packet_classes * sizeof (ipp_class_t), 3542*0Sstevel@tonic-gate KM_NOSLEEP)) == NULL) 3543*0Sstevel@tonic-gate return (ENOMEM); 3544*0Sstevel@tonic-gate 3545*0Sstevel@tonic-gate pp->ippp_class_array = cp; 3546*0Sstevel@tonic-gate pp->ippp_class_windex = 0; 3547*0Sstevel@tonic-gate pp->ippp_class_rindex = 0; 3548*0Sstevel@tonic-gate pp->ippp_class_limit = ipp_packet_classes - 1; 3549*0Sstevel@tonic-gate 3550*0Sstevel@tonic-gate return (0); 3551*0Sstevel@tonic-gate } 3552*0Sstevel@tonic-gate #undef __FN__ 3553*0Sstevel@tonic-gate 3554*0Sstevel@tonic-gate #define __FN__ "packet_destructor" 3555*0Sstevel@tonic-gate /*ARGSUSED*/ 3556*0Sstevel@tonic-gate static void 3557*0Sstevel@tonic-gate packet_destructor( 3558*0Sstevel@tonic-gate void *buf, 3559*0Sstevel@tonic-gate void *cdrarg) 3560*0Sstevel@tonic-gate { 3561*0Sstevel@tonic-gate ipp_packet_t *pp; 3562*0Sstevel@tonic-gate 3563*0Sstevel@tonic-gate ASSERT(buf != NULL); 3564*0Sstevel@tonic-gate pp = (ipp_packet_t *)buf; 3565*0Sstevel@tonic-gate 3566*0Sstevel@tonic-gate ASSERT(pp->ippp_data == NULL); 3567*0Sstevel@tonic-gate ASSERT(pp->ippp_class_windex == 0); 3568*0Sstevel@tonic-gate ASSERT(pp->ippp_class_rindex == 0); 3569*0Sstevel@tonic-gate ASSERT(pp->ippp_private == NULL); 3570*0Sstevel@tonic-gate ASSERT(pp->ippp_private_free == NULL); 3571*0Sstevel@tonic-gate 3572*0Sstevel@tonic-gate kmem_free(pp->ippp_class_array, 3573*0Sstevel@tonic-gate (pp->ippp_class_limit + 1) * sizeof (ipp_class_t)); 3574*0Sstevel@tonic-gate 3575*0Sstevel@tonic-gate if (pp->ippp_log != NULL) { 3576*0Sstevel@tonic-gate kmem_free(pp->ippp_log, 3577*0Sstevel@tonic-gate (pp->ippp_log_limit + 1) * sizeof (ipp_log_t)); 3578*0Sstevel@tonic-gate } 3579*0Sstevel@tonic-gate } 3580*0Sstevel@tonic-gate #undef __FN__ 3581*0Sstevel@tonic-gate 3582*0Sstevel@tonic-gate /* 3583*0Sstevel@tonic-gate * Debug message printout code. 3584*0Sstevel@tonic-gate */ 3585*0Sstevel@tonic-gate 3586*0Sstevel@tonic-gate #ifdef IPP_DBG 3587*0Sstevel@tonic-gate static void 3588*0Sstevel@tonic-gate ipp_debug( 3589*0Sstevel@tonic-gate uint64_t type, 3590*0Sstevel@tonic-gate const char *fn, 3591*0Sstevel@tonic-gate char *fmt, 3592*0Sstevel@tonic-gate ...) 3593*0Sstevel@tonic-gate { 3594*0Sstevel@tonic-gate char buf[255]; 3595*0Sstevel@tonic-gate va_list adx; 3596*0Sstevel@tonic-gate 3597*0Sstevel@tonic-gate if ((type & ipp_debug_flags) == 0) 3598*0Sstevel@tonic-gate return; 3599*0Sstevel@tonic-gate 3600*0Sstevel@tonic-gate mutex_enter(debug_mutex); 3601*0Sstevel@tonic-gate va_start(adx, fmt); 3602*0Sstevel@tonic-gate (void) vsnprintf(buf, 255, fmt, adx); 3603*0Sstevel@tonic-gate va_end(adx); 3604*0Sstevel@tonic-gate 3605*0Sstevel@tonic-gate printf("(%llx) %s: %s", (unsigned long long)curthread->t_did, fn, 3606*0Sstevel@tonic-gate buf); 3607*0Sstevel@tonic-gate mutex_exit(debug_mutex); 3608*0Sstevel@tonic-gate } 3609*0Sstevel@tonic-gate #endif /* IPP_DBG */ 3610