xref: /onnv-gate/usr/src/uts/common/ipp/ippconf.c (revision 2951:8e5048c1f58e)
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