10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*2951Selowe * Common Development and Distribution License (the "License").
6*2951Selowe * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*2951Selowe * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/param.h>
300Sstevel@tonic-gate #include <sys/modctl.h>
310Sstevel@tonic-gate #include <sys/sysmacros.h>
320Sstevel@tonic-gate #include <sys/kmem.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/spl.h>
370Sstevel@tonic-gate #include <sys/time.h>
380Sstevel@tonic-gate #include <sys/varargs.h>
390Sstevel@tonic-gate #include <ipp/ipp.h>
400Sstevel@tonic-gate #include <ipp/ipp_impl.h>
410Sstevel@tonic-gate #include <ipp/ipgpc/ipgpc.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate * Debug switch.
450Sstevel@tonic-gate */
460Sstevel@tonic-gate
470Sstevel@tonic-gate #if defined(DEBUG)
480Sstevel@tonic-gate #define IPP_DBG
490Sstevel@tonic-gate #endif
500Sstevel@tonic-gate
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate * Globals
530Sstevel@tonic-gate */
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * ipp_action_count is not static because it is imported by inet/ipp_common.h
570Sstevel@tonic-gate */
580Sstevel@tonic-gate uint32_t ipp_action_count = 0;
590Sstevel@tonic-gate
600Sstevel@tonic-gate static kmem_cache_t *ipp_mod_cache = NULL;
610Sstevel@tonic-gate static uint32_t ipp_mod_count = 0;
620Sstevel@tonic-gate static uint32_t ipp_max_mod = IPP_NMOD;
630Sstevel@tonic-gate static ipp_mod_t **ipp_mod_byid;
640Sstevel@tonic-gate static krwlock_t ipp_mod_byid_lock[1];
650Sstevel@tonic-gate
660Sstevel@tonic-gate static ipp_mod_id_t ipp_next_mid = IPP_MOD_RESERVED + 1;
670Sstevel@tonic-gate static ipp_mod_id_t ipp_mid_limit;
680Sstevel@tonic-gate
690Sstevel@tonic-gate static ipp_ref_t *ipp_mod_byname[IPP_NBUCKET];
700Sstevel@tonic-gate static krwlock_t ipp_mod_byname_lock[1];
710Sstevel@tonic-gate
720Sstevel@tonic-gate static kmem_cache_t *ipp_action_cache = NULL;
730Sstevel@tonic-gate static uint32_t ipp_max_action = IPP_NACTION;
740Sstevel@tonic-gate static ipp_action_t **ipp_action_byid;
750Sstevel@tonic-gate static krwlock_t ipp_action_byid_lock[1];
760Sstevel@tonic-gate
770Sstevel@tonic-gate static ipp_action_id_t ipp_next_aid = IPP_ACTION_RESERVED + 1;
780Sstevel@tonic-gate static ipp_action_id_t ipp_aid_limit;
790Sstevel@tonic-gate
800Sstevel@tonic-gate static ipp_ref_t *ipp_action_byname[IPP_NBUCKET];
810Sstevel@tonic-gate static krwlock_t ipp_action_byname_lock[1];
820Sstevel@tonic-gate static ipp_ref_t *ipp_action_noname;
830Sstevel@tonic-gate
840Sstevel@tonic-gate static kmem_cache_t *ipp_packet_cache = NULL;
850Sstevel@tonic-gate static uint_t ipp_packet_classes = IPP_NCLASS;
860Sstevel@tonic-gate static uint_t ipp_packet_logging = 0;
870Sstevel@tonic-gate static uint_t ipp_packet_log_entries = IPP_NLOG;
880Sstevel@tonic-gate
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate * Prototypes
910Sstevel@tonic-gate */
920Sstevel@tonic-gate
930Sstevel@tonic-gate void ipp_init(void);
940Sstevel@tonic-gate
950Sstevel@tonic-gate int ipp_list_mods(ipp_mod_id_t **, int *);
960Sstevel@tonic-gate
970Sstevel@tonic-gate ipp_mod_id_t ipp_mod_lookup(const char *);
980Sstevel@tonic-gate int ipp_mod_name(ipp_mod_id_t, char **);
990Sstevel@tonic-gate int ipp_mod_register(const char *, ipp_ops_t *);
1000Sstevel@tonic-gate int ipp_mod_unregister(ipp_mod_id_t);
1010Sstevel@tonic-gate int ipp_mod_list_actions(ipp_mod_id_t, ipp_action_id_t **,
1020Sstevel@tonic-gate int *);
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate ipp_action_id_t ipp_action_lookup(const char *);
1050Sstevel@tonic-gate int ipp_action_name(ipp_action_id_t, char **);
1060Sstevel@tonic-gate int ipp_action_mod(ipp_action_id_t, ipp_mod_id_t *);
1070Sstevel@tonic-gate int ipp_action_create(ipp_mod_id_t, const char *,
1080Sstevel@tonic-gate nvlist_t **, ipp_flags_t, ipp_action_id_t *);
1090Sstevel@tonic-gate int ipp_action_modify(ipp_action_id_t, nvlist_t **,
1100Sstevel@tonic-gate ipp_flags_t);
1110Sstevel@tonic-gate int ipp_action_destroy(ipp_action_id_t, ipp_flags_t);
1120Sstevel@tonic-gate int ipp_action_info(ipp_action_id_t, int (*)(nvlist_t *,
1130Sstevel@tonic-gate void *), void *, ipp_flags_t);
1140Sstevel@tonic-gate void ipp_action_set_ptr(ipp_action_id_t, void *);
1150Sstevel@tonic-gate void *ipp_action_get_ptr(ipp_action_id_t);
1160Sstevel@tonic-gate int ipp_action_ref(ipp_action_id_t, ipp_action_id_t,
1170Sstevel@tonic-gate ipp_flags_t);
1180Sstevel@tonic-gate int ipp_action_unref(ipp_action_id_t, ipp_action_id_t,
1190Sstevel@tonic-gate ipp_flags_t);
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate int ipp_packet_alloc(ipp_packet_t **, const char *,
1220Sstevel@tonic-gate ipp_action_id_t);
1230Sstevel@tonic-gate void ipp_packet_free(ipp_packet_t *);
1240Sstevel@tonic-gate int ipp_packet_add_class(ipp_packet_t *, const char *,
1250Sstevel@tonic-gate ipp_action_id_t);
1260Sstevel@tonic-gate int ipp_packet_process(ipp_packet_t **);
1270Sstevel@tonic-gate int ipp_packet_next(ipp_packet_t *, ipp_action_id_t);
1280Sstevel@tonic-gate void ipp_packet_set_data(ipp_packet_t *, mblk_t *);
1290Sstevel@tonic-gate mblk_t *ipp_packet_get_data(ipp_packet_t *);
1300Sstevel@tonic-gate void ipp_packet_set_private(ipp_packet_t *, void *,
1310Sstevel@tonic-gate void (*)(void *));
1320Sstevel@tonic-gate void *ipp_packet_get_private(ipp_packet_t *);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate int ipp_stat_create(ipp_action_id_t, const char *, int,
1350Sstevel@tonic-gate int (*)(ipp_stat_t *, void *, int), void *, ipp_stat_t **);
1360Sstevel@tonic-gate void ipp_stat_install(ipp_stat_t *);
1370Sstevel@tonic-gate void ipp_stat_destroy(ipp_stat_t *);
1380Sstevel@tonic-gate int ipp_stat_named_init(ipp_stat_t *, const char *, uchar_t,
1390Sstevel@tonic-gate ipp_named_t *);
1400Sstevel@tonic-gate int ipp_stat_named_op(ipp_named_t *, void *, int);
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate static int ref_mod(ipp_action_t *, ipp_mod_t *);
1430Sstevel@tonic-gate static void unref_mod(ipp_action_t *, ipp_mod_t *);
1440Sstevel@tonic-gate static int is_mod_busy(ipp_mod_t *);
1450Sstevel@tonic-gate static int get_mod_ref(ipp_mod_t *, ipp_action_id_t **, int *);
1460Sstevel@tonic-gate static int get_mods(ipp_mod_id_t **bufp, int *);
1470Sstevel@tonic-gate static ipp_mod_id_t find_mod(const char *);
1480Sstevel@tonic-gate static int alloc_mod(const char *, ipp_mod_id_t *);
1490Sstevel@tonic-gate static void free_mod(ipp_mod_t *);
1500Sstevel@tonic-gate static ipp_mod_t *hold_mod(ipp_mod_id_t);
1510Sstevel@tonic-gate static void rele_mod(ipp_mod_t *);
1520Sstevel@tonic-gate static ipp_mod_id_t get_mid(void);
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static int condemn_action(ipp_ref_t **, ipp_action_t *);
1550Sstevel@tonic-gate static int destroy_action(ipp_action_t *, ipp_flags_t);
1560Sstevel@tonic-gate static int ref_action(ipp_action_t *, ipp_action_t *);
1570Sstevel@tonic-gate static int unref_action(ipp_action_t *, ipp_action_t *);
1580Sstevel@tonic-gate static int is_action_refd(ipp_action_t *);
1590Sstevel@tonic-gate static ipp_action_id_t find_action(const char *);
1600Sstevel@tonic-gate static int alloc_action(const char *, ipp_action_id_t *);
1610Sstevel@tonic-gate static void free_action(ipp_action_t *);
1620Sstevel@tonic-gate static ipp_action_t *hold_action(ipp_action_id_t);
1630Sstevel@tonic-gate static void rele_action(ipp_action_t *);
1640Sstevel@tonic-gate static ipp_action_id_t get_aid(void);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate static int alloc_packet(const char *, ipp_action_id_t,
1670Sstevel@tonic-gate ipp_packet_t **);
1680Sstevel@tonic-gate static int realloc_packet(ipp_packet_t *);
1690Sstevel@tonic-gate static void free_packet(ipp_packet_t *);
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate static int hash(const char *);
1720Sstevel@tonic-gate static int update_stats(kstat_t *, int);
1730Sstevel@tonic-gate static void init_mods(void);
1740Sstevel@tonic-gate static void init_actions(void);
1750Sstevel@tonic-gate static void init_packets(void);
1760Sstevel@tonic-gate static int mod_constructor(void *, void *, int);
1770Sstevel@tonic-gate static void mod_destructor(void *, void *);
1780Sstevel@tonic-gate static int action_constructor(void *, void *, int);
1790Sstevel@tonic-gate static void action_destructor(void *, void *);
1800Sstevel@tonic-gate static int packet_constructor(void *, void *, int);
1810Sstevel@tonic-gate static void packet_destructor(void *, void *);
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * Debug message macros
1850Sstevel@tonic-gate */
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate #ifdef IPP_DBG
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate #define DBG_MOD 0x00000001ull
1900Sstevel@tonic-gate #define DBG_ACTION 0x00000002ull
1910Sstevel@tonic-gate #define DBG_PACKET 0x00000004ull
1920Sstevel@tonic-gate #define DBG_STATS 0x00000008ull
1930Sstevel@tonic-gate #define DBG_LIST 0x00000010ull
1940Sstevel@tonic-gate
1950Sstevel@tonic-gate static uint64_t ipp_debug_flags =
1960Sstevel@tonic-gate /*
1970Sstevel@tonic-gate * DBG_PACKET |
1980Sstevel@tonic-gate * DBG_STATS |
1990Sstevel@tonic-gate * DBG_LIST |
2000Sstevel@tonic-gate * DBG_MOD |
2010Sstevel@tonic-gate * DBG_ACTION |
2020Sstevel@tonic-gate */
2030Sstevel@tonic-gate 0;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate static kmutex_t debug_mutex[1];
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate /*PRINTFLIKE3*/
2080Sstevel@tonic-gate static void ipp_debug(uint64_t, const char *, char *, ...)
2090Sstevel@tonic-gate __KPRINTFLIKE(3);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate #define DBG0(_type, _fmt) \
2120Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt));
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate #define DBG1(_type, _fmt, _a1) \
2150Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1));
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate #define DBG2(_type, _fmt, _a1, _a2) \
2180Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2));
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate #define DBG3(_type, _fmt, _a1, _a2, _a3) \
2210Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
2220Sstevel@tonic-gate (_a3));
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4) \
2250Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
2260Sstevel@tonic-gate (_a3), (_a4));
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5) \
2290Sstevel@tonic-gate ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2), \
2300Sstevel@tonic-gate (_a3), (_a4), (_a5));
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate #else /* IPP_DBG */
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate #define DBG0(_type, _fmt)
2350Sstevel@tonic-gate #define DBG1(_type, _fmt, _a1)
2360Sstevel@tonic-gate #define DBG2(_type, _fmt, _a1, _a2)
2370Sstevel@tonic-gate #define DBG3(_type, _fmt, _a1, _a2, _a3)
2380Sstevel@tonic-gate #define DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
2390Sstevel@tonic-gate #define DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate #endif /* IPP_DBG */
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate * Lock macros
2450Sstevel@tonic-gate */
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate #define LOCK_MOD(_imp, _rw) \
2480Sstevel@tonic-gate rw_enter((_imp)->ippm_lock, (_rw))
2490Sstevel@tonic-gate #define UNLOCK_MOD(_imp) \
2500Sstevel@tonic-gate rw_exit((_imp)->ippm_lock)
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate #define LOCK_ACTION(_ap, _rw) \
2530Sstevel@tonic-gate rw_enter((_ap)->ippa_lock, (_rw))
2540Sstevel@tonic-gate #define UNLOCK_ACTION(_imp) \
2550Sstevel@tonic-gate rw_exit((_imp)->ippa_lock)
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate #define CONFIG_WRITE_START(_ap) \
2580Sstevel@tonic-gate CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_WRITE)
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate #define CONFIG_WRITE_END(_ap) \
2610Sstevel@tonic-gate CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate #define CONFIG_READ_START(_ap) \
2640Sstevel@tonic-gate CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_READ)
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate #define CONFIG_READ_END(_ap) \
2670Sstevel@tonic-gate CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate * Exported functions
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate #define __FN__ "ipp_init"
2740Sstevel@tonic-gate void
ipp_init(void)2750Sstevel@tonic-gate ipp_init(
2760Sstevel@tonic-gate void)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate #ifdef IPP_DBG
2790Sstevel@tonic-gate mutex_init(debug_mutex, NULL, MUTEX_ADAPTIVE,
2800Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
2810Sstevel@tonic-gate #endif /* IPP_DBG */
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate * Initialize module and action structure caches and associated locks.
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate init_mods();
2880Sstevel@tonic-gate init_actions();
2890Sstevel@tonic-gate init_packets();
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate #undef __FN__
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate #define __FN__ "ipp_list_mods"
2940Sstevel@tonic-gate int
ipp_list_mods(ipp_mod_id_t ** bufp,int * neltp)2950Sstevel@tonic-gate ipp_list_mods(
2960Sstevel@tonic-gate ipp_mod_id_t **bufp,
2970Sstevel@tonic-gate int *neltp)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate ASSERT(bufp != NULL);
3000Sstevel@tonic-gate ASSERT(neltp != NULL);
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate return (get_mods(bufp, neltp));
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate #undef __FN__
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate /*
3070Sstevel@tonic-gate * Module manipulation interface.
3080Sstevel@tonic-gate */
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate #define __FN__ "ipp_mod_lookup"
3110Sstevel@tonic-gate ipp_mod_id_t
ipp_mod_lookup(const char * modname)3120Sstevel@tonic-gate ipp_mod_lookup(
3130Sstevel@tonic-gate const char *modname)
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate ipp_mod_id_t mid;
3160Sstevel@tonic-gate #define FIRST_TIME 0
3170Sstevel@tonic-gate int try = FIRST_TIME;
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate * Sanity check the module name.
3210Sstevel@tonic-gate */
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
3240Sstevel@tonic-gate return (IPP_MOD_INVAL);
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate try_again:
3270Sstevel@tonic-gate if ((mid = find_mod(modname)) == IPP_MOD_INVAL) {
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate * Module not installed.
3310Sstevel@tonic-gate */
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate if (try++ == FIRST_TIME) {
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate * This is the first attempt to find the module so
3370Sstevel@tonic-gate * try to 'demand load' it.
3380Sstevel@tonic-gate */
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate DBG1(DBG_MOD, "loading module '%s'\n", modname);
3410Sstevel@tonic-gate (void) modload("ipp", (char *)modname);
3420Sstevel@tonic-gate goto try_again;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate return (mid);
3470Sstevel@tonic-gate
3480Sstevel@tonic-gate #undef FIRST_TIME
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate #undef __FN__
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate #define __FN__ "ipp_mod_name"
3530Sstevel@tonic-gate int
ipp_mod_name(ipp_mod_id_t mid,char ** modnamep)3540Sstevel@tonic-gate ipp_mod_name(
3550Sstevel@tonic-gate ipp_mod_id_t mid,
3560Sstevel@tonic-gate char **modnamep)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate ipp_mod_t *imp;
3590Sstevel@tonic-gate char *modname;
3600Sstevel@tonic-gate char *buf;
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate ASSERT(modnamep != NULL);
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate /*
3650Sstevel@tonic-gate * Translate the module id into the module pointer.
3660Sstevel@tonic-gate */
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL)
3690Sstevel@tonic-gate return (ENOENT);
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
3720Sstevel@tonic-gate modname = imp->ippm_name;
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate /*
3750Sstevel@tonic-gate * Allocate a buffer to pass back to the caller.
3760Sstevel@tonic-gate */
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate if ((buf = kmem_zalloc(strlen(modname) + 1, KM_NOSLEEP)) == NULL) {
3790Sstevel@tonic-gate UNLOCK_MOD(imp);
3800Sstevel@tonic-gate rele_mod(imp);
3810Sstevel@tonic-gate return (ENOMEM);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate * Copy the module name into the buffer.
3860Sstevel@tonic-gate */
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate (void) strcpy(buf, modname);
3890Sstevel@tonic-gate UNLOCK_MOD(imp);
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate *modnamep = buf;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate rele_mod(imp);
3940Sstevel@tonic-gate return (0);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate #undef __FN__
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate #define __FN__ "ipp_mod_register"
3990Sstevel@tonic-gate int
ipp_mod_register(const char * modname,ipp_ops_t * ipp_ops)4000Sstevel@tonic-gate ipp_mod_register(
4010Sstevel@tonic-gate const char *modname,
4020Sstevel@tonic-gate ipp_ops_t *ipp_ops)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate ipp_mod_id_t mid;
4050Sstevel@tonic-gate ipp_mod_t *imp;
4060Sstevel@tonic-gate int rc;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate ASSERT(ipp_ops != NULL);
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate /*
4110Sstevel@tonic-gate * Sanity check the module name.
4120Sstevel@tonic-gate */
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
4150Sstevel@tonic-gate return (EINVAL);
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate /*
4180Sstevel@tonic-gate * Allocate a module structure.
4190Sstevel@tonic-gate */
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate if ((rc = alloc_mod(modname, &mid)) != 0)
4220Sstevel@tonic-gate return (rc);
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate imp = hold_mod(mid);
4250Sstevel@tonic-gate ASSERT(imp != NULL);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * Make module available for use.
4290Sstevel@tonic-gate */
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
4320Sstevel@tonic-gate DBG1(DBG_MOD, "registering module '%s'\n", imp->ippm_name);
4330Sstevel@tonic-gate imp->ippm_ops = ipp_ops;
4340Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_AVAILABLE;
4350Sstevel@tonic-gate UNLOCK_MOD(imp);
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate rele_mod(imp);
4380Sstevel@tonic-gate return (0);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate #undef __FN__
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate #define __FN__ "ipp_mod_unregister"
4430Sstevel@tonic-gate int
ipp_mod_unregister(ipp_mod_id_t mid)4440Sstevel@tonic-gate ipp_mod_unregister(
4450Sstevel@tonic-gate ipp_mod_id_t mid)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate ipp_mod_t *imp;
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /*
4500Sstevel@tonic-gate * Translate the module id into the module pointer.
4510Sstevel@tonic-gate */
4520Sstevel@tonic-gate
4530Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL)
4540Sstevel@tonic-gate return (ENOENT);
4550Sstevel@tonic-gate
4560Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
4570Sstevel@tonic-gate ASSERT(imp->ippm_state == IPP_MODSTATE_AVAILABLE);
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate /*
4600Sstevel@tonic-gate * Check to see if there are any actions that reference the module.
4610Sstevel@tonic-gate */
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate if (is_mod_busy(imp)) {
4640Sstevel@tonic-gate UNLOCK_MOD(imp);
4650Sstevel@tonic-gate rele_mod(imp);
4660Sstevel@tonic-gate return (EBUSY);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * Prevent further use of the module.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate DBG1(DBG_MOD, "unregistering module '%s'\n", imp->ippm_name);
4740Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_PROTO;
4750Sstevel@tonic-gate imp->ippm_ops = NULL;
4760Sstevel@tonic-gate UNLOCK_MOD(imp);
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate /*
4790Sstevel@tonic-gate * Free the module structure.
4800Sstevel@tonic-gate */
4810Sstevel@tonic-gate
4820Sstevel@tonic-gate free_mod(imp);
4830Sstevel@tonic-gate rele_mod(imp);
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate return (0);
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate #undef __FN__
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate #define __FN__ "ipp_mod_list_actions"
4900Sstevel@tonic-gate int
ipp_mod_list_actions(ipp_mod_id_t mid,ipp_action_id_t ** bufp,int * neltp)4910Sstevel@tonic-gate ipp_mod_list_actions(
4920Sstevel@tonic-gate ipp_mod_id_t mid,
4930Sstevel@tonic-gate ipp_action_id_t **bufp,
4940Sstevel@tonic-gate int *neltp)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate ipp_mod_t *imp;
4970Sstevel@tonic-gate int rc;
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate ASSERT(bufp != NULL);
5000Sstevel@tonic-gate ASSERT(neltp != NULL);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * Translate the module id into the module pointer.
5040Sstevel@tonic-gate */
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL)
5070Sstevel@tonic-gate return (ENOENT);
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /*
5100Sstevel@tonic-gate * Get the list of actions referencing the module.
5110Sstevel@tonic-gate */
5120Sstevel@tonic-gate
5130Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
5140Sstevel@tonic-gate rc = get_mod_ref(imp, bufp, neltp);
5150Sstevel@tonic-gate UNLOCK_MOD(imp);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate rele_mod(imp);
5180Sstevel@tonic-gate return (rc);
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate #undef __FN__
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /*
5230Sstevel@tonic-gate * Action manipulation interface.
5240Sstevel@tonic-gate */
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate #define __FN__ "ipp_action_lookup"
5270Sstevel@tonic-gate ipp_action_id_t
ipp_action_lookup(const char * aname)5280Sstevel@tonic-gate ipp_action_lookup(
5290Sstevel@tonic-gate const char *aname)
5300Sstevel@tonic-gate {
5310Sstevel@tonic-gate if (aname == NULL)
5320Sstevel@tonic-gate return (IPP_ACTION_INVAL);
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate /*
5350Sstevel@tonic-gate * Check for special case 'virtual action' names.
5360Sstevel@tonic-gate */
5370Sstevel@tonic-gate
5380Sstevel@tonic-gate if (strcmp(aname, IPP_ANAME_CONT) == 0)
5390Sstevel@tonic-gate return (IPP_ACTION_CONT);
5400Sstevel@tonic-gate else if (strcmp(aname, IPP_ANAME_DEFER) == 0)
5410Sstevel@tonic-gate return (IPP_ACTION_DEFER);
5420Sstevel@tonic-gate else if (strcmp(aname, IPP_ANAME_DROP) == 0)
5430Sstevel@tonic-gate return (IPP_ACTION_DROP);
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate /*
5460Sstevel@tonic-gate * Now check real actions.
5470Sstevel@tonic-gate */
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate return (find_action(aname));
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate #undef __FN__
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate #define __FN__ "ipp_action_name"
5540Sstevel@tonic-gate int
ipp_action_name(ipp_action_id_t aid,char ** anamep)5550Sstevel@tonic-gate ipp_action_name(
5560Sstevel@tonic-gate ipp_action_id_t aid,
5570Sstevel@tonic-gate char **anamep)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate ipp_action_t *ap;
5600Sstevel@tonic-gate char *aname;
5610Sstevel@tonic-gate char *buf;
5620Sstevel@tonic-gate int rc;
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate ASSERT(anamep != NULL);
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate * Check for special case 'virtual action' ids.
5680Sstevel@tonic-gate */
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate switch (aid) {
5710Sstevel@tonic-gate case IPP_ACTION_CONT:
5720Sstevel@tonic-gate ap = NULL;
5730Sstevel@tonic-gate aname = IPP_ANAME_CONT;
5740Sstevel@tonic-gate break;
5750Sstevel@tonic-gate case IPP_ACTION_DEFER:
5760Sstevel@tonic-gate ap = NULL;
5770Sstevel@tonic-gate aname = IPP_ANAME_DEFER;
5780Sstevel@tonic-gate break;
5790Sstevel@tonic-gate case IPP_ACTION_DROP:
5800Sstevel@tonic-gate ap = NULL;
5810Sstevel@tonic-gate aname = IPP_ANAME_DROP;
5820Sstevel@tonic-gate break;
5830Sstevel@tonic-gate default:
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate * Not a special case. Check for a real action.
5870Sstevel@tonic-gate */
5880Sstevel@tonic-gate
5890Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
5900Sstevel@tonic-gate return (ENOENT);
5910Sstevel@tonic-gate
5920Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
5930Sstevel@tonic-gate aname = ap->ippa_name;
5940Sstevel@tonic-gate break;
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate /*
5980Sstevel@tonic-gate * Allocate a buffer to pass back to the caller.
5990Sstevel@tonic-gate */
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate if ((buf = kmem_zalloc(strlen(aname) + 1, KM_NOSLEEP)) == NULL) {
6020Sstevel@tonic-gate rc = ENOMEM;
6030Sstevel@tonic-gate goto done;
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate /*
6070Sstevel@tonic-gate * Copy the action name into the buffer.
6080Sstevel@tonic-gate */
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate (void) strcpy(buf, aname);
6110Sstevel@tonic-gate *anamep = buf;
6120Sstevel@tonic-gate rc = 0;
6130Sstevel@tonic-gate done:
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate * Unlock the action if necessary (i.e. it wasn't a virtual action).
6160Sstevel@tonic-gate */
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate if (ap != NULL) {
6190Sstevel@tonic-gate UNLOCK_ACTION(ap);
6200Sstevel@tonic-gate rele_action(ap);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate return (rc);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate #undef __FN__
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate #define __FN__ "ipp_action_mod"
6280Sstevel@tonic-gate int
ipp_action_mod(ipp_action_id_t aid,ipp_mod_id_t * midp)6290Sstevel@tonic-gate ipp_action_mod(
6300Sstevel@tonic-gate ipp_action_id_t aid,
6310Sstevel@tonic-gate ipp_mod_id_t *midp)
6320Sstevel@tonic-gate {
6330Sstevel@tonic-gate ipp_action_t *ap;
6340Sstevel@tonic-gate ipp_mod_t *imp;
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate ASSERT(midp != NULL);
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate * Return an error for 'virtual action' ids.
6400Sstevel@tonic-gate */
6410Sstevel@tonic-gate
6420Sstevel@tonic-gate switch (aid) {
6430Sstevel@tonic-gate case IPP_ACTION_CONT:
6440Sstevel@tonic-gate /*FALLTHRU*/
6450Sstevel@tonic-gate case IPP_ACTION_DEFER:
6460Sstevel@tonic-gate /*FALLTHRU*/
6470Sstevel@tonic-gate case IPP_ACTION_DROP:
6480Sstevel@tonic-gate return (EINVAL);
6490Sstevel@tonic-gate default:
6500Sstevel@tonic-gate break;
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate /*
6540Sstevel@tonic-gate * This is a real action.
6550Sstevel@tonic-gate */
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
6580Sstevel@tonic-gate return (ENOENT);
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate /*
6610Sstevel@tonic-gate * Check that the action is not in prototype state.
6620Sstevel@tonic-gate */
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
6650Sstevel@tonic-gate if (ap->ippa_state == IPP_ASTATE_PROTO) {
6660Sstevel@tonic-gate UNLOCK_ACTION(ap);
6670Sstevel@tonic-gate rele_action(ap);
6680Sstevel@tonic-gate return (ENOENT);
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate imp = ap->ippa_mod;
6720Sstevel@tonic-gate ASSERT(imp != NULL);
6730Sstevel@tonic-gate UNLOCK_ACTION(ap);
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate *midp = imp->ippm_id;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate rele_action(ap);
6780Sstevel@tonic-gate return (0);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate #undef __FN__
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate #define __FN__ "ipp_action_create"
6830Sstevel@tonic-gate int
ipp_action_create(ipp_mod_id_t mid,const char * aname,nvlist_t ** nvlpp,ipp_flags_t flags,ipp_action_id_t * aidp)6840Sstevel@tonic-gate ipp_action_create(
6850Sstevel@tonic-gate ipp_mod_id_t mid,
6860Sstevel@tonic-gate const char *aname,
6870Sstevel@tonic-gate nvlist_t **nvlpp,
6880Sstevel@tonic-gate ipp_flags_t flags,
6890Sstevel@tonic-gate ipp_action_id_t *aidp)
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate ipp_ops_t *ippo;
6920Sstevel@tonic-gate ipp_mod_t *imp;
6930Sstevel@tonic-gate ipp_action_id_t aid;
6940Sstevel@tonic-gate ipp_action_t *ap;
6950Sstevel@tonic-gate int rc;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate ASSERT(nvlpp != NULL);
6980Sstevel@tonic-gate ASSERT(*nvlpp != NULL);
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate /*
7010Sstevel@tonic-gate * Sanity check the action name (NULL means the framework chooses the
7020Sstevel@tonic-gate * name).
7030Sstevel@tonic-gate */
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate if (aname != NULL && strlen(aname) > MAXNAMELEN - 1)
7060Sstevel@tonic-gate return (EINVAL);
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate * Translate the module id into the module pointer.
7100Sstevel@tonic-gate */
7110Sstevel@tonic-gate
7120Sstevel@tonic-gate if ((imp = hold_mod(mid)) == NULL)
7130Sstevel@tonic-gate return (ENOENT);
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate /*
7160Sstevel@tonic-gate * Allocate an action.
7170Sstevel@tonic-gate */
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate if ((rc = alloc_action(aname, &aid)) != 0) {
7200Sstevel@tonic-gate rele_mod(imp);
7210Sstevel@tonic-gate return (rc);
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate ap = hold_action(aid);
7250Sstevel@tonic-gate ASSERT(ap != NULL);
7260Sstevel@tonic-gate
7270Sstevel@tonic-gate /*
7280Sstevel@tonic-gate * Note that the action is in the process of creation/destruction.
7290Sstevel@tonic-gate */
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
7320Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate /*
7350Sstevel@tonic-gate * Reference the module for which the action is being created.
7360Sstevel@tonic-gate */
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
7390Sstevel@tonic-gate if ((rc = ref_mod(ap, imp)) != 0) {
7400Sstevel@tonic-gate UNLOCK_MOD(imp);
7410Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO;
7420Sstevel@tonic-gate UNLOCK_ACTION(ap);
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate free_action(ap);
7450Sstevel@tonic-gate rele_action(ap);
7460Sstevel@tonic-gate rele_mod(imp);
7470Sstevel@tonic-gate return (rc);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate
7500Sstevel@tonic-gate UNLOCK_ACTION(ap);
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate ippo = imp->ippm_ops;
7530Sstevel@tonic-gate ASSERT(ippo != NULL);
7540Sstevel@tonic-gate UNLOCK_MOD(imp);
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /*
7570Sstevel@tonic-gate * Call into the module to create the action context.
7580Sstevel@tonic-gate */
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate CONFIG_WRITE_START(ap);
7610Sstevel@tonic-gate DBG2(DBG_ACTION, "creating action '%s' in module '%s'\n",
7620Sstevel@tonic-gate ap->ippa_name, imp->ippm_name);
7630Sstevel@tonic-gate if ((rc = ippo->ippo_action_create(ap->ippa_id, nvlpp, flags)) != 0) {
7640Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
7650Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
7660Sstevel@tonic-gate unref_mod(ap, imp);
7670Sstevel@tonic-gate UNLOCK_MOD(imp);
7680Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO;
7690Sstevel@tonic-gate UNLOCK_ACTION(ap);
7700Sstevel@tonic-gate
7710Sstevel@tonic-gate CONFIG_WRITE_END(ap);
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate free_action(ap);
7740Sstevel@tonic-gate rele_action(ap);
7750Sstevel@tonic-gate rele_mod(imp);
7760Sstevel@tonic-gate return (rc);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate CONFIG_WRITE_END(ap);
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate /*
7810Sstevel@tonic-gate * Make the action available for use.
7820Sstevel@tonic-gate */
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
7850Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE;
7860Sstevel@tonic-gate if (aidp != NULL)
7870Sstevel@tonic-gate *aidp = ap->ippa_id;
7880Sstevel@tonic-gate UNLOCK_ACTION(ap);
7890Sstevel@tonic-gate
7900Sstevel@tonic-gate rele_action(ap);
7910Sstevel@tonic-gate rele_mod(imp);
7920Sstevel@tonic-gate return (0);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate #undef __FN__
7950Sstevel@tonic-gate
7960Sstevel@tonic-gate #define __FN__ "ipp_action_destroy"
7970Sstevel@tonic-gate int
ipp_action_destroy(ipp_action_id_t aid,ipp_flags_t flags)7980Sstevel@tonic-gate ipp_action_destroy(
7990Sstevel@tonic-gate ipp_action_id_t aid,
8000Sstevel@tonic-gate ipp_flags_t flags)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate ipp_ref_t *rp = NULL;
8030Sstevel@tonic-gate ipp_ref_t *tmp;
8040Sstevel@tonic-gate ipp_action_t *ap;
8050Sstevel@tonic-gate int rc;
8060Sstevel@tonic-gate
8070Sstevel@tonic-gate /*
8080Sstevel@tonic-gate * Translate the action id into the action pointer.
8090Sstevel@tonic-gate */
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
8120Sstevel@tonic-gate return (ENOENT);
8130Sstevel@tonic-gate
8140Sstevel@tonic-gate /*
8150Sstevel@tonic-gate * Set the condemned action list pointer and destroy the action.
8160Sstevel@tonic-gate */
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate ap->ippa_condemned = &rp;
8190Sstevel@tonic-gate if ((rc = destroy_action(ap, flags)) == 0) {
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate * Destroy any other actions condemned by the destruction of
8230Sstevel@tonic-gate * the first action.
8240Sstevel@tonic-gate */
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
8270Sstevel@tonic-gate ap = tmp->ippr_action;
8280Sstevel@tonic-gate ap->ippa_condemned = &rp;
8290Sstevel@tonic-gate (void) destroy_action(ap, flags);
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate } else {
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate /*
8340Sstevel@tonic-gate * Unreference any condemned actions since the destruction of
8350Sstevel@tonic-gate * the first action failed.
8360Sstevel@tonic-gate */
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
8390Sstevel@tonic-gate ap = tmp->ippr_action;
8400Sstevel@tonic-gate rele_action(ap);
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate }
8430Sstevel@tonic-gate
8440Sstevel@tonic-gate /*
8450Sstevel@tonic-gate * Clean up the condemned list.
8460Sstevel@tonic-gate */
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate while (rp != NULL) {
8490Sstevel@tonic-gate tmp = rp;
8500Sstevel@tonic-gate rp = rp->ippr_nextp;
8510Sstevel@tonic-gate kmem_free(tmp, sizeof (ipp_ref_t));
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate return (rc);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate #undef __FN__
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate #define __FN__ "ipp_action_modify"
8590Sstevel@tonic-gate int
ipp_action_modify(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)8600Sstevel@tonic-gate ipp_action_modify(
8610Sstevel@tonic-gate ipp_action_id_t aid,
8620Sstevel@tonic-gate nvlist_t **nvlpp,
8630Sstevel@tonic-gate ipp_flags_t flags)
8640Sstevel@tonic-gate {
8650Sstevel@tonic-gate ipp_action_t *ap;
8660Sstevel@tonic-gate ipp_ops_t *ippo;
8670Sstevel@tonic-gate ipp_mod_t *imp;
8680Sstevel@tonic-gate int rc;
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate ASSERT(nvlpp != NULL);
8710Sstevel@tonic-gate ASSERT(*nvlpp != NULL);
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate /*
8740Sstevel@tonic-gate * Translate the action id into the action pointer.
8750Sstevel@tonic-gate */
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
8780Sstevel@tonic-gate return (ENOENT);
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate /*
8810Sstevel@tonic-gate * Check that the action is either available for use or is in the
8820Sstevel@tonic-gate * process of creation/destruction.
8830Sstevel@tonic-gate *
8840Sstevel@tonic-gate * NOTE: It is up to the module to lock multiple configuration
8850Sstevel@tonic-gate * operations against each other if necessary.
8860Sstevel@tonic-gate */
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
8890Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE &&
8900Sstevel@tonic-gate ap->ippa_state != IPP_ASTATE_CONFIG_PENDING) {
8910Sstevel@tonic-gate UNLOCK_ACTION(ap);
8920Sstevel@tonic-gate rele_action(ap);
8930Sstevel@tonic-gate return (EPROTO);
8940Sstevel@tonic-gate }
8950Sstevel@tonic-gate
8960Sstevel@tonic-gate imp = ap->ippa_mod;
8970Sstevel@tonic-gate ASSERT(imp != NULL);
8980Sstevel@tonic-gate UNLOCK_ACTION(ap);
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate ippo = imp->ippm_ops;
9010Sstevel@tonic-gate ASSERT(ippo != NULL);
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate /*
9040Sstevel@tonic-gate * Call into the module to modify the action context.
9050Sstevel@tonic-gate */
9060Sstevel@tonic-gate
9070Sstevel@tonic-gate DBG1(DBG_ACTION, "modifying action '%s'\n", ap->ippa_name);
9080Sstevel@tonic-gate CONFIG_WRITE_START(ap);
9090Sstevel@tonic-gate rc = ippo->ippo_action_modify(aid, nvlpp, flags);
9100Sstevel@tonic-gate CONFIG_WRITE_END(ap);
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate rele_action(ap);
9130Sstevel@tonic-gate return (rc);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate #undef __FN__
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate #define __FN__ "ipp_action_info"
9180Sstevel@tonic-gate int
ipp_action_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)9190Sstevel@tonic-gate ipp_action_info(
9200Sstevel@tonic-gate ipp_action_id_t aid,
9210Sstevel@tonic-gate int (*fn)(nvlist_t *, void *),
9220Sstevel@tonic-gate void *arg,
9230Sstevel@tonic-gate ipp_flags_t flags)
9240Sstevel@tonic-gate {
9250Sstevel@tonic-gate ipp_action_t *ap;
9260Sstevel@tonic-gate ipp_mod_t *imp;
9270Sstevel@tonic-gate ipp_ops_t *ippo;
9280Sstevel@tonic-gate int rc;
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*
9310Sstevel@tonic-gate * Translate the action id into the action pointer.
9320Sstevel@tonic-gate */
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
9350Sstevel@tonic-gate return (ENOENT);
9360Sstevel@tonic-gate
9370Sstevel@tonic-gate /*
9380Sstevel@tonic-gate * Check that the action is available for use. We don't want to
9390Sstevel@tonic-gate * read back parameters while the action is in the process of
9400Sstevel@tonic-gate * creation/destruction.
9410Sstevel@tonic-gate */
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
9440Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
9450Sstevel@tonic-gate UNLOCK_ACTION(ap);
9460Sstevel@tonic-gate rele_action(ap);
9470Sstevel@tonic-gate return (EPROTO);
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate imp = ap->ippa_mod;
9510Sstevel@tonic-gate ASSERT(imp != NULL);
9520Sstevel@tonic-gate UNLOCK_ACTION(ap);
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate ippo = imp->ippm_ops;
9550Sstevel@tonic-gate ASSERT(ippo != NULL);
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate /*
9580Sstevel@tonic-gate * Call into the module to get the action configuration information.
9590Sstevel@tonic-gate */
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate DBG1(DBG_ACTION,
9620Sstevel@tonic-gate "getting configuration information from action '%s'\n",
9630Sstevel@tonic-gate ap->ippa_name);
9640Sstevel@tonic-gate CONFIG_READ_START(ap);
9650Sstevel@tonic-gate if ((rc = ippo->ippo_action_info(aid, fn, arg, flags)) != 0) {
9660Sstevel@tonic-gate CONFIG_READ_END(ap);
9670Sstevel@tonic-gate rele_action(ap);
9680Sstevel@tonic-gate return (rc);
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate CONFIG_READ_END(ap);
9710Sstevel@tonic-gate
9720Sstevel@tonic-gate rele_action(ap);
9730Sstevel@tonic-gate return (0);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate #undef __FN__
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate #define __FN__ "ipp_action_set_ptr"
9780Sstevel@tonic-gate void
ipp_action_set_ptr(ipp_action_id_t aid,void * ptr)9790Sstevel@tonic-gate ipp_action_set_ptr(
9800Sstevel@tonic-gate ipp_action_id_t aid,
9810Sstevel@tonic-gate void *ptr)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate ipp_action_t *ap;
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate /*
9860Sstevel@tonic-gate * Translate the action id into the action pointer.
9870Sstevel@tonic-gate */
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate ap = hold_action(aid);
9900Sstevel@tonic-gate ASSERT(ap != NULL);
9910Sstevel@tonic-gate
9920Sstevel@tonic-gate /*
9930Sstevel@tonic-gate * Set the private data pointer.
9940Sstevel@tonic-gate */
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate ap->ippa_ptr = ptr;
9970Sstevel@tonic-gate rele_action(ap);
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate #undef __FN__
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate #define __FN__ "ipp_action_get_ptr"
10020Sstevel@tonic-gate void *
ipp_action_get_ptr(ipp_action_id_t aid)10030Sstevel@tonic-gate ipp_action_get_ptr(
10040Sstevel@tonic-gate ipp_action_id_t aid)
10050Sstevel@tonic-gate {
10060Sstevel@tonic-gate ipp_action_t *ap;
10070Sstevel@tonic-gate void *ptr;
10080Sstevel@tonic-gate
10090Sstevel@tonic-gate /*
10100Sstevel@tonic-gate * Translate the action id into the action pointer.
10110Sstevel@tonic-gate */
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate ap = hold_action(aid);
10140Sstevel@tonic-gate ASSERT(ap != NULL);
10150Sstevel@tonic-gate
10160Sstevel@tonic-gate /*
10170Sstevel@tonic-gate * Return the private data pointer.
10180Sstevel@tonic-gate */
10190Sstevel@tonic-gate
10200Sstevel@tonic-gate ptr = ap->ippa_ptr;
10210Sstevel@tonic-gate rele_action(ap);
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate return (ptr);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate #undef __FN__
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate #define __FN__ "ipp_action_ref"
10280Sstevel@tonic-gate /*ARGSUSED*/
10290Sstevel@tonic-gate int
ipp_action_ref(ipp_action_id_t aid,ipp_action_id_t ref_aid,ipp_flags_t flags)10300Sstevel@tonic-gate ipp_action_ref(
10310Sstevel@tonic-gate ipp_action_id_t aid,
10320Sstevel@tonic-gate ipp_action_id_t ref_aid,
10330Sstevel@tonic-gate ipp_flags_t flags)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate ipp_action_t *ap;
10360Sstevel@tonic-gate ipp_action_t *ref_ap;
10370Sstevel@tonic-gate int rc;
10380Sstevel@tonic-gate
10390Sstevel@tonic-gate /*
10400Sstevel@tonic-gate * Actions are not allowed to reference themselves.
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate if (aid == ref_aid)
10440Sstevel@tonic-gate return (EINVAL);
10450Sstevel@tonic-gate
10460Sstevel@tonic-gate /*
10470Sstevel@tonic-gate * Check for a special case 'virtual action' id.
10480Sstevel@tonic-gate */
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate switch (ref_aid) {
10510Sstevel@tonic-gate case IPP_ACTION_CONT:
10520Sstevel@tonic-gate /*FALLTHRU*/
10530Sstevel@tonic-gate case IPP_ACTION_DEFER:
10540Sstevel@tonic-gate /*FALLTHRU*/
10550Sstevel@tonic-gate case IPP_ACTION_DROP:
10560Sstevel@tonic-gate return (0);
10570Sstevel@tonic-gate default:
10580Sstevel@tonic-gate break;
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate /*
10620Sstevel@tonic-gate * Translate the action ids into action pointers.
10630Sstevel@tonic-gate */
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
10660Sstevel@tonic-gate return (ENOENT);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate if ((ref_ap = hold_action(ref_aid)) == NULL) {
10690Sstevel@tonic-gate rele_action(ap);
10700Sstevel@tonic-gate return (ENOENT);
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
10740Sstevel@tonic-gate LOCK_ACTION(ref_ap, RW_WRITER);
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate if (ref_ap->ippa_state != IPP_ASTATE_AVAILABLE) {
10770Sstevel@tonic-gate UNLOCK_ACTION(ref_ap);
10780Sstevel@tonic-gate UNLOCK_ACTION(ap);
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate rele_action(ref_ap);
10810Sstevel@tonic-gate rele_action(ap);
10820Sstevel@tonic-gate return (EPROTO);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * Create references between the two actions.
10870Sstevel@tonic-gate */
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate rc = ref_action(ap, ref_ap);
10900Sstevel@tonic-gate UNLOCK_ACTION(ref_ap);
10910Sstevel@tonic-gate UNLOCK_ACTION(ap);
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate rele_action(ref_ap);
10940Sstevel@tonic-gate rele_action(ap);
10950Sstevel@tonic-gate return (rc);
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate #undef __FN__
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate #define __FN__ "ipp_action_unref"
11000Sstevel@tonic-gate int
ipp_action_unref(ipp_action_id_t aid,ipp_action_id_t ref_aid,ipp_flags_t flags)11010Sstevel@tonic-gate ipp_action_unref(
11020Sstevel@tonic-gate ipp_action_id_t aid,
11030Sstevel@tonic-gate ipp_action_id_t ref_aid,
11040Sstevel@tonic-gate ipp_flags_t flags)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate ipp_action_t *ap;
11070Sstevel@tonic-gate ipp_action_t *ref_ap;
11080Sstevel@tonic-gate int ref_is_busy;
11090Sstevel@tonic-gate int rc;
11100Sstevel@tonic-gate
11110Sstevel@tonic-gate if (aid == ref_aid)
11120Sstevel@tonic-gate return (EINVAL);
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate /*
11150Sstevel@tonic-gate * Check for a special case 'virtual action' id.
11160Sstevel@tonic-gate */
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate switch (ref_aid) {
11190Sstevel@tonic-gate case IPP_ACTION_CONT:
11200Sstevel@tonic-gate /*FALLTHRU*/
11210Sstevel@tonic-gate case IPP_ACTION_DEFER:
11220Sstevel@tonic-gate /*FALLTHRU*/
11230Sstevel@tonic-gate case IPP_ACTION_DROP:
11240Sstevel@tonic-gate return (0);
11250Sstevel@tonic-gate default:
11260Sstevel@tonic-gate break;
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate * Translate the action ids into action pointers.
11310Sstevel@tonic-gate */
11320Sstevel@tonic-gate
11330Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
11340Sstevel@tonic-gate return (ENOENT);
11350Sstevel@tonic-gate
11360Sstevel@tonic-gate if ((ref_ap = hold_action(ref_aid)) == NULL) {
11370Sstevel@tonic-gate rele_action(ap);
11380Sstevel@tonic-gate return (ENOENT);
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
11420Sstevel@tonic-gate LOCK_ACTION(ref_ap, RW_WRITER);
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate /*
11450Sstevel@tonic-gate * Remove the reference between the actions.
11460Sstevel@tonic-gate */
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate if ((rc = unref_action(ap, ref_ap)) != 0) {
11490Sstevel@tonic-gate UNLOCK_ACTION(ref_ap);
11500Sstevel@tonic-gate UNLOCK_ACTION(ap);
11510Sstevel@tonic-gate rele_action(ref_ap);
11520Sstevel@tonic-gate rele_action(ap);
11530Sstevel@tonic-gate return (rc);
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate ref_is_busy = is_action_refd(ref_ap);
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate UNLOCK_ACTION(ref_ap);
11590Sstevel@tonic-gate UNLOCK_ACTION(ap);
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate if (flags & IPP_DESTROY_REF) {
11620Sstevel@tonic-gate if (!ref_is_busy) {
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * Condemn the action so that it will be destroyed.
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate (void) condemn_action(ap->ippa_condemned, ref_ap);
11690Sstevel@tonic-gate return (0);
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate
11730Sstevel@tonic-gate rele_action(ref_ap);
11740Sstevel@tonic-gate rele_action(ap);
11750Sstevel@tonic-gate return (0);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate #undef __FN__
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate /*
11800Sstevel@tonic-gate * Packet manipulation interface.
11810Sstevel@tonic-gate */
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate #define __FN__ "ipp_packet_alloc"
11840Sstevel@tonic-gate int
ipp_packet_alloc(ipp_packet_t ** ppp,const char * name,ipp_action_id_t aid)11850Sstevel@tonic-gate ipp_packet_alloc(
11860Sstevel@tonic-gate ipp_packet_t **ppp,
11870Sstevel@tonic-gate const char *name,
11880Sstevel@tonic-gate ipp_action_id_t aid)
11890Sstevel@tonic-gate {
11900Sstevel@tonic-gate ipp_packet_t *pp;
11910Sstevel@tonic-gate int rc;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate ASSERT(ppp != NULL);
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate /*
11960Sstevel@tonic-gate * A name is required.
11970Sstevel@tonic-gate */
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate if (name == NULL || strlen(name) > MAXNAMELEN - 1)
12000Sstevel@tonic-gate return (EINVAL);
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate /*
12030Sstevel@tonic-gate * Allocate a packet structure from the cache.
12040Sstevel@tonic-gate */
12050Sstevel@tonic-gate
12060Sstevel@tonic-gate if ((rc = alloc_packet(name, aid, &pp)) != 0)
12070Sstevel@tonic-gate return (rc);
12080Sstevel@tonic-gate
12090Sstevel@tonic-gate if (ipp_packet_logging != 0 && pp->ippp_log == NULL) {
12100Sstevel@tonic-gate
12110Sstevel@tonic-gate /*
12120Sstevel@tonic-gate * Logging is turned on but there's no log buffer. We need
12130Sstevel@tonic-gate * to allocate one.
12140Sstevel@tonic-gate */
12150Sstevel@tonic-gate if ((pp->ippp_log = kmem_alloc(
12160Sstevel@tonic-gate ipp_packet_log_entries * sizeof (ipp_log_t),
12170Sstevel@tonic-gate KM_NOSLEEP)) != NULL) {
12180Sstevel@tonic-gate pp->ippp_log_limit = ipp_packet_log_entries - 1;
12190Sstevel@tonic-gate pp->ippp_log_windex = 0;
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate } else if (ipp_packet_logging == 0 && pp->ippp_log != NULL) {
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * A log buffer is present but logging has been turned off.
12250Sstevel@tonic-gate * Free the buffer now,
12260Sstevel@tonic-gate */
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate kmem_free(pp->ippp_log,
12290Sstevel@tonic-gate (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
12300Sstevel@tonic-gate pp->ippp_log = NULL;
12310Sstevel@tonic-gate pp->ippp_log_limit = 0;
12320Sstevel@tonic-gate pp->ippp_log_windex = 0;
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate *ppp = pp;
12360Sstevel@tonic-gate return (0);
12370Sstevel@tonic-gate }
12380Sstevel@tonic-gate #undef __FN__
12390Sstevel@tonic-gate
12400Sstevel@tonic-gate #define __FN__ "ipp_packet_free"
12410Sstevel@tonic-gate void
ipp_packet_free(ipp_packet_t * pp)12420Sstevel@tonic-gate ipp_packet_free(
12430Sstevel@tonic-gate ipp_packet_t *pp)
12440Sstevel@tonic-gate {
12450Sstevel@tonic-gate
12460Sstevel@tonic-gate ASSERT(pp != NULL);
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate /*
12490Sstevel@tonic-gate * If there is a private structure pointer set, call its free
12500Sstevel@tonic-gate * function.
12510Sstevel@tonic-gate */
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate if (pp->ippp_private) {
12540Sstevel@tonic-gate pp->ippp_private_free(pp->ippp_private);
12550Sstevel@tonic-gate pp->ippp_private = NULL;
12560Sstevel@tonic-gate pp->ippp_private_free = NULL;
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate /*
12600Sstevel@tonic-gate * Free the packet structure back to the cache.
12610Sstevel@tonic-gate */
12620Sstevel@tonic-gate
12630Sstevel@tonic-gate free_packet(pp);
12640Sstevel@tonic-gate }
12650Sstevel@tonic-gate #undef __FN__
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate #define __FN__ "ipp_packet_add_class"
12680Sstevel@tonic-gate int
ipp_packet_add_class(ipp_packet_t * pp,const char * name,ipp_action_id_t aid)12690Sstevel@tonic-gate ipp_packet_add_class(
12700Sstevel@tonic-gate ipp_packet_t *pp,
12710Sstevel@tonic-gate const char *name,
12720Sstevel@tonic-gate ipp_action_id_t aid)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate ipp_class_t *cp;
12750Sstevel@tonic-gate int rc;
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate ASSERT(pp != NULL);
12780Sstevel@tonic-gate
12790Sstevel@tonic-gate /*
12800Sstevel@tonic-gate * A name is required.
12810Sstevel@tonic-gate */
12820Sstevel@tonic-gate
12830Sstevel@tonic-gate if (name == NULL || strlen(name) > MAXNAMELEN - 1)
12840Sstevel@tonic-gate return (EINVAL);
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate /*
12870Sstevel@tonic-gate * Check if there is an available class structure.
12880Sstevel@tonic-gate */
12890Sstevel@tonic-gate
12900Sstevel@tonic-gate if (pp->ippp_class_windex == pp->ippp_class_limit) {
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate * No more structures. Re-allocate the array.
12940Sstevel@tonic-gate */
12950Sstevel@tonic-gate
12960Sstevel@tonic-gate if ((rc = realloc_packet(pp)) != 0)
12970Sstevel@tonic-gate return (rc);
12980Sstevel@tonic-gate }
12990Sstevel@tonic-gate ASSERT(pp->ippp_class_windex < pp->ippp_class_limit);
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate /*
13020Sstevel@tonic-gate * Set up a new class structure.
13030Sstevel@tonic-gate */
13040Sstevel@tonic-gate
13050Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_windex++]);
13060Sstevel@tonic-gate (void) strcpy(cp->ippc_name, name);
13070Sstevel@tonic-gate cp->ippc_aid = aid;
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate return (0);
13100Sstevel@tonic-gate }
13110Sstevel@tonic-gate #undef __FN__
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate #define __FN__ "ipp_packet_process"
13140Sstevel@tonic-gate int
ipp_packet_process(ipp_packet_t ** ppp)13150Sstevel@tonic-gate ipp_packet_process(
13160Sstevel@tonic-gate ipp_packet_t **ppp)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate ipp_packet_t *pp;
13190Sstevel@tonic-gate ipp_action_id_t aid;
13200Sstevel@tonic-gate ipp_class_t *cp;
13210Sstevel@tonic-gate ipp_log_t *lp;
13220Sstevel@tonic-gate ipp_action_t *ap;
13230Sstevel@tonic-gate ipp_mod_t *imp;
13240Sstevel@tonic-gate ipp_ops_t *ippo;
13250Sstevel@tonic-gate int rc;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate ASSERT(ppp != NULL);
13280Sstevel@tonic-gate pp = *ppp;
13290Sstevel@tonic-gate ASSERT(pp != NULL);
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate /*
13320Sstevel@tonic-gate * Walk the class list.
13330Sstevel@tonic-gate */
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate while (pp->ippp_class_rindex < pp->ippp_class_windex) {
13360Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate /*
13390Sstevel@tonic-gate * While there is a real action to invoke...
13400Sstevel@tonic-gate */
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate aid = cp->ippc_aid;
13430Sstevel@tonic-gate while (aid != IPP_ACTION_CONT &&
13440Sstevel@tonic-gate aid != IPP_ACTION_DEFER &&
13450Sstevel@tonic-gate aid != IPP_ACTION_DROP) {
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate ASSERT(aid != IPP_ACTION_INVAL);
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate /*
13500Sstevel@tonic-gate * Translate the action id to the action pointer.
13510Sstevel@tonic-gate */
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) {
13540Sstevel@tonic-gate DBG1(DBG_PACKET,
13550Sstevel@tonic-gate "action id '%d' not found\n", aid);
13560Sstevel@tonic-gate return (ENOENT);
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate
13590Sstevel@tonic-gate /*
13600Sstevel@tonic-gate * Check that the action is available for use...
13610Sstevel@tonic-gate */
13620Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
13630Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
13640Sstevel@tonic-gate UNLOCK_ACTION(ap);
13650Sstevel@tonic-gate rele_action(ap);
13660Sstevel@tonic-gate return (EPROTO);
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate * Increment the action's packet count to note that
13710Sstevel@tonic-gate * it's being used.
13720Sstevel@tonic-gate *
13730Sstevel@tonic-gate * NOTE: We only have a read lock, so we need to use
13740Sstevel@tonic-gate * atomic_add_32(). The read lock is still
13750Sstevel@tonic-gate * important though as it is crucial to block
13760Sstevel@tonic-gate * out a destroy operation between the action
13770Sstevel@tonic-gate * state being checked and the packet count
13780Sstevel@tonic-gate * being incremented.
13790Sstevel@tonic-gate */
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate atomic_add_32(&(ap->ippa_packets), 1);
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate imp = ap->ippa_mod;
13840Sstevel@tonic-gate ASSERT(imp != NULL);
13850Sstevel@tonic-gate UNLOCK_ACTION(ap);
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate ippo = imp->ippm_ops;
13880Sstevel@tonic-gate ASSERT(ippo != NULL);
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate /*
13910Sstevel@tonic-gate * If there's a log, grab the next entry and fill it
13920Sstevel@tonic-gate * in.
13930Sstevel@tonic-gate */
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate if (pp->ippp_log != NULL &&
13960Sstevel@tonic-gate pp->ippp_log_windex <= pp->ippp_log_limit) {
13970Sstevel@tonic-gate lp = &(pp->ippp_log[pp->ippp_log_windex++]);
13980Sstevel@tonic-gate lp->ippl_aid = aid;
13990Sstevel@tonic-gate (void) strcpy(lp->ippl_name, cp->ippc_name);
14000Sstevel@tonic-gate gethrestime(&lp->ippl_begin);
14010Sstevel@tonic-gate } else {
14020Sstevel@tonic-gate lp = NULL;
14030Sstevel@tonic-gate }
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate /*
14060Sstevel@tonic-gate * Invoke the action.
14070Sstevel@tonic-gate */
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate rc = ippo->ippo_action_invoke(aid, pp);
14100Sstevel@tonic-gate
14110Sstevel@tonic-gate /*
14120Sstevel@tonic-gate * Also log the time that the action finished
14130Sstevel@tonic-gate * processing.
14140Sstevel@tonic-gate */
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate if (lp != NULL)
14170Sstevel@tonic-gate gethrestime(&lp->ippl_end);
14180Sstevel@tonic-gate
14190Sstevel@tonic-gate /*
14200Sstevel@tonic-gate * Decrement the packet count.
14210Sstevel@tonic-gate */
14220Sstevel@tonic-gate
14230Sstevel@tonic-gate atomic_add_32(&(ap->ippa_packets), -1);
14240Sstevel@tonic-gate
14250Sstevel@tonic-gate /*
14260Sstevel@tonic-gate * If the class' action id is the same now as it was
14270Sstevel@tonic-gate * before then clearly no 'next action' has been set.
14280Sstevel@tonic-gate * This is a protocol error.
14290Sstevel@tonic-gate */
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate if (cp->ippc_aid == aid) {
14320Sstevel@tonic-gate DBG1(DBG_PACKET,
14330Sstevel@tonic-gate "action '%s' did not set next action\n",
14340Sstevel@tonic-gate ap->ippa_name);
14350Sstevel@tonic-gate rele_action(ap);
14360Sstevel@tonic-gate return (EPROTO);
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate
14390Sstevel@tonic-gate /*
14400Sstevel@tonic-gate * The action did not complete successfully. Terminate
14410Sstevel@tonic-gate * packet processing.
14420Sstevel@tonic-gate */
14430Sstevel@tonic-gate
14440Sstevel@tonic-gate if (rc != 0) {
14450Sstevel@tonic-gate DBG2(DBG_PACKET,
14460Sstevel@tonic-gate "action error '%d' from action '%s'\n",
14470Sstevel@tonic-gate rc, ap->ippa_name);
14480Sstevel@tonic-gate rele_action(ap);
14490Sstevel@tonic-gate return (rc);
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate rele_action(ap);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate /*
14550Sstevel@tonic-gate * Look at the next action.
14560Sstevel@tonic-gate */
14570Sstevel@tonic-gate
14580Sstevel@tonic-gate aid = cp->ippc_aid;
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate /*
14620Sstevel@tonic-gate * No more real actions to invoke, check for 'virtual' ones.
14630Sstevel@tonic-gate */
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate /*
14660Sstevel@tonic-gate * Packet deferred: module has held onto packet for processing
14670Sstevel@tonic-gate * later.
14680Sstevel@tonic-gate */
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate if (cp->ippc_aid == IPP_ACTION_DEFER) {
14710Sstevel@tonic-gate *ppp = NULL;
14720Sstevel@tonic-gate return (0);
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate
14750Sstevel@tonic-gate /*
14760Sstevel@tonic-gate * Packet dropped: free the packet and discontinue processing.
14770Sstevel@tonic-gate */
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate if (cp->ippc_aid == IPP_ACTION_DROP) {
14800Sstevel@tonic-gate freemsg(pp->ippp_data);
14810Sstevel@tonic-gate ipp_packet_free(pp);
14820Sstevel@tonic-gate *ppp = NULL;
14830Sstevel@tonic-gate return (0);
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate
14860Sstevel@tonic-gate /*
14870Sstevel@tonic-gate * Must be 'continue processing': move onto the next class.
14880Sstevel@tonic-gate */
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate ASSERT(cp->ippc_aid == IPP_ACTION_CONT);
14910Sstevel@tonic-gate pp->ippp_class_rindex++;
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate
14940Sstevel@tonic-gate return (0);
14950Sstevel@tonic-gate }
14960Sstevel@tonic-gate #undef __FN__
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate #define __FN__ "ipp_packet_next"
14990Sstevel@tonic-gate int
ipp_packet_next(ipp_packet_t * pp,ipp_action_id_t aid)15000Sstevel@tonic-gate ipp_packet_next(
15010Sstevel@tonic-gate ipp_packet_t *pp,
15020Sstevel@tonic-gate ipp_action_id_t aid)
15030Sstevel@tonic-gate {
15040Sstevel@tonic-gate ipp_action_t *ap;
15050Sstevel@tonic-gate ipp_class_t *cp;
15060Sstevel@tonic-gate
15070Sstevel@tonic-gate ASSERT(pp != NULL);
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
15100Sstevel@tonic-gate ASSERT(cp != NULL);
15110Sstevel@tonic-gate
15120Sstevel@tonic-gate /*
15130Sstevel@tonic-gate * Check for a special case 'virtual action' id.
15140Sstevel@tonic-gate */
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate switch (aid) {
15170Sstevel@tonic-gate case IPP_ACTION_INVAL:
15180Sstevel@tonic-gate return (EINVAL);
15190Sstevel@tonic-gate case IPP_ACTION_DEFER:
15200Sstevel@tonic-gate /*FALLTHRU*/
15210Sstevel@tonic-gate case IPP_ACTION_CONT:
15220Sstevel@tonic-gate /*FALLTHRU*/
15230Sstevel@tonic-gate case IPP_ACTION_DROP:
15240Sstevel@tonic-gate break;
15250Sstevel@tonic-gate default:
15260Sstevel@tonic-gate
15270Sstevel@tonic-gate /*
15280Sstevel@tonic-gate * Not a virtual action so try to translate the action id
15290Sstevel@tonic-gate * into the action pointer to confirm the actions existence.
15300Sstevel@tonic-gate */
15310Sstevel@tonic-gate
15320Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL) {
15330Sstevel@tonic-gate DBG0(DBG_PACKET, "invalid action\n");
15340Sstevel@tonic-gate return (ENOENT);
15350Sstevel@tonic-gate }
15360Sstevel@tonic-gate rele_action(ap);
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate break;
15390Sstevel@tonic-gate }
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate /*
15420Sstevel@tonic-gate * Set the class' new action id.
15430Sstevel@tonic-gate */
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate cp->ippc_aid = aid;
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate return (0);
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate #undef __FN__
15500Sstevel@tonic-gate
15510Sstevel@tonic-gate #define __FN__ "ipp_packet_set_data"
15520Sstevel@tonic-gate void
ipp_packet_set_data(ipp_packet_t * pp,mblk_t * data)15530Sstevel@tonic-gate ipp_packet_set_data(
15540Sstevel@tonic-gate ipp_packet_t *pp,
15550Sstevel@tonic-gate mblk_t *data)
15560Sstevel@tonic-gate {
15570Sstevel@tonic-gate ASSERT(pp != NULL);
15580Sstevel@tonic-gate pp->ippp_data = data;
15590Sstevel@tonic-gate }
15600Sstevel@tonic-gate #undef __FN__
15610Sstevel@tonic-gate
15620Sstevel@tonic-gate #define __FN__ "ipp_packet_get_data"
15630Sstevel@tonic-gate mblk_t *
ipp_packet_get_data(ipp_packet_t * pp)15640Sstevel@tonic-gate ipp_packet_get_data(
15650Sstevel@tonic-gate ipp_packet_t *pp)
15660Sstevel@tonic-gate {
15670Sstevel@tonic-gate ASSERT(pp != NULL);
15680Sstevel@tonic-gate return (pp->ippp_data);
15690Sstevel@tonic-gate }
15700Sstevel@tonic-gate #undef __FN__
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate #define __FN__ "ipp_packet_set_private"
15730Sstevel@tonic-gate void
ipp_packet_set_private(ipp_packet_t * pp,void * buf,void (* free_func)(void *))15740Sstevel@tonic-gate ipp_packet_set_private(
15750Sstevel@tonic-gate ipp_packet_t *pp,
15760Sstevel@tonic-gate void *buf,
15770Sstevel@tonic-gate void (*free_func)(void *))
15780Sstevel@tonic-gate {
15790Sstevel@tonic-gate ASSERT(pp != NULL);
15800Sstevel@tonic-gate ASSERT(free_func != NULL);
15810Sstevel@tonic-gate
15820Sstevel@tonic-gate pp->ippp_private = buf;
15830Sstevel@tonic-gate pp->ippp_private_free = free_func;
15840Sstevel@tonic-gate }
15850Sstevel@tonic-gate #undef __FN__
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate #define __FN__ "ipp_packet_get_private"
15880Sstevel@tonic-gate void *
ipp_packet_get_private(ipp_packet_t * pp)15890Sstevel@tonic-gate ipp_packet_get_private(
15900Sstevel@tonic-gate ipp_packet_t *pp)
15910Sstevel@tonic-gate {
15920Sstevel@tonic-gate ASSERT(pp != NULL);
15930Sstevel@tonic-gate return (pp->ippp_private);
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate #undef __FN__
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate /*
15980Sstevel@tonic-gate * Statistics interface.
15990Sstevel@tonic-gate */
16000Sstevel@tonic-gate
16010Sstevel@tonic-gate #define __FN__ "ipp_stat_create"
16020Sstevel@tonic-gate int
ipp_stat_create(ipp_action_id_t aid,const char * name,int nstat,int (* update)(ipp_stat_t *,void *,int),void * arg,ipp_stat_t ** spp)16030Sstevel@tonic-gate ipp_stat_create(
16040Sstevel@tonic-gate ipp_action_id_t aid,
16050Sstevel@tonic-gate const char *name,
16060Sstevel@tonic-gate int nstat,
16070Sstevel@tonic-gate int (*update)(ipp_stat_t *, void *, int),
16080Sstevel@tonic-gate void *arg,
16090Sstevel@tonic-gate ipp_stat_t **spp)
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate ipp_action_t *ap;
16120Sstevel@tonic-gate ipp_mod_t *imp;
16130Sstevel@tonic-gate ipp_stat_impl_t *sip;
16140Sstevel@tonic-gate ipp_stat_t *sp;
16150Sstevel@tonic-gate kstat_t *ksp;
16160Sstevel@tonic-gate char *class;
16170Sstevel@tonic-gate char *modname;
16180Sstevel@tonic-gate int instance;
16190Sstevel@tonic-gate
16200Sstevel@tonic-gate ASSERT(spp != NULL);
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate /*
16230Sstevel@tonic-gate * Sanity check the arguments.
16240Sstevel@tonic-gate */
16250Sstevel@tonic-gate
16260Sstevel@tonic-gate if (name == NULL || nstat <= 0 || update == NULL)
16270Sstevel@tonic-gate return (EINVAL);
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate /*
16300Sstevel@tonic-gate * Translate the action id into the action pointer.
16310Sstevel@tonic-gate */
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate if ((ap = hold_action(aid)) == NULL)
16340Sstevel@tonic-gate return (ENOENT);
16350Sstevel@tonic-gate
16360Sstevel@tonic-gate /*
16370Sstevel@tonic-gate * Grab relevant action and module information.
16380Sstevel@tonic-gate */
16390Sstevel@tonic-gate
16400Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
16410Sstevel@tonic-gate class = ap->ippa_name;
16420Sstevel@tonic-gate instance = (int)ap->ippa_id;
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate imp = ap->ippa_mod;
16450Sstevel@tonic-gate ASSERT(imp != NULL);
16460Sstevel@tonic-gate
16470Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
16480Sstevel@tonic-gate modname = imp->ippm_name;
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate /*
16510Sstevel@tonic-gate * Allocate a stats info structure.
16520Sstevel@tonic-gate */
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate if ((sip = kmem_alloc(sizeof (ipp_stat_impl_t), KM_NOSLEEP)) == NULL)
16550Sstevel@tonic-gate return (ENOMEM);
16560Sstevel@tonic-gate
16570Sstevel@tonic-gate /*
16580Sstevel@tonic-gate * Create a set of kstats.
16590Sstevel@tonic-gate */
16600Sstevel@tonic-gate
16610Sstevel@tonic-gate DBG2(DBG_STATS, "creating stat set '%s' for action '%s'\n",
16620Sstevel@tonic-gate name, class);
1663*2951Selowe if ((ksp = kstat_create(modname, instance, name, class,
16640Sstevel@tonic-gate KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_WRITABLE)) == NULL) {
16650Sstevel@tonic-gate kmem_free(sip, sizeof (ipp_stat_impl_t));
16660Sstevel@tonic-gate UNLOCK_ACTION(ap);
16670Sstevel@tonic-gate UNLOCK_MOD(imp);
16680Sstevel@tonic-gate return (EINVAL); /* Assume EINVAL was the cause */
16690Sstevel@tonic-gate }
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate UNLOCK_ACTION(ap);
16720Sstevel@tonic-gate UNLOCK_MOD(imp);
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate DBG1(DBG_STATS, "ks_data = %p\n", ksp->ks_data);
16750Sstevel@tonic-gate
16760Sstevel@tonic-gate /*
16770Sstevel@tonic-gate * Set up the kstats structure with a private data pointer and an
16780Sstevel@tonic-gate * 'update' function.
16790Sstevel@tonic-gate */
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate ksp->ks_update = update_stats;
16820Sstevel@tonic-gate ksp->ks_private = (void *)sip;
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate /*
16850Sstevel@tonic-gate * Keep a reference to the kstats structure in our own stats info
16860Sstevel@tonic-gate * structure.
16870Sstevel@tonic-gate */
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate sip->ippsi_ksp = ksp;
16900Sstevel@tonic-gate sip->ippsi_data = ksp->ks_data;
16910Sstevel@tonic-gate
16920Sstevel@tonic-gate /*
16930Sstevel@tonic-gate * Fill in the rest of the stats info structure.
16940Sstevel@tonic-gate */
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate (void) strcpy(sip->ippsi_name, name);
16970Sstevel@tonic-gate sip->ippsi_arg = arg;
16980Sstevel@tonic-gate sip->ippsi_update = update;
16990Sstevel@tonic-gate sip->ippsi_limit = nstat;
17000Sstevel@tonic-gate sip->ippsi_count = 0;
17010Sstevel@tonic-gate mutex_init(sip->ippsi_lock, NULL, MUTEX_ADAPTIVE,
17020Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate /*
17050Sstevel@tonic-gate * Case the stats info structure to a semi-opaque structure that
17060Sstevel@tonic-gate * we pass back to the caller.
17070Sstevel@tonic-gate */
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate sp = (ipp_stat_t *)sip;
17100Sstevel@tonic-gate ASSERT(sp->ipps_data == sip->ippsi_data);
17110Sstevel@tonic-gate *spp = sp;
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate rele_action(ap);
17140Sstevel@tonic-gate return (0);
17150Sstevel@tonic-gate }
17160Sstevel@tonic-gate #undef __FN__
17170Sstevel@tonic-gate
17180Sstevel@tonic-gate #define __FN__ "ipp_stat_install"
17190Sstevel@tonic-gate void
ipp_stat_install(ipp_stat_t * sp)17200Sstevel@tonic-gate ipp_stat_install(
17210Sstevel@tonic-gate ipp_stat_t *sp)
17220Sstevel@tonic-gate {
17230Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
17240Sstevel@tonic-gate
17250Sstevel@tonic-gate ASSERT(sp != NULL);
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate /*
17280Sstevel@tonic-gate * Install the set of kstats referenced by the stats info structure.
17290Sstevel@tonic-gate */
17300Sstevel@tonic-gate
17310Sstevel@tonic-gate DBG1(DBG_STATS, "installing stat set '%s'\n", sip->ippsi_name);
17320Sstevel@tonic-gate kstat_install(sip->ippsi_ksp);
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate #undef __FN__
17350Sstevel@tonic-gate
17360Sstevel@tonic-gate #define __FN__ "ipp_stat_destroy"
17370Sstevel@tonic-gate void
ipp_stat_destroy(ipp_stat_t * sp)17380Sstevel@tonic-gate ipp_stat_destroy(
17390Sstevel@tonic-gate ipp_stat_t *sp)
17400Sstevel@tonic-gate {
17410Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
17420Sstevel@tonic-gate
17430Sstevel@tonic-gate ASSERT(sp != NULL);
17440Sstevel@tonic-gate
17450Sstevel@tonic-gate /*
17460Sstevel@tonic-gate * Destroy the set of kstats referenced by the stats info structure.
17470Sstevel@tonic-gate */
17480Sstevel@tonic-gate
17490Sstevel@tonic-gate DBG1(DBG_STATS, "destroying stat set '%s'\n", sip->ippsi_name);
17500Sstevel@tonic-gate kstat_delete(sip->ippsi_ksp);
17510Sstevel@tonic-gate
17520Sstevel@tonic-gate /*
17530Sstevel@tonic-gate * Destroy the stats info structure itself.
17540Sstevel@tonic-gate */
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate mutex_destroy(sip->ippsi_lock);
17570Sstevel@tonic-gate kmem_free(sip, sizeof (ipp_stat_impl_t));
17580Sstevel@tonic-gate }
17590Sstevel@tonic-gate #undef __FN__
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate #define __FN__ "ipp_stat_named_init"
17620Sstevel@tonic-gate int
ipp_stat_named_init(ipp_stat_t * sp,const char * name,uchar_t type,ipp_named_t * np)17630Sstevel@tonic-gate ipp_stat_named_init(
17640Sstevel@tonic-gate ipp_stat_t *sp,
17650Sstevel@tonic-gate const char *name,
17660Sstevel@tonic-gate uchar_t type,
17670Sstevel@tonic-gate ipp_named_t *np)
17680Sstevel@tonic-gate {
17690Sstevel@tonic-gate ipp_stat_impl_t *sip = (ipp_stat_impl_t *)sp;
17700Sstevel@tonic-gate uchar_t ktype;
17710Sstevel@tonic-gate
17720Sstevel@tonic-gate ASSERT(sp != NULL);
17730Sstevel@tonic-gate ASSERT(np != NULL);
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate if (name == NULL)
17760Sstevel@tonic-gate return (EINVAL);
17770Sstevel@tonic-gate
17780Sstevel@tonic-gate if ((type & IPP_STAT_TAG) == 0)
17790Sstevel@tonic-gate return (EINVAL);
17800Sstevel@tonic-gate ktype = type & ~IPP_STAT_TAG;
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate /*
17830Sstevel@tonic-gate * Check we will not exceed the maximum number of a stats that was
17840Sstevel@tonic-gate * indicated during set creation.
17850Sstevel@tonic-gate */
17860Sstevel@tonic-gate
17870Sstevel@tonic-gate mutex_enter(sip->ippsi_lock);
17880Sstevel@tonic-gate if (sip->ippsi_count >= sip->ippsi_limit) {
17890Sstevel@tonic-gate mutex_exit(sip->ippsi_lock);
17900Sstevel@tonic-gate return (ENOSPC);
17910Sstevel@tonic-gate }
17920Sstevel@tonic-gate
17930Sstevel@tonic-gate /*
17940Sstevel@tonic-gate * Bump the count.
17950Sstevel@tonic-gate */
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate sip->ippsi_count++;
17980Sstevel@tonic-gate
17990Sstevel@tonic-gate /*
18000Sstevel@tonic-gate * Create a new named kstat.
18010Sstevel@tonic-gate */
18020Sstevel@tonic-gate
18030Sstevel@tonic-gate DBG3(DBG_STATS, "%s.%s: knp = %p\n", sip->ippsi_name, name, np);
1804*2951Selowe kstat_named_init(np, name, ktype);
18050Sstevel@tonic-gate mutex_exit(sip->ippsi_lock);
18060Sstevel@tonic-gate
18070Sstevel@tonic-gate return (0);
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate #undef __FN__
18100Sstevel@tonic-gate
18110Sstevel@tonic-gate #define __FN__ "ipp_stat_named_op"
18120Sstevel@tonic-gate int
ipp_stat_named_op(ipp_named_t * np,void * valp,int rw)18130Sstevel@tonic-gate ipp_stat_named_op(
18140Sstevel@tonic-gate ipp_named_t *np,
18150Sstevel@tonic-gate void *valp,
18160Sstevel@tonic-gate int rw)
18170Sstevel@tonic-gate {
18180Sstevel@tonic-gate kstat_named_t *knp;
18190Sstevel@tonic-gate uchar_t type;
18200Sstevel@tonic-gate int rc = 0;
18210Sstevel@tonic-gate
18220Sstevel@tonic-gate ASSERT(np != NULL);
18230Sstevel@tonic-gate ASSERT(valp != NULL);
18240Sstevel@tonic-gate
18250Sstevel@tonic-gate knp = np;
18260Sstevel@tonic-gate type = knp->data_type | IPP_STAT_TAG;
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate /*
18290Sstevel@tonic-gate * Copy data to or from the named kstat, depending on the specified
18300Sstevel@tonic-gate * opcode.
18310Sstevel@tonic-gate */
18320Sstevel@tonic-gate
18330Sstevel@tonic-gate switch (rw) {
18340Sstevel@tonic-gate case IPP_STAT_WRITE:
18350Sstevel@tonic-gate switch (type) {
18360Sstevel@tonic-gate case IPP_STAT_INT32:
18370Sstevel@tonic-gate *(int32_t *)valp = knp->value.i32;
18380Sstevel@tonic-gate break;
18390Sstevel@tonic-gate case IPP_STAT_UINT32:
18400Sstevel@tonic-gate *(uint32_t *)valp = knp->value.ui32;
18410Sstevel@tonic-gate break;
18420Sstevel@tonic-gate case IPP_STAT_INT64:
18430Sstevel@tonic-gate *(int64_t *)valp = knp->value.i64;
18440Sstevel@tonic-gate break;
18450Sstevel@tonic-gate case IPP_STAT_UINT64:
18460Sstevel@tonic-gate *(uint64_t *)valp = knp->value.ui64;
18470Sstevel@tonic-gate break;
18480Sstevel@tonic-gate case IPP_STAT_STRING:
18490Sstevel@tonic-gate (void) strncpy(valp, knp->value.c, 16);
18500Sstevel@tonic-gate break;
18510Sstevel@tonic-gate default:
18520Sstevel@tonic-gate ASSERT(0); /* should not reach here */
18530Sstevel@tonic-gate break;
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate break;
18570Sstevel@tonic-gate case IPP_STAT_READ:
18580Sstevel@tonic-gate switch (type) {
18590Sstevel@tonic-gate case IPP_STAT_INT32:
18600Sstevel@tonic-gate knp->value.i32 = *(int32_t *)valp;
18610Sstevel@tonic-gate break;
18620Sstevel@tonic-gate case IPP_STAT_UINT32:
18630Sstevel@tonic-gate knp->value.ui32 = *(uint32_t *)valp;
18640Sstevel@tonic-gate break;
18650Sstevel@tonic-gate case IPP_STAT_INT64:
18660Sstevel@tonic-gate knp->value.i64 = *(int64_t *)valp;
18670Sstevel@tonic-gate break;
18680Sstevel@tonic-gate case IPP_STAT_UINT64:
18690Sstevel@tonic-gate knp->value.ui64 = *(uint64_t *)valp;
18700Sstevel@tonic-gate break;
18710Sstevel@tonic-gate case IPP_STAT_STRING:
18720Sstevel@tonic-gate (void) strncpy(knp->value.c, valp, 16);
18730Sstevel@tonic-gate break;
18740Sstevel@tonic-gate default:
18750Sstevel@tonic-gate ASSERT(0); /* should not reach here */
18760Sstevel@tonic-gate break;
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate break;
18800Sstevel@tonic-gate default:
18810Sstevel@tonic-gate rc = EINVAL;
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate return (rc);
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate #undef __FN__
18870Sstevel@tonic-gate
18880Sstevel@tonic-gate /*
18890Sstevel@tonic-gate * Local functions (for local people. There's nothing for you here!)
18900Sstevel@tonic-gate */
18910Sstevel@tonic-gate
18920Sstevel@tonic-gate #define __FN__ "ref_mod"
18930Sstevel@tonic-gate static int
ref_mod(ipp_action_t * ap,ipp_mod_t * imp)18940Sstevel@tonic-gate ref_mod(
18950Sstevel@tonic-gate ipp_action_t *ap,
18960Sstevel@tonic-gate ipp_mod_t *imp)
18970Sstevel@tonic-gate {
18980Sstevel@tonic-gate ipp_ref_t **rpp;
18990Sstevel@tonic-gate ipp_ref_t *rp;
19000Sstevel@tonic-gate
19010Sstevel@tonic-gate ASSERT(rw_write_held(ap->ippa_lock));
19020Sstevel@tonic-gate ASSERT(rw_write_held(imp->ippm_lock));
19030Sstevel@tonic-gate
19040Sstevel@tonic-gate /*
19050Sstevel@tonic-gate * Add the new reference at the end of the module's list.
19060Sstevel@tonic-gate */
19070Sstevel@tonic-gate
19080Sstevel@tonic-gate rpp = &(imp->ippm_action);
19090Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
19100Sstevel@tonic-gate ASSERT(rp->ippr_action != ap);
19110Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
19120Sstevel@tonic-gate }
19130Sstevel@tonic-gate
19140Sstevel@tonic-gate /*
19150Sstevel@tonic-gate * Allocate a reference structure.
19160Sstevel@tonic-gate */
19170Sstevel@tonic-gate
19180Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
19190Sstevel@tonic-gate return (ENOMEM);
19200Sstevel@tonic-gate
19210Sstevel@tonic-gate /*
19220Sstevel@tonic-gate * Set the reference to the action and link it onto the module's list.
19230Sstevel@tonic-gate */
19240Sstevel@tonic-gate
19250Sstevel@tonic-gate rp->ippr_action = ap;
19260Sstevel@tonic-gate *rpp = rp;
19270Sstevel@tonic-gate
19280Sstevel@tonic-gate /*
19290Sstevel@tonic-gate * Keep a 'back pointer' from the action structure to the module
19300Sstevel@tonic-gate * structure.
19310Sstevel@tonic-gate */
19320Sstevel@tonic-gate
19330Sstevel@tonic-gate ap->ippa_mod = imp;
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate return (0);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate #undef __FN__
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate #define __FN__ "unref_mod"
19400Sstevel@tonic-gate static void
unref_mod(ipp_action_t * ap,ipp_mod_t * imp)19410Sstevel@tonic-gate unref_mod(
19420Sstevel@tonic-gate ipp_action_t *ap,
19430Sstevel@tonic-gate ipp_mod_t *imp)
19440Sstevel@tonic-gate {
19450Sstevel@tonic-gate ipp_ref_t **rpp;
19460Sstevel@tonic-gate ipp_ref_t *rp;
19470Sstevel@tonic-gate
19480Sstevel@tonic-gate ASSERT(rw_write_held(ap->ippa_lock));
19490Sstevel@tonic-gate ASSERT(rw_write_held(imp->ippm_lock));
19500Sstevel@tonic-gate
19510Sstevel@tonic-gate /*
19520Sstevel@tonic-gate * Scan the module's list for the reference to the action.
19530Sstevel@tonic-gate */
19540Sstevel@tonic-gate
19550Sstevel@tonic-gate rpp = &(imp->ippm_action);
19560Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
19570Sstevel@tonic-gate if (rp->ippr_action == ap)
19580Sstevel@tonic-gate break;
19590Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
19600Sstevel@tonic-gate }
19610Sstevel@tonic-gate ASSERT(rp != NULL);
19620Sstevel@tonic-gate
19630Sstevel@tonic-gate /*
19640Sstevel@tonic-gate * Unlink the reference structure and free it.
19650Sstevel@tonic-gate */
19660Sstevel@tonic-gate
19670Sstevel@tonic-gate *rpp = rp->ippr_nextp;
19680Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
19690Sstevel@tonic-gate
19700Sstevel@tonic-gate /*
19710Sstevel@tonic-gate * NULL the 'back pointer'.
19720Sstevel@tonic-gate */
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate ap->ippa_mod = NULL;
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate #undef __FN__
19770Sstevel@tonic-gate
19780Sstevel@tonic-gate #define __FN__ "is_mod_busy"
19790Sstevel@tonic-gate static int
is_mod_busy(ipp_mod_t * imp)19800Sstevel@tonic-gate is_mod_busy(
19810Sstevel@tonic-gate ipp_mod_t *imp)
19820Sstevel@tonic-gate {
19830Sstevel@tonic-gate /*
19840Sstevel@tonic-gate * Return a value which is true (non-zero) iff the module refers
19850Sstevel@tonic-gate * to no actions.
19860Sstevel@tonic-gate */
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate return (imp->ippm_action != NULL);
19890Sstevel@tonic-gate }
19900Sstevel@tonic-gate #undef __FN__
19910Sstevel@tonic-gate
19920Sstevel@tonic-gate #define __FN__ "get_mod_ref"
19930Sstevel@tonic-gate static int
get_mod_ref(ipp_mod_t * imp,ipp_action_id_t ** bufp,int * neltp)19940Sstevel@tonic-gate get_mod_ref(
19950Sstevel@tonic-gate ipp_mod_t *imp,
19960Sstevel@tonic-gate ipp_action_id_t **bufp,
19970Sstevel@tonic-gate int *neltp)
19980Sstevel@tonic-gate {
19990Sstevel@tonic-gate ipp_ref_t *rp;
20000Sstevel@tonic-gate int nelt;
20010Sstevel@tonic-gate ipp_action_t *ap;
20020Sstevel@tonic-gate ipp_action_id_t *buf;
20030Sstevel@tonic-gate int length;
20040Sstevel@tonic-gate
20050Sstevel@tonic-gate ASSERT(rw_lock_held(imp->ippm_lock));
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate /*
20080Sstevel@tonic-gate * Count the number of actions referred to from the module structure.
20090Sstevel@tonic-gate */
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate nelt = 0;
20120Sstevel@tonic-gate for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
20130Sstevel@tonic-gate nelt++;
20140Sstevel@tonic-gate }
20150Sstevel@tonic-gate DBG1(DBG_LIST, "%d actions found\n", nelt);
20160Sstevel@tonic-gate
20170Sstevel@tonic-gate /*
20180Sstevel@tonic-gate * If there are no actions referred to then there's nothing to do.
20190Sstevel@tonic-gate */
20200Sstevel@tonic-gate
20210Sstevel@tonic-gate if (nelt == 0) {
20220Sstevel@tonic-gate *bufp = NULL;
20230Sstevel@tonic-gate *neltp = 0;
20240Sstevel@tonic-gate return (0);
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate /*
20280Sstevel@tonic-gate * Allocate a buffer to pass back to the caller.
20290Sstevel@tonic-gate */
20300Sstevel@tonic-gate
20310Sstevel@tonic-gate length = nelt * sizeof (ipp_action_id_t);
20320Sstevel@tonic-gate if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL)
20330Sstevel@tonic-gate return (ENOMEM);
20340Sstevel@tonic-gate
20350Sstevel@tonic-gate /*
20360Sstevel@tonic-gate * Fill the buffer with an array of action ids.
20370Sstevel@tonic-gate */
20380Sstevel@tonic-gate
20390Sstevel@tonic-gate *bufp = buf;
20400Sstevel@tonic-gate *neltp = nelt;
20410Sstevel@tonic-gate
20420Sstevel@tonic-gate for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
20430Sstevel@tonic-gate ap = rp->ippr_action;
20440Sstevel@tonic-gate *buf++ = ap->ippa_id;
20450Sstevel@tonic-gate }
20460Sstevel@tonic-gate
20470Sstevel@tonic-gate ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
20480Sstevel@tonic-gate return (0);
20490Sstevel@tonic-gate }
20500Sstevel@tonic-gate #undef __FN__
20510Sstevel@tonic-gate
20520Sstevel@tonic-gate #define __FN__ "get_mods"
20530Sstevel@tonic-gate static int
get_mods(ipp_mod_id_t ** bufp,int * neltp)20540Sstevel@tonic-gate get_mods(
20550Sstevel@tonic-gate ipp_mod_id_t **bufp,
20560Sstevel@tonic-gate int *neltp)
20570Sstevel@tonic-gate {
20580Sstevel@tonic-gate ipp_mod_id_t *buf;
20590Sstevel@tonic-gate int length;
20600Sstevel@tonic-gate ipp_mod_id_t mid;
20610Sstevel@tonic-gate ipp_mod_t *imp;
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate
20640Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_READER);
20650Sstevel@tonic-gate
20660Sstevel@tonic-gate /*
20670Sstevel@tonic-gate * If there are no modules registered then there's nothing to do.
20680Sstevel@tonic-gate */
20690Sstevel@tonic-gate
20700Sstevel@tonic-gate if (ipp_mod_count == 0) {
20710Sstevel@tonic-gate DBG0(DBG_LIST, "no modules registered\n");
20720Sstevel@tonic-gate *bufp = NULL;
20730Sstevel@tonic-gate *neltp = 0;
20740Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
20750Sstevel@tonic-gate return (0);
20760Sstevel@tonic-gate }
20770Sstevel@tonic-gate
20780Sstevel@tonic-gate /*
20790Sstevel@tonic-gate * Allocate a buffer to pass back to the caller.
20800Sstevel@tonic-gate */
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate DBG1(DBG_LIST, "%d modules registered\n", ipp_mod_count);
20830Sstevel@tonic-gate length = ipp_mod_count * sizeof (ipp_mod_id_t);
20840Sstevel@tonic-gate if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) {
20850Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
20860Sstevel@tonic-gate return (ENOMEM);
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_READER);
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate /*
20920Sstevel@tonic-gate * Search the array of all modules.
20930Sstevel@tonic-gate */
20940Sstevel@tonic-gate
20950Sstevel@tonic-gate *bufp = buf;
20960Sstevel@tonic-gate *neltp = ipp_mod_count;
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate for (mid = IPP_MOD_RESERVED + 1; mid <= ipp_mid_limit; mid++) {
20990Sstevel@tonic-gate if ((imp = ipp_mod_byid[mid]) == NULL)
21000Sstevel@tonic-gate continue;
21010Sstevel@tonic-gate
21020Sstevel@tonic-gate /*
21030Sstevel@tonic-gate * If the module has 'destruct pending' set then it means it
21040Sstevel@tonic-gate * is either still in the cache (i.e not allocated) or in the
21050Sstevel@tonic-gate * process of being set up by alloc_mod().
21060Sstevel@tonic-gate */
21070Sstevel@tonic-gate
21080Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
21090Sstevel@tonic-gate ASSERT(imp->ippm_id == mid);
21100Sstevel@tonic-gate
21110Sstevel@tonic-gate if (imp->ippm_destruct_pending) {
21120Sstevel@tonic-gate UNLOCK_MOD(imp);
21130Sstevel@tonic-gate continue;
21140Sstevel@tonic-gate }
21150Sstevel@tonic-gate UNLOCK_MOD(imp);
21160Sstevel@tonic-gate
21170Sstevel@tonic-gate *buf++ = mid;
21180Sstevel@tonic-gate }
21190Sstevel@tonic-gate
21200Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
21210Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
21220Sstevel@tonic-gate
21230Sstevel@tonic-gate ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
21240Sstevel@tonic-gate return (0);
21250Sstevel@tonic-gate }
21260Sstevel@tonic-gate #undef __FN__
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate #define __FN__ "find_mod"
21290Sstevel@tonic-gate static ipp_mod_id_t
find_mod(const char * modname)21300Sstevel@tonic-gate find_mod(
21310Sstevel@tonic-gate const char *modname)
21320Sstevel@tonic-gate {
21330Sstevel@tonic-gate ipp_mod_id_t mid;
21340Sstevel@tonic-gate ipp_mod_t *imp;
21350Sstevel@tonic-gate ipp_ref_t *rp;
21360Sstevel@tonic-gate int hb;
21370Sstevel@tonic-gate
21380Sstevel@tonic-gate ASSERT(modname != NULL);
21390Sstevel@tonic-gate
21400Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_READER);
21410Sstevel@tonic-gate
21420Sstevel@tonic-gate /*
21430Sstevel@tonic-gate * Quick return if no modules are registered.
21440Sstevel@tonic-gate */
21450Sstevel@tonic-gate
21460Sstevel@tonic-gate if (ipp_mod_count == 0) {
21470Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
21480Sstevel@tonic-gate return (IPP_MOD_INVAL);
21490Sstevel@tonic-gate }
21500Sstevel@tonic-gate
21510Sstevel@tonic-gate /*
21520Sstevel@tonic-gate * Find the hash bucket where the module structure should be.
21530Sstevel@tonic-gate */
21540Sstevel@tonic-gate
21550Sstevel@tonic-gate hb = hash(modname);
21560Sstevel@tonic-gate rp = ipp_mod_byname[hb];
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate /*
21590Sstevel@tonic-gate * Scan the bucket for a match.
21600Sstevel@tonic-gate */
21610Sstevel@tonic-gate
21620Sstevel@tonic-gate while (rp != NULL) {
21630Sstevel@tonic-gate imp = rp->ippr_mod;
21640Sstevel@tonic-gate if (strcmp(imp->ippm_name, modname) == 0)
21650Sstevel@tonic-gate break;
21660Sstevel@tonic-gate rp = rp->ippr_nextp;
21670Sstevel@tonic-gate }
21680Sstevel@tonic-gate
21690Sstevel@tonic-gate if (rp == NULL) {
21700Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
21710Sstevel@tonic-gate return (IPP_MOD_INVAL);
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate if (imp->ippm_state == IPP_MODSTATE_PROTO) {
21750Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
21760Sstevel@tonic-gate return (IPP_MOD_INVAL);
21770Sstevel@tonic-gate }
21780Sstevel@tonic-gate
21790Sstevel@tonic-gate mid = imp->ippm_id;
21800Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
21810Sstevel@tonic-gate
21820Sstevel@tonic-gate return (mid);
21830Sstevel@tonic-gate }
21840Sstevel@tonic-gate #undef __FN__
21850Sstevel@tonic-gate
21860Sstevel@tonic-gate #define __FN__ "alloc_mod"
21870Sstevel@tonic-gate static int
alloc_mod(const char * modname,ipp_mod_id_t * midp)21880Sstevel@tonic-gate alloc_mod(
21890Sstevel@tonic-gate const char *modname,
21900Sstevel@tonic-gate ipp_mod_id_t *midp)
21910Sstevel@tonic-gate {
21920Sstevel@tonic-gate ipp_mod_t *imp;
21930Sstevel@tonic-gate ipp_ref_t **rpp;
21940Sstevel@tonic-gate ipp_ref_t *rp;
21950Sstevel@tonic-gate int hb;
21960Sstevel@tonic-gate
21970Sstevel@tonic-gate ASSERT(modname != NULL);
21980Sstevel@tonic-gate ASSERT(midp != NULL);
21990Sstevel@tonic-gate
22000Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_WRITER);
22010Sstevel@tonic-gate
22020Sstevel@tonic-gate /*
22030Sstevel@tonic-gate * Find the right hash bucket for a module of the given name.
22040Sstevel@tonic-gate */
22050Sstevel@tonic-gate
22060Sstevel@tonic-gate hb = hash(modname);
22070Sstevel@tonic-gate rpp = &ipp_mod_byname[hb];
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate /*
22100Sstevel@tonic-gate * Scan the bucket making sure the module isn't already
22110Sstevel@tonic-gate * registered.
22120Sstevel@tonic-gate */
22130Sstevel@tonic-gate
22140Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
22150Sstevel@tonic-gate imp = rp->ippr_mod;
22160Sstevel@tonic-gate if (strcmp(imp->ippm_name, modname) == 0) {
22170Sstevel@tonic-gate DBG1(DBG_MOD, "module '%s' already exists\n", modname);
22180Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
22190Sstevel@tonic-gate return (EEXIST);
22200Sstevel@tonic-gate }
22210Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
22220Sstevel@tonic-gate }
22230Sstevel@tonic-gate
22240Sstevel@tonic-gate /*
22250Sstevel@tonic-gate * Allocate a new reference structure and a new module structure.
22260Sstevel@tonic-gate */
22270Sstevel@tonic-gate
22280Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
22290Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
22300Sstevel@tonic-gate return (ENOMEM);
22310Sstevel@tonic-gate }
22320Sstevel@tonic-gate
22330Sstevel@tonic-gate if ((imp = kmem_cache_alloc(ipp_mod_cache, KM_NOSLEEP)) == NULL) {
22340Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
22350Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
22360Sstevel@tonic-gate return (ENOMEM);
22370Sstevel@tonic-gate }
22380Sstevel@tonic-gate
22390Sstevel@tonic-gate /*
22400Sstevel@tonic-gate * Set up the name of the new structure.
22410Sstevel@tonic-gate */
22420Sstevel@tonic-gate
22430Sstevel@tonic-gate (void) strcpy(imp->ippm_name, modname);
22440Sstevel@tonic-gate
22450Sstevel@tonic-gate /*
22460Sstevel@tonic-gate * Make sure the 'destruct pending' flag is clear. This indicates
22470Sstevel@tonic-gate * that the structure is no longer part of the cache.
22480Sstevel@tonic-gate */
22490Sstevel@tonic-gate
22500Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
22510Sstevel@tonic-gate imp->ippm_destruct_pending = B_FALSE;
22520Sstevel@tonic-gate UNLOCK_MOD(imp);
22530Sstevel@tonic-gate
22540Sstevel@tonic-gate /*
22550Sstevel@tonic-gate * Set the reference and link it into the hash bucket.
22560Sstevel@tonic-gate */
22570Sstevel@tonic-gate
22580Sstevel@tonic-gate rp->ippr_mod = imp;
22590Sstevel@tonic-gate *rpp = rp;
22600Sstevel@tonic-gate
22610Sstevel@tonic-gate /*
22620Sstevel@tonic-gate * Increment the module count.
22630Sstevel@tonic-gate */
22640Sstevel@tonic-gate
22650Sstevel@tonic-gate ipp_mod_count++;
22660Sstevel@tonic-gate
22670Sstevel@tonic-gate *midp = imp->ippm_id;
22680Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
22690Sstevel@tonic-gate return (0);
22700Sstevel@tonic-gate }
22710Sstevel@tonic-gate #undef __FN__
22720Sstevel@tonic-gate
22730Sstevel@tonic-gate #define __FN__ "free_mod"
22740Sstevel@tonic-gate static void
free_mod(ipp_mod_t * imp)22750Sstevel@tonic-gate free_mod(
22760Sstevel@tonic-gate ipp_mod_t *imp)
22770Sstevel@tonic-gate {
22780Sstevel@tonic-gate ipp_ref_t **rpp;
22790Sstevel@tonic-gate ipp_ref_t *rp;
22800Sstevel@tonic-gate int hb;
22810Sstevel@tonic-gate
22820Sstevel@tonic-gate rw_enter(ipp_mod_byname_lock, RW_WRITER);
22830Sstevel@tonic-gate
22840Sstevel@tonic-gate /*
22850Sstevel@tonic-gate * Find the hash bucket where the module structure should be.
22860Sstevel@tonic-gate */
22870Sstevel@tonic-gate
22880Sstevel@tonic-gate hb = hash(imp->ippm_name);
22890Sstevel@tonic-gate rpp = &ipp_mod_byname[hb];
22900Sstevel@tonic-gate
22910Sstevel@tonic-gate /*
22920Sstevel@tonic-gate * Scan the bucket for a match.
22930Sstevel@tonic-gate */
22940Sstevel@tonic-gate
22950Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
22960Sstevel@tonic-gate if (rp->ippr_mod == imp)
22970Sstevel@tonic-gate break;
22980Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
22990Sstevel@tonic-gate }
23000Sstevel@tonic-gate ASSERT(rp != NULL);
23010Sstevel@tonic-gate
23020Sstevel@tonic-gate /*
23030Sstevel@tonic-gate * Unlink the reference structure and free it.
23040Sstevel@tonic-gate */
23050Sstevel@tonic-gate
23060Sstevel@tonic-gate *rpp = rp->ippr_nextp;
23070Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
23080Sstevel@tonic-gate
23090Sstevel@tonic-gate /*
23100Sstevel@tonic-gate * Decrement the module count.
23110Sstevel@tonic-gate */
23120Sstevel@tonic-gate
23130Sstevel@tonic-gate ipp_mod_count--;
23140Sstevel@tonic-gate
23150Sstevel@tonic-gate /*
23160Sstevel@tonic-gate * Empty the name.
23170Sstevel@tonic-gate */
23180Sstevel@tonic-gate
23190Sstevel@tonic-gate *imp->ippm_name = '\0';
23200Sstevel@tonic-gate
23210Sstevel@tonic-gate /*
23220Sstevel@tonic-gate * If the hold count is zero then we can free the structure
23230Sstevel@tonic-gate * immediately, otherwise we defer to rele_mod().
23240Sstevel@tonic-gate */
23250Sstevel@tonic-gate
23260Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
23270Sstevel@tonic-gate imp->ippm_destruct_pending = B_TRUE;
23280Sstevel@tonic-gate if (imp->ippm_hold_count == 0) {
23290Sstevel@tonic-gate UNLOCK_MOD(imp);
23300Sstevel@tonic-gate kmem_cache_free(ipp_mod_cache, imp);
23310Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
23320Sstevel@tonic-gate return;
23330Sstevel@tonic-gate }
23340Sstevel@tonic-gate UNLOCK_MOD(imp);
23350Sstevel@tonic-gate
23360Sstevel@tonic-gate rw_exit(ipp_mod_byname_lock);
23370Sstevel@tonic-gate }
23380Sstevel@tonic-gate #undef __FN__
23390Sstevel@tonic-gate
23400Sstevel@tonic-gate #define __FN__ "hold_mod"
23410Sstevel@tonic-gate static ipp_mod_t *
hold_mod(ipp_mod_id_t mid)23420Sstevel@tonic-gate hold_mod(
23430Sstevel@tonic-gate ipp_mod_id_t mid)
23440Sstevel@tonic-gate {
23450Sstevel@tonic-gate ipp_mod_t *imp;
23460Sstevel@tonic-gate
23470Sstevel@tonic-gate if (mid < 0)
23480Sstevel@tonic-gate return (NULL);
23490Sstevel@tonic-gate
23500Sstevel@tonic-gate /*
23510Sstevel@tonic-gate * Use the module id as an index into the array of all module
23520Sstevel@tonic-gate * structures.
23530Sstevel@tonic-gate */
23540Sstevel@tonic-gate
23550Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_READER);
23560Sstevel@tonic-gate if ((imp = ipp_mod_byid[mid]) == NULL) {
23570Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
23580Sstevel@tonic-gate return (NULL);
23590Sstevel@tonic-gate }
23600Sstevel@tonic-gate
23610Sstevel@tonic-gate ASSERT(imp->ippm_id == mid);
23620Sstevel@tonic-gate
23630Sstevel@tonic-gate /*
23640Sstevel@tonic-gate * If the modul has 'destruct pending' set then it means it is either
23650Sstevel@tonic-gate * still in the cache (i.e not allocated) or in the process of
23660Sstevel@tonic-gate * being set up by alloc_mod().
23670Sstevel@tonic-gate */
23680Sstevel@tonic-gate
23690Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
23700Sstevel@tonic-gate if (imp->ippm_destruct_pending) {
23710Sstevel@tonic-gate UNLOCK_MOD(imp);
23720Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
23730Sstevel@tonic-gate return (NULL);
23740Sstevel@tonic-gate }
23750Sstevel@tonic-gate UNLOCK_MOD(imp);
23760Sstevel@tonic-gate
23770Sstevel@tonic-gate /*
23780Sstevel@tonic-gate * Increment the hold count to prevent the structure from being
23790Sstevel@tonic-gate * freed.
23800Sstevel@tonic-gate */
23810Sstevel@tonic-gate
23820Sstevel@tonic-gate atomic_add_32(&(imp->ippm_hold_count), 1);
23830Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
23840Sstevel@tonic-gate
23850Sstevel@tonic-gate return (imp);
23860Sstevel@tonic-gate }
23870Sstevel@tonic-gate #undef __FN__
23880Sstevel@tonic-gate
23890Sstevel@tonic-gate #define __FN__ "rele_mod"
23900Sstevel@tonic-gate static void
rele_mod(ipp_mod_t * imp)23910Sstevel@tonic-gate rele_mod(
23920Sstevel@tonic-gate ipp_mod_t *imp)
23930Sstevel@tonic-gate {
23940Sstevel@tonic-gate /*
23950Sstevel@tonic-gate * This call means we're done with the pointer so we can drop the
23960Sstevel@tonic-gate * hold count.
23970Sstevel@tonic-gate */
23980Sstevel@tonic-gate
23990Sstevel@tonic-gate ASSERT(imp->ippm_hold_count != 0);
24000Sstevel@tonic-gate atomic_add_32(&(imp->ippm_hold_count), -1);
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate /*
24030Sstevel@tonic-gate * If the structure has 'destruct pending' set then we tried to free
24040Sstevel@tonic-gate * it but couldn't, so do it now.
24050Sstevel@tonic-gate */
24060Sstevel@tonic-gate
24070Sstevel@tonic-gate LOCK_MOD(imp, RW_READER);
24080Sstevel@tonic-gate if (imp->ippm_destruct_pending && imp->ippm_hold_count == 0) {
24090Sstevel@tonic-gate UNLOCK_MOD(imp);
24100Sstevel@tonic-gate kmem_cache_free(ipp_mod_cache, imp);
24110Sstevel@tonic-gate return;
24120Sstevel@tonic-gate }
24130Sstevel@tonic-gate
24140Sstevel@tonic-gate UNLOCK_MOD(imp);
24150Sstevel@tonic-gate }
24160Sstevel@tonic-gate #undef __FN__
24170Sstevel@tonic-gate
24180Sstevel@tonic-gate #define __FN__ "get_mid"
24190Sstevel@tonic-gate static ipp_mod_id_t
get_mid(void)24200Sstevel@tonic-gate get_mid(
24210Sstevel@tonic-gate void)
24220Sstevel@tonic-gate {
24230Sstevel@tonic-gate int index;
24240Sstevel@tonic-gate int start;
24250Sstevel@tonic-gate int limit;
24260Sstevel@tonic-gate
24270Sstevel@tonic-gate ASSERT(rw_write_held(ipp_mod_byid_lock));
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate /*
24300Sstevel@tonic-gate * Start searching after the last module id we allocated.
24310Sstevel@tonic-gate */
24320Sstevel@tonic-gate
24330Sstevel@tonic-gate start = (int)ipp_next_mid;
24340Sstevel@tonic-gate limit = (int)ipp_mid_limit;
24350Sstevel@tonic-gate
24360Sstevel@tonic-gate /*
24370Sstevel@tonic-gate * Look for a spare slot in the array.
24380Sstevel@tonic-gate */
24390Sstevel@tonic-gate
24400Sstevel@tonic-gate index = start;
24410Sstevel@tonic-gate while (ipp_mod_byid[index] != NULL) {
24420Sstevel@tonic-gate index++;
24430Sstevel@tonic-gate if (index > limit)
24440Sstevel@tonic-gate index = IPP_MOD_RESERVED + 1;
24450Sstevel@tonic-gate if (index == start)
24460Sstevel@tonic-gate return (IPP_MOD_INVAL);
24470Sstevel@tonic-gate }
24480Sstevel@tonic-gate
24490Sstevel@tonic-gate /*
24500Sstevel@tonic-gate * Note that we've just allocated a new module id so that we can
24510Sstevel@tonic-gate * start our search there next time.
24520Sstevel@tonic-gate */
24530Sstevel@tonic-gate
24540Sstevel@tonic-gate index++;
24550Sstevel@tonic-gate if (index > limit) {
24560Sstevel@tonic-gate ipp_next_mid = IPP_MOD_RESERVED + 1;
24570Sstevel@tonic-gate } else
24580Sstevel@tonic-gate ipp_next_mid = (ipp_mod_id_t)index;
24590Sstevel@tonic-gate
24600Sstevel@tonic-gate return ((ipp_mod_id_t)(--index));
24610Sstevel@tonic-gate }
24620Sstevel@tonic-gate #undef __FN__
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate #define __FN__ "condemn_action"
24650Sstevel@tonic-gate static int
condemn_action(ipp_ref_t ** rpp,ipp_action_t * ap)24660Sstevel@tonic-gate condemn_action(
24670Sstevel@tonic-gate ipp_ref_t **rpp,
24680Sstevel@tonic-gate ipp_action_t *ap)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate ipp_ref_t *rp;
24710Sstevel@tonic-gate
24720Sstevel@tonic-gate DBG1(DBG_ACTION, "condemning action '%s'\n", ap->ippa_name);
24730Sstevel@tonic-gate
24740Sstevel@tonic-gate /*
24750Sstevel@tonic-gate * Check to see if the action is already condemned.
24760Sstevel@tonic-gate */
24770Sstevel@tonic-gate
24780Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
24790Sstevel@tonic-gate if (rp->ippr_action == ap)
24800Sstevel@tonic-gate break;
24810Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
24820Sstevel@tonic-gate }
24830Sstevel@tonic-gate
24840Sstevel@tonic-gate /*
24850Sstevel@tonic-gate * Create a new entry for the action.
24860Sstevel@tonic-gate */
24870Sstevel@tonic-gate
24880Sstevel@tonic-gate if (rp == NULL) {
24890Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
24900Sstevel@tonic-gate return (ENOMEM);
24910Sstevel@tonic-gate
24920Sstevel@tonic-gate rp->ippr_action = ap;
24930Sstevel@tonic-gate *rpp = rp;
24940Sstevel@tonic-gate }
24950Sstevel@tonic-gate
24960Sstevel@tonic-gate return (0);
24970Sstevel@tonic-gate }
24980Sstevel@tonic-gate #undef __FN__
24990Sstevel@tonic-gate
25000Sstevel@tonic-gate #define __FN__ "destroy_action"
25010Sstevel@tonic-gate static int
destroy_action(ipp_action_t * ap,ipp_flags_t flags)25020Sstevel@tonic-gate destroy_action(
25030Sstevel@tonic-gate ipp_action_t *ap,
25040Sstevel@tonic-gate ipp_flags_t flags)
25050Sstevel@tonic-gate {
25060Sstevel@tonic-gate ipp_ops_t *ippo;
25070Sstevel@tonic-gate ipp_mod_t *imp;
25080Sstevel@tonic-gate #define MAXWAIT 10
25090Sstevel@tonic-gate uint32_t wait;
25100Sstevel@tonic-gate int rc;
25110Sstevel@tonic-gate
25120Sstevel@tonic-gate /*
25130Sstevel@tonic-gate * Check that the action is available.
25140Sstevel@tonic-gate */
25150Sstevel@tonic-gate
25160Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
25170Sstevel@tonic-gate if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
25180Sstevel@tonic-gate UNLOCK_ACTION(ap);
25190Sstevel@tonic-gate rele_action(ap);
25200Sstevel@tonic-gate return (EPROTO);
25210Sstevel@tonic-gate }
25220Sstevel@tonic-gate
25230Sstevel@tonic-gate /*
25240Sstevel@tonic-gate * Note that the action is in the process of creation/destruction.
25250Sstevel@tonic-gate */
25260Sstevel@tonic-gate
25270Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
25280Sstevel@tonic-gate
25290Sstevel@tonic-gate /*
25300Sstevel@tonic-gate * Wait for the in-transit packet count for this action to fall to
25310Sstevel@tonic-gate * zero (checking at millisecond intervals).
25320Sstevel@tonic-gate *
25330Sstevel@tonic-gate * NOTE: no new packets will enter the action now that the
25340Sstevel@tonic-gate * state has been changed.
25350Sstevel@tonic-gate */
25360Sstevel@tonic-gate
25370Sstevel@tonic-gate for (wait = 0; ap->ippa_packets > 0 && wait < (MAXWAIT * 1000000);
25380Sstevel@tonic-gate wait += 1000) {
25390Sstevel@tonic-gate
25400Sstevel@tonic-gate /*
25410Sstevel@tonic-gate * NOTE: We can hang onto the lock because the packet count is
25420Sstevel@tonic-gate * decremented without needing to take the lock.
25430Sstevel@tonic-gate */
25440Sstevel@tonic-gate
25450Sstevel@tonic-gate drv_usecwait(1000);
25460Sstevel@tonic-gate }
25470Sstevel@tonic-gate
25480Sstevel@tonic-gate /*
25490Sstevel@tonic-gate * The packet count did not fall to zero.
25500Sstevel@tonic-gate */
25510Sstevel@tonic-gate if (ap->ippa_packets > 0) {
25520Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE;
25530Sstevel@tonic-gate UNLOCK_ACTION(ap);
25540Sstevel@tonic-gate rele_action(ap);
25550Sstevel@tonic-gate return (EAGAIN);
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate
25580Sstevel@tonic-gate /*
25590Sstevel@tonic-gate * Check to see if any other action has a dependency on this one.
25600Sstevel@tonic-gate */
25610Sstevel@tonic-gate
25620Sstevel@tonic-gate if (is_action_refd(ap)) {
25630Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE;
25640Sstevel@tonic-gate UNLOCK_ACTION(ap);
25650Sstevel@tonic-gate rele_action(ap);
25660Sstevel@tonic-gate return (EBUSY);
25670Sstevel@tonic-gate }
25680Sstevel@tonic-gate
25690Sstevel@tonic-gate imp = ap->ippa_mod;
25700Sstevel@tonic-gate ASSERT(imp != NULL);
25710Sstevel@tonic-gate UNLOCK_ACTION(ap);
25720Sstevel@tonic-gate
25730Sstevel@tonic-gate ippo = imp->ippm_ops;
25740Sstevel@tonic-gate ASSERT(ippo != NULL);
25750Sstevel@tonic-gate
25760Sstevel@tonic-gate /*
25770Sstevel@tonic-gate * Call into the module to destroy the action context.
25780Sstevel@tonic-gate */
25790Sstevel@tonic-gate
25800Sstevel@tonic-gate CONFIG_WRITE_START(ap);
25810Sstevel@tonic-gate DBG1(DBG_ACTION, "destroying action '%s'\n", ap->ippa_name);
25820Sstevel@tonic-gate if ((rc = ippo->ippo_action_destroy(ap->ippa_id, flags)) != 0) {
25830Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
25840Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_AVAILABLE;
25850Sstevel@tonic-gate UNLOCK_ACTION(ap);
25860Sstevel@tonic-gate
25870Sstevel@tonic-gate CONFIG_WRITE_END(ap);
25880Sstevel@tonic-gate
25890Sstevel@tonic-gate rele_action(ap);
25900Sstevel@tonic-gate return (rc);
25910Sstevel@tonic-gate }
25920Sstevel@tonic-gate CONFIG_WRITE_END(ap);
25930Sstevel@tonic-gate
25940Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
25950Sstevel@tonic-gate LOCK_MOD(imp, RW_WRITER);
25960Sstevel@tonic-gate unref_mod(ap, imp);
25970Sstevel@tonic-gate UNLOCK_MOD(imp);
25980Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO;
25990Sstevel@tonic-gate UNLOCK_ACTION(ap);
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate /*
26020Sstevel@tonic-gate * Free the action structure.
26030Sstevel@tonic-gate */
26040Sstevel@tonic-gate
26050Sstevel@tonic-gate ASSERT(ap->ippa_ref == NULL);
26060Sstevel@tonic-gate free_action(ap);
26070Sstevel@tonic-gate rele_action(ap);
26080Sstevel@tonic-gate return (0);
26090Sstevel@tonic-gate #undef MAXWAIT
26100Sstevel@tonic-gate }
26110Sstevel@tonic-gate #undef __FN__
26120Sstevel@tonic-gate
26130Sstevel@tonic-gate #define __FN__ "ref_action"
26140Sstevel@tonic-gate static int
ref_action(ipp_action_t * refby_ap,ipp_action_t * ref_ap)26150Sstevel@tonic-gate ref_action(
26160Sstevel@tonic-gate ipp_action_t *refby_ap,
26170Sstevel@tonic-gate ipp_action_t *ref_ap)
26180Sstevel@tonic-gate {
26190Sstevel@tonic-gate ipp_ref_t **rpp;
26200Sstevel@tonic-gate ipp_ref_t **save_rpp;
26210Sstevel@tonic-gate ipp_ref_t *rp;
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate ASSERT(rw_write_held(refby_ap->ippa_lock));
26240Sstevel@tonic-gate ASSERT(rw_write_held(ref_ap->ippa_lock));
26250Sstevel@tonic-gate
26260Sstevel@tonic-gate /*
26270Sstevel@tonic-gate * We want to add the new reference at the end of the refering
26280Sstevel@tonic-gate * action's list.
26290Sstevel@tonic-gate */
26300Sstevel@tonic-gate
26310Sstevel@tonic-gate rpp = &(refby_ap->ippa_ref);
26320Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
26330Sstevel@tonic-gate if (rp->ippr_action == ref_ap)
26340Sstevel@tonic-gate break;
26350Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
26360Sstevel@tonic-gate }
26370Sstevel@tonic-gate
26380Sstevel@tonic-gate if ((rp = *rpp) != NULL) {
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate /*
26410Sstevel@tonic-gate * There is an existing reference so increment its counter.
26420Sstevel@tonic-gate */
26430Sstevel@tonic-gate
26440Sstevel@tonic-gate rp->ippr_count++;
26450Sstevel@tonic-gate
26460Sstevel@tonic-gate /*
26470Sstevel@tonic-gate * Find the 'back pointer' and increment its counter too.
26480Sstevel@tonic-gate */
26490Sstevel@tonic-gate
26500Sstevel@tonic-gate rp = ref_ap->ippa_refby;
26510Sstevel@tonic-gate while (rp != NULL) {
26520Sstevel@tonic-gate if (rp->ippr_action == refby_ap)
26530Sstevel@tonic-gate break;
26540Sstevel@tonic-gate rp = rp->ippr_nextp;
26550Sstevel@tonic-gate }
26560Sstevel@tonic-gate ASSERT(rp != NULL);
26570Sstevel@tonic-gate
26580Sstevel@tonic-gate rp->ippr_count++;
26590Sstevel@tonic-gate } else {
26600Sstevel@tonic-gate
26610Sstevel@tonic-gate /*
26620Sstevel@tonic-gate * Allocate, fill in and link a new reference structure.
26630Sstevel@tonic-gate */
26640Sstevel@tonic-gate
26650Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
26660Sstevel@tonic-gate return (ENOMEM);
26670Sstevel@tonic-gate
26680Sstevel@tonic-gate rp->ippr_action = ref_ap;
26690Sstevel@tonic-gate rp->ippr_count = 1;
26700Sstevel@tonic-gate *rpp = rp;
26710Sstevel@tonic-gate save_rpp = rpp;
26720Sstevel@tonic-gate
26730Sstevel@tonic-gate /*
26740Sstevel@tonic-gate * We keep a 'back pointer' which we want to add at the end of
26750Sstevel@tonic-gate * a list in the referred action's structure.
26760Sstevel@tonic-gate */
26770Sstevel@tonic-gate
26780Sstevel@tonic-gate rpp = &(ref_ap->ippa_refby);
26790Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
26800Sstevel@tonic-gate ASSERT(rp->ippr_action != refby_ap);
26810Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
26820Sstevel@tonic-gate }
26830Sstevel@tonic-gate
26840Sstevel@tonic-gate /*
26850Sstevel@tonic-gate * Allocate another reference structure and, if this fails,
26860Sstevel@tonic-gate * remember to clean up the first reference structure we
26870Sstevel@tonic-gate * allocated.
26880Sstevel@tonic-gate */
26890Sstevel@tonic-gate
26900Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t),
26910Sstevel@tonic-gate KM_NOSLEEP)) == NULL) {
26920Sstevel@tonic-gate rpp = save_rpp;
26930Sstevel@tonic-gate rp = *rpp;
26940Sstevel@tonic-gate *rpp = NULL;
26950Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
26960Sstevel@tonic-gate
26970Sstevel@tonic-gate return (ENOMEM);
26980Sstevel@tonic-gate }
26990Sstevel@tonic-gate
27000Sstevel@tonic-gate /*
27010Sstevel@tonic-gate * Fill in the reference structure with the 'back pointer' and
27020Sstevel@tonic-gate * link it into the list.
27030Sstevel@tonic-gate */
27040Sstevel@tonic-gate
27050Sstevel@tonic-gate rp->ippr_action = refby_ap;
27060Sstevel@tonic-gate rp->ippr_count = 1;
27070Sstevel@tonic-gate *rpp = rp;
27080Sstevel@tonic-gate }
27090Sstevel@tonic-gate
27100Sstevel@tonic-gate return (0);
27110Sstevel@tonic-gate }
27120Sstevel@tonic-gate #undef __FN__
27130Sstevel@tonic-gate
27140Sstevel@tonic-gate #define __FN__ "unref_action"
27150Sstevel@tonic-gate static int
unref_action(ipp_action_t * refby_ap,ipp_action_t * ref_ap)27160Sstevel@tonic-gate unref_action(
27170Sstevel@tonic-gate ipp_action_t *refby_ap,
27180Sstevel@tonic-gate ipp_action_t *ref_ap)
27190Sstevel@tonic-gate {
27200Sstevel@tonic-gate ipp_ref_t **rpp;
27210Sstevel@tonic-gate ipp_ref_t *rp;
27220Sstevel@tonic-gate
27230Sstevel@tonic-gate ASSERT(rw_write_held(refby_ap->ippa_lock));
27240Sstevel@tonic-gate ASSERT(rw_write_held(ref_ap->ippa_lock));
27250Sstevel@tonic-gate
27260Sstevel@tonic-gate /*
27270Sstevel@tonic-gate * Scan for the reference in the referring action's list.
27280Sstevel@tonic-gate */
27290Sstevel@tonic-gate
27300Sstevel@tonic-gate rpp = &(refby_ap->ippa_ref);
27310Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
27320Sstevel@tonic-gate if (rp->ippr_action == ref_ap)
27330Sstevel@tonic-gate break;
27340Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
27350Sstevel@tonic-gate }
27360Sstevel@tonic-gate
27370Sstevel@tonic-gate if (rp == NULL)
27380Sstevel@tonic-gate return (ENOENT);
27390Sstevel@tonic-gate
27400Sstevel@tonic-gate if (rp->ippr_count > 1) {
27410Sstevel@tonic-gate
27420Sstevel@tonic-gate /*
27430Sstevel@tonic-gate * There are currently multiple references so decrement the
27440Sstevel@tonic-gate * count.
27450Sstevel@tonic-gate */
27460Sstevel@tonic-gate
27470Sstevel@tonic-gate rp->ippr_count--;
27480Sstevel@tonic-gate
27490Sstevel@tonic-gate /*
27500Sstevel@tonic-gate * Find the 'back pointer' and decrement its counter too.
27510Sstevel@tonic-gate */
27520Sstevel@tonic-gate
27530Sstevel@tonic-gate rp = ref_ap->ippa_refby;
27540Sstevel@tonic-gate while (rp != NULL) {
27550Sstevel@tonic-gate if (rp->ippr_action == refby_ap)
27560Sstevel@tonic-gate break;
27570Sstevel@tonic-gate rp = rp->ippr_nextp;
27580Sstevel@tonic-gate }
27590Sstevel@tonic-gate ASSERT(rp != NULL);
27600Sstevel@tonic-gate
27610Sstevel@tonic-gate rp->ippr_count--;
27620Sstevel@tonic-gate } else {
27630Sstevel@tonic-gate
27640Sstevel@tonic-gate /*
27650Sstevel@tonic-gate * There is currently only a single reference, so unlink and
27660Sstevel@tonic-gate * free the reference structure.
27670Sstevel@tonic-gate */
27680Sstevel@tonic-gate
27690Sstevel@tonic-gate *rpp = rp->ippr_nextp;
27700Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
27710Sstevel@tonic-gate
27720Sstevel@tonic-gate /*
27730Sstevel@tonic-gate * Scan for the 'back pointer' in the referred action's list.
27740Sstevel@tonic-gate */
27750Sstevel@tonic-gate
27760Sstevel@tonic-gate rpp = &(ref_ap->ippa_refby);
27770Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
27780Sstevel@tonic-gate if (rp->ippr_action == refby_ap)
27790Sstevel@tonic-gate break;
27800Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
27810Sstevel@tonic-gate }
27820Sstevel@tonic-gate ASSERT(rp != NULL);
27830Sstevel@tonic-gate
27840Sstevel@tonic-gate /*
27850Sstevel@tonic-gate * Unlink and free this reference structure too.
27860Sstevel@tonic-gate */
27870Sstevel@tonic-gate
27880Sstevel@tonic-gate *rpp = rp->ippr_nextp;
27890Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
27900Sstevel@tonic-gate }
27910Sstevel@tonic-gate
27920Sstevel@tonic-gate return (0);
27930Sstevel@tonic-gate }
27940Sstevel@tonic-gate #undef __FN__
27950Sstevel@tonic-gate
27960Sstevel@tonic-gate #define __FN__ "is_action_refd"
27970Sstevel@tonic-gate static int
is_action_refd(ipp_action_t * ap)27980Sstevel@tonic-gate is_action_refd(
27990Sstevel@tonic-gate ipp_action_t *ap)
28000Sstevel@tonic-gate {
28010Sstevel@tonic-gate /*
28020Sstevel@tonic-gate * Return a value which is true (non-zero) iff the action is not
28030Sstevel@tonic-gate * referred to by any other actions.
28040Sstevel@tonic-gate */
28050Sstevel@tonic-gate
28060Sstevel@tonic-gate return (ap->ippa_refby != NULL);
28070Sstevel@tonic-gate }
28080Sstevel@tonic-gate #undef __FN__
28090Sstevel@tonic-gate
28100Sstevel@tonic-gate #define __FN__ "find_action"
28110Sstevel@tonic-gate static ipp_action_id_t
find_action(const char * aname)28120Sstevel@tonic-gate find_action(
28130Sstevel@tonic-gate const char *aname)
28140Sstevel@tonic-gate {
28150Sstevel@tonic-gate ipp_action_id_t aid;
28160Sstevel@tonic-gate ipp_action_t *ap;
28170Sstevel@tonic-gate ipp_ref_t *rp;
28180Sstevel@tonic-gate int hb;
28190Sstevel@tonic-gate
28200Sstevel@tonic-gate ASSERT(aname != NULL);
28210Sstevel@tonic-gate
28220Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_READER);
28230Sstevel@tonic-gate
28240Sstevel@tonic-gate /*
28250Sstevel@tonic-gate * Quick return if there are no actions defined at all.
28260Sstevel@tonic-gate */
28270Sstevel@tonic-gate
28280Sstevel@tonic-gate if (ipp_action_count == 0) {
28290Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
28300Sstevel@tonic-gate return (IPP_ACTION_INVAL);
28310Sstevel@tonic-gate }
28320Sstevel@tonic-gate
28330Sstevel@tonic-gate /*
28340Sstevel@tonic-gate * Find the hash bucket where the action structure should be.
28350Sstevel@tonic-gate */
28360Sstevel@tonic-gate
28370Sstevel@tonic-gate hb = hash(aname);
28380Sstevel@tonic-gate rp = ipp_action_byname[hb];
28390Sstevel@tonic-gate
28400Sstevel@tonic-gate /*
28410Sstevel@tonic-gate * Scan the bucket looking for a match.
28420Sstevel@tonic-gate */
28430Sstevel@tonic-gate
28440Sstevel@tonic-gate while (rp != NULL) {
28450Sstevel@tonic-gate ap = rp->ippr_action;
28460Sstevel@tonic-gate if (strcmp(ap->ippa_name, aname) == 0)
28470Sstevel@tonic-gate break;
28480Sstevel@tonic-gate rp = rp->ippr_nextp;
28490Sstevel@tonic-gate }
28500Sstevel@tonic-gate
28510Sstevel@tonic-gate if (rp == NULL) {
28520Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
28530Sstevel@tonic-gate return (IPP_ACTION_INVAL);
28540Sstevel@tonic-gate }
28550Sstevel@tonic-gate
28560Sstevel@tonic-gate if (ap->ippa_state == IPP_ASTATE_PROTO) {
28570Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
28580Sstevel@tonic-gate return (IPP_ACTION_INVAL);
28590Sstevel@tonic-gate }
28600Sstevel@tonic-gate
28610Sstevel@tonic-gate aid = ap->ippa_id;
28620Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
28630Sstevel@tonic-gate
28640Sstevel@tonic-gate return (aid);
28650Sstevel@tonic-gate }
28660Sstevel@tonic-gate #undef __FN__
28670Sstevel@tonic-gate
28680Sstevel@tonic-gate #define __FN__ "alloc_action"
28690Sstevel@tonic-gate static int
alloc_action(const char * aname,ipp_action_id_t * aidp)28700Sstevel@tonic-gate alloc_action(
28710Sstevel@tonic-gate const char *aname,
28720Sstevel@tonic-gate ipp_action_id_t *aidp)
28730Sstevel@tonic-gate {
28740Sstevel@tonic-gate ipp_action_t *ap;
28750Sstevel@tonic-gate ipp_ref_t **rpp;
28760Sstevel@tonic-gate ipp_ref_t *rp;
28770Sstevel@tonic-gate int hb;
28780Sstevel@tonic-gate
28790Sstevel@tonic-gate ASSERT(aidp != NULL);
28800Sstevel@tonic-gate
28810Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_WRITER);
28820Sstevel@tonic-gate
28830Sstevel@tonic-gate /*
28840Sstevel@tonic-gate * Find the right hash bucket for an action of the given name.
28850Sstevel@tonic-gate * (Nameless actions always go in a special bucket).
28860Sstevel@tonic-gate */
28870Sstevel@tonic-gate
28880Sstevel@tonic-gate if (aname != NULL) {
28890Sstevel@tonic-gate hb = hash(aname);
28900Sstevel@tonic-gate rpp = &ipp_action_byname[hb];
28910Sstevel@tonic-gate } else
28920Sstevel@tonic-gate rpp = &ipp_action_noname;
28930Sstevel@tonic-gate
28940Sstevel@tonic-gate /*
28950Sstevel@tonic-gate * Scan the bucket to make sure that an action with the given name
28960Sstevel@tonic-gate * does not already exist.
28970Sstevel@tonic-gate */
28980Sstevel@tonic-gate
28990Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
29000Sstevel@tonic-gate ap = rp->ippr_action;
29010Sstevel@tonic-gate if (aname != NULL && strcmp(ap->ippa_name, aname) == 0) {
29020Sstevel@tonic-gate DBG1(DBG_ACTION, "action '%s' already exists\n",
29030Sstevel@tonic-gate aname);
29040Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
29050Sstevel@tonic-gate return (EEXIST);
29060Sstevel@tonic-gate }
29070Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
29080Sstevel@tonic-gate }
29090Sstevel@tonic-gate
29100Sstevel@tonic-gate /*
29110Sstevel@tonic-gate * Allocate a new reference structure and a new action structure.
29120Sstevel@tonic-gate */
29130Sstevel@tonic-gate
29140Sstevel@tonic-gate if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
29150Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
29160Sstevel@tonic-gate return (ENOMEM);
29170Sstevel@tonic-gate }
29180Sstevel@tonic-gate
29190Sstevel@tonic-gate if ((ap = kmem_cache_alloc(ipp_action_cache, KM_NOSLEEP)) == NULL) {
29200Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
29210Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
29220Sstevel@tonic-gate return (ENOMEM);
29230Sstevel@tonic-gate }
29240Sstevel@tonic-gate
29250Sstevel@tonic-gate /*
29260Sstevel@tonic-gate * Dream up a name if there isn't a real one and note that the action is
29270Sstevel@tonic-gate * really nameless.
29280Sstevel@tonic-gate */
29290Sstevel@tonic-gate
29300Sstevel@tonic-gate if (aname == NULL) {
29310Sstevel@tonic-gate (void) sprintf(ap->ippa_name, "$%08X", ap->ippa_id);
29320Sstevel@tonic-gate ap->ippa_nameless = B_TRUE;
29330Sstevel@tonic-gate } else
29340Sstevel@tonic-gate (void) strcpy(ap->ippa_name, aname);
29350Sstevel@tonic-gate
29360Sstevel@tonic-gate /*
29370Sstevel@tonic-gate * Make sure the 'destruct pending' flag is clear. This indicates that
29380Sstevel@tonic-gate * the structure is no longer part of the cache.
29390Sstevel@tonic-gate */
29400Sstevel@tonic-gate
29410Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
29420Sstevel@tonic-gate ap->ippa_destruct_pending = B_FALSE;
29430Sstevel@tonic-gate UNLOCK_ACTION(ap);
29440Sstevel@tonic-gate
29450Sstevel@tonic-gate /*
29460Sstevel@tonic-gate * Fill in the reference structure and lint it onto the list.
29470Sstevel@tonic-gate */
29480Sstevel@tonic-gate
29490Sstevel@tonic-gate rp->ippr_action = ap;
29500Sstevel@tonic-gate *rpp = rp;
29510Sstevel@tonic-gate
29520Sstevel@tonic-gate /*
29530Sstevel@tonic-gate * Increment the action count.
29540Sstevel@tonic-gate */
29550Sstevel@tonic-gate
29560Sstevel@tonic-gate ipp_action_count++;
29570Sstevel@tonic-gate
29580Sstevel@tonic-gate *aidp = ap->ippa_id;
29590Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
29600Sstevel@tonic-gate return (0);
29610Sstevel@tonic-gate }
29620Sstevel@tonic-gate #undef __FN__
29630Sstevel@tonic-gate
29640Sstevel@tonic-gate #define __FN__ "free_action"
29650Sstevel@tonic-gate static void
free_action(ipp_action_t * ap)29660Sstevel@tonic-gate free_action(
29670Sstevel@tonic-gate ipp_action_t *ap)
29680Sstevel@tonic-gate {
29690Sstevel@tonic-gate ipp_ref_t **rpp;
29700Sstevel@tonic-gate ipp_ref_t *rp;
29710Sstevel@tonic-gate int hb;
29720Sstevel@tonic-gate
29730Sstevel@tonic-gate rw_enter(ipp_action_byname_lock, RW_WRITER);
29740Sstevel@tonic-gate
29750Sstevel@tonic-gate /*
29760Sstevel@tonic-gate * Find the hash bucket where the action structure should be.
29770Sstevel@tonic-gate */
29780Sstevel@tonic-gate
29790Sstevel@tonic-gate if (!ap->ippa_nameless) {
29800Sstevel@tonic-gate hb = hash(ap->ippa_name);
29810Sstevel@tonic-gate rpp = &ipp_action_byname[hb];
29820Sstevel@tonic-gate } else
29830Sstevel@tonic-gate rpp = &ipp_action_noname;
29840Sstevel@tonic-gate
29850Sstevel@tonic-gate /*
29860Sstevel@tonic-gate * Scan the bucket for a match.
29870Sstevel@tonic-gate */
29880Sstevel@tonic-gate
29890Sstevel@tonic-gate while ((rp = *rpp) != NULL) {
29900Sstevel@tonic-gate if (rp->ippr_action == ap)
29910Sstevel@tonic-gate break;
29920Sstevel@tonic-gate rpp = &(rp->ippr_nextp);
29930Sstevel@tonic-gate }
29940Sstevel@tonic-gate ASSERT(rp != NULL);
29950Sstevel@tonic-gate
29960Sstevel@tonic-gate /*
29970Sstevel@tonic-gate * Unlink and free the reference structure.
29980Sstevel@tonic-gate */
29990Sstevel@tonic-gate
30000Sstevel@tonic-gate *rpp = rp->ippr_nextp;
30010Sstevel@tonic-gate kmem_free(rp, sizeof (ipp_ref_t));
30020Sstevel@tonic-gate
30030Sstevel@tonic-gate /*
30040Sstevel@tonic-gate * Decrement the action count.
30050Sstevel@tonic-gate */
30060Sstevel@tonic-gate
30070Sstevel@tonic-gate ipp_action_count--;
30080Sstevel@tonic-gate
30090Sstevel@tonic-gate /*
30100Sstevel@tonic-gate * Empty the name.
30110Sstevel@tonic-gate */
30120Sstevel@tonic-gate
30130Sstevel@tonic-gate *ap->ippa_name = '\0';
30140Sstevel@tonic-gate
30150Sstevel@tonic-gate /*
30160Sstevel@tonic-gate * If the hold count is zero then we can free the structure
30170Sstevel@tonic-gate * immediately, otherwise we defer to rele_action().
30180Sstevel@tonic-gate */
30190Sstevel@tonic-gate
30200Sstevel@tonic-gate LOCK_ACTION(ap, RW_WRITER);
30210Sstevel@tonic-gate ap->ippa_destruct_pending = B_TRUE;
30220Sstevel@tonic-gate if (ap->ippa_hold_count == 0) {
30230Sstevel@tonic-gate UNLOCK_ACTION(ap);
30240Sstevel@tonic-gate kmem_cache_free(ipp_action_cache, ap);
30250Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
30260Sstevel@tonic-gate return;
30270Sstevel@tonic-gate }
30280Sstevel@tonic-gate UNLOCK_ACTION(ap);
30290Sstevel@tonic-gate
30300Sstevel@tonic-gate rw_exit(ipp_action_byname_lock);
30310Sstevel@tonic-gate }
30320Sstevel@tonic-gate #undef __FN__
30330Sstevel@tonic-gate
30340Sstevel@tonic-gate #define __FN__ "hold_action"
30350Sstevel@tonic-gate static ipp_action_t *
hold_action(ipp_action_id_t aid)30360Sstevel@tonic-gate hold_action(
30370Sstevel@tonic-gate ipp_action_id_t aid)
30380Sstevel@tonic-gate {
30390Sstevel@tonic-gate ipp_action_t *ap;
30400Sstevel@tonic-gate
30410Sstevel@tonic-gate if (aid < 0)
30420Sstevel@tonic-gate return (NULL);
30430Sstevel@tonic-gate
30440Sstevel@tonic-gate /*
30450Sstevel@tonic-gate * Use the action id as an index into the array of all action
30460Sstevel@tonic-gate * structures.
30470Sstevel@tonic-gate */
30480Sstevel@tonic-gate
30490Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_READER);
30500Sstevel@tonic-gate if ((ap = ipp_action_byid[aid]) == NULL) {
30510Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
30520Sstevel@tonic-gate return (NULL);
30530Sstevel@tonic-gate }
30540Sstevel@tonic-gate
30550Sstevel@tonic-gate /*
30560Sstevel@tonic-gate * If the action has 'destruct pending' set then it means it is either
30570Sstevel@tonic-gate * still in the cache (i.e not allocated) or in the process of
30580Sstevel@tonic-gate * being set up by alloc_action().
30590Sstevel@tonic-gate */
30600Sstevel@tonic-gate
30610Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
30620Sstevel@tonic-gate if (ap->ippa_destruct_pending) {
30630Sstevel@tonic-gate UNLOCK_ACTION(ap);
30640Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
30650Sstevel@tonic-gate return (NULL);
30660Sstevel@tonic-gate }
30670Sstevel@tonic-gate UNLOCK_ACTION(ap);
30680Sstevel@tonic-gate
30690Sstevel@tonic-gate /*
30700Sstevel@tonic-gate * Increment the hold count to prevent the structure from being
30710Sstevel@tonic-gate * freed.
30720Sstevel@tonic-gate */
30730Sstevel@tonic-gate
30740Sstevel@tonic-gate atomic_add_32(&(ap->ippa_hold_count), 1);
30750Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
30760Sstevel@tonic-gate
30770Sstevel@tonic-gate return (ap);
30780Sstevel@tonic-gate }
30790Sstevel@tonic-gate #undef __FN__
30800Sstevel@tonic-gate
30810Sstevel@tonic-gate #define __FN__ "rele_action"
30820Sstevel@tonic-gate static void
rele_action(ipp_action_t * ap)30830Sstevel@tonic-gate rele_action(
30840Sstevel@tonic-gate ipp_action_t *ap)
30850Sstevel@tonic-gate {
30860Sstevel@tonic-gate /*
30870Sstevel@tonic-gate * This call means we're done with the pointer so we can drop the
30880Sstevel@tonic-gate * hold count.
30890Sstevel@tonic-gate */
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate ASSERT(ap->ippa_hold_count != 0);
30920Sstevel@tonic-gate atomic_add_32(&(ap->ippa_hold_count), -1);
30930Sstevel@tonic-gate
30940Sstevel@tonic-gate /*
30950Sstevel@tonic-gate * If the structure has 'destruct pending' set then we tried to free
30960Sstevel@tonic-gate * it but couldn't, so do it now.
30970Sstevel@tonic-gate */
30980Sstevel@tonic-gate
30990Sstevel@tonic-gate LOCK_ACTION(ap, RW_READER);
31000Sstevel@tonic-gate if (ap->ippa_destruct_pending && ap->ippa_hold_count == 0) {
31010Sstevel@tonic-gate UNLOCK_ACTION(ap);
31020Sstevel@tonic-gate kmem_cache_free(ipp_action_cache, ap);
31030Sstevel@tonic-gate return;
31040Sstevel@tonic-gate }
31050Sstevel@tonic-gate UNLOCK_ACTION(ap);
31060Sstevel@tonic-gate }
31070Sstevel@tonic-gate #undef __FN__
31080Sstevel@tonic-gate
31090Sstevel@tonic-gate #define __FN__ "get_aid"
31100Sstevel@tonic-gate static ipp_action_id_t
get_aid(void)31110Sstevel@tonic-gate get_aid(
31120Sstevel@tonic-gate void)
31130Sstevel@tonic-gate {
31140Sstevel@tonic-gate int index;
31150Sstevel@tonic-gate int start;
31160Sstevel@tonic-gate int limit;
31170Sstevel@tonic-gate
31180Sstevel@tonic-gate ASSERT(rw_write_held(ipp_action_byid_lock));
31190Sstevel@tonic-gate
31200Sstevel@tonic-gate /*
31210Sstevel@tonic-gate * Start searching after the last action id that we allocated.
31220Sstevel@tonic-gate */
31230Sstevel@tonic-gate
31240Sstevel@tonic-gate start = (int)ipp_next_aid;
31250Sstevel@tonic-gate limit = (int)ipp_aid_limit;
31260Sstevel@tonic-gate
31270Sstevel@tonic-gate /*
31280Sstevel@tonic-gate * Look for a spare slot in the array.
31290Sstevel@tonic-gate */
31300Sstevel@tonic-gate
31310Sstevel@tonic-gate index = start;
31320Sstevel@tonic-gate while (ipp_action_byid[index] != NULL) {
31330Sstevel@tonic-gate index++;
31340Sstevel@tonic-gate if (index > limit)
31350Sstevel@tonic-gate index = IPP_ACTION_RESERVED + 1;
31360Sstevel@tonic-gate if (index == start)
31370Sstevel@tonic-gate return (IPP_ACTION_INVAL);
31380Sstevel@tonic-gate }
31390Sstevel@tonic-gate
31400Sstevel@tonic-gate /*
31410Sstevel@tonic-gate * Note that we've just allocated a new action id so that we can
31420Sstevel@tonic-gate * start our search there next time.
31430Sstevel@tonic-gate */
31440Sstevel@tonic-gate
31450Sstevel@tonic-gate index++;
31460Sstevel@tonic-gate if (index > limit)
31470Sstevel@tonic-gate ipp_next_aid = IPP_ACTION_RESERVED + 1;
31480Sstevel@tonic-gate else
31490Sstevel@tonic-gate ipp_next_aid = (ipp_action_id_t)index;
31500Sstevel@tonic-gate
31510Sstevel@tonic-gate return ((ipp_action_id_t)(--index));
31520Sstevel@tonic-gate }
31530Sstevel@tonic-gate #undef __FN__
31540Sstevel@tonic-gate
31550Sstevel@tonic-gate #define __FN__ "alloc_packet"
31560Sstevel@tonic-gate static int
alloc_packet(const char * name,ipp_action_id_t aid,ipp_packet_t ** ppp)31570Sstevel@tonic-gate alloc_packet(
31580Sstevel@tonic-gate const char *name,
31590Sstevel@tonic-gate ipp_action_id_t aid,
31600Sstevel@tonic-gate ipp_packet_t **ppp)
31610Sstevel@tonic-gate {
31620Sstevel@tonic-gate ipp_packet_t *pp;
31630Sstevel@tonic-gate ipp_class_t *cp;
31640Sstevel@tonic-gate
31650Sstevel@tonic-gate if ((pp = kmem_cache_alloc(ipp_packet_cache, KM_NOSLEEP)) == NULL)
31660Sstevel@tonic-gate return (ENOMEM);
31670Sstevel@tonic-gate
31680Sstevel@tonic-gate /*
31690Sstevel@tonic-gate * Set the packet up with a single class.
31700Sstevel@tonic-gate */
31710Sstevel@tonic-gate
31720Sstevel@tonic-gate cp = &(pp->ippp_class_array[0]);
31730Sstevel@tonic-gate pp->ippp_class_windex = 1;
31740Sstevel@tonic-gate
31750Sstevel@tonic-gate (void) strcpy(cp->ippc_name, name);
31760Sstevel@tonic-gate cp->ippc_aid = aid;
31770Sstevel@tonic-gate
31780Sstevel@tonic-gate *ppp = pp;
31790Sstevel@tonic-gate return (0);
31800Sstevel@tonic-gate }
31810Sstevel@tonic-gate #undef __FN__
31820Sstevel@tonic-gate
31830Sstevel@tonic-gate #define __FN__ "realloc_packet"
31840Sstevel@tonic-gate static int
realloc_packet(ipp_packet_t * pp)31850Sstevel@tonic-gate realloc_packet(
31860Sstevel@tonic-gate ipp_packet_t *pp)
31870Sstevel@tonic-gate {
31880Sstevel@tonic-gate uint_t length;
31890Sstevel@tonic-gate ipp_class_t *array;
31900Sstevel@tonic-gate
31910Sstevel@tonic-gate length = (pp->ippp_class_limit + 1) << 1;
31920Sstevel@tonic-gate if ((array = kmem_alloc(length * sizeof (ipp_class_t),
31930Sstevel@tonic-gate KM_NOSLEEP)) == NULL)
31940Sstevel@tonic-gate return (ENOMEM);
31950Sstevel@tonic-gate
31960Sstevel@tonic-gate bcopy(pp->ippp_class_array, array,
31970Sstevel@tonic-gate (length >> 1) * sizeof (ipp_class_t));
31980Sstevel@tonic-gate
31990Sstevel@tonic-gate kmem_free(pp->ippp_class_array,
32000Sstevel@tonic-gate (length >> 1) * sizeof (ipp_class_t));
32010Sstevel@tonic-gate
32020Sstevel@tonic-gate pp->ippp_class_array = array;
32030Sstevel@tonic-gate pp->ippp_class_limit = length - 1;
32040Sstevel@tonic-gate
32050Sstevel@tonic-gate return (0);
32060Sstevel@tonic-gate }
32070Sstevel@tonic-gate #undef __FN__
32080Sstevel@tonic-gate
32090Sstevel@tonic-gate #define __FN__ "free_packet"
32100Sstevel@tonic-gate static void
free_packet(ipp_packet_t * pp)32110Sstevel@tonic-gate free_packet(
32120Sstevel@tonic-gate ipp_packet_t *pp)
32130Sstevel@tonic-gate {
32140Sstevel@tonic-gate pp->ippp_class_windex = 0;
32150Sstevel@tonic-gate pp->ippp_class_rindex = 0;
32160Sstevel@tonic-gate
32170Sstevel@tonic-gate pp->ippp_data = NULL;
32180Sstevel@tonic-gate pp->ippp_private = NULL;
32190Sstevel@tonic-gate
32200Sstevel@tonic-gate kmem_cache_free(ipp_packet_cache, pp);
32210Sstevel@tonic-gate }
32220Sstevel@tonic-gate #undef __FN__
32230Sstevel@tonic-gate
32240Sstevel@tonic-gate #define __FN__ "hash"
32250Sstevel@tonic-gate static int
hash(const char * name)32260Sstevel@tonic-gate hash(
32270Sstevel@tonic-gate const char *name)
32280Sstevel@tonic-gate {
32290Sstevel@tonic-gate int val = 0;
32300Sstevel@tonic-gate char *ptr;
32310Sstevel@tonic-gate
32320Sstevel@tonic-gate /*
32330Sstevel@tonic-gate * Make a hash value by XORing all the ascii codes in the text string.
32340Sstevel@tonic-gate */
32350Sstevel@tonic-gate
32360Sstevel@tonic-gate for (ptr = (char *)name; *ptr != NULL; ptr++) {
32370Sstevel@tonic-gate val ^= *ptr;
32380Sstevel@tonic-gate }
32390Sstevel@tonic-gate
32400Sstevel@tonic-gate /*
32410Sstevel@tonic-gate * Return the value modulo the number of hash buckets we allow.
32420Sstevel@tonic-gate */
32430Sstevel@tonic-gate
32440Sstevel@tonic-gate return (val % IPP_NBUCKET);
32450Sstevel@tonic-gate }
32460Sstevel@tonic-gate #undef __FN__
32470Sstevel@tonic-gate
32480Sstevel@tonic-gate #define __FN__ "update_stats"
32490Sstevel@tonic-gate static int
update_stats(kstat_t * ksp,int rw)32500Sstevel@tonic-gate update_stats(
32510Sstevel@tonic-gate kstat_t *ksp,
32520Sstevel@tonic-gate int rw)
32530Sstevel@tonic-gate {
32540Sstevel@tonic-gate ipp_stat_impl_t *sip;
32550Sstevel@tonic-gate
32560Sstevel@tonic-gate ASSERT(ksp->ks_private != NULL);
32570Sstevel@tonic-gate sip = (ipp_stat_impl_t *)ksp->ks_private;
32580Sstevel@tonic-gate
32590Sstevel@tonic-gate /*
32600Sstevel@tonic-gate * Call the update function passed to ipp_stat_create() for the given
32610Sstevel@tonic-gate * set of kstats.
32620Sstevel@tonic-gate */
32630Sstevel@tonic-gate
32640Sstevel@tonic-gate return (sip->ippsi_update((ipp_stat_t *)sip, sip->ippsi_arg, rw));
32650Sstevel@tonic-gate }
32660Sstevel@tonic-gate #undef __FN__
32670Sstevel@tonic-gate
32680Sstevel@tonic-gate #define __FN__ "init_mods"
32690Sstevel@tonic-gate static void
init_mods(void)32700Sstevel@tonic-gate init_mods(
32710Sstevel@tonic-gate void)
32720Sstevel@tonic-gate {
32730Sstevel@tonic-gate /*
32740Sstevel@tonic-gate * Initialise the array of all module structures and the module
32750Sstevel@tonic-gate * structure kmem cache.
32760Sstevel@tonic-gate */
32770Sstevel@tonic-gate
32780Sstevel@tonic-gate rw_init(ipp_mod_byid_lock, NULL, RW_DEFAULT,
32790Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
32800Sstevel@tonic-gate ipp_mod_byid = kmem_zalloc(sizeof (ipp_mod_t *) * (ipp_max_mod + 1),
32810Sstevel@tonic-gate KM_SLEEP);
32820Sstevel@tonic-gate ipp_mod_byid[ipp_max_mod] = (ipp_mod_t *)-1;
32830Sstevel@tonic-gate ipp_mid_limit = (ipp_mod_id_t)(ipp_max_mod - 1);
32840Sstevel@tonic-gate
32850Sstevel@tonic-gate ipp_mod_cache = kmem_cache_create("ipp_mod", sizeof (ipp_mod_t),
32860Sstevel@tonic-gate IPP_ALIGN, mod_constructor, mod_destructor, NULL, NULL, NULL, 0);
32870Sstevel@tonic-gate ASSERT(ipp_mod_cache != NULL);
32880Sstevel@tonic-gate
32890Sstevel@tonic-gate /*
32900Sstevel@tonic-gate * Initialize the 'module by name' hash bucket array.
32910Sstevel@tonic-gate */
32920Sstevel@tonic-gate
32930Sstevel@tonic-gate rw_init(ipp_mod_byname_lock, NULL, RW_DEFAULT,
32940Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
32950Sstevel@tonic-gate bzero(ipp_mod_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
32960Sstevel@tonic-gate }
32970Sstevel@tonic-gate #undef __FN__
32980Sstevel@tonic-gate
32990Sstevel@tonic-gate #define __FN__ "init_actions"
33000Sstevel@tonic-gate static void
init_actions(void)33010Sstevel@tonic-gate init_actions(
33020Sstevel@tonic-gate void)
33030Sstevel@tonic-gate {
33040Sstevel@tonic-gate /*
33050Sstevel@tonic-gate * Initialise the array of all action structures and the action
33060Sstevel@tonic-gate * structure cache.
33070Sstevel@tonic-gate */
33080Sstevel@tonic-gate
33090Sstevel@tonic-gate rw_init(ipp_action_byid_lock, NULL, RW_DEFAULT,
33100Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
33110Sstevel@tonic-gate ipp_action_byid = kmem_zalloc(sizeof (ipp_action_t *) *
33120Sstevel@tonic-gate (ipp_max_action + 1), KM_SLEEP);
33130Sstevel@tonic-gate ipp_action_byid[ipp_max_action] = (ipp_action_t *)-1;
33140Sstevel@tonic-gate ipp_aid_limit = (ipp_action_id_t)(ipp_max_action - 1);
33150Sstevel@tonic-gate
33160Sstevel@tonic-gate ipp_action_cache = kmem_cache_create("ipp_action",
33170Sstevel@tonic-gate sizeof (ipp_action_t), IPP_ALIGN, action_constructor,
33180Sstevel@tonic-gate action_destructor, NULL, NULL, NULL, 0);
33190Sstevel@tonic-gate ASSERT(ipp_action_cache != NULL);
33200Sstevel@tonic-gate
33210Sstevel@tonic-gate /*
33220Sstevel@tonic-gate * Initialize the 'action by name' hash bucket array (and the special
33230Sstevel@tonic-gate * 'hash' bucket for nameless actions).
33240Sstevel@tonic-gate */
33250Sstevel@tonic-gate
33260Sstevel@tonic-gate rw_init(ipp_action_byname_lock, NULL, RW_DEFAULT,
33270Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
33280Sstevel@tonic-gate bzero(ipp_action_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
33290Sstevel@tonic-gate ipp_action_noname = NULL;
33300Sstevel@tonic-gate }
33310Sstevel@tonic-gate #undef __FN__
33320Sstevel@tonic-gate
33330Sstevel@tonic-gate #define __FN__ "init_packets"
33340Sstevel@tonic-gate static void
init_packets(void)33350Sstevel@tonic-gate init_packets(
33360Sstevel@tonic-gate void)
33370Sstevel@tonic-gate {
33380Sstevel@tonic-gate /*
33390Sstevel@tonic-gate * Initialise the packet structure cache.
33400Sstevel@tonic-gate */
33410Sstevel@tonic-gate
33420Sstevel@tonic-gate ipp_packet_cache = kmem_cache_create("ipp_packet",
33430Sstevel@tonic-gate sizeof (ipp_packet_t), IPP_ALIGN, packet_constructor,
33440Sstevel@tonic-gate packet_destructor, NULL, NULL, NULL, 0);
33450Sstevel@tonic-gate ASSERT(ipp_packet_cache != NULL);
33460Sstevel@tonic-gate }
33470Sstevel@tonic-gate #undef __FN__
33480Sstevel@tonic-gate
33490Sstevel@tonic-gate /*
33500Sstevel@tonic-gate * Kmem cache constructor/destructor functions.
33510Sstevel@tonic-gate */
33520Sstevel@tonic-gate
33530Sstevel@tonic-gate #define __FN__ "mod_constructor"
33540Sstevel@tonic-gate /*ARGSUSED*/
33550Sstevel@tonic-gate static int
mod_constructor(void * buf,void * cdrarg,int kmflags)33560Sstevel@tonic-gate mod_constructor(
33570Sstevel@tonic-gate void *buf,
33580Sstevel@tonic-gate void *cdrarg,
33590Sstevel@tonic-gate int kmflags)
33600Sstevel@tonic-gate {
33610Sstevel@tonic-gate ipp_mod_t *imp;
33620Sstevel@tonic-gate ipp_mod_id_t mid;
33630Sstevel@tonic-gate
33640Sstevel@tonic-gate ASSERT(buf != NULL);
33650Sstevel@tonic-gate bzero(buf, sizeof (ipp_mod_t));
33660Sstevel@tonic-gate imp = (ipp_mod_t *)buf;
33670Sstevel@tonic-gate
33680Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_WRITER);
33690Sstevel@tonic-gate
33700Sstevel@tonic-gate /*
33710Sstevel@tonic-gate * Get a new module id.
33720Sstevel@tonic-gate */
33730Sstevel@tonic-gate
33740Sstevel@tonic-gate if ((mid = get_mid()) <= IPP_MOD_RESERVED) {
33750Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
33760Sstevel@tonic-gate return (-1);
33770Sstevel@tonic-gate }
33780Sstevel@tonic-gate
33790Sstevel@tonic-gate /*
33800Sstevel@tonic-gate * Initialize the buffer as a module structure in PROTO form.
33810Sstevel@tonic-gate */
33820Sstevel@tonic-gate
33830Sstevel@tonic-gate imp->ippm_destruct_pending = B_TRUE;
33840Sstevel@tonic-gate imp->ippm_state = IPP_MODSTATE_PROTO;
33850Sstevel@tonic-gate rw_init(imp->ippm_lock, NULL, RW_DEFAULT,
33860Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate /*
33890Sstevel@tonic-gate * Insert it into the array of all module structures.
33900Sstevel@tonic-gate */
33910Sstevel@tonic-gate
33920Sstevel@tonic-gate imp->ippm_id = mid;
33930Sstevel@tonic-gate ipp_mod_byid[mid] = imp;
33940Sstevel@tonic-gate
33950Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
33960Sstevel@tonic-gate
33970Sstevel@tonic-gate return (0);
33980Sstevel@tonic-gate }
33990Sstevel@tonic-gate #undef __FN__
34000Sstevel@tonic-gate
34010Sstevel@tonic-gate #define __FN__ "mod_destructor"
34020Sstevel@tonic-gate /*ARGSUSED*/
34030Sstevel@tonic-gate static void
mod_destructor(void * buf,void * cdrarg)34040Sstevel@tonic-gate mod_destructor(
34050Sstevel@tonic-gate void *buf,
34060Sstevel@tonic-gate void *cdrarg)
34070Sstevel@tonic-gate {
34080Sstevel@tonic-gate ipp_mod_t *imp;
34090Sstevel@tonic-gate
34100Sstevel@tonic-gate ASSERT(buf != NULL);
34110Sstevel@tonic-gate imp = (ipp_mod_t *)buf;
34120Sstevel@tonic-gate
34130Sstevel@tonic-gate ASSERT(imp->ippm_state == IPP_MODSTATE_PROTO);
34140Sstevel@tonic-gate ASSERT(imp->ippm_action == NULL);
34150Sstevel@tonic-gate ASSERT(*imp->ippm_name == '\0');
34160Sstevel@tonic-gate ASSERT(imp->ippm_destruct_pending);
34170Sstevel@tonic-gate
34180Sstevel@tonic-gate rw_enter(ipp_mod_byid_lock, RW_WRITER);
34190Sstevel@tonic-gate ASSERT(imp->ippm_hold_count == 0);
34200Sstevel@tonic-gate
34210Sstevel@tonic-gate /*
34220Sstevel@tonic-gate * NULL the entry in the array of all module structures.
34230Sstevel@tonic-gate */
34240Sstevel@tonic-gate
34250Sstevel@tonic-gate ipp_mod_byid[imp->ippm_id] = NULL;
34260Sstevel@tonic-gate
34270Sstevel@tonic-gate /*
34280Sstevel@tonic-gate * Clean up any remnants of the module structure as the buffer is
34290Sstevel@tonic-gate * about to disappear.
34300Sstevel@tonic-gate */
34310Sstevel@tonic-gate
34320Sstevel@tonic-gate rw_destroy(imp->ippm_lock);
34330Sstevel@tonic-gate rw_exit(ipp_mod_byid_lock);
34340Sstevel@tonic-gate }
34350Sstevel@tonic-gate #undef __FN__
34360Sstevel@tonic-gate
34370Sstevel@tonic-gate #define __FN__ "action_constructor"
34380Sstevel@tonic-gate /*ARGSUSED*/
34390Sstevel@tonic-gate static int
action_constructor(void * buf,void * cdrarg,int kmflags)34400Sstevel@tonic-gate action_constructor(
34410Sstevel@tonic-gate void *buf,
34420Sstevel@tonic-gate void *cdrarg,
34430Sstevel@tonic-gate int kmflags)
34440Sstevel@tonic-gate {
34450Sstevel@tonic-gate ipp_action_t *ap;
34460Sstevel@tonic-gate ipp_action_id_t aid;
34470Sstevel@tonic-gate
34480Sstevel@tonic-gate ASSERT(buf != NULL);
34490Sstevel@tonic-gate bzero(buf, sizeof (ipp_action_t));
34500Sstevel@tonic-gate ap = (ipp_action_t *)buf;
34510Sstevel@tonic-gate
34520Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_WRITER);
34530Sstevel@tonic-gate
34540Sstevel@tonic-gate /*
34550Sstevel@tonic-gate * Get a new action id.
34560Sstevel@tonic-gate */
34570Sstevel@tonic-gate
34580Sstevel@tonic-gate if ((aid = get_aid()) <= IPP_ACTION_RESERVED) {
34590Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
34600Sstevel@tonic-gate return (-1);
34610Sstevel@tonic-gate }
34620Sstevel@tonic-gate
34630Sstevel@tonic-gate /*
34640Sstevel@tonic-gate * Initialize the buffer as an action structure in PROTO form.
34650Sstevel@tonic-gate */
34660Sstevel@tonic-gate
34670Sstevel@tonic-gate ap->ippa_state = IPP_ASTATE_PROTO;
34680Sstevel@tonic-gate ap->ippa_destruct_pending = B_TRUE;
34690Sstevel@tonic-gate rw_init(ap->ippa_lock, NULL, RW_DEFAULT,
34700Sstevel@tonic-gate (void *)ipltospl(LOCK_LEVEL));
34710Sstevel@tonic-gate CONFIG_LOCK_INIT(ap->ippa_config_lock);
34720Sstevel@tonic-gate
34730Sstevel@tonic-gate /*
34740Sstevel@tonic-gate * Insert it into the array of all action structures.
34750Sstevel@tonic-gate */
34760Sstevel@tonic-gate
34770Sstevel@tonic-gate ap->ippa_id = aid;
34780Sstevel@tonic-gate ipp_action_byid[aid] = ap;
34790Sstevel@tonic-gate
34800Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
34810Sstevel@tonic-gate return (0);
34820Sstevel@tonic-gate }
34830Sstevel@tonic-gate #undef __FN__
34840Sstevel@tonic-gate
34850Sstevel@tonic-gate #define __FN__ "action_destructor"
34860Sstevel@tonic-gate /*ARGSUSED*/
34870Sstevel@tonic-gate static void
action_destructor(void * buf,void * cdrarg)34880Sstevel@tonic-gate action_destructor(
34890Sstevel@tonic-gate void *buf,
34900Sstevel@tonic-gate void *cdrarg)
34910Sstevel@tonic-gate {
34920Sstevel@tonic-gate ipp_action_t *ap;
34930Sstevel@tonic-gate
34940Sstevel@tonic-gate ASSERT(buf != NULL);
34950Sstevel@tonic-gate ap = (ipp_action_t *)buf;
34960Sstevel@tonic-gate
34970Sstevel@tonic-gate ASSERT(ap->ippa_state == IPP_ASTATE_PROTO);
34980Sstevel@tonic-gate ASSERT(ap->ippa_ref == NULL);
34990Sstevel@tonic-gate ASSERT(ap->ippa_refby == NULL);
35000Sstevel@tonic-gate ASSERT(ap->ippa_packets == 0);
35010Sstevel@tonic-gate ASSERT(*ap->ippa_name == '\0');
35020Sstevel@tonic-gate ASSERT(ap->ippa_destruct_pending);
35030Sstevel@tonic-gate
35040Sstevel@tonic-gate rw_enter(ipp_action_byid_lock, RW_WRITER);
35050Sstevel@tonic-gate ASSERT(ap->ippa_hold_count == 0);
35060Sstevel@tonic-gate
35070Sstevel@tonic-gate /*
35080Sstevel@tonic-gate * NULL the entry in the array of all action structures.
35090Sstevel@tonic-gate */
35100Sstevel@tonic-gate
35110Sstevel@tonic-gate ipp_action_byid[ap->ippa_id] = NULL;
35120Sstevel@tonic-gate
35130Sstevel@tonic-gate /*
35140Sstevel@tonic-gate * Clean up any remnants of the action structure as the buffer is
35150Sstevel@tonic-gate * about to disappear.
35160Sstevel@tonic-gate */
35170Sstevel@tonic-gate
35180Sstevel@tonic-gate CONFIG_LOCK_FINI(ap->ippa_config_lock);
35190Sstevel@tonic-gate rw_destroy(ap->ippa_lock);
35200Sstevel@tonic-gate
35210Sstevel@tonic-gate rw_exit(ipp_action_byid_lock);
35220Sstevel@tonic-gate }
35230Sstevel@tonic-gate #undef __FN__
35240Sstevel@tonic-gate
35250Sstevel@tonic-gate #define __FN__ "packet_constructor"
35260Sstevel@tonic-gate /*ARGSUSED*/
35270Sstevel@tonic-gate static int
packet_constructor(void * buf,void * cdrarg,int kmflags)35280Sstevel@tonic-gate packet_constructor(
35290Sstevel@tonic-gate void *buf,
35300Sstevel@tonic-gate void *cdrarg,
35310Sstevel@tonic-gate int kmflags)
35320Sstevel@tonic-gate {
35330Sstevel@tonic-gate ipp_packet_t *pp;
35340Sstevel@tonic-gate ipp_class_t *cp;
35350Sstevel@tonic-gate
35360Sstevel@tonic-gate ASSERT(buf != NULL);
35370Sstevel@tonic-gate bzero(buf, sizeof (ipp_packet_t));
35380Sstevel@tonic-gate pp = (ipp_packet_t *)buf;
35390Sstevel@tonic-gate
35400Sstevel@tonic-gate if ((cp = kmem_alloc(ipp_packet_classes * sizeof (ipp_class_t),
35410Sstevel@tonic-gate KM_NOSLEEP)) == NULL)
35420Sstevel@tonic-gate return (ENOMEM);
35430Sstevel@tonic-gate
35440Sstevel@tonic-gate pp->ippp_class_array = cp;
35450Sstevel@tonic-gate pp->ippp_class_windex = 0;
35460Sstevel@tonic-gate pp->ippp_class_rindex = 0;
35470Sstevel@tonic-gate pp->ippp_class_limit = ipp_packet_classes - 1;
35480Sstevel@tonic-gate
35490Sstevel@tonic-gate return (0);
35500Sstevel@tonic-gate }
35510Sstevel@tonic-gate #undef __FN__
35520Sstevel@tonic-gate
35530Sstevel@tonic-gate #define __FN__ "packet_destructor"
35540Sstevel@tonic-gate /*ARGSUSED*/
35550Sstevel@tonic-gate static void
packet_destructor(void * buf,void * cdrarg)35560Sstevel@tonic-gate packet_destructor(
35570Sstevel@tonic-gate void *buf,
35580Sstevel@tonic-gate void *cdrarg)
35590Sstevel@tonic-gate {
35600Sstevel@tonic-gate ipp_packet_t *pp;
35610Sstevel@tonic-gate
35620Sstevel@tonic-gate ASSERT(buf != NULL);
35630Sstevel@tonic-gate pp = (ipp_packet_t *)buf;
35640Sstevel@tonic-gate
35650Sstevel@tonic-gate ASSERT(pp->ippp_data == NULL);
35660Sstevel@tonic-gate ASSERT(pp->ippp_class_windex == 0);
35670Sstevel@tonic-gate ASSERT(pp->ippp_class_rindex == 0);
35680Sstevel@tonic-gate ASSERT(pp->ippp_private == NULL);
35690Sstevel@tonic-gate ASSERT(pp->ippp_private_free == NULL);
35700Sstevel@tonic-gate
35710Sstevel@tonic-gate kmem_free(pp->ippp_class_array,
35720Sstevel@tonic-gate (pp->ippp_class_limit + 1) * sizeof (ipp_class_t));
35730Sstevel@tonic-gate
35740Sstevel@tonic-gate if (pp->ippp_log != NULL) {
35750Sstevel@tonic-gate kmem_free(pp->ippp_log,
35760Sstevel@tonic-gate (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
35770Sstevel@tonic-gate }
35780Sstevel@tonic-gate }
35790Sstevel@tonic-gate #undef __FN__
35800Sstevel@tonic-gate
35810Sstevel@tonic-gate /*
35820Sstevel@tonic-gate * Debug message printout code.
35830Sstevel@tonic-gate */
35840Sstevel@tonic-gate
35850Sstevel@tonic-gate #ifdef IPP_DBG
35860Sstevel@tonic-gate static void
ipp_debug(uint64_t type,const char * fn,char * fmt,...)35870Sstevel@tonic-gate ipp_debug(
35880Sstevel@tonic-gate uint64_t type,
35890Sstevel@tonic-gate const char *fn,
35900Sstevel@tonic-gate char *fmt,
35910Sstevel@tonic-gate ...)
35920Sstevel@tonic-gate {
35930Sstevel@tonic-gate char buf[255];
35940Sstevel@tonic-gate va_list adx;
35950Sstevel@tonic-gate
35960Sstevel@tonic-gate if ((type & ipp_debug_flags) == 0)
35970Sstevel@tonic-gate return;
35980Sstevel@tonic-gate
35990Sstevel@tonic-gate mutex_enter(debug_mutex);
36000Sstevel@tonic-gate va_start(adx, fmt);
36010Sstevel@tonic-gate (void) vsnprintf(buf, 255, fmt, adx);
36020Sstevel@tonic-gate va_end(adx);
36030Sstevel@tonic-gate
36040Sstevel@tonic-gate printf("(%llx) %s: %s", (unsigned long long)curthread->t_did, fn,
36050Sstevel@tonic-gate buf);
36060Sstevel@tonic-gate mutex_exit(debug_mutex);
36070Sstevel@tonic-gate }
36080Sstevel@tonic-gate #endif /* IPP_DBG */
3609