xref: /titanic_51/usr/src/uts/common/ipp/ippconf.c (revision 1a5e258f5471356ca102c7176637cdce45bac147)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d624471bSelowe  * Common Development and Distribution License (the "License").
6d624471bSelowe  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d624471bSelowe  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
297c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
307c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
317c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
327c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
347c478bd9Sstevel@tonic-gate #include <sys/spl.h>
357c478bd9Sstevel@tonic-gate #include <sys/time.h>
367c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
377c478bd9Sstevel@tonic-gate #include <ipp/ipp.h>
387c478bd9Sstevel@tonic-gate #include <ipp/ipp_impl.h>
397c478bd9Sstevel@tonic-gate #include <ipp/ipgpc/ipgpc.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Debug switch.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #if	defined(DEBUG)
467c478bd9Sstevel@tonic-gate #define	IPP_DBG
477c478bd9Sstevel@tonic-gate #endif
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * Globals
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * ipp_action_count is not static because it is imported by inet/ipp_common.h
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate uint32_t		ipp_action_count = 0;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static kmem_cache_t	*ipp_mod_cache = NULL;
597c478bd9Sstevel@tonic-gate static uint32_t		ipp_mod_count = 0;
607c478bd9Sstevel@tonic-gate static uint32_t		ipp_max_mod = IPP_NMOD;
617c478bd9Sstevel@tonic-gate static ipp_mod_t	**ipp_mod_byid;
627c478bd9Sstevel@tonic-gate static krwlock_t	ipp_mod_byid_lock[1];
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static ipp_mod_id_t	ipp_next_mid = IPP_MOD_RESERVED + 1;
657c478bd9Sstevel@tonic-gate static ipp_mod_id_t	ipp_mid_limit;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static ipp_ref_t	*ipp_mod_byname[IPP_NBUCKET];
687c478bd9Sstevel@tonic-gate static krwlock_t	ipp_mod_byname_lock[1];
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static kmem_cache_t	*ipp_action_cache = NULL;
717c478bd9Sstevel@tonic-gate static uint32_t		ipp_max_action = IPP_NACTION;
727c478bd9Sstevel@tonic-gate static ipp_action_t	**ipp_action_byid;
737c478bd9Sstevel@tonic-gate static krwlock_t	ipp_action_byid_lock[1];
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static ipp_action_id_t	ipp_next_aid = IPP_ACTION_RESERVED + 1;
767c478bd9Sstevel@tonic-gate static ipp_action_id_t	ipp_aid_limit;
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static ipp_ref_t	*ipp_action_byname[IPP_NBUCKET];
797c478bd9Sstevel@tonic-gate static krwlock_t	ipp_action_byname_lock[1];
807c478bd9Sstevel@tonic-gate static ipp_ref_t	*ipp_action_noname;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate static kmem_cache_t	*ipp_packet_cache = NULL;
837c478bd9Sstevel@tonic-gate static uint_t		ipp_packet_classes = IPP_NCLASS;
847c478bd9Sstevel@tonic-gate static uint_t		ipp_packet_logging = 0;
857c478bd9Sstevel@tonic-gate static uint_t		ipp_packet_log_entries = IPP_NLOG;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Prototypes
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate void			ipp_init(void);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate int			ipp_list_mods(ipp_mod_id_t **, int *);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate ipp_mod_id_t		ipp_mod_lookup(const char *);
967c478bd9Sstevel@tonic-gate int			ipp_mod_name(ipp_mod_id_t, char **);
977c478bd9Sstevel@tonic-gate int			ipp_mod_register(const char *, ipp_ops_t *);
987c478bd9Sstevel@tonic-gate int			ipp_mod_unregister(ipp_mod_id_t);
997c478bd9Sstevel@tonic-gate int			ipp_mod_list_actions(ipp_mod_id_t, ipp_action_id_t **,
1007c478bd9Sstevel@tonic-gate     int *);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate ipp_action_id_t		ipp_action_lookup(const char *);
1037c478bd9Sstevel@tonic-gate int			ipp_action_name(ipp_action_id_t, char **);
1047c478bd9Sstevel@tonic-gate int			ipp_action_mod(ipp_action_id_t, ipp_mod_id_t *);
1057c478bd9Sstevel@tonic-gate int			ipp_action_create(ipp_mod_id_t, const char *,
1067c478bd9Sstevel@tonic-gate     nvlist_t **, ipp_flags_t, ipp_action_id_t *);
1077c478bd9Sstevel@tonic-gate int			ipp_action_modify(ipp_action_id_t, nvlist_t **,
1087c478bd9Sstevel@tonic-gate     ipp_flags_t);
1097c478bd9Sstevel@tonic-gate int			ipp_action_destroy(ipp_action_id_t, ipp_flags_t);
1107c478bd9Sstevel@tonic-gate int			ipp_action_info(ipp_action_id_t, int (*)(nvlist_t *,
1117c478bd9Sstevel@tonic-gate     void *), void *, ipp_flags_t);
1127c478bd9Sstevel@tonic-gate void			ipp_action_set_ptr(ipp_action_id_t, void *);
1137c478bd9Sstevel@tonic-gate void			*ipp_action_get_ptr(ipp_action_id_t);
1147c478bd9Sstevel@tonic-gate int			ipp_action_ref(ipp_action_id_t,	ipp_action_id_t,
1157c478bd9Sstevel@tonic-gate     ipp_flags_t);
1167c478bd9Sstevel@tonic-gate int			ipp_action_unref(ipp_action_id_t, ipp_action_id_t,
1177c478bd9Sstevel@tonic-gate     ipp_flags_t);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate int			ipp_packet_alloc(ipp_packet_t **, const char *,
1207c478bd9Sstevel@tonic-gate     ipp_action_id_t);
1217c478bd9Sstevel@tonic-gate void			ipp_packet_free(ipp_packet_t *);
1227c478bd9Sstevel@tonic-gate int			ipp_packet_add_class(ipp_packet_t *, const char *,
1237c478bd9Sstevel@tonic-gate     ipp_action_id_t);
1247c478bd9Sstevel@tonic-gate int			ipp_packet_process(ipp_packet_t **);
1257c478bd9Sstevel@tonic-gate int			ipp_packet_next(ipp_packet_t *, ipp_action_id_t);
1267c478bd9Sstevel@tonic-gate void			ipp_packet_set_data(ipp_packet_t *, mblk_t *);
1277c478bd9Sstevel@tonic-gate mblk_t			*ipp_packet_get_data(ipp_packet_t *);
1287c478bd9Sstevel@tonic-gate void			ipp_packet_set_private(ipp_packet_t *, void *,
1297c478bd9Sstevel@tonic-gate     void (*)(void *));
1307c478bd9Sstevel@tonic-gate void			*ipp_packet_get_private(ipp_packet_t *);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate int			ipp_stat_create(ipp_action_id_t, const char *, int,
1337c478bd9Sstevel@tonic-gate     int (*)(ipp_stat_t *, void *, int), void *, ipp_stat_t **);
1347c478bd9Sstevel@tonic-gate void			ipp_stat_install(ipp_stat_t *);
1357c478bd9Sstevel@tonic-gate void			ipp_stat_destroy(ipp_stat_t *);
1367c478bd9Sstevel@tonic-gate int			ipp_stat_named_init(ipp_stat_t *, const char *, uchar_t,
1377c478bd9Sstevel@tonic-gate     ipp_named_t	*);
1387c478bd9Sstevel@tonic-gate int			ipp_stat_named_op(ipp_named_t *, void *, int);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static int		ref_mod(ipp_action_t *, ipp_mod_t *);
1417c478bd9Sstevel@tonic-gate static void		unref_mod(ipp_action_t *, ipp_mod_t *);
1427c478bd9Sstevel@tonic-gate static int		is_mod_busy(ipp_mod_t *);
1437c478bd9Sstevel@tonic-gate static int		get_mod_ref(ipp_mod_t *, ipp_action_id_t **, int *);
1447c478bd9Sstevel@tonic-gate static int		get_mods(ipp_mod_id_t **bufp, int *);
1457c478bd9Sstevel@tonic-gate static ipp_mod_id_t	find_mod(const char *);
1467c478bd9Sstevel@tonic-gate static int		alloc_mod(const char *, ipp_mod_id_t *);
1477c478bd9Sstevel@tonic-gate static void		free_mod(ipp_mod_t *);
1487c478bd9Sstevel@tonic-gate static ipp_mod_t	*hold_mod(ipp_mod_id_t);
1497c478bd9Sstevel@tonic-gate static void		rele_mod(ipp_mod_t *);
1507c478bd9Sstevel@tonic-gate static ipp_mod_id_t	get_mid(void);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static int		condemn_action(ipp_ref_t **, ipp_action_t *);
1537c478bd9Sstevel@tonic-gate static int		destroy_action(ipp_action_t *, ipp_flags_t);
1547c478bd9Sstevel@tonic-gate static int		ref_action(ipp_action_t *, ipp_action_t *);
1557c478bd9Sstevel@tonic-gate static int		unref_action(ipp_action_t *, ipp_action_t *);
1567c478bd9Sstevel@tonic-gate static int		is_action_refd(ipp_action_t *);
1577c478bd9Sstevel@tonic-gate static ipp_action_id_t	find_action(const char *);
1587c478bd9Sstevel@tonic-gate static int		alloc_action(const char *, ipp_action_id_t *);
1597c478bd9Sstevel@tonic-gate static void		free_action(ipp_action_t *);
1607c478bd9Sstevel@tonic-gate static ipp_action_t	*hold_action(ipp_action_id_t);
1617c478bd9Sstevel@tonic-gate static void		rele_action(ipp_action_t *);
1627c478bd9Sstevel@tonic-gate static ipp_action_id_t	get_aid(void);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate static int		alloc_packet(const char *, ipp_action_id_t,
1657c478bd9Sstevel@tonic-gate     ipp_packet_t **);
1667c478bd9Sstevel@tonic-gate static int		realloc_packet(ipp_packet_t *);
1677c478bd9Sstevel@tonic-gate static void		free_packet(ipp_packet_t *);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static int		hash(const char *);
1707c478bd9Sstevel@tonic-gate static int		update_stats(kstat_t *, int);
1717c478bd9Sstevel@tonic-gate static void		init_mods(void);
1727c478bd9Sstevel@tonic-gate static void		init_actions(void);
1737c478bd9Sstevel@tonic-gate static void		init_packets(void);
1747c478bd9Sstevel@tonic-gate static int		mod_constructor(void *, void *, int);
1757c478bd9Sstevel@tonic-gate static void		mod_destructor(void *, void *);
1767c478bd9Sstevel@tonic-gate static int		action_constructor(void *, void *, int);
1777c478bd9Sstevel@tonic-gate static void		action_destructor(void *, void *);
1787c478bd9Sstevel@tonic-gate static int		packet_constructor(void *, void *, int);
1797c478bd9Sstevel@tonic-gate static void		packet_destructor(void *, void *);
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * Debug message macros
1837c478bd9Sstevel@tonic-gate  */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate #ifdef	IPP_DBG
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate #define	DBG_MOD		0x00000001ull
1887c478bd9Sstevel@tonic-gate #define	DBG_ACTION	0x00000002ull
1897c478bd9Sstevel@tonic-gate #define	DBG_PACKET	0x00000004ull
1907c478bd9Sstevel@tonic-gate #define	DBG_STATS	0x00000008ull
1917c478bd9Sstevel@tonic-gate #define	DBG_LIST	0x00000010ull
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate static uint64_t		ipp_debug_flags =
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * DBG_PACKET |
1967c478bd9Sstevel@tonic-gate  * DBG_STATS |
1977c478bd9Sstevel@tonic-gate  * DBG_LIST |
1987c478bd9Sstevel@tonic-gate  * DBG_MOD |
1997c478bd9Sstevel@tonic-gate  * DBG_ACTION |
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate 0;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate static kmutex_t	debug_mutex[1];
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/
2067c478bd9Sstevel@tonic-gate static void ipp_debug(uint64_t, const char *, char *, ...)
2077c478bd9Sstevel@tonic-gate 	__KPRINTFLIKE(3);
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate #define	DBG0(_type, _fmt)		    			\
2107c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt));
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate #define	DBG1(_type, _fmt, _a1) 					\
2137c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt), (_a1));
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate #define	DBG2(_type, _fmt, _a1, _a2)				\
2167c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2));
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate #define	DBG3(_type, _fmt, _a1, _a2, _a3)			\
2197c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
2207c478bd9Sstevel@tonic-gate 	    (_a3));
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)			\
2237c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
2247c478bd9Sstevel@tonic-gate 	    (_a3), (_a4));
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)		\
2277c478bd9Sstevel@tonic-gate 	ipp_debug((_type), __FN__, (_fmt), (_a1), (_a2),	\
2287c478bd9Sstevel@tonic-gate 	    (_a3), (_a4), (_a5));
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate #else	/* IPP_DBG */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate #define	DBG0(_type, _fmt)
2337c478bd9Sstevel@tonic-gate #define	DBG1(_type, _fmt, _a1)
2347c478bd9Sstevel@tonic-gate #define	DBG2(_type, _fmt, _a1, _a2)
2357c478bd9Sstevel@tonic-gate #define	DBG3(_type, _fmt, _a1, _a2, _a3)
2367c478bd9Sstevel@tonic-gate #define	DBG4(_type, _fmt, _a1, _a2, _a3, _a4)
2377c478bd9Sstevel@tonic-gate #define	DBG5(_type, _fmt, _a1, _a2, _a3, _a4, _a5)
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate #endif	/* IPP_DBG */
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate /*
2427c478bd9Sstevel@tonic-gate  * Lock macros
2437c478bd9Sstevel@tonic-gate  */
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate #define	LOCK_MOD(_imp, _rw)						\
2467c478bd9Sstevel@tonic-gate 	rw_enter((_imp)->ippm_lock, (_rw))
2477c478bd9Sstevel@tonic-gate #define	UNLOCK_MOD(_imp)						\
2487c478bd9Sstevel@tonic-gate 	rw_exit((_imp)->ippm_lock)
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate #define	LOCK_ACTION(_ap, _rw)						\
2517c478bd9Sstevel@tonic-gate 	rw_enter((_ap)->ippa_lock, (_rw))
2527c478bd9Sstevel@tonic-gate #define	UNLOCK_ACTION(_imp)						\
2537c478bd9Sstevel@tonic-gate 	rw_exit((_imp)->ippa_lock)
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate #define	CONFIG_WRITE_START(_ap)						\
2567c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_WRITE)
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate #define	CONFIG_WRITE_END(_ap)						\
2597c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate #define	CONFIG_READ_START(_ap)						\
2627c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_ENTER((_ap)->ippa_config_lock, CL_READ)
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate #define	CONFIG_READ_END(_ap)						\
2657c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_EXIT((_ap)->ippa_config_lock)
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate  * Exported functions
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_init"
2727c478bd9Sstevel@tonic-gate void
2737c478bd9Sstevel@tonic-gate ipp_init(
2747c478bd9Sstevel@tonic-gate 	void)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate #ifdef	IPP_DBG
2777c478bd9Sstevel@tonic-gate 	mutex_init(debug_mutex, NULL, MUTEX_ADAPTIVE,
2787c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
2797c478bd9Sstevel@tonic-gate #endif	/* IPP_DBG */
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	/*
2827c478bd9Sstevel@tonic-gate 	 * Initialize module and action structure caches and associated locks.
2837c478bd9Sstevel@tonic-gate 	 */
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	init_mods();
2867c478bd9Sstevel@tonic-gate 	init_actions();
2877c478bd9Sstevel@tonic-gate 	init_packets();
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate #undef	__FN__
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_list_mods"
2927c478bd9Sstevel@tonic-gate int
2937c478bd9Sstevel@tonic-gate ipp_list_mods(
2947c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	**bufp,
2957c478bd9Sstevel@tonic-gate 	int		*neltp)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	ASSERT(bufp != NULL);
2987c478bd9Sstevel@tonic-gate 	ASSERT(neltp != NULL);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	return (get_mods(bufp, neltp));
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate #undef	__FN__
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * Module manipulation interface.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_mod_lookup"
3097c478bd9Sstevel@tonic-gate ipp_mod_id_t
3107c478bd9Sstevel@tonic-gate ipp_mod_lookup(
3117c478bd9Sstevel@tonic-gate 	const char	*modname)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid;
3147c478bd9Sstevel@tonic-gate #define	FIRST_TIME	0
3157c478bd9Sstevel@tonic-gate 	int		try = FIRST_TIME;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * Sanity check the module name.
3197c478bd9Sstevel@tonic-gate 	 */
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
3227c478bd9Sstevel@tonic-gate 		return (IPP_MOD_INVAL);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate try_again:
3257c478bd9Sstevel@tonic-gate 	if ((mid = find_mod(modname)) == IPP_MOD_INVAL) {
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		/*
3287c478bd9Sstevel@tonic-gate 		 * Module not installed.
3297c478bd9Sstevel@tonic-gate 		 */
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 		if (try++ == FIRST_TIME) {
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 			/*
3347c478bd9Sstevel@tonic-gate 			 * This is the first attempt to find the module so
3357c478bd9Sstevel@tonic-gate 			 * try to 'demand load' it.
3367c478bd9Sstevel@tonic-gate 			 */
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 			DBG1(DBG_MOD, "loading module '%s'\n", modname);
3397c478bd9Sstevel@tonic-gate 			(void) modload("ipp", (char *)modname);
3407c478bd9Sstevel@tonic-gate 			goto try_again;
3417c478bd9Sstevel@tonic-gate 		}
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	return (mid);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate #undef	FIRST_TIME
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate #undef	__FN__
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_mod_name"
3517c478bd9Sstevel@tonic-gate int
3527c478bd9Sstevel@tonic-gate ipp_mod_name(
3537c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid,
3547c478bd9Sstevel@tonic-gate 	char		**modnamep)
3557c478bd9Sstevel@tonic-gate {
3567c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
3577c478bd9Sstevel@tonic-gate 	char		*modname;
3587c478bd9Sstevel@tonic-gate 	char		*buf;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	ASSERT(modnamep != NULL);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/*
3637c478bd9Sstevel@tonic-gate 	 * Translate the module id into the module pointer.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if ((imp = hold_mod(mid)) == NULL)
3677c478bd9Sstevel@tonic-gate 		return (ENOENT);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_READER);
3707c478bd9Sstevel@tonic-gate 	modname = imp->ippm_name;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/*
3737c478bd9Sstevel@tonic-gate 	 * Allocate a buffer to pass back to the caller.
3747c478bd9Sstevel@tonic-gate 	 */
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if ((buf = kmem_zalloc(strlen(modname) + 1, KM_NOSLEEP)) == NULL) {
3777c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
3787c478bd9Sstevel@tonic-gate 		rele_mod(imp);
3797c478bd9Sstevel@tonic-gate 		return (ENOMEM);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/*
3837c478bd9Sstevel@tonic-gate 	 * Copy the module name into the buffer.
3847c478bd9Sstevel@tonic-gate 	 */
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, modname);
3877c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	*modnamep = buf;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	rele_mod(imp);
3927c478bd9Sstevel@tonic-gate 	return (0);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate #undef	__FN__
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_mod_register"
3977c478bd9Sstevel@tonic-gate int
3987c478bd9Sstevel@tonic-gate ipp_mod_register(
3997c478bd9Sstevel@tonic-gate 	const char	*modname,
4007c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ipp_ops)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid;
4037c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
4047c478bd9Sstevel@tonic-gate 	int		rc;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	ASSERT(ipp_ops != NULL);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/*
4097c478bd9Sstevel@tonic-gate 	 * Sanity check the module name.
4107c478bd9Sstevel@tonic-gate 	 */
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (modname == NULL || strlen(modname) > MAXNAMELEN - 1)
4137c478bd9Sstevel@tonic-gate 		return (EINVAL);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	/*
4167c478bd9Sstevel@tonic-gate 	 * Allocate a module structure.
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if ((rc = alloc_mod(modname, &mid)) != 0)
4207c478bd9Sstevel@tonic-gate 		return (rc);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	imp = hold_mod(mid);
4237c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * Make module available for use.
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
4307c478bd9Sstevel@tonic-gate 	DBG1(DBG_MOD, "registering module '%s'\n", imp->ippm_name);
4317c478bd9Sstevel@tonic-gate 	imp->ippm_ops = ipp_ops;
4327c478bd9Sstevel@tonic-gate 	imp->ippm_state = IPP_MODSTATE_AVAILABLE;
4337c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	rele_mod(imp);
4367c478bd9Sstevel@tonic-gate 	return (0);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate #undef	__FN__
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_mod_unregister"
4417c478bd9Sstevel@tonic-gate int
4427c478bd9Sstevel@tonic-gate ipp_mod_unregister(
4437c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/*
4487c478bd9Sstevel@tonic-gate 	 * Translate the module id into the module pointer.
4497c478bd9Sstevel@tonic-gate 	 */
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if ((imp = hold_mod(mid)) == NULL)
4527c478bd9Sstevel@tonic-gate 		return (ENOENT);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
4557c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_state == IPP_MODSTATE_AVAILABLE);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/*
4587c478bd9Sstevel@tonic-gate 	 * Check to see if there are any actions that reference the module.
4597c478bd9Sstevel@tonic-gate 	 */
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if (is_mod_busy(imp)) {
4627c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
4637c478bd9Sstevel@tonic-gate 		rele_mod(imp);
4647c478bd9Sstevel@tonic-gate 		return (EBUSY);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	/*
4687c478bd9Sstevel@tonic-gate 	 * Prevent further use of the module.
4697c478bd9Sstevel@tonic-gate 	 */
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	DBG1(DBG_MOD, "unregistering module '%s'\n", imp->ippm_name);
4727c478bd9Sstevel@tonic-gate 	imp->ippm_state = IPP_MODSTATE_PROTO;
4737c478bd9Sstevel@tonic-gate 	imp->ippm_ops = NULL;
4747c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	/*
4777c478bd9Sstevel@tonic-gate 	 * Free the module structure.
4787c478bd9Sstevel@tonic-gate 	 */
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	free_mod(imp);
4817c478bd9Sstevel@tonic-gate 	rele_mod(imp);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	return (0);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate #undef	__FN__
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_mod_list_actions"
4887c478bd9Sstevel@tonic-gate int
4897c478bd9Sstevel@tonic-gate ipp_mod_list_actions(
4907c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid,
4917c478bd9Sstevel@tonic-gate 	ipp_action_id_t	**bufp,
4927c478bd9Sstevel@tonic-gate 	int		*neltp)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
4957c478bd9Sstevel@tonic-gate 	int		rc;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	ASSERT(bufp != NULL);
4987c478bd9Sstevel@tonic-gate 	ASSERT(neltp != NULL);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/*
5017c478bd9Sstevel@tonic-gate 	 * Translate the module id into the module pointer.
5027c478bd9Sstevel@tonic-gate 	 */
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if ((imp = hold_mod(mid)) == NULL)
5057c478bd9Sstevel@tonic-gate 		return (ENOENT);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * Get the list of actions referencing the module.
5097c478bd9Sstevel@tonic-gate 	 */
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_READER);
5127c478bd9Sstevel@tonic-gate 	rc = get_mod_ref(imp, bufp, neltp);
5137c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	rele_mod(imp);
5167c478bd9Sstevel@tonic-gate 	return (rc);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate #undef	__FN__
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate  * Action manipulation interface.
5227c478bd9Sstevel@tonic-gate  */
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_lookup"
5257c478bd9Sstevel@tonic-gate ipp_action_id_t
5267c478bd9Sstevel@tonic-gate ipp_action_lookup(
5277c478bd9Sstevel@tonic-gate 	const char	*aname)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	if (aname == NULL)
5307c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_INVAL);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/*
5337c478bd9Sstevel@tonic-gate 	 * Check for special case 'virtual action' names.
5347c478bd9Sstevel@tonic-gate 	 */
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (strcmp(aname, IPP_ANAME_CONT) == 0)
5377c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_CONT);
5387c478bd9Sstevel@tonic-gate 	else if (strcmp(aname, IPP_ANAME_DEFER) == 0)
5397c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_DEFER);
5407c478bd9Sstevel@tonic-gate 	else if (strcmp(aname, IPP_ANAME_DROP) == 0)
5417c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_DROP);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/*
5447c478bd9Sstevel@tonic-gate 	 * Now check real actions.
5457c478bd9Sstevel@tonic-gate 	 */
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	return (find_action(aname));
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate #undef	__FN__
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_name"
5527c478bd9Sstevel@tonic-gate int
5537c478bd9Sstevel@tonic-gate ipp_action_name(
5547c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
5557c478bd9Sstevel@tonic-gate 	char		**anamep)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
5587c478bd9Sstevel@tonic-gate 	char		*aname;
5597c478bd9Sstevel@tonic-gate 	char		*buf;
5607c478bd9Sstevel@tonic-gate 	int		rc;
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	ASSERT(anamep != NULL);
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	/*
5657c478bd9Sstevel@tonic-gate 	 * Check for special case 'virtual action' ids.
5667c478bd9Sstevel@tonic-gate 	 */
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	switch (aid) {
5697c478bd9Sstevel@tonic-gate 	case IPP_ACTION_CONT:
5707c478bd9Sstevel@tonic-gate 		ap = NULL;
5717c478bd9Sstevel@tonic-gate 		aname = IPP_ANAME_CONT;
5727c478bd9Sstevel@tonic-gate 		break;
5737c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DEFER:
5747c478bd9Sstevel@tonic-gate 		ap = NULL;
5757c478bd9Sstevel@tonic-gate 		aname = IPP_ANAME_DEFER;
5767c478bd9Sstevel@tonic-gate 		break;
5777c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DROP:
5787c478bd9Sstevel@tonic-gate 		ap = NULL;
5797c478bd9Sstevel@tonic-gate 		aname = IPP_ANAME_DROP;
5807c478bd9Sstevel@tonic-gate 		break;
5817c478bd9Sstevel@tonic-gate 	default:
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 		/*
5847c478bd9Sstevel@tonic-gate 		 * Not a special case. Check for a real action.
5857c478bd9Sstevel@tonic-gate 		 */
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 		if ((ap = hold_action(aid)) == NULL)
5887c478bd9Sstevel@tonic-gate 			return (ENOENT);
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 		LOCK_ACTION(ap, RW_READER);
5917c478bd9Sstevel@tonic-gate 		aname = ap->ippa_name;
5927c478bd9Sstevel@tonic-gate 		break;
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * Allocate a buffer to pass back to the caller.
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if ((buf = kmem_zalloc(strlen(aname) + 1, KM_NOSLEEP)) == NULL) {
6007c478bd9Sstevel@tonic-gate 		rc = ENOMEM;
6017c478bd9Sstevel@tonic-gate 		goto done;
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/*
6057c478bd9Sstevel@tonic-gate 	 * Copy the action name into the buffer.
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, aname);
6097c478bd9Sstevel@tonic-gate 	*anamep = buf;
6107c478bd9Sstevel@tonic-gate 	rc = 0;
6117c478bd9Sstevel@tonic-gate done:
6127c478bd9Sstevel@tonic-gate 	/*
6137c478bd9Sstevel@tonic-gate 	 * Unlock the action if necessary (i.e. it wasn't a virtual action).
6147c478bd9Sstevel@tonic-gate 	 */
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (ap != NULL) {
6177c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
6187c478bd9Sstevel@tonic-gate 		rele_action(ap);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	return (rc);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate #undef	__FN__
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_mod"
6267c478bd9Sstevel@tonic-gate int
6277c478bd9Sstevel@tonic-gate ipp_action_mod(
6287c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
6297c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	*midp)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
6327c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	ASSERT(midp != NULL);
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * Return an error for  'virtual action' ids.
6387c478bd9Sstevel@tonic-gate 	 */
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	switch (aid) {
6417c478bd9Sstevel@tonic-gate 	case IPP_ACTION_CONT:
6427c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
6437c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DEFER:
6447c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
6457c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DROP:
6467c478bd9Sstevel@tonic-gate 		return (EINVAL);
6477c478bd9Sstevel@tonic-gate 	default:
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	/*
6527c478bd9Sstevel@tonic-gate 	 * This is a real action.
6537c478bd9Sstevel@tonic-gate 	 */
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
6567c478bd9Sstevel@tonic-gate 		return (ENOENT);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	/*
6597c478bd9Sstevel@tonic-gate 	 * Check that the action is not in prototype state.
6607c478bd9Sstevel@tonic-gate 	 */
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
6637c478bd9Sstevel@tonic-gate 	if (ap->ippa_state == IPP_ASTATE_PROTO) {
6647c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
6657c478bd9Sstevel@tonic-gate 		rele_action(ap);
6667c478bd9Sstevel@tonic-gate 		return (ENOENT);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	imp = ap->ippa_mod;
6707c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
6717c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	*midp = imp->ippm_id;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	rele_action(ap);
6767c478bd9Sstevel@tonic-gate 	return (0);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate #undef	__FN__
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_create"
6817c478bd9Sstevel@tonic-gate int
6827c478bd9Sstevel@tonic-gate ipp_action_create(
6837c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid,
6847c478bd9Sstevel@tonic-gate 	const char	*aname,
6857c478bd9Sstevel@tonic-gate 	nvlist_t	**nvlpp,
6867c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags,
6877c478bd9Sstevel@tonic-gate 	ipp_action_id_t	*aidp)
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ippo;
6907c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
6917c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid;
6927c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
6937c478bd9Sstevel@tonic-gate 	int		rc;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	ASSERT(nvlpp != NULL);
6967c478bd9Sstevel@tonic-gate 	ASSERT(*nvlpp != NULL);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	/*
6997c478bd9Sstevel@tonic-gate 	 * Sanity check the action name (NULL means the framework chooses the
7007c478bd9Sstevel@tonic-gate 	 * name).
7017c478bd9Sstevel@tonic-gate 	 */
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (aname != NULL && strlen(aname) > MAXNAMELEN - 1)
7047c478bd9Sstevel@tonic-gate 		return (EINVAL);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/*
7077c478bd9Sstevel@tonic-gate 	 * Translate the module id into the module pointer.
7087c478bd9Sstevel@tonic-gate 	 */
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if ((imp = hold_mod(mid)) == NULL)
7117c478bd9Sstevel@tonic-gate 		return (ENOENT);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/*
7147c478bd9Sstevel@tonic-gate 	 * Allocate an action.
7157c478bd9Sstevel@tonic-gate 	 */
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	if ((rc = alloc_action(aname, &aid)) != 0) {
7187c478bd9Sstevel@tonic-gate 		rele_mod(imp);
7197c478bd9Sstevel@tonic-gate 		return (rc);
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	ap = hold_action(aid);
7237c478bd9Sstevel@tonic-gate 	ASSERT(ap != NULL);
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	/*
7267c478bd9Sstevel@tonic-gate 	 * Note that the action is in the process of creation/destruction.
7277c478bd9Sstevel@tonic-gate 	 */
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
7307c478bd9Sstevel@tonic-gate 	ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * Reference the module for which the action is being created.
7347c478bd9Sstevel@tonic-gate 	 */
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
7377c478bd9Sstevel@tonic-gate 	if ((rc = ref_mod(ap, imp)) != 0) {
7387c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
7397c478bd9Sstevel@tonic-gate 		ap->ippa_state = IPP_ASTATE_PROTO;
7407c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		free_action(ap);
7437c478bd9Sstevel@tonic-gate 		rele_action(ap);
7447c478bd9Sstevel@tonic-gate 		rele_mod(imp);
7457c478bd9Sstevel@tonic-gate 		return (rc);
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	ippo = imp->ippm_ops;
7517c478bd9Sstevel@tonic-gate 	ASSERT(ippo != NULL);
7527c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	/*
7557c478bd9Sstevel@tonic-gate 	 * Call into the module to create the action context.
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_START(ap);
7597c478bd9Sstevel@tonic-gate 	DBG2(DBG_ACTION, "creating action '%s' in module '%s'\n",
7607c478bd9Sstevel@tonic-gate 	    ap->ippa_name, imp->ippm_name);
7617c478bd9Sstevel@tonic-gate 	if ((rc = ippo->ippo_action_create(ap->ippa_id, nvlpp, flags)) != 0) {
7627c478bd9Sstevel@tonic-gate 		LOCK_ACTION(ap, RW_WRITER);
7637c478bd9Sstevel@tonic-gate 		LOCK_MOD(imp, RW_WRITER);
7647c478bd9Sstevel@tonic-gate 		unref_mod(ap, imp);
7657c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
7667c478bd9Sstevel@tonic-gate 		ap->ippa_state = IPP_ASTATE_PROTO;
7677c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 		CONFIG_WRITE_END(ap);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 		free_action(ap);
7727c478bd9Sstevel@tonic-gate 		rele_action(ap);
7737c478bd9Sstevel@tonic-gate 		rele_mod(imp);
7747c478bd9Sstevel@tonic-gate 		return (rc);
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_END(ap);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	/*
7797c478bd9Sstevel@tonic-gate 	 * Make the action available for use.
7807c478bd9Sstevel@tonic-gate 	 */
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
7837c478bd9Sstevel@tonic-gate 	ap->ippa_state = IPP_ASTATE_AVAILABLE;
7847c478bd9Sstevel@tonic-gate 	if (aidp != NULL)
7857c478bd9Sstevel@tonic-gate 		*aidp = ap->ippa_id;
7867c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	rele_action(ap);
7897c478bd9Sstevel@tonic-gate 	rele_mod(imp);
7907c478bd9Sstevel@tonic-gate 	return (0);
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate #undef	__FN__
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_destroy"
7957c478bd9Sstevel@tonic-gate int
7967c478bd9Sstevel@tonic-gate ipp_action_destroy(
7977c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
7987c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags)
7997c478bd9Sstevel@tonic-gate {
8007c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp = NULL;
8017c478bd9Sstevel@tonic-gate 	ipp_ref_t	*tmp;
8027c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
8037c478bd9Sstevel@tonic-gate 	int		rc;
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	/*
8067c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
8107c478bd9Sstevel@tonic-gate 		return (ENOENT);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	/*
8137c478bd9Sstevel@tonic-gate 	 * Set the condemned action list pointer and destroy the action.
8147c478bd9Sstevel@tonic-gate 	 */
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	ap->ippa_condemned = &rp;
8177c478bd9Sstevel@tonic-gate 	if ((rc = destroy_action(ap, flags)) == 0) {
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 		/*
8207c478bd9Sstevel@tonic-gate 		 * Destroy any other actions condemned by the destruction of
8217c478bd9Sstevel@tonic-gate 		 * the first action.
8227c478bd9Sstevel@tonic-gate 		 */
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
8257c478bd9Sstevel@tonic-gate 			ap = tmp->ippr_action;
8267c478bd9Sstevel@tonic-gate 			ap->ippa_condemned = &rp;
8277c478bd9Sstevel@tonic-gate 			(void) destroy_action(ap, flags);
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 	} else {
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		/*
8327c478bd9Sstevel@tonic-gate 		 * Unreference any condemned actions since the destruction of
8337c478bd9Sstevel@tonic-gate 		 * the first action failed.
8347c478bd9Sstevel@tonic-gate 		 */
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		for (tmp = rp; tmp != NULL; tmp = tmp->ippr_nextp) {
8377c478bd9Sstevel@tonic-gate 			ap = tmp->ippr_action;
8387c478bd9Sstevel@tonic-gate 			rele_action(ap);
8397c478bd9Sstevel@tonic-gate 		}
8407c478bd9Sstevel@tonic-gate 	}
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/*
8437c478bd9Sstevel@tonic-gate 	 * Clean up the condemned list.
8447c478bd9Sstevel@tonic-gate 	 */
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	while (rp != NULL) {
8477c478bd9Sstevel@tonic-gate 		tmp = rp;
8487c478bd9Sstevel@tonic-gate 		rp = rp->ippr_nextp;
8497c478bd9Sstevel@tonic-gate 		kmem_free(tmp, sizeof (ipp_ref_t));
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	return (rc);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate #undef	__FN__
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_modify"
8577c478bd9Sstevel@tonic-gate int
8587c478bd9Sstevel@tonic-gate ipp_action_modify(
8597c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
8607c478bd9Sstevel@tonic-gate 	nvlist_t	**nvlpp,
8617c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags)
8627c478bd9Sstevel@tonic-gate {
8637c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
8647c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ippo;
8657c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
8667c478bd9Sstevel@tonic-gate 	int		rc;
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	ASSERT(nvlpp != NULL);
8697c478bd9Sstevel@tonic-gate 	ASSERT(*nvlpp != NULL);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	/*
8727c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
8767c478bd9Sstevel@tonic-gate 		return (ENOENT);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	/*
8797c478bd9Sstevel@tonic-gate 	 * Check that the action is either available for use or is in the
8807c478bd9Sstevel@tonic-gate 	 * process of creation/destruction.
8817c478bd9Sstevel@tonic-gate 	 *
8827c478bd9Sstevel@tonic-gate 	 * NOTE: It is up to the module to lock multiple configuration
8837c478bd9Sstevel@tonic-gate 	 *	 operations against each other if necessary.
8847c478bd9Sstevel@tonic-gate 	 */
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
8877c478bd9Sstevel@tonic-gate 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE &&
8887c478bd9Sstevel@tonic-gate 	    ap->ippa_state != IPP_ASTATE_CONFIG_PENDING) {
8897c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
8907c478bd9Sstevel@tonic-gate 		rele_action(ap);
8917c478bd9Sstevel@tonic-gate 		return (EPROTO);
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	imp = ap->ippa_mod;
8957c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
8967c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	ippo = imp->ippm_ops;
8997c478bd9Sstevel@tonic-gate 	ASSERT(ippo != NULL);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	/*
9027c478bd9Sstevel@tonic-gate 	 * Call into the module to modify the action context.
9037c478bd9Sstevel@tonic-gate 	 */
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	DBG1(DBG_ACTION, "modifying action '%s'\n", ap->ippa_name);
9067c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_START(ap);
9077c478bd9Sstevel@tonic-gate 	rc = ippo->ippo_action_modify(aid, nvlpp, flags);
9087c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_END(ap);
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	rele_action(ap);
9117c478bd9Sstevel@tonic-gate 	return (rc);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate #undef	__FN__
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_info"
9167c478bd9Sstevel@tonic-gate int
9177c478bd9Sstevel@tonic-gate ipp_action_info(
9187c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
9197c478bd9Sstevel@tonic-gate 	int		(*fn)(nvlist_t *, void *),
9207c478bd9Sstevel@tonic-gate 	void		*arg,
9217c478bd9Sstevel@tonic-gate 	ipp_flags_t    	flags)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
9247c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
9257c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ippo;
9267c478bd9Sstevel@tonic-gate 	int		rc;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/*
9297c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
9307c478bd9Sstevel@tonic-gate 	 */
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
9337c478bd9Sstevel@tonic-gate 		return (ENOENT);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	/*
9367c478bd9Sstevel@tonic-gate 	 * Check that the action is available for use. We don't want to
9377c478bd9Sstevel@tonic-gate 	 * read back parameters while the action is in the process of
9387c478bd9Sstevel@tonic-gate 	 * creation/destruction.
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
9427c478bd9Sstevel@tonic-gate 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
9437c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
9447c478bd9Sstevel@tonic-gate 		rele_action(ap);
9457c478bd9Sstevel@tonic-gate 		return (EPROTO);
9467c478bd9Sstevel@tonic-gate 	}
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	imp = ap->ippa_mod;
9497c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
9507c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	ippo = imp->ippm_ops;
9537c478bd9Sstevel@tonic-gate 	ASSERT(ippo != NULL);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/*
9567c478bd9Sstevel@tonic-gate 	 * Call into the module to get the action configuration information.
9577c478bd9Sstevel@tonic-gate 	 */
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	DBG1(DBG_ACTION,
9607c478bd9Sstevel@tonic-gate 	    "getting configuration information from action '%s'\n",
9617c478bd9Sstevel@tonic-gate 	    ap->ippa_name);
9627c478bd9Sstevel@tonic-gate 	CONFIG_READ_START(ap);
9637c478bd9Sstevel@tonic-gate 	if ((rc = ippo->ippo_action_info(aid, fn, arg, flags)) != 0) {
9647c478bd9Sstevel@tonic-gate 		CONFIG_READ_END(ap);
9657c478bd9Sstevel@tonic-gate 		rele_action(ap);
9667c478bd9Sstevel@tonic-gate 		return (rc);
9677c478bd9Sstevel@tonic-gate 	}
9687c478bd9Sstevel@tonic-gate 	CONFIG_READ_END(ap);
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	rele_action(ap);
9717c478bd9Sstevel@tonic-gate 	return (0);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate #undef	__FN__
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_set_ptr"
9767c478bd9Sstevel@tonic-gate void
9777c478bd9Sstevel@tonic-gate ipp_action_set_ptr(
9787c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
9797c478bd9Sstevel@tonic-gate 	void		*ptr)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/*
9847c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
9857c478bd9Sstevel@tonic-gate 	 */
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	ap = hold_action(aid);
9887c478bd9Sstevel@tonic-gate 	ASSERT(ap != NULL);
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 	/*
9917c478bd9Sstevel@tonic-gate 	 * Set the private data pointer.
9927c478bd9Sstevel@tonic-gate 	 */
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	ap->ippa_ptr = ptr;
9957c478bd9Sstevel@tonic-gate 	rele_action(ap);
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate #undef	__FN__
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_get_ptr"
10007c478bd9Sstevel@tonic-gate void *
10017c478bd9Sstevel@tonic-gate ipp_action_get_ptr(
10027c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid)
10037c478bd9Sstevel@tonic-gate {
10047c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
10057c478bd9Sstevel@tonic-gate 	void		*ptr;
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	/*
10087c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
10097c478bd9Sstevel@tonic-gate 	 */
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 	ap = hold_action(aid);
10127c478bd9Sstevel@tonic-gate 	ASSERT(ap != NULL);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 	/*
10157c478bd9Sstevel@tonic-gate 	 * Return the private data pointer.
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	ptr = ap->ippa_ptr;
10197c478bd9Sstevel@tonic-gate 	rele_action(ap);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	return (ptr);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate #undef	__FN__
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_ref"
10267c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10277c478bd9Sstevel@tonic-gate int
10287c478bd9Sstevel@tonic-gate ipp_action_ref(
10297c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
10307c478bd9Sstevel@tonic-gate 	ipp_action_id_t	ref_aid,
10317c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags)
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
10347c478bd9Sstevel@tonic-gate 	ipp_action_t	*ref_ap;
10357c478bd9Sstevel@tonic-gate 	int		rc;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	/*
10387c478bd9Sstevel@tonic-gate 	 * Actions are not allowed to reference themselves.
10397c478bd9Sstevel@tonic-gate 	 */
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	if (aid == ref_aid)
10427c478bd9Sstevel@tonic-gate 		return (EINVAL);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	/*
10457c478bd9Sstevel@tonic-gate 	 * Check for a special case 'virtual action' id.
10467c478bd9Sstevel@tonic-gate 	 */
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	switch (ref_aid) {
10497c478bd9Sstevel@tonic-gate 	case IPP_ACTION_CONT:
10507c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
10517c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DEFER:
10527c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
10537c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DROP:
10547c478bd9Sstevel@tonic-gate 		return (0);
10557c478bd9Sstevel@tonic-gate 	default:
10567c478bd9Sstevel@tonic-gate 		break;
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/*
10607c478bd9Sstevel@tonic-gate 	 * Translate the action ids into action pointers.
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
10647c478bd9Sstevel@tonic-gate 		return (ENOENT);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	if ((ref_ap = hold_action(ref_aid)) == NULL) {
10677c478bd9Sstevel@tonic-gate 		rele_action(ap);
10687c478bd9Sstevel@tonic-gate 		return (ENOENT);
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
10727c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ref_ap, RW_WRITER);
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if (ref_ap->ippa_state != IPP_ASTATE_AVAILABLE) {
10757c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ref_ap);
10767c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 		rele_action(ref_ap);
10797c478bd9Sstevel@tonic-gate 		rele_action(ap);
10807c478bd9Sstevel@tonic-gate 		return (EPROTO);
10817c478bd9Sstevel@tonic-gate 	}
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	/*
10847c478bd9Sstevel@tonic-gate 	 * Create references between the two actions.
10857c478bd9Sstevel@tonic-gate 	 */
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	rc = ref_action(ap, ref_ap);
10887c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ref_ap);
10897c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	rele_action(ref_ap);
10927c478bd9Sstevel@tonic-gate 	rele_action(ap);
10937c478bd9Sstevel@tonic-gate 	return (rc);
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate #undef	__FN__
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_action_unref"
10987c478bd9Sstevel@tonic-gate int
10997c478bd9Sstevel@tonic-gate ipp_action_unref(
11007c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
11017c478bd9Sstevel@tonic-gate 	ipp_action_id_t	ref_aid,
11027c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags)
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
11057c478bd9Sstevel@tonic-gate 	ipp_action_t	*ref_ap;
11067c478bd9Sstevel@tonic-gate 	int		ref_is_busy;
11077c478bd9Sstevel@tonic-gate 	int		rc;
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if (aid == ref_aid)
11107c478bd9Sstevel@tonic-gate 		return (EINVAL);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	/*
11137c478bd9Sstevel@tonic-gate 	 * Check for a special case 'virtual action' id.
11147c478bd9Sstevel@tonic-gate 	 */
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 	switch (ref_aid) {
11177c478bd9Sstevel@tonic-gate 	case IPP_ACTION_CONT:
11187c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
11197c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DEFER:
11207c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
11217c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DROP:
11227c478bd9Sstevel@tonic-gate 		return (0);
11237c478bd9Sstevel@tonic-gate 	default:
11247c478bd9Sstevel@tonic-gate 		break;
11257c478bd9Sstevel@tonic-gate 	}
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	/*
11287c478bd9Sstevel@tonic-gate 	 * Translate the action ids into action pointers.
11297c478bd9Sstevel@tonic-gate 	 */
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
11327c478bd9Sstevel@tonic-gate 		return (ENOENT);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	if ((ref_ap = hold_action(ref_aid)) == NULL) {
11357c478bd9Sstevel@tonic-gate 		rele_action(ap);
11367c478bd9Sstevel@tonic-gate 		return (ENOENT);
11377c478bd9Sstevel@tonic-gate 	}
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
11407c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ref_ap, RW_WRITER);
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	/*
11437c478bd9Sstevel@tonic-gate 	 * Remove the reference between the actions.
11447c478bd9Sstevel@tonic-gate 	 */
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if ((rc = unref_action(ap, ref_ap)) != 0) {
11477c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ref_ap);
11487c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
11497c478bd9Sstevel@tonic-gate 		rele_action(ref_ap);
11507c478bd9Sstevel@tonic-gate 		rele_action(ap);
11517c478bd9Sstevel@tonic-gate 		return (rc);
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	ref_is_busy = is_action_refd(ref_ap);
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ref_ap);
11577c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	if (flags & IPP_DESTROY_REF) {
11607c478bd9Sstevel@tonic-gate 		if (!ref_is_busy) {
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 			/*
11637c478bd9Sstevel@tonic-gate 			 * Condemn the action so that it will be destroyed.
11647c478bd9Sstevel@tonic-gate 			 */
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 			(void) condemn_action(ap->ippa_condemned, ref_ap);
11677c478bd9Sstevel@tonic-gate 			return (0);
11687c478bd9Sstevel@tonic-gate 		}
11697c478bd9Sstevel@tonic-gate 	}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	rele_action(ref_ap);
11727c478bd9Sstevel@tonic-gate 	rele_action(ap);
11737c478bd9Sstevel@tonic-gate 	return (0);
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate #undef	__FN__
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate /*
11787c478bd9Sstevel@tonic-gate  * Packet manipulation interface.
11797c478bd9Sstevel@tonic-gate  */
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_alloc"
11827c478bd9Sstevel@tonic-gate int
11837c478bd9Sstevel@tonic-gate ipp_packet_alloc(
11847c478bd9Sstevel@tonic-gate 	ipp_packet_t	**ppp,
11857c478bd9Sstevel@tonic-gate 	const char	*name,
11867c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid)
11877c478bd9Sstevel@tonic-gate {
11887c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp;
11897c478bd9Sstevel@tonic-gate 	int		rc;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	ASSERT(ppp != NULL);
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	/*
11947c478bd9Sstevel@tonic-gate 	 * A name is required.
11957c478bd9Sstevel@tonic-gate 	 */
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	if (name == NULL || strlen(name) > MAXNAMELEN - 1)
11987c478bd9Sstevel@tonic-gate 		return (EINVAL);
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	/*
12017c478bd9Sstevel@tonic-gate 	 * Allocate a packet structure from the cache.
12027c478bd9Sstevel@tonic-gate 	 */
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 	if ((rc = alloc_packet(name, aid, &pp)) != 0)
12057c478bd9Sstevel@tonic-gate 		return (rc);
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	if (ipp_packet_logging != 0 && pp->ippp_log == NULL) {
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		/*
12107c478bd9Sstevel@tonic-gate 		 * Logging is turned on but there's no log buffer. We need
12117c478bd9Sstevel@tonic-gate 		 * to allocate one.
12127c478bd9Sstevel@tonic-gate 		 */
12137c478bd9Sstevel@tonic-gate 		if ((pp->ippp_log = kmem_alloc(
12147c478bd9Sstevel@tonic-gate 		    ipp_packet_log_entries * sizeof (ipp_log_t),
12157c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP)) != NULL) {
12167c478bd9Sstevel@tonic-gate 			pp->ippp_log_limit = ipp_packet_log_entries - 1;
12177c478bd9Sstevel@tonic-gate 			pp->ippp_log_windex = 0;
12187c478bd9Sstevel@tonic-gate 		}
12197c478bd9Sstevel@tonic-gate 	} else if (ipp_packet_logging == 0 && pp->ippp_log != NULL) {
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		/*
12227c478bd9Sstevel@tonic-gate 		 * A log buffer is present but logging has been turned off.
12237c478bd9Sstevel@tonic-gate 		 * Free the buffer now,
12247c478bd9Sstevel@tonic-gate 		 */
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		kmem_free(pp->ippp_log,
12277c478bd9Sstevel@tonic-gate 		    (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
12287c478bd9Sstevel@tonic-gate 		pp->ippp_log = NULL;
12297c478bd9Sstevel@tonic-gate 		pp->ippp_log_limit = 0;
12307c478bd9Sstevel@tonic-gate 		pp->ippp_log_windex = 0;
12317c478bd9Sstevel@tonic-gate 	}
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	*ppp = pp;
12347c478bd9Sstevel@tonic-gate 	return (0);
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate #undef	__FN__
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_free"
12397c478bd9Sstevel@tonic-gate void
12407c478bd9Sstevel@tonic-gate ipp_packet_free(
12417c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp)
12427c478bd9Sstevel@tonic-gate {
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	/*
12477c478bd9Sstevel@tonic-gate 	 * If there is a private structure pointer set, call its free
12487c478bd9Sstevel@tonic-gate 	 * function.
12497c478bd9Sstevel@tonic-gate 	 */
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	if (pp->ippp_private) {
12527c478bd9Sstevel@tonic-gate 		pp->ippp_private_free(pp->ippp_private);
12537c478bd9Sstevel@tonic-gate 		pp->ippp_private = NULL;
12547c478bd9Sstevel@tonic-gate 		pp->ippp_private_free = NULL;
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	/*
12587c478bd9Sstevel@tonic-gate 	 * Free the packet structure back to the cache.
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	free_packet(pp);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate #undef	__FN__
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_add_class"
12667c478bd9Sstevel@tonic-gate int
12677c478bd9Sstevel@tonic-gate ipp_packet_add_class(
12687c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp,
12697c478bd9Sstevel@tonic-gate 	const char	*name,
12707c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid)
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate 	ipp_class_t	*cp;
12737c478bd9Sstevel@tonic-gate 	int		rc;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate 	/*
12787c478bd9Sstevel@tonic-gate 	 * A name is required.
12797c478bd9Sstevel@tonic-gate 	 */
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	if (name == NULL || strlen(name) > MAXNAMELEN - 1)
12827c478bd9Sstevel@tonic-gate 		return (EINVAL);
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	/*
12857c478bd9Sstevel@tonic-gate 	 * Check if there is an available class structure.
12867c478bd9Sstevel@tonic-gate 	 */
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	if (pp->ippp_class_windex == pp->ippp_class_limit) {
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 		/*
12917c478bd9Sstevel@tonic-gate 		 * No more structures. Re-allocate the array.
12927c478bd9Sstevel@tonic-gate 		 */
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 		if ((rc = realloc_packet(pp)) != 0)
12957c478bd9Sstevel@tonic-gate 			return (rc);
12967c478bd9Sstevel@tonic-gate 	}
12977c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_class_windex < pp->ippp_class_limit);
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
13007c478bd9Sstevel@tonic-gate 	 * Set up a new class structure.
13017c478bd9Sstevel@tonic-gate 	 */
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	cp = &(pp->ippp_class_array[pp->ippp_class_windex++]);
13047c478bd9Sstevel@tonic-gate 	(void) strcpy(cp->ippc_name, name);
13057c478bd9Sstevel@tonic-gate 	cp->ippc_aid = aid;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	return (0);
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate #undef	__FN__
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_process"
13127c478bd9Sstevel@tonic-gate int
13137c478bd9Sstevel@tonic-gate ipp_packet_process(
13147c478bd9Sstevel@tonic-gate 	ipp_packet_t	**ppp)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp;
13177c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid;
13187c478bd9Sstevel@tonic-gate 	ipp_class_t	*cp;
13197c478bd9Sstevel@tonic-gate 	ipp_log_t	*lp;
13207c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
13217c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
13227c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ippo;
13237c478bd9Sstevel@tonic-gate 	int		rc;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	ASSERT(ppp != NULL);
13267c478bd9Sstevel@tonic-gate 	pp = *ppp;
13277c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	/*
13307c478bd9Sstevel@tonic-gate 	 * Walk the class list.
13317c478bd9Sstevel@tonic-gate 	 */
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	while (pp->ippp_class_rindex < pp->ippp_class_windex) {
13347c478bd9Sstevel@tonic-gate 		cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		/*
13377c478bd9Sstevel@tonic-gate 		 * While there is a real action to invoke...
13387c478bd9Sstevel@tonic-gate 		 */
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 		aid = cp->ippc_aid;
13417c478bd9Sstevel@tonic-gate 		while (aid != IPP_ACTION_CONT &&
13427c478bd9Sstevel@tonic-gate 		    aid != IPP_ACTION_DEFER &&
13437c478bd9Sstevel@tonic-gate 		    aid != IPP_ACTION_DROP) {
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 			ASSERT(aid != IPP_ACTION_INVAL);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 			/*
13487c478bd9Sstevel@tonic-gate 			 * Translate the action id to the action pointer.
13497c478bd9Sstevel@tonic-gate 			 */
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 			if ((ap = hold_action(aid)) == NULL) {
13527c478bd9Sstevel@tonic-gate 				DBG1(DBG_PACKET,
13537c478bd9Sstevel@tonic-gate 				    "action id '%d' not found\n", aid);
13547c478bd9Sstevel@tonic-gate 				return (ENOENT);
13557c478bd9Sstevel@tonic-gate 			}
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 			/*
13587c478bd9Sstevel@tonic-gate 			 * Check that the action is available for use...
13597c478bd9Sstevel@tonic-gate 			 */
13607c478bd9Sstevel@tonic-gate 			LOCK_ACTION(ap, RW_READER);
13617c478bd9Sstevel@tonic-gate 			if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
13627c478bd9Sstevel@tonic-gate 				UNLOCK_ACTION(ap);
13637c478bd9Sstevel@tonic-gate 				rele_action(ap);
13647c478bd9Sstevel@tonic-gate 				return (EPROTO);
13657c478bd9Sstevel@tonic-gate 			}
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 			/*
13687c478bd9Sstevel@tonic-gate 			 * Increment the action's packet count to note that
13697c478bd9Sstevel@tonic-gate 			 * it's being used.
13707c478bd9Sstevel@tonic-gate 			 *
13717c478bd9Sstevel@tonic-gate 			 * NOTE: We only have a read lock, so we need to use
13727c478bd9Sstevel@tonic-gate 			 *	 atomic_add_32(). The read lock is still
13737c478bd9Sstevel@tonic-gate 			 *	 important though as it is crucial to block
13747c478bd9Sstevel@tonic-gate 			 *	 out a destroy operation between the action
13757c478bd9Sstevel@tonic-gate 			 *	 state being checked and the packet count
13767c478bd9Sstevel@tonic-gate 			 *	 being incremented.
13777c478bd9Sstevel@tonic-gate 			 */
13787c478bd9Sstevel@tonic-gate 
1379*1a5e258fSJosef 'Jeff' Sipek 			atomic_inc_32(&(ap->ippa_packets));
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 			imp = ap->ippa_mod;
13827c478bd9Sstevel@tonic-gate 			ASSERT(imp != NULL);
13837c478bd9Sstevel@tonic-gate 			UNLOCK_ACTION(ap);
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 			ippo = imp->ippm_ops;
13867c478bd9Sstevel@tonic-gate 			ASSERT(ippo != NULL);
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 			/*
13897c478bd9Sstevel@tonic-gate 			 * If there's a log, grab the next entry and fill it
13907c478bd9Sstevel@tonic-gate 			 * in.
13917c478bd9Sstevel@tonic-gate 			 */
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 			if (pp->ippp_log != NULL &&
13947c478bd9Sstevel@tonic-gate 			    pp->ippp_log_windex <= pp->ippp_log_limit) {
13957c478bd9Sstevel@tonic-gate 				lp = &(pp->ippp_log[pp->ippp_log_windex++]);
13967c478bd9Sstevel@tonic-gate 				lp->ippl_aid = aid;
13977c478bd9Sstevel@tonic-gate 				(void) strcpy(lp->ippl_name, cp->ippc_name);
13987c478bd9Sstevel@tonic-gate 				gethrestime(&lp->ippl_begin);
13997c478bd9Sstevel@tonic-gate 			} else {
14007c478bd9Sstevel@tonic-gate 				lp = NULL;
14017c478bd9Sstevel@tonic-gate 			}
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 			/*
14047c478bd9Sstevel@tonic-gate 			 * Invoke the action.
14057c478bd9Sstevel@tonic-gate 			 */
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 			rc = ippo->ippo_action_invoke(aid, pp);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 			/*
14107c478bd9Sstevel@tonic-gate 			 * Also log the time that the action finished
14117c478bd9Sstevel@tonic-gate 			 * processing.
14127c478bd9Sstevel@tonic-gate 			 */
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 			if (lp != NULL)
14157c478bd9Sstevel@tonic-gate 				gethrestime(&lp->ippl_end);
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 			/*
14187c478bd9Sstevel@tonic-gate 			 * Decrement the packet count.
14197c478bd9Sstevel@tonic-gate 			 */
14207c478bd9Sstevel@tonic-gate 
1421*1a5e258fSJosef 'Jeff' Sipek 			atomic_dec_32(&(ap->ippa_packets));
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 			/*
14247c478bd9Sstevel@tonic-gate 			 * If the class' action id is the same now as it was
14257c478bd9Sstevel@tonic-gate 			 * before then clearly no 'next action' has been set.
14267c478bd9Sstevel@tonic-gate 			 * This is a protocol error.
14277c478bd9Sstevel@tonic-gate 			 */
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 			if (cp->ippc_aid == aid) {
14307c478bd9Sstevel@tonic-gate 				DBG1(DBG_PACKET,
14317c478bd9Sstevel@tonic-gate 				    "action '%s' did not set next action\n",
14327c478bd9Sstevel@tonic-gate 				    ap->ippa_name);
14337c478bd9Sstevel@tonic-gate 				rele_action(ap);
14347c478bd9Sstevel@tonic-gate 				return (EPROTO);
14357c478bd9Sstevel@tonic-gate 			}
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 			/*
14387c478bd9Sstevel@tonic-gate 			 * The action did not complete successfully. Terminate
14397c478bd9Sstevel@tonic-gate 			 * packet processing.
14407c478bd9Sstevel@tonic-gate 			 */
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 			if (rc != 0) {
14437c478bd9Sstevel@tonic-gate 				DBG2(DBG_PACKET,
14447c478bd9Sstevel@tonic-gate 				    "action error '%d' from action '%s'\n",
14457c478bd9Sstevel@tonic-gate 				    rc, ap->ippa_name);
14467c478bd9Sstevel@tonic-gate 				rele_action(ap);
14477c478bd9Sstevel@tonic-gate 				return (rc);
14487c478bd9Sstevel@tonic-gate 			}
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 			rele_action(ap);
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 			/*
14537c478bd9Sstevel@tonic-gate 			 * Look at the next action.
14547c478bd9Sstevel@tonic-gate 			 */
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 			aid = cp->ippc_aid;
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 		/*
14607c478bd9Sstevel@tonic-gate 		 * No more real actions to invoke, check for 'virtual' ones.
14617c478bd9Sstevel@tonic-gate 		 */
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 		/*
14647c478bd9Sstevel@tonic-gate 		 * Packet deferred: module has held onto packet for processing
14657c478bd9Sstevel@tonic-gate 		 * later.
14667c478bd9Sstevel@tonic-gate 		 */
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 		if (cp->ippc_aid == IPP_ACTION_DEFER) {
14697c478bd9Sstevel@tonic-gate 			*ppp = NULL;
14707c478bd9Sstevel@tonic-gate 			return (0);
14717c478bd9Sstevel@tonic-gate 		}
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 		/*
14747c478bd9Sstevel@tonic-gate 		 * Packet dropped: free the packet and discontinue processing.
14757c478bd9Sstevel@tonic-gate 		 */
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 		if (cp->ippc_aid == IPP_ACTION_DROP) {
14787c478bd9Sstevel@tonic-gate 			freemsg(pp->ippp_data);
14797c478bd9Sstevel@tonic-gate 			ipp_packet_free(pp);
14807c478bd9Sstevel@tonic-gate 			*ppp = NULL;
14817c478bd9Sstevel@tonic-gate 			return (0);
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 		/*
14857c478bd9Sstevel@tonic-gate 		 * Must be 'continue processing': move onto the next class.
14867c478bd9Sstevel@tonic-gate 		 */
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 		ASSERT(cp->ippc_aid == IPP_ACTION_CONT);
14897c478bd9Sstevel@tonic-gate 		pp->ippp_class_rindex++;
14907c478bd9Sstevel@tonic-gate 	}
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	return (0);
14937c478bd9Sstevel@tonic-gate }
14947c478bd9Sstevel@tonic-gate #undef	__FN__
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_next"
14977c478bd9Sstevel@tonic-gate int
14987c478bd9Sstevel@tonic-gate ipp_packet_next(
14997c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp,
15007c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid)
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
15037c478bd9Sstevel@tonic-gate 	ipp_class_t	*cp;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	cp = &(pp->ippp_class_array[pp->ippp_class_rindex]);
15087c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	/*
15117c478bd9Sstevel@tonic-gate 	 * Check for a special case 'virtual action' id.
15127c478bd9Sstevel@tonic-gate 	 */
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	switch (aid) {
15157c478bd9Sstevel@tonic-gate 	case IPP_ACTION_INVAL:
15167c478bd9Sstevel@tonic-gate 		return (EINVAL);
15177c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DEFER:
15187c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
15197c478bd9Sstevel@tonic-gate 	case IPP_ACTION_CONT:
15207c478bd9Sstevel@tonic-gate 	/*FALLTHRU*/
15217c478bd9Sstevel@tonic-gate 	case IPP_ACTION_DROP:
15227c478bd9Sstevel@tonic-gate 		break;
15237c478bd9Sstevel@tonic-gate 	default:
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 		/*
15267c478bd9Sstevel@tonic-gate 		 * Not a virtual action so try to translate the action id
15277c478bd9Sstevel@tonic-gate 		 * into the action pointer to confirm the actions existence.
15287c478bd9Sstevel@tonic-gate 		 */
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		if ((ap = hold_action(aid)) == NULL) {
15317c478bd9Sstevel@tonic-gate 			DBG0(DBG_PACKET, "invalid action\n");
15327c478bd9Sstevel@tonic-gate 			return (ENOENT);
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 		rele_action(ap);
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		break;
15377c478bd9Sstevel@tonic-gate 	}
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 	/*
15407c478bd9Sstevel@tonic-gate 	 * Set the class' new action id.
15417c478bd9Sstevel@tonic-gate 	 */
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 	cp->ippc_aid = aid;
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	return (0);
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate #undef	__FN__
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_set_data"
15507c478bd9Sstevel@tonic-gate void
15517c478bd9Sstevel@tonic-gate ipp_packet_set_data(
15527c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp,
15537c478bd9Sstevel@tonic-gate 	mblk_t		*data)
15547c478bd9Sstevel@tonic-gate {
15557c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
15567c478bd9Sstevel@tonic-gate 	pp->ippp_data = data;
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate #undef	__FN__
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_get_data"
15617c478bd9Sstevel@tonic-gate mblk_t *
15627c478bd9Sstevel@tonic-gate ipp_packet_get_data(
15637c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp)
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
15667c478bd9Sstevel@tonic-gate 	return (pp->ippp_data);
15677c478bd9Sstevel@tonic-gate }
15687c478bd9Sstevel@tonic-gate #undef	__FN__
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_set_private"
15717c478bd9Sstevel@tonic-gate void
15727c478bd9Sstevel@tonic-gate ipp_packet_set_private(
15737c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp,
15747c478bd9Sstevel@tonic-gate 	void		*buf,
15757c478bd9Sstevel@tonic-gate 	void		(*free_func)(void *))
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
15787c478bd9Sstevel@tonic-gate 	ASSERT(free_func != NULL);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	pp->ippp_private = buf;
15817c478bd9Sstevel@tonic-gate 	pp->ippp_private_free = free_func;
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate #undef	__FN__
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_packet_get_private"
15867c478bd9Sstevel@tonic-gate void *
15877c478bd9Sstevel@tonic-gate ipp_packet_get_private(
15887c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	ASSERT(pp != NULL);
15917c478bd9Sstevel@tonic-gate 	return (pp->ippp_private);
15927c478bd9Sstevel@tonic-gate }
15937c478bd9Sstevel@tonic-gate #undef	__FN__
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate /*
15967c478bd9Sstevel@tonic-gate  * Statistics interface.
15977c478bd9Sstevel@tonic-gate  */
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_stat_create"
16007c478bd9Sstevel@tonic-gate int
16017c478bd9Sstevel@tonic-gate ipp_stat_create(
16027c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
16037c478bd9Sstevel@tonic-gate 	const char	*name,
16047c478bd9Sstevel@tonic-gate 	int		nstat,
16057c478bd9Sstevel@tonic-gate 	int		(*update)(ipp_stat_t *, void *, int),
16067c478bd9Sstevel@tonic-gate 	void		*arg,
16077c478bd9Sstevel@tonic-gate 	ipp_stat_t	**spp)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
16107c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
16117c478bd9Sstevel@tonic-gate 	ipp_stat_impl_t	*sip;
16127c478bd9Sstevel@tonic-gate 	ipp_stat_t	*sp;
16137c478bd9Sstevel@tonic-gate 	kstat_t		*ksp;
16147c478bd9Sstevel@tonic-gate 	char		*class;
16157c478bd9Sstevel@tonic-gate 	char		*modname;
16167c478bd9Sstevel@tonic-gate 	int		instance;
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	ASSERT(spp != NULL);
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	/*
16217c478bd9Sstevel@tonic-gate 	 * Sanity check the arguments.
16227c478bd9Sstevel@tonic-gate 	 */
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	if (name == NULL || nstat <= 0 || update == NULL)
16257c478bd9Sstevel@tonic-gate 		return (EINVAL);
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 	/*
16287c478bd9Sstevel@tonic-gate 	 * Translate the action id into the action pointer.
16297c478bd9Sstevel@tonic-gate 	 */
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	if ((ap = hold_action(aid)) == NULL)
16327c478bd9Sstevel@tonic-gate 		return (ENOENT);
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	/*
16357c478bd9Sstevel@tonic-gate 	 * Grab relevant action and module information.
16367c478bd9Sstevel@tonic-gate 	 */
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
16397c478bd9Sstevel@tonic-gate 	class = ap->ippa_name;
16407c478bd9Sstevel@tonic-gate 	instance = (int)ap->ippa_id;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	imp = ap->ippa_mod;
16437c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_READER);
16467c478bd9Sstevel@tonic-gate 	modname = imp->ippm_name;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	/*
16497c478bd9Sstevel@tonic-gate 	 * Allocate a stats info structure.
16507c478bd9Sstevel@tonic-gate 	 */
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	if ((sip = kmem_alloc(sizeof (ipp_stat_impl_t), KM_NOSLEEP)) == NULL)
16537c478bd9Sstevel@tonic-gate 		return (ENOMEM);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	/*
16567c478bd9Sstevel@tonic-gate 	 * Create a set of kstats.
16577c478bd9Sstevel@tonic-gate 	 */
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	DBG2(DBG_STATS, "creating stat set '%s' for action '%s'\n",
16607c478bd9Sstevel@tonic-gate 	    name, class);
1661d624471bSelowe 	if ((ksp = kstat_create(modname, instance, name, class,
16627c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, nstat, KSTAT_FLAG_WRITABLE)) == NULL) {
16637c478bd9Sstevel@tonic-gate 		kmem_free(sip, sizeof (ipp_stat_impl_t));
16647c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
16657c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
16667c478bd9Sstevel@tonic-gate 		return (EINVAL);	/* Assume EINVAL was the cause */
16677c478bd9Sstevel@tonic-gate 	}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
16707c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	DBG1(DBG_STATS, "ks_data = %p\n", ksp->ks_data);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	 * Set up the kstats structure with a private data pointer and an
16767c478bd9Sstevel@tonic-gate 	 * 'update' function.
16777c478bd9Sstevel@tonic-gate 	 */
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	ksp->ks_update = update_stats;
16807c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)sip;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	/*
16837c478bd9Sstevel@tonic-gate 	 * Keep a reference to the kstats structure in our own stats info
16847c478bd9Sstevel@tonic-gate 	 * structure.
16857c478bd9Sstevel@tonic-gate 	 */
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 	sip->ippsi_ksp = ksp;
16887c478bd9Sstevel@tonic-gate 	sip->ippsi_data = ksp->ks_data;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	/*
16917c478bd9Sstevel@tonic-gate 	 * Fill in the rest of the stats info structure.
16927c478bd9Sstevel@tonic-gate 	 */
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	(void) strcpy(sip->ippsi_name, name);
16957c478bd9Sstevel@tonic-gate 	sip->ippsi_arg = arg;
16967c478bd9Sstevel@tonic-gate 	sip->ippsi_update = update;
16977c478bd9Sstevel@tonic-gate 	sip->ippsi_limit = nstat;
16987c478bd9Sstevel@tonic-gate 	sip->ippsi_count = 0;
16997c478bd9Sstevel@tonic-gate 	mutex_init(sip->ippsi_lock, NULL, MUTEX_ADAPTIVE,
17007c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	/*
17037c478bd9Sstevel@tonic-gate 	 * Case the stats info structure to a semi-opaque structure that
17047c478bd9Sstevel@tonic-gate 	 * we pass back to the caller.
17057c478bd9Sstevel@tonic-gate 	 */
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	sp = (ipp_stat_t *)sip;
17087c478bd9Sstevel@tonic-gate 	ASSERT(sp->ipps_data == sip->ippsi_data);
17097c478bd9Sstevel@tonic-gate 	*spp = sp;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	rele_action(ap);
17127c478bd9Sstevel@tonic-gate 	return (0);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate #undef __FN__
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_stat_install"
17177c478bd9Sstevel@tonic-gate void
17187c478bd9Sstevel@tonic-gate ipp_stat_install(
17197c478bd9Sstevel@tonic-gate 	ipp_stat_t	*sp)
17207c478bd9Sstevel@tonic-gate {
17217c478bd9Sstevel@tonic-gate 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	ASSERT(sp != NULL);
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	/*
17267c478bd9Sstevel@tonic-gate 	 * Install the set of kstats referenced by the stats info structure.
17277c478bd9Sstevel@tonic-gate 	 */
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	DBG1(DBG_STATS, "installing stat set '%s'\n", sip->ippsi_name);
17307c478bd9Sstevel@tonic-gate 	kstat_install(sip->ippsi_ksp);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate #undef	__FN__
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_stat_destroy"
17357c478bd9Sstevel@tonic-gate void
17367c478bd9Sstevel@tonic-gate ipp_stat_destroy(
17377c478bd9Sstevel@tonic-gate 	ipp_stat_t	*sp)
17387c478bd9Sstevel@tonic-gate {
17397c478bd9Sstevel@tonic-gate 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	ASSERT(sp != NULL);
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	/*
17447c478bd9Sstevel@tonic-gate 	 * Destroy the set of kstats referenced by the stats info structure.
17457c478bd9Sstevel@tonic-gate 	 */
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 	DBG1(DBG_STATS, "destroying stat set '%s'\n", sip->ippsi_name);
17487c478bd9Sstevel@tonic-gate 	kstat_delete(sip->ippsi_ksp);
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	/*
17517c478bd9Sstevel@tonic-gate 	 * Destroy the stats info structure itself.
17527c478bd9Sstevel@tonic-gate 	 */
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	mutex_destroy(sip->ippsi_lock);
17557c478bd9Sstevel@tonic-gate 	kmem_free(sip, sizeof (ipp_stat_impl_t));
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate #undef	__FN__
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_stat_named_init"
17607c478bd9Sstevel@tonic-gate int
17617c478bd9Sstevel@tonic-gate ipp_stat_named_init(
17627c478bd9Sstevel@tonic-gate 	ipp_stat_t	*sp,
17637c478bd9Sstevel@tonic-gate 	const char	*name,
17647c478bd9Sstevel@tonic-gate 	uchar_t		type,
17657c478bd9Sstevel@tonic-gate 	ipp_named_t	*np)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate 	ipp_stat_impl_t	*sip = (ipp_stat_impl_t *)sp;
17687c478bd9Sstevel@tonic-gate 	uchar_t		ktype;
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 	ASSERT(sp != NULL);
17717c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	if (name == NULL)
17747c478bd9Sstevel@tonic-gate 		return (EINVAL);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	if ((type & IPP_STAT_TAG) == 0)
17777c478bd9Sstevel@tonic-gate 		return (EINVAL);
17787c478bd9Sstevel@tonic-gate 	ktype = type & ~IPP_STAT_TAG;
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	/*
17817c478bd9Sstevel@tonic-gate 	 * Check we will not exceed the maximum number of a stats that was
17827c478bd9Sstevel@tonic-gate 	 * indicated during set creation.
17837c478bd9Sstevel@tonic-gate 	 */
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	mutex_enter(sip->ippsi_lock);
17867c478bd9Sstevel@tonic-gate 	if (sip->ippsi_count >= sip->ippsi_limit) {
17877c478bd9Sstevel@tonic-gate 		mutex_exit(sip->ippsi_lock);
17887c478bd9Sstevel@tonic-gate 		return (ENOSPC);
17897c478bd9Sstevel@tonic-gate 	}
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	/*
17927c478bd9Sstevel@tonic-gate 	 * Bump the count.
17937c478bd9Sstevel@tonic-gate 	 */
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	sip->ippsi_count++;
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	/*
17987c478bd9Sstevel@tonic-gate 	 * Create a new named kstat.
17997c478bd9Sstevel@tonic-gate 	 */
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 	DBG3(DBG_STATS, "%s.%s: knp = %p\n", sip->ippsi_name, name, np);
1802d624471bSelowe 	kstat_named_init(np, name, ktype);
18037c478bd9Sstevel@tonic-gate 	mutex_exit(sip->ippsi_lock);
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	return (0);
18067c478bd9Sstevel@tonic-gate }
18077c478bd9Sstevel@tonic-gate #undef	__FN__
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate #define	__FN__	"ipp_stat_named_op"
18107c478bd9Sstevel@tonic-gate int
18117c478bd9Sstevel@tonic-gate ipp_stat_named_op(
18127c478bd9Sstevel@tonic-gate 	ipp_named_t	*np,
18137c478bd9Sstevel@tonic-gate 	void		*valp,
18147c478bd9Sstevel@tonic-gate 	int		rw)
18157c478bd9Sstevel@tonic-gate {
18167c478bd9Sstevel@tonic-gate 	kstat_named_t	*knp;
18177c478bd9Sstevel@tonic-gate 	uchar_t		type;
18187c478bd9Sstevel@tonic-gate 	int		rc = 0;
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	ASSERT(np != NULL);
18217c478bd9Sstevel@tonic-gate 	ASSERT(valp != NULL);
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 	knp = np;
18247c478bd9Sstevel@tonic-gate 	type = knp->data_type | IPP_STAT_TAG;
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	/*
18277c478bd9Sstevel@tonic-gate 	 * Copy data to or from the named kstat, depending on the specified
18287c478bd9Sstevel@tonic-gate 	 * opcode.
18297c478bd9Sstevel@tonic-gate 	 */
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	switch (rw) {
18327c478bd9Sstevel@tonic-gate 	case IPP_STAT_WRITE:
18337c478bd9Sstevel@tonic-gate 		switch (type) {
18347c478bd9Sstevel@tonic-gate 		case IPP_STAT_INT32:
18357c478bd9Sstevel@tonic-gate 			*(int32_t *)valp = knp->value.i32;
18367c478bd9Sstevel@tonic-gate 			break;
18377c478bd9Sstevel@tonic-gate 		case IPP_STAT_UINT32:
18387c478bd9Sstevel@tonic-gate 			*(uint32_t *)valp = knp->value.ui32;
18397c478bd9Sstevel@tonic-gate 			break;
18407c478bd9Sstevel@tonic-gate 		case IPP_STAT_INT64:
18417c478bd9Sstevel@tonic-gate 			*(int64_t *)valp = knp->value.i64;
18427c478bd9Sstevel@tonic-gate 			break;
18437c478bd9Sstevel@tonic-gate 		case IPP_STAT_UINT64:
18447c478bd9Sstevel@tonic-gate 			*(uint64_t *)valp = knp->value.ui64;
18457c478bd9Sstevel@tonic-gate 			break;
18467c478bd9Sstevel@tonic-gate 		case IPP_STAT_STRING:
18477c478bd9Sstevel@tonic-gate 			(void) strncpy(valp, knp->value.c, 16);
18487c478bd9Sstevel@tonic-gate 			break;
18497c478bd9Sstevel@tonic-gate 		default:
18507c478bd9Sstevel@tonic-gate 			ASSERT(0);	/* should not reach here */
18517c478bd9Sstevel@tonic-gate 			break;
18527c478bd9Sstevel@tonic-gate 		}
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 		break;
18557c478bd9Sstevel@tonic-gate 	case IPP_STAT_READ:
18567c478bd9Sstevel@tonic-gate 		switch (type) {
18577c478bd9Sstevel@tonic-gate 		case IPP_STAT_INT32:
18587c478bd9Sstevel@tonic-gate 			knp->value.i32 = *(int32_t *)valp;
18597c478bd9Sstevel@tonic-gate 			break;
18607c478bd9Sstevel@tonic-gate 		case IPP_STAT_UINT32:
18617c478bd9Sstevel@tonic-gate 			knp->value.ui32 = *(uint32_t *)valp;
18627c478bd9Sstevel@tonic-gate 			break;
18637c478bd9Sstevel@tonic-gate 		case IPP_STAT_INT64:
18647c478bd9Sstevel@tonic-gate 			knp->value.i64 = *(int64_t *)valp;
18657c478bd9Sstevel@tonic-gate 			break;
18667c478bd9Sstevel@tonic-gate 		case IPP_STAT_UINT64:
18677c478bd9Sstevel@tonic-gate 			knp->value.ui64 = *(uint64_t *)valp;
18687c478bd9Sstevel@tonic-gate 			break;
18697c478bd9Sstevel@tonic-gate 		case IPP_STAT_STRING:
18707c478bd9Sstevel@tonic-gate 			(void) strncpy(knp->value.c, valp, 16);
18717c478bd9Sstevel@tonic-gate 			break;
18727c478bd9Sstevel@tonic-gate 		default:
18737c478bd9Sstevel@tonic-gate 			ASSERT(0);	/* should not reach here */
18747c478bd9Sstevel@tonic-gate 			break;
18757c478bd9Sstevel@tonic-gate 		}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 		break;
18787c478bd9Sstevel@tonic-gate 	default:
18797c478bd9Sstevel@tonic-gate 		rc = EINVAL;
18807c478bd9Sstevel@tonic-gate 	}
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	return (rc);
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate #undef	__FN__
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate /*
18877c478bd9Sstevel@tonic-gate  * Local functions (for local people. There's nothing for you here!)
18887c478bd9Sstevel@tonic-gate  */
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate #define	__FN__	"ref_mod"
18917c478bd9Sstevel@tonic-gate static int
18927c478bd9Sstevel@tonic-gate ref_mod(
18937c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap,
18947c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp)
18957c478bd9Sstevel@tonic-gate {
18967c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
18977c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ap->ippa_lock));
19007c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(imp->ippm_lock));
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate 	/*
19037c478bd9Sstevel@tonic-gate 	 * Add the new reference at the end of the module's list.
19047c478bd9Sstevel@tonic-gate 	 */
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	rpp = &(imp->ippm_action);
19077c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
19087c478bd9Sstevel@tonic-gate 		ASSERT(rp->ippr_action != ap);
19097c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	/*
19137c478bd9Sstevel@tonic-gate 	 * Allocate a reference structure.
19147c478bd9Sstevel@tonic-gate 	 */
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
19177c478bd9Sstevel@tonic-gate 		return (ENOMEM);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	/*
19207c478bd9Sstevel@tonic-gate 	 * Set the reference to the action and link it onto the module's list.
19217c478bd9Sstevel@tonic-gate 	 */
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	rp->ippr_action = ap;
19247c478bd9Sstevel@tonic-gate 	*rpp = rp;
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	/*
19277c478bd9Sstevel@tonic-gate 	 * Keep a 'back pointer' from the action structure to the module
19287c478bd9Sstevel@tonic-gate 	 * structure.
19297c478bd9Sstevel@tonic-gate 	 */
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	ap->ippa_mod = imp;
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	return (0);
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate #undef	__FN__
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate #define	__FN__	"unref_mod"
19387c478bd9Sstevel@tonic-gate static void
19397c478bd9Sstevel@tonic-gate unref_mod(
19407c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap,
19417c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp)
19427c478bd9Sstevel@tonic-gate {
19437c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
19447c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ap->ippa_lock));
19477c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(imp->ippm_lock));
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	/*
19507c478bd9Sstevel@tonic-gate 	 * Scan the module's list for the reference to the action.
19517c478bd9Sstevel@tonic-gate 	 */
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	rpp = &(imp->ippm_action);
19547c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
19557c478bd9Sstevel@tonic-gate 		if (rp->ippr_action == ap)
19567c478bd9Sstevel@tonic-gate 			break;
19577c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
19587c478bd9Sstevel@tonic-gate 	}
19597c478bd9Sstevel@tonic-gate 	ASSERT(rp != NULL);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	/*
19627c478bd9Sstevel@tonic-gate 	 * Unlink the reference structure and free it.
19637c478bd9Sstevel@tonic-gate 	 */
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	*rpp = rp->ippr_nextp;
19667c478bd9Sstevel@tonic-gate 	kmem_free(rp, sizeof (ipp_ref_t));
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	/*
19697c478bd9Sstevel@tonic-gate 	 * NULL the 'back pointer'.
19707c478bd9Sstevel@tonic-gate 	 */
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	ap->ippa_mod = NULL;
19737c478bd9Sstevel@tonic-gate }
19747c478bd9Sstevel@tonic-gate #undef	__FN__
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate #define	__FN__	"is_mod_busy"
19777c478bd9Sstevel@tonic-gate static int
19787c478bd9Sstevel@tonic-gate is_mod_busy(
19797c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp)
19807c478bd9Sstevel@tonic-gate {
19817c478bd9Sstevel@tonic-gate 	/*
19827c478bd9Sstevel@tonic-gate 	 * Return a value which is true (non-zero) iff the module refers
19837c478bd9Sstevel@tonic-gate 	 * to no actions.
19847c478bd9Sstevel@tonic-gate 	 */
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	return (imp->ippm_action != NULL);
19877c478bd9Sstevel@tonic-gate }
19887c478bd9Sstevel@tonic-gate #undef	__FN__
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate #define	__FN__	"get_mod_ref"
19917c478bd9Sstevel@tonic-gate static int
19927c478bd9Sstevel@tonic-gate get_mod_ref(
19937c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp,
19947c478bd9Sstevel@tonic-gate 	ipp_action_id_t	**bufp,
19957c478bd9Sstevel@tonic-gate 	int		*neltp)
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
19987c478bd9Sstevel@tonic-gate 	int		nelt;
19997c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
20007c478bd9Sstevel@tonic-gate 	ipp_action_id_t	*buf;
20017c478bd9Sstevel@tonic-gate 	int		length;
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	ASSERT(rw_lock_held(imp->ippm_lock));
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 	/*
20067c478bd9Sstevel@tonic-gate 	 * Count the number of actions referred to from the module structure.
20077c478bd9Sstevel@tonic-gate 	 */
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	nelt = 0;
20107c478bd9Sstevel@tonic-gate 	for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
20117c478bd9Sstevel@tonic-gate 		nelt++;
20127c478bd9Sstevel@tonic-gate 	}
20137c478bd9Sstevel@tonic-gate 	DBG1(DBG_LIST, "%d actions found\n", nelt);
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	/*
20167c478bd9Sstevel@tonic-gate 	 * If there are no actions referred to then there's nothing to do.
20177c478bd9Sstevel@tonic-gate 	 */
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	if (nelt == 0) {
20207c478bd9Sstevel@tonic-gate 		*bufp = NULL;
20217c478bd9Sstevel@tonic-gate 		*neltp = 0;
20227c478bd9Sstevel@tonic-gate 		return (0);
20237c478bd9Sstevel@tonic-gate 	}
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 	/*
20267c478bd9Sstevel@tonic-gate 	 * Allocate a buffer to pass back to the caller.
20277c478bd9Sstevel@tonic-gate 	 */
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	length = nelt * sizeof (ipp_action_id_t);
20307c478bd9Sstevel@tonic-gate 	if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL)
20317c478bd9Sstevel@tonic-gate 		return (ENOMEM);
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	/*
20347c478bd9Sstevel@tonic-gate 	 * Fill the buffer with an array of action ids.
20357c478bd9Sstevel@tonic-gate 	 */
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	*bufp = buf;
20387c478bd9Sstevel@tonic-gate 	*neltp = nelt;
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	for (rp = imp->ippm_action; rp != NULL; rp = rp->ippr_nextp) {
20417c478bd9Sstevel@tonic-gate 		ap = rp->ippr_action;
20427c478bd9Sstevel@tonic-gate 		*buf++ = ap->ippa_id;
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
20467c478bd9Sstevel@tonic-gate 	return (0);
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate #undef	__FN__
20497c478bd9Sstevel@tonic-gate 
20507c478bd9Sstevel@tonic-gate #define	__FN__	"get_mods"
20517c478bd9Sstevel@tonic-gate static int
20527c478bd9Sstevel@tonic-gate get_mods(
20537c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	**bufp,
20547c478bd9Sstevel@tonic-gate 	int		*neltp)
20557c478bd9Sstevel@tonic-gate {
20567c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	*buf;
20577c478bd9Sstevel@tonic-gate 	int		length;
20587c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid;
20597c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byname_lock, RW_READER);
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	/*
20657c478bd9Sstevel@tonic-gate 	 * If there are no modules registered then there's nothing to do.
20667c478bd9Sstevel@tonic-gate 	 */
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	if (ipp_mod_count == 0) {
20697c478bd9Sstevel@tonic-gate 		DBG0(DBG_LIST, "no modules registered\n");
20707c478bd9Sstevel@tonic-gate 		*bufp = NULL;
20717c478bd9Sstevel@tonic-gate 		*neltp = 0;
20727c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
20737c478bd9Sstevel@tonic-gate 		return (0);
20747c478bd9Sstevel@tonic-gate 	}
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	/*
20777c478bd9Sstevel@tonic-gate 	 * Allocate a buffer to pass back to the caller.
20787c478bd9Sstevel@tonic-gate 	 */
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	DBG1(DBG_LIST, "%d modules registered\n", ipp_mod_count);
20817c478bd9Sstevel@tonic-gate 	length = ipp_mod_count * sizeof (ipp_mod_id_t);
20827c478bd9Sstevel@tonic-gate 	if ((buf = kmem_alloc(length, KM_NOSLEEP)) == NULL) {
20837c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
20847c478bd9Sstevel@tonic-gate 		return (ENOMEM);
20857c478bd9Sstevel@tonic-gate 	}
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byid_lock, RW_READER);
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	/*
20907c478bd9Sstevel@tonic-gate 	 * Search the array of all modules.
20917c478bd9Sstevel@tonic-gate 	 */
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	*bufp = buf;
20947c478bd9Sstevel@tonic-gate 	*neltp = ipp_mod_count;
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	for (mid = IPP_MOD_RESERVED + 1; mid <= ipp_mid_limit; mid++) {
20977c478bd9Sstevel@tonic-gate 		if ((imp = ipp_mod_byid[mid]) == NULL)
20987c478bd9Sstevel@tonic-gate 			continue;
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 		/*
21017c478bd9Sstevel@tonic-gate 		 * If the module has 'destruct pending' set then it means it
21027c478bd9Sstevel@tonic-gate 		 * is either still in the cache (i.e not allocated) or in the
21037c478bd9Sstevel@tonic-gate 		 * process of being set up by alloc_mod().
21047c478bd9Sstevel@tonic-gate 		 */
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 		LOCK_MOD(imp, RW_READER);
21077c478bd9Sstevel@tonic-gate 		ASSERT(imp->ippm_id == mid);
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 		if (imp->ippm_destruct_pending) {
21107c478bd9Sstevel@tonic-gate 			UNLOCK_MOD(imp);
21117c478bd9Sstevel@tonic-gate 			continue;
21127c478bd9Sstevel@tonic-gate 		}
21137c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 		*buf++ = mid;
21167c478bd9Sstevel@tonic-gate 	}
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byid_lock);
21197c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byname_lock);
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	ASSERT((uintptr_t)buf == (uintptr_t)*bufp + length);
21227c478bd9Sstevel@tonic-gate 	return (0);
21237c478bd9Sstevel@tonic-gate }
21247c478bd9Sstevel@tonic-gate #undef	__FN__
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate #define	__FN__	"find_mod"
21277c478bd9Sstevel@tonic-gate static ipp_mod_id_t
21287c478bd9Sstevel@tonic-gate find_mod(
21297c478bd9Sstevel@tonic-gate 	const char	*modname)
21307c478bd9Sstevel@tonic-gate {
21317c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid;
21327c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
21337c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
21347c478bd9Sstevel@tonic-gate 	int		hb;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	ASSERT(modname != NULL);
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byname_lock, RW_READER);
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	/*
21417c478bd9Sstevel@tonic-gate 	 * Quick return if no modules are registered.
21427c478bd9Sstevel@tonic-gate 	 */
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	if (ipp_mod_count == 0) {
21457c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
21467c478bd9Sstevel@tonic-gate 		return (IPP_MOD_INVAL);
21477c478bd9Sstevel@tonic-gate 	}
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	/*
21507c478bd9Sstevel@tonic-gate 	 * Find the hash bucket where the module structure should be.
21517c478bd9Sstevel@tonic-gate 	 */
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	hb = hash(modname);
21547c478bd9Sstevel@tonic-gate 	rp = ipp_mod_byname[hb];
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	/*
21577c478bd9Sstevel@tonic-gate 	 * Scan the bucket for a match.
21587c478bd9Sstevel@tonic-gate 	 */
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	while (rp != NULL) {
21617c478bd9Sstevel@tonic-gate 		imp = rp->ippr_mod;
21627c478bd9Sstevel@tonic-gate 		if (strcmp(imp->ippm_name, modname) == 0)
21637c478bd9Sstevel@tonic-gate 			break;
21647c478bd9Sstevel@tonic-gate 		rp = rp->ippr_nextp;
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	if (rp == NULL) {
21687c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
21697c478bd9Sstevel@tonic-gate 		return (IPP_MOD_INVAL);
21707c478bd9Sstevel@tonic-gate 	}
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (imp->ippm_state == IPP_MODSTATE_PROTO) {
21737c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
21747c478bd9Sstevel@tonic-gate 		return (IPP_MOD_INVAL);
21757c478bd9Sstevel@tonic-gate 	}
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	mid = imp->ippm_id;
21787c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byname_lock);
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	return (mid);
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate #undef __FN__
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate #define	__FN__	"alloc_mod"
21857c478bd9Sstevel@tonic-gate static int
21867c478bd9Sstevel@tonic-gate alloc_mod(
21877c478bd9Sstevel@tonic-gate 	const char	*modname,
21887c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	*midp)
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
21917c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
21927c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
21937c478bd9Sstevel@tonic-gate 	int		hb;
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate 	ASSERT(modname != NULL);
21967c478bd9Sstevel@tonic-gate 	ASSERT(midp != NULL);
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byname_lock, RW_WRITER);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	/*
22017c478bd9Sstevel@tonic-gate 	 * Find the right hash bucket for a module of the given name.
22027c478bd9Sstevel@tonic-gate 	 */
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 	hb = hash(modname);
22057c478bd9Sstevel@tonic-gate 	rpp = &ipp_mod_byname[hb];
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	/*
22087c478bd9Sstevel@tonic-gate 	 * Scan the bucket making sure the module isn't already
22097c478bd9Sstevel@tonic-gate 	 * registered.
22107c478bd9Sstevel@tonic-gate 	 */
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
22137c478bd9Sstevel@tonic-gate 		imp = rp->ippr_mod;
22147c478bd9Sstevel@tonic-gate 		if (strcmp(imp->ippm_name, modname) == 0) {
22157c478bd9Sstevel@tonic-gate 			DBG1(DBG_MOD, "module '%s' already exists\n", modname);
22167c478bd9Sstevel@tonic-gate 			rw_exit(ipp_mod_byname_lock);
22177c478bd9Sstevel@tonic-gate 			return (EEXIST);
22187c478bd9Sstevel@tonic-gate 		}
22197c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
22207c478bd9Sstevel@tonic-gate 	}
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 	/*
22237c478bd9Sstevel@tonic-gate 	 * Allocate a new reference structure and a new module structure.
22247c478bd9Sstevel@tonic-gate 	 */
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
22277c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
22287c478bd9Sstevel@tonic-gate 		return (ENOMEM);
22297c478bd9Sstevel@tonic-gate 	}
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	if ((imp = kmem_cache_alloc(ipp_mod_cache, KM_NOSLEEP)) == NULL) {
22327c478bd9Sstevel@tonic-gate 		kmem_free(rp, sizeof (ipp_ref_t));
22337c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
22347c478bd9Sstevel@tonic-gate 		return (ENOMEM);
22357c478bd9Sstevel@tonic-gate 	}
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	/*
22387c478bd9Sstevel@tonic-gate 	 * Set up the name of the new structure.
22397c478bd9Sstevel@tonic-gate 	 */
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	(void) strcpy(imp->ippm_name, modname);
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	/*
22447c478bd9Sstevel@tonic-gate 	 * Make sure the 'destruct pending' flag is clear. This indicates
22457c478bd9Sstevel@tonic-gate 	 * that the structure is no longer part of the cache.
22467c478bd9Sstevel@tonic-gate 	 */
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
22497c478bd9Sstevel@tonic-gate 	imp->ippm_destruct_pending = B_FALSE;
22507c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	/*
22537c478bd9Sstevel@tonic-gate 	 * Set the reference and link it into the hash bucket.
22547c478bd9Sstevel@tonic-gate 	 */
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	rp->ippr_mod = imp;
22577c478bd9Sstevel@tonic-gate 	*rpp = rp;
22587c478bd9Sstevel@tonic-gate 
22597c478bd9Sstevel@tonic-gate 	/*
22607c478bd9Sstevel@tonic-gate 	 * Increment the module count.
22617c478bd9Sstevel@tonic-gate 	 */
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	ipp_mod_count++;
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 	*midp = imp->ippm_id;
22667c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byname_lock);
22677c478bd9Sstevel@tonic-gate 	return (0);
22687c478bd9Sstevel@tonic-gate }
22697c478bd9Sstevel@tonic-gate #undef	__FN__
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate #define	__FN__	"free_mod"
22727c478bd9Sstevel@tonic-gate static void
22737c478bd9Sstevel@tonic-gate free_mod(
22747c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp)
22757c478bd9Sstevel@tonic-gate {
22767c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
22777c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
22787c478bd9Sstevel@tonic-gate 	int		hb;
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byname_lock, RW_WRITER);
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 	/*
22837c478bd9Sstevel@tonic-gate 	 * Find the hash bucket where the module structure should be.
22847c478bd9Sstevel@tonic-gate 	 */
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 	hb = hash(imp->ippm_name);
22877c478bd9Sstevel@tonic-gate 	rpp = &ipp_mod_byname[hb];
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	/*
22907c478bd9Sstevel@tonic-gate 	 * Scan the bucket for a match.
22917c478bd9Sstevel@tonic-gate 	 */
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
22947c478bd9Sstevel@tonic-gate 		if (rp->ippr_mod == imp)
22957c478bd9Sstevel@tonic-gate 			break;
22967c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
22977c478bd9Sstevel@tonic-gate 	}
22987c478bd9Sstevel@tonic-gate 	ASSERT(rp != NULL);
22997c478bd9Sstevel@tonic-gate 
23007c478bd9Sstevel@tonic-gate 	/*
23017c478bd9Sstevel@tonic-gate 	 * Unlink the reference structure and free it.
23027c478bd9Sstevel@tonic-gate 	 */
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 	*rpp = rp->ippr_nextp;
23057c478bd9Sstevel@tonic-gate 	kmem_free(rp, sizeof (ipp_ref_t));
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	/*
23087c478bd9Sstevel@tonic-gate 	 * Decrement the module count.
23097c478bd9Sstevel@tonic-gate 	 */
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 	ipp_mod_count--;
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 	/*
23147c478bd9Sstevel@tonic-gate 	 * Empty the name.
23157c478bd9Sstevel@tonic-gate 	 */
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	*imp->ippm_name = '\0';
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	/*
23207c478bd9Sstevel@tonic-gate 	 * If the hold count is zero then we can free the structure
23217c478bd9Sstevel@tonic-gate 	 * immediately, otherwise we defer to rele_mod().
23227c478bd9Sstevel@tonic-gate 	 */
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
23257c478bd9Sstevel@tonic-gate 	imp->ippm_destruct_pending = B_TRUE;
23267c478bd9Sstevel@tonic-gate 	if (imp->ippm_hold_count == 0) {
23277c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
23287c478bd9Sstevel@tonic-gate 		kmem_cache_free(ipp_mod_cache, imp);
23297c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byname_lock);
23307c478bd9Sstevel@tonic-gate 		return;
23317c478bd9Sstevel@tonic-gate 	}
23327c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
23337c478bd9Sstevel@tonic-gate 
23347c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byname_lock);
23357c478bd9Sstevel@tonic-gate }
23367c478bd9Sstevel@tonic-gate #undef __FN__
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate #define	__FN__	"hold_mod"
23397c478bd9Sstevel@tonic-gate static ipp_mod_t *
23407c478bd9Sstevel@tonic-gate hold_mod(
23417c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid)
23427c478bd9Sstevel@tonic-gate {
23437c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 	if (mid < 0)
23467c478bd9Sstevel@tonic-gate 		return (NULL);
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	/*
23497c478bd9Sstevel@tonic-gate 	 * Use the module id as an index into the array of all module
23507c478bd9Sstevel@tonic-gate 	 * structures.
23517c478bd9Sstevel@tonic-gate 	 */
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byid_lock, RW_READER);
23547c478bd9Sstevel@tonic-gate 	if ((imp = ipp_mod_byid[mid]) == NULL) {
23557c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byid_lock);
23567c478bd9Sstevel@tonic-gate 		return (NULL);
23577c478bd9Sstevel@tonic-gate 	}
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_id == mid);
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 	/*
23627c478bd9Sstevel@tonic-gate 	 * If the modul has 'destruct pending' set then it means it is either
23637c478bd9Sstevel@tonic-gate 	 * still in the cache (i.e not allocated) or in the process of
23647c478bd9Sstevel@tonic-gate 	 * being set up by alloc_mod().
23657c478bd9Sstevel@tonic-gate 	 */
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_READER);
23687c478bd9Sstevel@tonic-gate 	if (imp->ippm_destruct_pending) {
23697c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
23707c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byid_lock);
23717c478bd9Sstevel@tonic-gate 		return (NULL);
23727c478bd9Sstevel@tonic-gate 	}
23737c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 	/*
23767c478bd9Sstevel@tonic-gate 	 * Increment the hold count to prevent the structure from being
23777c478bd9Sstevel@tonic-gate 	 * freed.
23787c478bd9Sstevel@tonic-gate 	 */
23797c478bd9Sstevel@tonic-gate 
2380*1a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&(imp->ippm_hold_count));
23817c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byid_lock);
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 	return (imp);
23847c478bd9Sstevel@tonic-gate }
23857c478bd9Sstevel@tonic-gate #undef	__FN__
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate #define	__FN__	"rele_mod"
23887c478bd9Sstevel@tonic-gate static void
23897c478bd9Sstevel@tonic-gate rele_mod(
23907c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp)
23917c478bd9Sstevel@tonic-gate {
23927c478bd9Sstevel@tonic-gate 	/*
23937c478bd9Sstevel@tonic-gate 	 * This call means we're done with the pointer so we can drop the
23947c478bd9Sstevel@tonic-gate 	 * hold count.
23957c478bd9Sstevel@tonic-gate 	 */
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_hold_count != 0);
2398*1a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&(imp->ippm_hold_count));
23997c478bd9Sstevel@tonic-gate 
24007c478bd9Sstevel@tonic-gate 	/*
24017c478bd9Sstevel@tonic-gate 	 * If the structure has 'destruct pending' set then we tried to free
24027c478bd9Sstevel@tonic-gate 	 * it but couldn't, so do it now.
24037c478bd9Sstevel@tonic-gate 	 */
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_READER);
24067c478bd9Sstevel@tonic-gate 	if (imp->ippm_destruct_pending && imp->ippm_hold_count == 0) {
24077c478bd9Sstevel@tonic-gate 		UNLOCK_MOD(imp);
24087c478bd9Sstevel@tonic-gate 		kmem_cache_free(ipp_mod_cache, imp);
24097c478bd9Sstevel@tonic-gate 		return;
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
24137c478bd9Sstevel@tonic-gate }
24147c478bd9Sstevel@tonic-gate #undef	__FN__
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate #define	__FN__	"get_mid"
24177c478bd9Sstevel@tonic-gate static ipp_mod_id_t
24187c478bd9Sstevel@tonic-gate get_mid(
24197c478bd9Sstevel@tonic-gate 	void)
24207c478bd9Sstevel@tonic-gate {
24217c478bd9Sstevel@tonic-gate 	int	index;
24227c478bd9Sstevel@tonic-gate 	int	start;
24237c478bd9Sstevel@tonic-gate 	int	limit;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ipp_mod_byid_lock));
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	/*
24287c478bd9Sstevel@tonic-gate 	 * Start searching after the last module id we allocated.
24297c478bd9Sstevel@tonic-gate 	 */
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 	start = (int)ipp_next_mid;
24327c478bd9Sstevel@tonic-gate 	limit = (int)ipp_mid_limit;
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	/*
24357c478bd9Sstevel@tonic-gate 	 * Look for a spare slot in the array.
24367c478bd9Sstevel@tonic-gate 	 */
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	index = start;
24397c478bd9Sstevel@tonic-gate 	while (ipp_mod_byid[index] != NULL) {
24407c478bd9Sstevel@tonic-gate 		index++;
24417c478bd9Sstevel@tonic-gate 		if (index > limit)
24427c478bd9Sstevel@tonic-gate 			index = IPP_MOD_RESERVED + 1;
24437c478bd9Sstevel@tonic-gate 		if (index == start)
24447c478bd9Sstevel@tonic-gate 			return (IPP_MOD_INVAL);
24457c478bd9Sstevel@tonic-gate 	}
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 	/*
24487c478bd9Sstevel@tonic-gate 	 * Note that we've just allocated a new module id so that we can
24497c478bd9Sstevel@tonic-gate 	 * start our search there next time.
24507c478bd9Sstevel@tonic-gate 	 */
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 	index++;
24537c478bd9Sstevel@tonic-gate 	if (index > limit) {
24547c478bd9Sstevel@tonic-gate 		ipp_next_mid = IPP_MOD_RESERVED + 1;
24557c478bd9Sstevel@tonic-gate 	} else
24567c478bd9Sstevel@tonic-gate 		ipp_next_mid = (ipp_mod_id_t)index;
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	return ((ipp_mod_id_t)(--index));
24597c478bd9Sstevel@tonic-gate }
24607c478bd9Sstevel@tonic-gate #undef	__FN__
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate #define	__FN__	"condemn_action"
24637c478bd9Sstevel@tonic-gate static int
24647c478bd9Sstevel@tonic-gate condemn_action(
24657c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp,
24667c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap)
24677c478bd9Sstevel@tonic-gate {
24687c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
24697c478bd9Sstevel@tonic-gate 
24707c478bd9Sstevel@tonic-gate 	DBG1(DBG_ACTION, "condemning action '%s'\n", ap->ippa_name);
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 	/*
24737c478bd9Sstevel@tonic-gate 	 * Check to see if the action is already condemned.
24747c478bd9Sstevel@tonic-gate 	 */
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
24777c478bd9Sstevel@tonic-gate 		if (rp->ippr_action == ap)
24787c478bd9Sstevel@tonic-gate 			break;
24797c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	/*
24837c478bd9Sstevel@tonic-gate 	 * Create a new entry for the action.
24847c478bd9Sstevel@tonic-gate 	 */
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	if (rp == NULL) {
24877c478bd9Sstevel@tonic-gate 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
24887c478bd9Sstevel@tonic-gate 			return (ENOMEM);
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 		rp->ippr_action = ap;
24917c478bd9Sstevel@tonic-gate 		*rpp = rp;
24927c478bd9Sstevel@tonic-gate 	}
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 	return (0);
24957c478bd9Sstevel@tonic-gate }
24967c478bd9Sstevel@tonic-gate #undef	__FN__
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate #define	__FN__	"destroy_action"
24997c478bd9Sstevel@tonic-gate static int
25007c478bd9Sstevel@tonic-gate destroy_action(
25017c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap,
25027c478bd9Sstevel@tonic-gate 	ipp_flags_t	flags)
25037c478bd9Sstevel@tonic-gate {
25047c478bd9Sstevel@tonic-gate 	ipp_ops_t	*ippo;
25057c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
25067c478bd9Sstevel@tonic-gate #define	MAXWAIT		10
25077c478bd9Sstevel@tonic-gate 	uint32_t	wait;
25087c478bd9Sstevel@tonic-gate 	int		rc;
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate 	/*
25117c478bd9Sstevel@tonic-gate 	 * Check that the action is available.
25127c478bd9Sstevel@tonic-gate 	 */
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
25157c478bd9Sstevel@tonic-gate 	if (ap->ippa_state != IPP_ASTATE_AVAILABLE) {
25167c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
25177c478bd9Sstevel@tonic-gate 		rele_action(ap);
25187c478bd9Sstevel@tonic-gate 		return (EPROTO);
25197c478bd9Sstevel@tonic-gate 	}
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	/*
25227c478bd9Sstevel@tonic-gate 	 * Note that the action is in the process of creation/destruction.
25237c478bd9Sstevel@tonic-gate 	 */
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate 	ap->ippa_state = IPP_ASTATE_CONFIG_PENDING;
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate 	/*
25287c478bd9Sstevel@tonic-gate 	 * Wait for the in-transit packet count for this action to fall to
25297c478bd9Sstevel@tonic-gate 	 * zero (checking at millisecond intervals).
25307c478bd9Sstevel@tonic-gate 	 *
25317c478bd9Sstevel@tonic-gate 	 * NOTE: no new packets will enter the action now that the
25327c478bd9Sstevel@tonic-gate 	 *	 state has been changed.
25337c478bd9Sstevel@tonic-gate 	 */
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	for (wait = 0; ap->ippa_packets > 0 && wait < (MAXWAIT * 1000000);
25367c478bd9Sstevel@tonic-gate 	    wait += 1000) {
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 		/*
25397c478bd9Sstevel@tonic-gate 		 * NOTE: We can hang onto the lock because the packet count is
25407c478bd9Sstevel@tonic-gate 		 *	 decremented without needing to take the lock.
25417c478bd9Sstevel@tonic-gate 		 */
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 		drv_usecwait(1000);
25447c478bd9Sstevel@tonic-gate 	}
25457c478bd9Sstevel@tonic-gate 
25467c478bd9Sstevel@tonic-gate 	/*
25477c478bd9Sstevel@tonic-gate 	 * The packet count did not fall to zero.
25487c478bd9Sstevel@tonic-gate 	 */
25497c478bd9Sstevel@tonic-gate 	if (ap->ippa_packets > 0) {
25507c478bd9Sstevel@tonic-gate 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
25517c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
25527c478bd9Sstevel@tonic-gate 		rele_action(ap);
25537c478bd9Sstevel@tonic-gate 		return (EAGAIN);
25547c478bd9Sstevel@tonic-gate 	}
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 	/*
25577c478bd9Sstevel@tonic-gate 	 * Check to see if any other action has a dependency on this one.
25587c478bd9Sstevel@tonic-gate 	 */
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	if (is_action_refd(ap)) {
25617c478bd9Sstevel@tonic-gate 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
25627c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
25637c478bd9Sstevel@tonic-gate 		rele_action(ap);
25647c478bd9Sstevel@tonic-gate 		return (EBUSY);
25657c478bd9Sstevel@tonic-gate 	}
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	imp = ap->ippa_mod;
25687c478bd9Sstevel@tonic-gate 	ASSERT(imp != NULL);
25697c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate 	ippo = imp->ippm_ops;
25727c478bd9Sstevel@tonic-gate 	ASSERT(ippo != NULL);
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	/*
25757c478bd9Sstevel@tonic-gate 	 * Call into the module to destroy the action context.
25767c478bd9Sstevel@tonic-gate 	 */
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_START(ap);
25797c478bd9Sstevel@tonic-gate 	DBG1(DBG_ACTION, "destroying action '%s'\n", ap->ippa_name);
25807c478bd9Sstevel@tonic-gate 	if ((rc = ippo->ippo_action_destroy(ap->ippa_id, flags)) != 0) {
25817c478bd9Sstevel@tonic-gate 		LOCK_ACTION(ap, RW_WRITER);
25827c478bd9Sstevel@tonic-gate 		ap->ippa_state = IPP_ASTATE_AVAILABLE;
25837c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 		CONFIG_WRITE_END(ap);
25867c478bd9Sstevel@tonic-gate 
25877c478bd9Sstevel@tonic-gate 		rele_action(ap);
25887c478bd9Sstevel@tonic-gate 		return (rc);
25897c478bd9Sstevel@tonic-gate 	}
25907c478bd9Sstevel@tonic-gate 	CONFIG_WRITE_END(ap);
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
25937c478bd9Sstevel@tonic-gate 	LOCK_MOD(imp, RW_WRITER);
25947c478bd9Sstevel@tonic-gate 	unref_mod(ap, imp);
25957c478bd9Sstevel@tonic-gate 	UNLOCK_MOD(imp);
25967c478bd9Sstevel@tonic-gate 	ap->ippa_state = IPP_ASTATE_PROTO;
25977c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate 	/*
26007c478bd9Sstevel@tonic-gate 	 * Free the action structure.
26017c478bd9Sstevel@tonic-gate 	 */
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_ref == NULL);
26047c478bd9Sstevel@tonic-gate 	free_action(ap);
26057c478bd9Sstevel@tonic-gate 	rele_action(ap);
26067c478bd9Sstevel@tonic-gate 	return (0);
26077c478bd9Sstevel@tonic-gate #undef	MAXWAIT
26087c478bd9Sstevel@tonic-gate }
26097c478bd9Sstevel@tonic-gate #undef	__FN__
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate #define	__FN__	"ref_action"
26127c478bd9Sstevel@tonic-gate static int
26137c478bd9Sstevel@tonic-gate ref_action(
26147c478bd9Sstevel@tonic-gate 	ipp_action_t	*refby_ap,
26157c478bd9Sstevel@tonic-gate 	ipp_action_t	*ref_ap)
26167c478bd9Sstevel@tonic-gate {
26177c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
26187c478bd9Sstevel@tonic-gate 	ipp_ref_t	**save_rpp;
26197c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(refby_ap->ippa_lock));
26227c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ref_ap->ippa_lock));
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 	/*
26257c478bd9Sstevel@tonic-gate 	 * We want to add the new reference at the end of the refering
26267c478bd9Sstevel@tonic-gate 	 * action's list.
26277c478bd9Sstevel@tonic-gate 	 */
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	rpp = &(refby_ap->ippa_ref);
26307c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
26317c478bd9Sstevel@tonic-gate 		if (rp->ippr_action == ref_ap)
26327c478bd9Sstevel@tonic-gate 			break;
26337c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
26347c478bd9Sstevel@tonic-gate 	}
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 	if ((rp = *rpp) != NULL) {
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 		/*
26397c478bd9Sstevel@tonic-gate 		 * There is an existing reference so increment its counter.
26407c478bd9Sstevel@tonic-gate 		 */
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 		rp->ippr_count++;
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 		/*
26457c478bd9Sstevel@tonic-gate 		 * Find the 'back pointer' and increment its counter too.
26467c478bd9Sstevel@tonic-gate 		 */
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 		rp = ref_ap->ippa_refby;
26497c478bd9Sstevel@tonic-gate 		while (rp != NULL) {
26507c478bd9Sstevel@tonic-gate 			if (rp->ippr_action == refby_ap)
26517c478bd9Sstevel@tonic-gate 				break;
26527c478bd9Sstevel@tonic-gate 			rp = rp->ippr_nextp;
26537c478bd9Sstevel@tonic-gate 		}
26547c478bd9Sstevel@tonic-gate 		ASSERT(rp != NULL);
26557c478bd9Sstevel@tonic-gate 
26567c478bd9Sstevel@tonic-gate 		rp->ippr_count++;
26577c478bd9Sstevel@tonic-gate 	} else {
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 		/*
26607c478bd9Sstevel@tonic-gate 		 * Allocate, fill in and link a new reference structure.
26617c478bd9Sstevel@tonic-gate 		 */
26627c478bd9Sstevel@tonic-gate 
26637c478bd9Sstevel@tonic-gate 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL)
26647c478bd9Sstevel@tonic-gate 			return (ENOMEM);
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 		rp->ippr_action = ref_ap;
26677c478bd9Sstevel@tonic-gate 		rp->ippr_count = 1;
26687c478bd9Sstevel@tonic-gate 		*rpp = rp;
26697c478bd9Sstevel@tonic-gate 		save_rpp = rpp;
26707c478bd9Sstevel@tonic-gate 
26717c478bd9Sstevel@tonic-gate 		/*
26727c478bd9Sstevel@tonic-gate 		 * We keep a 'back pointer' which we want to add at the end of
26737c478bd9Sstevel@tonic-gate 		 * a list in the referred action's structure.
26747c478bd9Sstevel@tonic-gate 		 */
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		rpp = &(ref_ap->ippa_refby);
26777c478bd9Sstevel@tonic-gate 		while ((rp = *rpp) != NULL) {
26787c478bd9Sstevel@tonic-gate 			ASSERT(rp->ippr_action != refby_ap);
26797c478bd9Sstevel@tonic-gate 			rpp = &(rp->ippr_nextp);
26807c478bd9Sstevel@tonic-gate 		}
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 		/*
26837c478bd9Sstevel@tonic-gate 		 * Allocate another reference structure and, if this fails,
26847c478bd9Sstevel@tonic-gate 		 * remember to clean up the first reference structure we
26857c478bd9Sstevel@tonic-gate 		 * allocated.
26867c478bd9Sstevel@tonic-gate 		 */
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate 		if ((rp = kmem_zalloc(sizeof (ipp_ref_t),
26897c478bd9Sstevel@tonic-gate 		    KM_NOSLEEP)) == NULL) {
26907c478bd9Sstevel@tonic-gate 			rpp = save_rpp;
26917c478bd9Sstevel@tonic-gate 			rp = *rpp;
26927c478bd9Sstevel@tonic-gate 			*rpp = NULL;
26937c478bd9Sstevel@tonic-gate 			kmem_free(rp, sizeof (ipp_ref_t));
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 			return (ENOMEM);
26967c478bd9Sstevel@tonic-gate 		}
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 		/*
26997c478bd9Sstevel@tonic-gate 		 * Fill in the reference structure with the 'back pointer' and
27007c478bd9Sstevel@tonic-gate 		 * link it into the list.
27017c478bd9Sstevel@tonic-gate 		 */
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate 		rp->ippr_action = refby_ap;
27047c478bd9Sstevel@tonic-gate 		rp->ippr_count = 1;
27057c478bd9Sstevel@tonic-gate 		*rpp = rp;
27067c478bd9Sstevel@tonic-gate 	}
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate 	return (0);
27097c478bd9Sstevel@tonic-gate }
27107c478bd9Sstevel@tonic-gate #undef	__FN__
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate #define	__FN__	"unref_action"
27137c478bd9Sstevel@tonic-gate static int
27147c478bd9Sstevel@tonic-gate unref_action(
27157c478bd9Sstevel@tonic-gate 	ipp_action_t	*refby_ap,
27167c478bd9Sstevel@tonic-gate 	ipp_action_t	*ref_ap)
27177c478bd9Sstevel@tonic-gate {
27187c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
27197c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(refby_ap->ippa_lock));
27227c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ref_ap->ippa_lock));
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	/*
27257c478bd9Sstevel@tonic-gate 	 * Scan for the reference in the referring action's list.
27267c478bd9Sstevel@tonic-gate 	 */
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	rpp = &(refby_ap->ippa_ref);
27297c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
27307c478bd9Sstevel@tonic-gate 		if (rp->ippr_action == ref_ap)
27317c478bd9Sstevel@tonic-gate 			break;
27327c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	if (rp == NULL)
27367c478bd9Sstevel@tonic-gate 		return (ENOENT);
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate 	if (rp->ippr_count > 1) {
27397c478bd9Sstevel@tonic-gate 
27407c478bd9Sstevel@tonic-gate 		/*
27417c478bd9Sstevel@tonic-gate 		 * There are currently multiple references so decrement the
27427c478bd9Sstevel@tonic-gate 		 * count.
27437c478bd9Sstevel@tonic-gate 		 */
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 		rp->ippr_count--;
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate 		/*
27487c478bd9Sstevel@tonic-gate 		 * Find the 'back pointer' and decrement its counter too.
27497c478bd9Sstevel@tonic-gate 		 */
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 		rp = ref_ap->ippa_refby;
27527c478bd9Sstevel@tonic-gate 		while (rp != NULL) {
27537c478bd9Sstevel@tonic-gate 			if (rp->ippr_action == refby_ap)
27547c478bd9Sstevel@tonic-gate 				break;
27557c478bd9Sstevel@tonic-gate 			rp = rp->ippr_nextp;
27567c478bd9Sstevel@tonic-gate 		}
27577c478bd9Sstevel@tonic-gate 		ASSERT(rp != NULL);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 		rp->ippr_count--;
27607c478bd9Sstevel@tonic-gate 	} else {
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 		/*
27637c478bd9Sstevel@tonic-gate 		 * There is currently only a single reference, so unlink and
27647c478bd9Sstevel@tonic-gate 		 * free the reference structure.
27657c478bd9Sstevel@tonic-gate 		 */
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate 		*rpp = rp->ippr_nextp;
27687c478bd9Sstevel@tonic-gate 		kmem_free(rp, sizeof (ipp_ref_t));
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 		/*
27717c478bd9Sstevel@tonic-gate 		 * Scan for the 'back pointer' in the referred action's list.
27727c478bd9Sstevel@tonic-gate 		 */
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 		rpp = &(ref_ap->ippa_refby);
27757c478bd9Sstevel@tonic-gate 		while ((rp = *rpp) != NULL) {
27767c478bd9Sstevel@tonic-gate 			if (rp->ippr_action == refby_ap)
27777c478bd9Sstevel@tonic-gate 				break;
27787c478bd9Sstevel@tonic-gate 			rpp = &(rp->ippr_nextp);
27797c478bd9Sstevel@tonic-gate 		}
27807c478bd9Sstevel@tonic-gate 		ASSERT(rp != NULL);
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate 		/*
27837c478bd9Sstevel@tonic-gate 		 * Unlink and free this reference structure too.
27847c478bd9Sstevel@tonic-gate 		 */
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 		*rpp = rp->ippr_nextp;
27877c478bd9Sstevel@tonic-gate 		kmem_free(rp, sizeof (ipp_ref_t));
27887c478bd9Sstevel@tonic-gate 	}
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 	return (0);
27917c478bd9Sstevel@tonic-gate }
27927c478bd9Sstevel@tonic-gate #undef	__FN__
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate #define	__FN__	"is_action_refd"
27957c478bd9Sstevel@tonic-gate static int
27967c478bd9Sstevel@tonic-gate is_action_refd(
27977c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap)
27987c478bd9Sstevel@tonic-gate {
27997c478bd9Sstevel@tonic-gate 	/*
28007c478bd9Sstevel@tonic-gate 	 * Return a value which is true (non-zero) iff the action is not
28017c478bd9Sstevel@tonic-gate 	 * referred to by any other actions.
28027c478bd9Sstevel@tonic-gate 	 */
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 	return (ap->ippa_refby != NULL);
28057c478bd9Sstevel@tonic-gate }
28067c478bd9Sstevel@tonic-gate #undef	__FN__
28077c478bd9Sstevel@tonic-gate 
28087c478bd9Sstevel@tonic-gate #define	__FN__	"find_action"
28097c478bd9Sstevel@tonic-gate static ipp_action_id_t
28107c478bd9Sstevel@tonic-gate find_action(
28117c478bd9Sstevel@tonic-gate 	const char	*aname)
28127c478bd9Sstevel@tonic-gate {
28137c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid;
28147c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
28157c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
28167c478bd9Sstevel@tonic-gate 	int		hb;
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate 	ASSERT(aname != NULL);
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byname_lock, RW_READER);
28217c478bd9Sstevel@tonic-gate 
28227c478bd9Sstevel@tonic-gate 	/*
28237c478bd9Sstevel@tonic-gate 	 * Quick return if there are no actions defined at all.
28247c478bd9Sstevel@tonic-gate 	 */
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	if (ipp_action_count == 0) {
28277c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
28287c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_INVAL);
28297c478bd9Sstevel@tonic-gate 	}
28307c478bd9Sstevel@tonic-gate 
28317c478bd9Sstevel@tonic-gate 	/*
28327c478bd9Sstevel@tonic-gate 	 * Find the hash bucket where the action structure should be.
28337c478bd9Sstevel@tonic-gate 	 */
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 	hb = hash(aname);
28367c478bd9Sstevel@tonic-gate 	rp = ipp_action_byname[hb];
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 	/*
28397c478bd9Sstevel@tonic-gate 	 * Scan the bucket looking for a match.
28407c478bd9Sstevel@tonic-gate 	 */
28417c478bd9Sstevel@tonic-gate 
28427c478bd9Sstevel@tonic-gate 	while (rp != NULL) {
28437c478bd9Sstevel@tonic-gate 		ap = rp->ippr_action;
28447c478bd9Sstevel@tonic-gate 		if (strcmp(ap->ippa_name, aname) == 0)
28457c478bd9Sstevel@tonic-gate 			break;
28467c478bd9Sstevel@tonic-gate 		rp = rp->ippr_nextp;
28477c478bd9Sstevel@tonic-gate 	}
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 	if (rp == NULL) {
28507c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
28517c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_INVAL);
28527c478bd9Sstevel@tonic-gate 	}
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	if (ap->ippa_state == IPP_ASTATE_PROTO) {
28557c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
28567c478bd9Sstevel@tonic-gate 		return (IPP_ACTION_INVAL);
28577c478bd9Sstevel@tonic-gate 	}
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	aid = ap->ippa_id;
28607c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byname_lock);
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate 	return (aid);
28637c478bd9Sstevel@tonic-gate }
28647c478bd9Sstevel@tonic-gate #undef __FN__
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate #define	__FN__	"alloc_action"
28677c478bd9Sstevel@tonic-gate static int
28687c478bd9Sstevel@tonic-gate alloc_action(
28697c478bd9Sstevel@tonic-gate 	const char	*aname,
28707c478bd9Sstevel@tonic-gate 	ipp_action_id_t	*aidp)
28717c478bd9Sstevel@tonic-gate {
28727c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
28737c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
28747c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
28757c478bd9Sstevel@tonic-gate 	int		hb;
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate 	ASSERT(aidp != NULL);
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byname_lock, RW_WRITER);
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate 	/*
28827c478bd9Sstevel@tonic-gate 	 * Find the right hash bucket for an action of the given name.
28837c478bd9Sstevel@tonic-gate 	 * (Nameless actions always go in a special bucket).
28847c478bd9Sstevel@tonic-gate 	 */
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate 	if (aname != NULL) {
28877c478bd9Sstevel@tonic-gate 		hb = hash(aname);
28887c478bd9Sstevel@tonic-gate 		rpp = &ipp_action_byname[hb];
28897c478bd9Sstevel@tonic-gate 	} else
28907c478bd9Sstevel@tonic-gate 		rpp = &ipp_action_noname;
28917c478bd9Sstevel@tonic-gate 
28927c478bd9Sstevel@tonic-gate 	/*
28937c478bd9Sstevel@tonic-gate 	 * Scan the bucket to make sure that an action with the given name
28947c478bd9Sstevel@tonic-gate 	 * does not already exist.
28957c478bd9Sstevel@tonic-gate 	 */
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
28987c478bd9Sstevel@tonic-gate 		ap = rp->ippr_action;
28997c478bd9Sstevel@tonic-gate 		if (aname != NULL && strcmp(ap->ippa_name, aname) == 0) {
29007c478bd9Sstevel@tonic-gate 			DBG1(DBG_ACTION, "action '%s' already exists\n",
29017c478bd9Sstevel@tonic-gate 			    aname);
29027c478bd9Sstevel@tonic-gate 			rw_exit(ipp_action_byname_lock);
29037c478bd9Sstevel@tonic-gate 			return (EEXIST);
29047c478bd9Sstevel@tonic-gate 		}
29057c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
29067c478bd9Sstevel@tonic-gate 	}
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 	/*
29097c478bd9Sstevel@tonic-gate 	 * Allocate a new reference structure and a new action structure.
29107c478bd9Sstevel@tonic-gate 	 */
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 	if ((rp = kmem_zalloc(sizeof (ipp_ref_t), KM_NOSLEEP)) == NULL) {
29137c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
29147c478bd9Sstevel@tonic-gate 		return (ENOMEM);
29157c478bd9Sstevel@tonic-gate 	}
29167c478bd9Sstevel@tonic-gate 
29177c478bd9Sstevel@tonic-gate 	if ((ap = kmem_cache_alloc(ipp_action_cache, KM_NOSLEEP)) == NULL) {
29187c478bd9Sstevel@tonic-gate 		kmem_free(rp, sizeof (ipp_ref_t));
29197c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
29207c478bd9Sstevel@tonic-gate 		return (ENOMEM);
29217c478bd9Sstevel@tonic-gate 	}
29227c478bd9Sstevel@tonic-gate 
29237c478bd9Sstevel@tonic-gate 	/*
29247c478bd9Sstevel@tonic-gate 	 * Dream up a name if there isn't a real one and note that the action is
29257c478bd9Sstevel@tonic-gate 	 * really nameless.
29267c478bd9Sstevel@tonic-gate 	 */
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 	if (aname == NULL) {
29297c478bd9Sstevel@tonic-gate 		(void) sprintf(ap->ippa_name, "$%08X", ap->ippa_id);
29307c478bd9Sstevel@tonic-gate 		ap->ippa_nameless = B_TRUE;
29317c478bd9Sstevel@tonic-gate 	} else
29327c478bd9Sstevel@tonic-gate 		(void) strcpy(ap->ippa_name, aname);
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate 	/*
29357c478bd9Sstevel@tonic-gate 	 * Make sure the 'destruct pending' flag is clear. This indicates that
29367c478bd9Sstevel@tonic-gate 	 * the structure is no longer part of the cache.
29377c478bd9Sstevel@tonic-gate 	 */
29387c478bd9Sstevel@tonic-gate 
29397c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
29407c478bd9Sstevel@tonic-gate 	ap->ippa_destruct_pending = B_FALSE;
29417c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
29427c478bd9Sstevel@tonic-gate 
29437c478bd9Sstevel@tonic-gate 	/*
29447c478bd9Sstevel@tonic-gate 	 * Fill in the reference structure and lint it onto the list.
29457c478bd9Sstevel@tonic-gate 	 */
29467c478bd9Sstevel@tonic-gate 
29477c478bd9Sstevel@tonic-gate 	rp->ippr_action = ap;
29487c478bd9Sstevel@tonic-gate 	*rpp = rp;
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	/*
29517c478bd9Sstevel@tonic-gate 	 * Increment the action count.
29527c478bd9Sstevel@tonic-gate 	 */
29537c478bd9Sstevel@tonic-gate 
29547c478bd9Sstevel@tonic-gate 	ipp_action_count++;
29557c478bd9Sstevel@tonic-gate 
29567c478bd9Sstevel@tonic-gate 	*aidp = ap->ippa_id;
29577c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byname_lock);
29587c478bd9Sstevel@tonic-gate 	return (0);
29597c478bd9Sstevel@tonic-gate }
29607c478bd9Sstevel@tonic-gate #undef	__FN__
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate #define	__FN__	"free_action"
29637c478bd9Sstevel@tonic-gate static void
29647c478bd9Sstevel@tonic-gate free_action(
29657c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap)
29667c478bd9Sstevel@tonic-gate {
29677c478bd9Sstevel@tonic-gate 	ipp_ref_t	**rpp;
29687c478bd9Sstevel@tonic-gate 	ipp_ref_t	*rp;
29697c478bd9Sstevel@tonic-gate 	int		hb;
29707c478bd9Sstevel@tonic-gate 
29717c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byname_lock, RW_WRITER);
29727c478bd9Sstevel@tonic-gate 
29737c478bd9Sstevel@tonic-gate 	/*
29747c478bd9Sstevel@tonic-gate 	 * Find the hash bucket where the action structure should be.
29757c478bd9Sstevel@tonic-gate 	 */
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate 	if (!ap->ippa_nameless) {
29787c478bd9Sstevel@tonic-gate 		hb = hash(ap->ippa_name);
29797c478bd9Sstevel@tonic-gate 		rpp = &ipp_action_byname[hb];
29807c478bd9Sstevel@tonic-gate 	} else
29817c478bd9Sstevel@tonic-gate 		rpp = &ipp_action_noname;
29827c478bd9Sstevel@tonic-gate 
29837c478bd9Sstevel@tonic-gate 	/*
29847c478bd9Sstevel@tonic-gate 	 * Scan the bucket for a match.
29857c478bd9Sstevel@tonic-gate 	 */
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	while ((rp = *rpp) != NULL) {
29887c478bd9Sstevel@tonic-gate 		if (rp->ippr_action == ap)
29897c478bd9Sstevel@tonic-gate 			break;
29907c478bd9Sstevel@tonic-gate 		rpp = &(rp->ippr_nextp);
29917c478bd9Sstevel@tonic-gate 	}
29927c478bd9Sstevel@tonic-gate 	ASSERT(rp != NULL);
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate 	/*
29957c478bd9Sstevel@tonic-gate 	 * Unlink and free the reference structure.
29967c478bd9Sstevel@tonic-gate 	 */
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate 	*rpp = rp->ippr_nextp;
29997c478bd9Sstevel@tonic-gate 	kmem_free(rp, sizeof (ipp_ref_t));
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate 	/*
30027c478bd9Sstevel@tonic-gate 	 * Decrement the action count.
30037c478bd9Sstevel@tonic-gate 	 */
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	ipp_action_count--;
30067c478bd9Sstevel@tonic-gate 
30077c478bd9Sstevel@tonic-gate 	/*
30087c478bd9Sstevel@tonic-gate 	 * Empty the name.
30097c478bd9Sstevel@tonic-gate 	 */
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate 	*ap->ippa_name = '\0';
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate 	/*
30147c478bd9Sstevel@tonic-gate 	 * If the hold count is zero then we can free the structure
30157c478bd9Sstevel@tonic-gate 	 * immediately, otherwise we defer to rele_action().
30167c478bd9Sstevel@tonic-gate 	 */
30177c478bd9Sstevel@tonic-gate 
30187c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_WRITER);
30197c478bd9Sstevel@tonic-gate 	ap->ippa_destruct_pending = B_TRUE;
30207c478bd9Sstevel@tonic-gate 	if (ap->ippa_hold_count == 0) {
30217c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
30227c478bd9Sstevel@tonic-gate 		kmem_cache_free(ipp_action_cache, ap);
30237c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byname_lock);
30247c478bd9Sstevel@tonic-gate 		return;
30257c478bd9Sstevel@tonic-gate 	}
30267c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byname_lock);
30297c478bd9Sstevel@tonic-gate }
30307c478bd9Sstevel@tonic-gate #undef __FN__
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate #define	__FN__	"hold_action"
30337c478bd9Sstevel@tonic-gate static ipp_action_t *
30347c478bd9Sstevel@tonic-gate hold_action(
30357c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid)
30367c478bd9Sstevel@tonic-gate {
30377c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	if (aid < 0)
30407c478bd9Sstevel@tonic-gate 		return (NULL);
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate 	/*
30437c478bd9Sstevel@tonic-gate 	 * Use the action id as an index into the array of all action
30447c478bd9Sstevel@tonic-gate 	 * structures.
30457c478bd9Sstevel@tonic-gate 	 */
30467c478bd9Sstevel@tonic-gate 
30477c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byid_lock, RW_READER);
30487c478bd9Sstevel@tonic-gate 	if ((ap = ipp_action_byid[aid]) == NULL) {
30497c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byid_lock);
30507c478bd9Sstevel@tonic-gate 		return (NULL);
30517c478bd9Sstevel@tonic-gate 	}
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	/*
30547c478bd9Sstevel@tonic-gate 	 * If the action has 'destruct pending' set then it means it is either
30557c478bd9Sstevel@tonic-gate 	 * still in the cache (i.e not allocated) or in the process of
30567c478bd9Sstevel@tonic-gate 	 * being set up by alloc_action().
30577c478bd9Sstevel@tonic-gate 	 */
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
30607c478bd9Sstevel@tonic-gate 	if (ap->ippa_destruct_pending) {
30617c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
30627c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byid_lock);
30637c478bd9Sstevel@tonic-gate 		return (NULL);
30647c478bd9Sstevel@tonic-gate 	}
30657c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 	/*
30687c478bd9Sstevel@tonic-gate 	 * Increment the hold count to prevent the structure from being
30697c478bd9Sstevel@tonic-gate 	 * freed.
30707c478bd9Sstevel@tonic-gate 	 */
30717c478bd9Sstevel@tonic-gate 
3072*1a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&(ap->ippa_hold_count));
30737c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byid_lock);
30747c478bd9Sstevel@tonic-gate 
30757c478bd9Sstevel@tonic-gate 	return (ap);
30767c478bd9Sstevel@tonic-gate }
30777c478bd9Sstevel@tonic-gate #undef	__FN__
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate #define	__FN__	"rele_action"
30807c478bd9Sstevel@tonic-gate static void
30817c478bd9Sstevel@tonic-gate rele_action(
30827c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap)
30837c478bd9Sstevel@tonic-gate {
30847c478bd9Sstevel@tonic-gate 	/*
30857c478bd9Sstevel@tonic-gate 	 * This call means we're done with the pointer so we can drop the
30867c478bd9Sstevel@tonic-gate 	 * hold count.
30877c478bd9Sstevel@tonic-gate 	 */
30887c478bd9Sstevel@tonic-gate 
30897c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_hold_count != 0);
3090*1a5e258fSJosef 'Jeff' Sipek 	atomic_dec_32(&(ap->ippa_hold_count));
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 	/*
30937c478bd9Sstevel@tonic-gate 	 * If the structure has 'destruct pending' set then we tried to free
30947c478bd9Sstevel@tonic-gate 	 * it but couldn't, so do it now.
30957c478bd9Sstevel@tonic-gate 	 */
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	LOCK_ACTION(ap, RW_READER);
30987c478bd9Sstevel@tonic-gate 	if (ap->ippa_destruct_pending && ap->ippa_hold_count == 0) {
30997c478bd9Sstevel@tonic-gate 		UNLOCK_ACTION(ap);
31007c478bd9Sstevel@tonic-gate 		kmem_cache_free(ipp_action_cache, ap);
31017c478bd9Sstevel@tonic-gate 		return;
31027c478bd9Sstevel@tonic-gate 	}
31037c478bd9Sstevel@tonic-gate 	UNLOCK_ACTION(ap);
31047c478bd9Sstevel@tonic-gate }
31057c478bd9Sstevel@tonic-gate #undef	__FN__
31067c478bd9Sstevel@tonic-gate 
31077c478bd9Sstevel@tonic-gate #define	__FN__	"get_aid"
31087c478bd9Sstevel@tonic-gate static ipp_action_id_t
31097c478bd9Sstevel@tonic-gate get_aid(
31107c478bd9Sstevel@tonic-gate 	void)
31117c478bd9Sstevel@tonic-gate {
31127c478bd9Sstevel@tonic-gate 	int	index;
31137c478bd9Sstevel@tonic-gate 	int	start;
31147c478bd9Sstevel@tonic-gate 	int	limit;
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate 	ASSERT(rw_write_held(ipp_action_byid_lock));
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 	/*
31197c478bd9Sstevel@tonic-gate 	 * Start searching after the last action id that we allocated.
31207c478bd9Sstevel@tonic-gate 	 */
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 	start = (int)ipp_next_aid;
31237c478bd9Sstevel@tonic-gate 	limit = (int)ipp_aid_limit;
31247c478bd9Sstevel@tonic-gate 
31257c478bd9Sstevel@tonic-gate 	/*
31267c478bd9Sstevel@tonic-gate 	 * Look for a spare slot in the array.
31277c478bd9Sstevel@tonic-gate 	 */
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 	index = start;
31307c478bd9Sstevel@tonic-gate 	while (ipp_action_byid[index] != NULL) {
31317c478bd9Sstevel@tonic-gate 		index++;
31327c478bd9Sstevel@tonic-gate 		if (index > limit)
31337c478bd9Sstevel@tonic-gate 			index = IPP_ACTION_RESERVED + 1;
31347c478bd9Sstevel@tonic-gate 		if (index == start)
31357c478bd9Sstevel@tonic-gate 			return (IPP_ACTION_INVAL);
31367c478bd9Sstevel@tonic-gate 	}
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate 	/*
31397c478bd9Sstevel@tonic-gate 	 * Note that we've just allocated a new action id so that we can
31407c478bd9Sstevel@tonic-gate 	 * start our search there next time.
31417c478bd9Sstevel@tonic-gate 	 */
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 	index++;
31447c478bd9Sstevel@tonic-gate 	if (index > limit)
31457c478bd9Sstevel@tonic-gate 		ipp_next_aid = IPP_ACTION_RESERVED + 1;
31467c478bd9Sstevel@tonic-gate 	else
31477c478bd9Sstevel@tonic-gate 		ipp_next_aid = (ipp_action_id_t)index;
31487c478bd9Sstevel@tonic-gate 
31497c478bd9Sstevel@tonic-gate 	return ((ipp_action_id_t)(--index));
31507c478bd9Sstevel@tonic-gate }
31517c478bd9Sstevel@tonic-gate #undef	__FN__
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate #define	__FN__	"alloc_packet"
31547c478bd9Sstevel@tonic-gate static int
31557c478bd9Sstevel@tonic-gate alloc_packet(
31567c478bd9Sstevel@tonic-gate 	const char	*name,
31577c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid,
31587c478bd9Sstevel@tonic-gate 	ipp_packet_t	**ppp)
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp;
31617c478bd9Sstevel@tonic-gate 	ipp_class_t	*cp;
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 	if ((pp = kmem_cache_alloc(ipp_packet_cache, KM_NOSLEEP)) == NULL)
31647c478bd9Sstevel@tonic-gate 		return (ENOMEM);
31657c478bd9Sstevel@tonic-gate 
31667c478bd9Sstevel@tonic-gate 	/*
31677c478bd9Sstevel@tonic-gate 	 * Set the packet up with a single class.
31687c478bd9Sstevel@tonic-gate 	 */
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate 	cp = &(pp->ippp_class_array[0]);
31717c478bd9Sstevel@tonic-gate 	pp->ippp_class_windex = 1;
31727c478bd9Sstevel@tonic-gate 
31737c478bd9Sstevel@tonic-gate 	(void) strcpy(cp->ippc_name, name);
31747c478bd9Sstevel@tonic-gate 	cp->ippc_aid = aid;
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	*ppp = pp;
31777c478bd9Sstevel@tonic-gate 	return (0);
31787c478bd9Sstevel@tonic-gate }
31797c478bd9Sstevel@tonic-gate #undef	__FN__
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate #define	__FN__	"realloc_packet"
31827c478bd9Sstevel@tonic-gate static int
31837c478bd9Sstevel@tonic-gate realloc_packet(
31847c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp)
31857c478bd9Sstevel@tonic-gate {
31867c478bd9Sstevel@tonic-gate 	uint_t		length;
31877c478bd9Sstevel@tonic-gate 	ipp_class_t	*array;
31887c478bd9Sstevel@tonic-gate 
31897c478bd9Sstevel@tonic-gate 	length = (pp->ippp_class_limit + 1) << 1;
31907c478bd9Sstevel@tonic-gate 	if ((array = kmem_alloc(length * sizeof (ipp_class_t),
31917c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL)
31927c478bd9Sstevel@tonic-gate 		return (ENOMEM);
31937c478bd9Sstevel@tonic-gate 
31947c478bd9Sstevel@tonic-gate 	bcopy(pp->ippp_class_array, array,
31957c478bd9Sstevel@tonic-gate 	    (length >> 1) * sizeof (ipp_class_t));
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 	kmem_free(pp->ippp_class_array,
31987c478bd9Sstevel@tonic-gate 	    (length >> 1) * sizeof (ipp_class_t));
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate 	pp->ippp_class_array = array;
32017c478bd9Sstevel@tonic-gate 	pp->ippp_class_limit = length - 1;
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	return (0);
32047c478bd9Sstevel@tonic-gate }
32057c478bd9Sstevel@tonic-gate #undef	__FN__
32067c478bd9Sstevel@tonic-gate 
32077c478bd9Sstevel@tonic-gate #define	__FN__	"free_packet"
32087c478bd9Sstevel@tonic-gate static void
32097c478bd9Sstevel@tonic-gate free_packet(
32107c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp)
32117c478bd9Sstevel@tonic-gate {
32127c478bd9Sstevel@tonic-gate 	pp->ippp_class_windex = 0;
32137c478bd9Sstevel@tonic-gate 	pp->ippp_class_rindex = 0;
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate 	pp->ippp_data = NULL;
32167c478bd9Sstevel@tonic-gate 	pp->ippp_private = NULL;
32177c478bd9Sstevel@tonic-gate 
32187c478bd9Sstevel@tonic-gate 	kmem_cache_free(ipp_packet_cache, pp);
32197c478bd9Sstevel@tonic-gate }
32207c478bd9Sstevel@tonic-gate #undef	__FN__
32217c478bd9Sstevel@tonic-gate 
32227c478bd9Sstevel@tonic-gate #define	__FN__ 	"hash"
32237c478bd9Sstevel@tonic-gate static int
32247c478bd9Sstevel@tonic-gate hash(
32257c478bd9Sstevel@tonic-gate 	const char	*name)
32267c478bd9Sstevel@tonic-gate {
32277c478bd9Sstevel@tonic-gate 	int		val = 0;
32287c478bd9Sstevel@tonic-gate 	char		*ptr;
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate 	/*
32317c478bd9Sstevel@tonic-gate 	 * Make a hash value by XORing all the ascii codes in the text string.
32327c478bd9Sstevel@tonic-gate 	 */
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 	for (ptr = (char *)name; *ptr != NULL; ptr++) {
32357c478bd9Sstevel@tonic-gate 		val ^= *ptr;
32367c478bd9Sstevel@tonic-gate 	}
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate 	/*
32397c478bd9Sstevel@tonic-gate 	 * Return the value modulo the number of hash buckets we allow.
32407c478bd9Sstevel@tonic-gate 	 */
32417c478bd9Sstevel@tonic-gate 
32427c478bd9Sstevel@tonic-gate 	return (val % IPP_NBUCKET);
32437c478bd9Sstevel@tonic-gate }
32447c478bd9Sstevel@tonic-gate #undef	__FN__
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate #define	__FN__	"update_stats"
32477c478bd9Sstevel@tonic-gate static int
32487c478bd9Sstevel@tonic-gate update_stats(
32497c478bd9Sstevel@tonic-gate 	kstat_t		*ksp,
32507c478bd9Sstevel@tonic-gate 	int		rw)
32517c478bd9Sstevel@tonic-gate {
32527c478bd9Sstevel@tonic-gate 	ipp_stat_impl_t	*sip;
32537c478bd9Sstevel@tonic-gate 
32547c478bd9Sstevel@tonic-gate 	ASSERT(ksp->ks_private != NULL);
32557c478bd9Sstevel@tonic-gate 	sip = (ipp_stat_impl_t *)ksp->ks_private;
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 	/*
32587c478bd9Sstevel@tonic-gate 	 * Call the update function passed to ipp_stat_create() for the given
32597c478bd9Sstevel@tonic-gate 	 * set of kstats.
32607c478bd9Sstevel@tonic-gate 	 */
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	return (sip->ippsi_update((ipp_stat_t *)sip, sip->ippsi_arg, rw));
32637c478bd9Sstevel@tonic-gate }
32647c478bd9Sstevel@tonic-gate #undef	__FN__
32657c478bd9Sstevel@tonic-gate 
32667c478bd9Sstevel@tonic-gate #define	__FN__	"init_mods"
32677c478bd9Sstevel@tonic-gate static void
32687c478bd9Sstevel@tonic-gate init_mods(
32697c478bd9Sstevel@tonic-gate 	void)
32707c478bd9Sstevel@tonic-gate {
32717c478bd9Sstevel@tonic-gate 	/*
32727c478bd9Sstevel@tonic-gate 	 * Initialise the array of all module structures and the module
32737c478bd9Sstevel@tonic-gate 	 * structure kmem cache.
32747c478bd9Sstevel@tonic-gate 	 */
32757c478bd9Sstevel@tonic-gate 
32767c478bd9Sstevel@tonic-gate 	rw_init(ipp_mod_byid_lock, NULL, RW_DEFAULT,
32777c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
32787c478bd9Sstevel@tonic-gate 	ipp_mod_byid = kmem_zalloc(sizeof (ipp_mod_t *) * (ipp_max_mod + 1),
32797c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
32807c478bd9Sstevel@tonic-gate 	ipp_mod_byid[ipp_max_mod] = (ipp_mod_t *)-1;
32817c478bd9Sstevel@tonic-gate 	ipp_mid_limit = (ipp_mod_id_t)(ipp_max_mod - 1);
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 	ipp_mod_cache = kmem_cache_create("ipp_mod", sizeof (ipp_mod_t),
32847c478bd9Sstevel@tonic-gate 	    IPP_ALIGN, mod_constructor, mod_destructor, NULL, NULL, NULL, 0);
32857c478bd9Sstevel@tonic-gate 	ASSERT(ipp_mod_cache != NULL);
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate 	/*
32887c478bd9Sstevel@tonic-gate 	 * Initialize the 'module by name' hash bucket array.
32897c478bd9Sstevel@tonic-gate 	 */
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate 	rw_init(ipp_mod_byname_lock, NULL, RW_DEFAULT,
32927c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
32937c478bd9Sstevel@tonic-gate 	bzero(ipp_mod_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
32947c478bd9Sstevel@tonic-gate }
32957c478bd9Sstevel@tonic-gate #undef	__FN__
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate #define	__FN__	"init_actions"
32987c478bd9Sstevel@tonic-gate static void
32997c478bd9Sstevel@tonic-gate init_actions(
33007c478bd9Sstevel@tonic-gate 	void)
33017c478bd9Sstevel@tonic-gate {
33027c478bd9Sstevel@tonic-gate 	/*
33037c478bd9Sstevel@tonic-gate 	 * Initialise the array of all action structures and the action
33047c478bd9Sstevel@tonic-gate 	 * structure cache.
33057c478bd9Sstevel@tonic-gate 	 */
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	rw_init(ipp_action_byid_lock, NULL, RW_DEFAULT,
33087c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
33097c478bd9Sstevel@tonic-gate 	ipp_action_byid = kmem_zalloc(sizeof (ipp_action_t *) *
33107c478bd9Sstevel@tonic-gate 	    (ipp_max_action + 1), KM_SLEEP);
33117c478bd9Sstevel@tonic-gate 	ipp_action_byid[ipp_max_action] = (ipp_action_t *)-1;
33127c478bd9Sstevel@tonic-gate 	ipp_aid_limit = (ipp_action_id_t)(ipp_max_action - 1);
33137c478bd9Sstevel@tonic-gate 
33147c478bd9Sstevel@tonic-gate 	ipp_action_cache = kmem_cache_create("ipp_action",
33157c478bd9Sstevel@tonic-gate 	    sizeof (ipp_action_t), IPP_ALIGN, action_constructor,
33167c478bd9Sstevel@tonic-gate 	    action_destructor, NULL, NULL, NULL, 0);
33177c478bd9Sstevel@tonic-gate 	ASSERT(ipp_action_cache != NULL);
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 	/*
33207c478bd9Sstevel@tonic-gate 	 * Initialize the 'action by name' hash bucket array (and the special
33217c478bd9Sstevel@tonic-gate 	 * 'hash' bucket for nameless actions).
33227c478bd9Sstevel@tonic-gate 	 */
33237c478bd9Sstevel@tonic-gate 
33247c478bd9Sstevel@tonic-gate 	rw_init(ipp_action_byname_lock, NULL, RW_DEFAULT,
33257c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
33267c478bd9Sstevel@tonic-gate 	bzero(ipp_action_byname, IPP_NBUCKET * sizeof (ipp_ref_t *));
33277c478bd9Sstevel@tonic-gate 	ipp_action_noname = NULL;
33287c478bd9Sstevel@tonic-gate }
33297c478bd9Sstevel@tonic-gate #undef	__FN__
33307c478bd9Sstevel@tonic-gate 
33317c478bd9Sstevel@tonic-gate #define	__FN__	"init_packets"
33327c478bd9Sstevel@tonic-gate static void
33337c478bd9Sstevel@tonic-gate init_packets(
33347c478bd9Sstevel@tonic-gate 	void)
33357c478bd9Sstevel@tonic-gate {
33367c478bd9Sstevel@tonic-gate 	/*
33377c478bd9Sstevel@tonic-gate 	 * Initialise the packet structure cache.
33387c478bd9Sstevel@tonic-gate 	 */
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	ipp_packet_cache = kmem_cache_create("ipp_packet",
33417c478bd9Sstevel@tonic-gate 	    sizeof (ipp_packet_t), IPP_ALIGN, packet_constructor,
33427c478bd9Sstevel@tonic-gate 	    packet_destructor, NULL, NULL, NULL, 0);
33437c478bd9Sstevel@tonic-gate 	ASSERT(ipp_packet_cache != NULL);
33447c478bd9Sstevel@tonic-gate }
33457c478bd9Sstevel@tonic-gate #undef	__FN__
33467c478bd9Sstevel@tonic-gate 
33477c478bd9Sstevel@tonic-gate /*
33487c478bd9Sstevel@tonic-gate  * Kmem cache constructor/destructor functions.
33497c478bd9Sstevel@tonic-gate  */
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate #define	__FN__	"mod_constructor"
33527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
33537c478bd9Sstevel@tonic-gate static int
33547c478bd9Sstevel@tonic-gate mod_constructor(
33557c478bd9Sstevel@tonic-gate 	void		*buf,
33567c478bd9Sstevel@tonic-gate 	void		*cdrarg,
33577c478bd9Sstevel@tonic-gate 	int		kmflags)
33587c478bd9Sstevel@tonic-gate {
33597c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
33607c478bd9Sstevel@tonic-gate 	ipp_mod_id_t	mid;
33617c478bd9Sstevel@tonic-gate 
33627c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
33637c478bd9Sstevel@tonic-gate 	bzero(buf, sizeof (ipp_mod_t));
33647c478bd9Sstevel@tonic-gate 	imp = (ipp_mod_t *)buf;
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byid_lock, RW_WRITER);
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 	/*
33697c478bd9Sstevel@tonic-gate 	 * Get a new module id.
33707c478bd9Sstevel@tonic-gate 	 */
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate 	if ((mid = get_mid()) <= IPP_MOD_RESERVED) {
33737c478bd9Sstevel@tonic-gate 		rw_exit(ipp_mod_byid_lock);
33747c478bd9Sstevel@tonic-gate 		return (-1);
33757c478bd9Sstevel@tonic-gate 	}
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate 	/*
33787c478bd9Sstevel@tonic-gate 	 * Initialize the buffer as a module structure in PROTO form.
33797c478bd9Sstevel@tonic-gate 	 */
33807c478bd9Sstevel@tonic-gate 
33817c478bd9Sstevel@tonic-gate 	imp->ippm_destruct_pending = B_TRUE;
33827c478bd9Sstevel@tonic-gate 	imp->ippm_state = IPP_MODSTATE_PROTO;
33837c478bd9Sstevel@tonic-gate 	rw_init(imp->ippm_lock, NULL, RW_DEFAULT,
33847c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
33857c478bd9Sstevel@tonic-gate 
33867c478bd9Sstevel@tonic-gate 	/*
33877c478bd9Sstevel@tonic-gate 	 * Insert it into the array of all module structures.
33887c478bd9Sstevel@tonic-gate 	 */
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 	imp->ippm_id = mid;
33917c478bd9Sstevel@tonic-gate 	ipp_mod_byid[mid] = imp;
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byid_lock);
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate 	return (0);
33967c478bd9Sstevel@tonic-gate }
33977c478bd9Sstevel@tonic-gate #undef	__FN__
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate #define	__FN__	"mod_destructor"
34007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34017c478bd9Sstevel@tonic-gate static void
34027c478bd9Sstevel@tonic-gate mod_destructor(
34037c478bd9Sstevel@tonic-gate 	void		*buf,
34047c478bd9Sstevel@tonic-gate 	void		*cdrarg)
34057c478bd9Sstevel@tonic-gate {
34067c478bd9Sstevel@tonic-gate 	ipp_mod_t	*imp;
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
34097c478bd9Sstevel@tonic-gate 	imp = (ipp_mod_t *)buf;
34107c478bd9Sstevel@tonic-gate 
34117c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_state == IPP_MODSTATE_PROTO);
34127c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_action == NULL);
34137c478bd9Sstevel@tonic-gate 	ASSERT(*imp->ippm_name == '\0');
34147c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_destruct_pending);
34157c478bd9Sstevel@tonic-gate 
34167c478bd9Sstevel@tonic-gate 	rw_enter(ipp_mod_byid_lock, RW_WRITER);
34177c478bd9Sstevel@tonic-gate 	ASSERT(imp->ippm_hold_count == 0);
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 	/*
34207c478bd9Sstevel@tonic-gate 	 * NULL the entry in the array of all module structures.
34217c478bd9Sstevel@tonic-gate 	 */
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate 	ipp_mod_byid[imp->ippm_id] = NULL;
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate 	/*
34267c478bd9Sstevel@tonic-gate 	 * Clean up any remnants of the module structure as the buffer is
34277c478bd9Sstevel@tonic-gate 	 * about to disappear.
34287c478bd9Sstevel@tonic-gate 	 */
34297c478bd9Sstevel@tonic-gate 
34307c478bd9Sstevel@tonic-gate 	rw_destroy(imp->ippm_lock);
34317c478bd9Sstevel@tonic-gate 	rw_exit(ipp_mod_byid_lock);
34327c478bd9Sstevel@tonic-gate }
34337c478bd9Sstevel@tonic-gate #undef	__FN__
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate #define	__FN__	"action_constructor"
34367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34377c478bd9Sstevel@tonic-gate static int
34387c478bd9Sstevel@tonic-gate action_constructor(
34397c478bd9Sstevel@tonic-gate 	void		*buf,
34407c478bd9Sstevel@tonic-gate 	void		*cdrarg,
34417c478bd9Sstevel@tonic-gate 	int		kmflags)
34427c478bd9Sstevel@tonic-gate {
34437c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
34447c478bd9Sstevel@tonic-gate 	ipp_action_id_t	aid;
34457c478bd9Sstevel@tonic-gate 
34467c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
34477c478bd9Sstevel@tonic-gate 	bzero(buf, sizeof (ipp_action_t));
34487c478bd9Sstevel@tonic-gate 	ap = (ipp_action_t *)buf;
34497c478bd9Sstevel@tonic-gate 
34507c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byid_lock, RW_WRITER);
34517c478bd9Sstevel@tonic-gate 
34527c478bd9Sstevel@tonic-gate 	/*
34537c478bd9Sstevel@tonic-gate 	 * Get a new action id.
34547c478bd9Sstevel@tonic-gate 	 */
34557c478bd9Sstevel@tonic-gate 
34567c478bd9Sstevel@tonic-gate 	if ((aid = get_aid()) <= IPP_ACTION_RESERVED) {
34577c478bd9Sstevel@tonic-gate 		rw_exit(ipp_action_byid_lock);
34587c478bd9Sstevel@tonic-gate 		return (-1);
34597c478bd9Sstevel@tonic-gate 	}
34607c478bd9Sstevel@tonic-gate 
34617c478bd9Sstevel@tonic-gate 	/*
34627c478bd9Sstevel@tonic-gate 	 * Initialize the buffer as an action structure in PROTO form.
34637c478bd9Sstevel@tonic-gate 	 */
34647c478bd9Sstevel@tonic-gate 
34657c478bd9Sstevel@tonic-gate 	ap->ippa_state = IPP_ASTATE_PROTO;
34667c478bd9Sstevel@tonic-gate 	ap->ippa_destruct_pending = B_TRUE;
34677c478bd9Sstevel@tonic-gate 	rw_init(ap->ippa_lock, NULL, RW_DEFAULT,
34687c478bd9Sstevel@tonic-gate 	    (void *)ipltospl(LOCK_LEVEL));
34697c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_INIT(ap->ippa_config_lock);
34707c478bd9Sstevel@tonic-gate 
34717c478bd9Sstevel@tonic-gate 	/*
34727c478bd9Sstevel@tonic-gate 	 * Insert it into the array of all action structures.
34737c478bd9Sstevel@tonic-gate 	 */
34747c478bd9Sstevel@tonic-gate 
34757c478bd9Sstevel@tonic-gate 	ap->ippa_id = aid;
34767c478bd9Sstevel@tonic-gate 	ipp_action_byid[aid] = ap;
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byid_lock);
34797c478bd9Sstevel@tonic-gate 	return (0);
34807c478bd9Sstevel@tonic-gate }
34817c478bd9Sstevel@tonic-gate #undef	__FN__
34827c478bd9Sstevel@tonic-gate 
34837c478bd9Sstevel@tonic-gate #define	__FN__	"action_destructor"
34847c478bd9Sstevel@tonic-gate /*ARGSUSED*/
34857c478bd9Sstevel@tonic-gate static void
34867c478bd9Sstevel@tonic-gate action_destructor(
34877c478bd9Sstevel@tonic-gate 	void		*buf,
34887c478bd9Sstevel@tonic-gate 	void		*cdrarg)
34897c478bd9Sstevel@tonic-gate {
34907c478bd9Sstevel@tonic-gate 	ipp_action_t	*ap;
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
34937c478bd9Sstevel@tonic-gate 	ap = (ipp_action_t *)buf;
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_state == IPP_ASTATE_PROTO);
34967c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_ref == NULL);
34977c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_refby == NULL);
34987c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_packets == 0);
34997c478bd9Sstevel@tonic-gate 	ASSERT(*ap->ippa_name == '\0');
35007c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_destruct_pending);
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	rw_enter(ipp_action_byid_lock, RW_WRITER);
35037c478bd9Sstevel@tonic-gate 	ASSERT(ap->ippa_hold_count == 0);
35047c478bd9Sstevel@tonic-gate 
35057c478bd9Sstevel@tonic-gate 	/*
35067c478bd9Sstevel@tonic-gate 	 * NULL the entry in the array of all action structures.
35077c478bd9Sstevel@tonic-gate 	 */
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	ipp_action_byid[ap->ippa_id] = NULL;
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 	/*
35127c478bd9Sstevel@tonic-gate 	 * Clean up any remnants of the action structure as the buffer is
35137c478bd9Sstevel@tonic-gate 	 * about to disappear.
35147c478bd9Sstevel@tonic-gate 	 */
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate 	CONFIG_LOCK_FINI(ap->ippa_config_lock);
35177c478bd9Sstevel@tonic-gate 	rw_destroy(ap->ippa_lock);
35187c478bd9Sstevel@tonic-gate 
35197c478bd9Sstevel@tonic-gate 	rw_exit(ipp_action_byid_lock);
35207c478bd9Sstevel@tonic-gate }
35217c478bd9Sstevel@tonic-gate #undef	__FN__
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate #define	__FN__	"packet_constructor"
35247c478bd9Sstevel@tonic-gate /*ARGSUSED*/
35257c478bd9Sstevel@tonic-gate static int
35267c478bd9Sstevel@tonic-gate packet_constructor(
35277c478bd9Sstevel@tonic-gate 	void		*buf,
35287c478bd9Sstevel@tonic-gate 	void		*cdrarg,
35297c478bd9Sstevel@tonic-gate 	int		kmflags)
35307c478bd9Sstevel@tonic-gate {
35317c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp;
35327c478bd9Sstevel@tonic-gate 	ipp_class_t	*cp;
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
35357c478bd9Sstevel@tonic-gate 	bzero(buf, sizeof (ipp_packet_t));
35367c478bd9Sstevel@tonic-gate 	pp = (ipp_packet_t *)buf;
35377c478bd9Sstevel@tonic-gate 
35387c478bd9Sstevel@tonic-gate 	if ((cp = kmem_alloc(ipp_packet_classes * sizeof (ipp_class_t),
35397c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL)
35407c478bd9Sstevel@tonic-gate 		return (ENOMEM);
35417c478bd9Sstevel@tonic-gate 
35427c478bd9Sstevel@tonic-gate 	pp->ippp_class_array = cp;
35437c478bd9Sstevel@tonic-gate 	pp->ippp_class_windex = 0;
35447c478bd9Sstevel@tonic-gate 	pp->ippp_class_rindex = 0;
35457c478bd9Sstevel@tonic-gate 	pp->ippp_class_limit = ipp_packet_classes - 1;
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate 	return (0);
35487c478bd9Sstevel@tonic-gate }
35497c478bd9Sstevel@tonic-gate #undef	__FN__
35507c478bd9Sstevel@tonic-gate 
35517c478bd9Sstevel@tonic-gate #define	__FN__	"packet_destructor"
35527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
35537c478bd9Sstevel@tonic-gate static void
35547c478bd9Sstevel@tonic-gate packet_destructor(
35557c478bd9Sstevel@tonic-gate 	void		*buf,
35567c478bd9Sstevel@tonic-gate 	void		*cdrarg)
35577c478bd9Sstevel@tonic-gate {
35587c478bd9Sstevel@tonic-gate 	ipp_packet_t	*pp;
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate 	ASSERT(buf != NULL);
35617c478bd9Sstevel@tonic-gate 	pp = (ipp_packet_t *)buf;
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_data == NULL);
35647c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_class_windex == 0);
35657c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_class_rindex == 0);
35667c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_private == NULL);
35677c478bd9Sstevel@tonic-gate 	ASSERT(pp->ippp_private_free == NULL);
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	kmem_free(pp->ippp_class_array,
35707c478bd9Sstevel@tonic-gate 	    (pp->ippp_class_limit + 1) * sizeof (ipp_class_t));
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate 	if (pp->ippp_log != NULL) {
35737c478bd9Sstevel@tonic-gate 		kmem_free(pp->ippp_log,
35747c478bd9Sstevel@tonic-gate 		    (pp->ippp_log_limit + 1) * sizeof (ipp_log_t));
35757c478bd9Sstevel@tonic-gate 	}
35767c478bd9Sstevel@tonic-gate }
35777c478bd9Sstevel@tonic-gate #undef	__FN__
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate /*
35807c478bd9Sstevel@tonic-gate  * Debug message printout code.
35817c478bd9Sstevel@tonic-gate  */
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate #ifdef	IPP_DBG
35847c478bd9Sstevel@tonic-gate static void
35857c478bd9Sstevel@tonic-gate ipp_debug(
35867c478bd9Sstevel@tonic-gate 	uint64_t	type,
35877c478bd9Sstevel@tonic-gate 	const char	*fn,
35887c478bd9Sstevel@tonic-gate 	char		*fmt,
35897c478bd9Sstevel@tonic-gate 			...)
35907c478bd9Sstevel@tonic-gate {
35917c478bd9Sstevel@tonic-gate 	char		buf[255];
35927c478bd9Sstevel@tonic-gate 	va_list		adx;
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 	if ((type & ipp_debug_flags) == 0)
35957c478bd9Sstevel@tonic-gate 		return;
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate 	mutex_enter(debug_mutex);
35987c478bd9Sstevel@tonic-gate 	va_start(adx, fmt);
35997c478bd9Sstevel@tonic-gate 	(void) vsnprintf(buf, 255, fmt, adx);
36007c478bd9Sstevel@tonic-gate 	va_end(adx);
36017c478bd9Sstevel@tonic-gate 
36027c478bd9Sstevel@tonic-gate 	printf("(%llx) %s: %s", (unsigned long long)curthread->t_did, fn,
36037c478bd9Sstevel@tonic-gate 	    buf);
36047c478bd9Sstevel@tonic-gate 	mutex_exit(debug_mutex);
36057c478bd9Sstevel@tonic-gate }
36067c478bd9Sstevel@tonic-gate #endif	/* IPP_DBG */
3607