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