xref: /titanic_51/usr/src/uts/common/os/damap.c (revision 641097441a6e36fb83135a28c834761ecbb80d36)
14c06356bSdh142964 /*
24c06356bSdh142964  * CDDL HEADER START
34c06356bSdh142964  *
44c06356bSdh142964  * The contents of this file are subject to the terms of the
54c06356bSdh142964  * Common Development and Distribution License (the "License").
64c06356bSdh142964  * You may not use this file except in compliance with the License.
74c06356bSdh142964  *
84c06356bSdh142964  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh142964  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh142964  * See the License for the specific language governing permissions
114c06356bSdh142964  * and limitations under the License.
124c06356bSdh142964  *
134c06356bSdh142964  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh142964  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh142964  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh142964  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh142964  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh142964  *
194c06356bSdh142964  * CDDL HEADER END
204c06356bSdh142964  */
214c06356bSdh142964 
224c06356bSdh142964 /*
239aed1621SDavid Hollister  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
244c06356bSdh142964  * Use is subject to license terms.
254c06356bSdh142964  */
264c06356bSdh142964 
274c06356bSdh142964 #include <sys/note.h>
284c06356bSdh142964 #include <sys/types.h>
294c06356bSdh142964 #include <sys/param.h>
304c06356bSdh142964 #include <sys/systm.h>
314c06356bSdh142964 #include <sys/buf.h>
324c06356bSdh142964 #include <sys/kmem.h>
334c06356bSdh142964 #include <sys/cmn_err.h>
344c06356bSdh142964 #include <sys/debug.h>
354c06356bSdh142964 #include <sys/sunndi.h>
364c06356bSdh142964 #include <sys/kstat.h>
374c06356bSdh142964 #include <sys/conf.h>
384c06356bSdh142964 #include <sys/ddi_timer.h>
394c06356bSdh142964 #include <sys/devctl.h>
404c06356bSdh142964 #include <sys/callb.h>
414c06356bSdh142964 #include <sys/sysevent.h>
424c06356bSdh142964 #include <sys/taskq.h>
434c06356bSdh142964 #include <sys/ddi.h>
444c06356bSdh142964 #include <sys/bitset.h>
454c06356bSdh142964 #include <sys/damap.h>
464c06356bSdh142964 #include <sys/damap_impl.h>
474c06356bSdh142964 
484c06356bSdh142964 #ifdef DEBUG
494c06356bSdh142964 static int damap_debug = 0;
504c06356bSdh142964 #endif /* DEBUG */
514c06356bSdh142964 
521b115575SJohn Danielson extern taskq_t *system_taskq;
531b115575SJohn Danielson 
544c06356bSdh142964 static void dam_addrset_activate(dam_t *, bitset_t *);
551b115575SJohn Danielson static void dam_addrset_deactivate(dam_t *, bitset_t *);
561b115575SJohn Danielson static void dam_stabilize_map(void *);
574c06356bSdh142964 static void dam_addr_stable_cb(void *);
581b115575SJohn Danielson static void dam_addrset_stable_cb(void *);
594c06356bSdh142964 static void dam_sched_tmo(dam_t *, clock_t, void (*tmo_cb)());
601b115575SJohn Danielson static void dam_addr_report(dam_t *, dam_da_t *, id_t, int);
611b115575SJohn Danielson static void dam_addr_release(dam_t *, id_t);
621b115575SJohn Danielson static void dam_addr_report_release(dam_t *, id_t);
631b115575SJohn Danielson static void dam_addr_deactivate(dam_t *, id_t);
64d189c170SReed static void dam_deact_cleanup(dam_t *, id_t, char *, damap_deact_rsn_t);
654c06356bSdh142964 static id_t dam_get_addrid(dam_t *, char *);
664c06356bSdh142964 static int dam_kstat_create(dam_t *);
671b115575SJohn Danielson static int dam_map_alloc(dam_t *);
684c06356bSdh142964 
694c06356bSdh142964 #define	DAM_INCR_STAT(mapp, stat)				\
704c06356bSdh142964 	if ((mapp)->dam_kstatsp) {				\
714c06356bSdh142964 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
724c06356bSdh142964 		stp->stat.value.ui32++;				\
734c06356bSdh142964 	}
744c06356bSdh142964 
754c06356bSdh142964 #define	DAM_SET_STAT(mapp, stat, val)				\
764c06356bSdh142964 	if ((mapp)->dam_kstatsp) {				\
774c06356bSdh142964 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
784c06356bSdh142964 		stp->stat.value.ui32 = (val);			\
794c06356bSdh142964 	}
804c06356bSdh142964 
811b115575SJohn Danielson 
821b115575SJohn Danielson /*
831b115575SJohn Danielson  * increase damap size by 64 entries at a time
841b115575SJohn Danielson  */
851b115575SJohn Danielson #define	DAM_SIZE_BUMP	64
861b115575SJohn Danielson 
87*64109744SChris Horne int	damap_taskq_dispatch_retry_usec = 1000;
88*64109744SChris Horne 
891b115575SJohn Danielson /*
901b115575SJohn Danielson  * config/unconfig taskq data
911b115575SJohn Danielson  */
921b115575SJohn Danielson typedef struct {
931b115575SJohn Danielson 	dam_t *tqd_mapp;
941b115575SJohn Danielson 	id_t tqd_id;
951b115575SJohn Danielson } cfg_tqd_t;
961b115575SJohn Danielson 
971b115575SJohn Danielson extern pri_t maxclsyspri;
981b115575SJohn Danielson 
994c06356bSdh142964 /*
1004c06356bSdh142964  * Create new device address map
1014c06356bSdh142964  *
1021b115575SJohn Danielson  * name:		map name (kstat unique)
1034c06356bSdh142964  * size:		max # of map entries
1041b115575SJohn Danielson  * mode:		style of address reports: per-address or fullset
1054c06356bSdh142964  * stable_usec:		# of quiescent microseconds before report/map is stable
1064c06356bSdh142964  *
1074c06356bSdh142964  * activate_arg:	address provider activation-callout private
1084c06356bSdh142964  * activate_cb:		address provider activation callback handler
1094c06356bSdh142964  * deactivate_cb:	address provider deactivation callback handler
1104c06356bSdh142964  *
1114c06356bSdh142964  * config_arg:		configuration-callout private
1124c06356bSdh142964  * config_cb:		class configuration callout
1134c06356bSdh142964  * unconfig_cb:		class unconfiguration callout
1144c06356bSdh142964  *
1154c06356bSdh142964  * damapp:		pointer to map handle (return)
1164c06356bSdh142964  *
1174c06356bSdh142964  * Returns:	DAM_SUCCESS
1184c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
1194c06356bSdh142964  *		DAM_FAILURE	General failure
1204c06356bSdh142964  */
1214c06356bSdh142964 int
1221b115575SJohn Danielson damap_create(char *name, damap_rptmode_t mode, int map_opts,
1231b115575SJohn Danielson     clock_t stable_usec, void *activate_arg, damap_activate_cb_t activate_cb,
1244c06356bSdh142964     damap_deactivate_cb_t deactivate_cb,
1254c06356bSdh142964     void *config_arg, damap_configure_cb_t configure_cb,
1264c06356bSdh142964     damap_unconfig_cb_t unconfig_cb,
1274c06356bSdh142964     damap_t **damapp)
1284c06356bSdh142964 {
1294c06356bSdh142964 	dam_t *mapp;
1304c06356bSdh142964 
1311b115575SJohn Danielson 	if (configure_cb == NULL || unconfig_cb == NULL || name == NULL)
1324c06356bSdh142964 		return (DAM_EINVAL);
1334c06356bSdh142964 
1341b115575SJohn Danielson 	DTRACE_PROBE3(damap__create, char *, name,
1351b115575SJohn Danielson 	    damap_rptmode_t, mode, clock_t, stable_usec);
1364c06356bSdh142964 
1374c06356bSdh142964 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
1381b115575SJohn Danielson 	mapp->dam_options = map_opts;
1394c06356bSdh142964 	mapp->dam_stabletmo = drv_usectohz(stable_usec);
1401b115575SJohn Danielson 	mapp->dam_size = 0;
1411b115575SJohn Danielson 	mapp->dam_rptmode = mode;
1424c06356bSdh142964 	mapp->dam_activate_arg = activate_arg;
1434c06356bSdh142964 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
1444c06356bSdh142964 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
1454c06356bSdh142964 	mapp->dam_config_arg = config_arg;
1464c06356bSdh142964 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
1474c06356bSdh142964 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
1481b115575SJohn Danielson 	mapp->dam_name = i_ddi_strdup(name, KM_SLEEP);
1494c06356bSdh142964 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
1504c06356bSdh142964 	cv_init(&mapp->dam_cv, NULL, CV_DRIVER, NULL);
1511b115575SJohn Danielson 	bitset_init(&mapp->dam_active_set);
1521b115575SJohn Danielson 	bitset_init(&mapp->dam_stable_set);
1531b115575SJohn Danielson 	bitset_init(&mapp->dam_report_set);
1544c06356bSdh142964 	*damapp = (damap_t *)mapp;
1554c06356bSdh142964 	return (DAM_SUCCESS);
1564c06356bSdh142964 }
1574c06356bSdh142964 
1584c06356bSdh142964 /*
1591b115575SJohn Danielson  * Allocate backing resources
1601b115575SJohn Danielson  *
1611b115575SJohn Danielson  * DAMs are lightly backed on create - major allocations occur
1621b115575SJohn Danielson  * at the time a report is made to the map, and are extended on
1631b115575SJohn Danielson  * a demand basis.
1641b115575SJohn Danielson  */
1651b115575SJohn Danielson static int
1661b115575SJohn Danielson dam_map_alloc(dam_t *mapp)
1671b115575SJohn Danielson {
1681b115575SJohn Danielson 	void *softstate_p;
1691b115575SJohn Danielson 
1701b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
1711b115575SJohn Danielson 	if (mapp->dam_flags & DAM_DESTROYPEND)
1721b115575SJohn Danielson 		return (DAM_FAILURE);
1731b115575SJohn Danielson 
1741b115575SJohn Danielson 	/*
1751b115575SJohn Danielson 	 * dam_high > 0 signals map allocation complete
1761b115575SJohn Danielson 	 */
1771b115575SJohn Danielson 	if (mapp->dam_high)
1781b115575SJohn Danielson 		return (DAM_SUCCESS);
1791b115575SJohn Danielson 
1801b115575SJohn Danielson 	mapp->dam_size = DAM_SIZE_BUMP;
1811b115575SJohn Danielson 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t),
1821b115575SJohn Danielson 	    mapp->dam_size) != DDI_SUCCESS)
1831b115575SJohn Danielson 		return (DAM_FAILURE);
1841b115575SJohn Danielson 
1851b115575SJohn Danielson 	if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) !=
1861b115575SJohn Danielson 	    DDI_SUCCESS) {
1871b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1881b115575SJohn Danielson 		return (DAM_FAILURE);
1891b115575SJohn Danielson 	}
1901b115575SJohn Danielson 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
1911b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1921b115575SJohn Danielson 		ddi_strid_fini(&mapp->dam_addr_hash);
1931b115575SJohn Danielson 		return (DAM_FAILURE);
1941b115575SJohn Danielson 	}
1951b115575SJohn Danielson 	mapp->dam_da = softstate_p;
1961b115575SJohn Danielson 	mapp->dam_high = 1;
1971b115575SJohn Danielson 	bitset_resize(&mapp->dam_active_set, mapp->dam_size);
1981b115575SJohn Danielson 	bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
1991b115575SJohn Danielson 	bitset_resize(&mapp->dam_report_set, mapp->dam_size);
2001b115575SJohn Danielson 	return (DAM_SUCCESS);
2011b115575SJohn Danielson }
2021b115575SJohn Danielson 
2031b115575SJohn Danielson /*
2041b115575SJohn Danielson  * Destroy address map
2054c06356bSdh142964  *
2064c06356bSdh142964  * damapp:	address map
2074c06356bSdh142964  *
2084c06356bSdh142964  * Returns:	DAM_SUCCESS
2094c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
2104c06356bSdh142964  *		DAM_FAILURE	General failure
2114c06356bSdh142964  */
2124c06356bSdh142964 void
2134c06356bSdh142964 damap_destroy(damap_t *damapp)
2144c06356bSdh142964 {
2154c06356bSdh142964 	int i;
2164c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
2174c06356bSdh142964 
2184c06356bSdh142964 	ASSERT(mapp);
2194c06356bSdh142964 
2201b115575SJohn Danielson 	DTRACE_PROBE1(damap__destroy, char *, mapp->dam_name);
2214c06356bSdh142964 
2221b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
2234c06356bSdh142964 
2244c06356bSdh142964 	/*
2251b115575SJohn Danielson 	 * prevent new reports from being added to the map
2264c06356bSdh142964 	 */
2271b115575SJohn Danielson 	mapp->dam_flags |= DAM_DESTROYPEND;
2284c06356bSdh142964 
2291b115575SJohn Danielson 	if (mapp->dam_high) {
2301b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2311b115575SJohn Danielson 		/*
2321b115575SJohn Danielson 		 * wait for outstanding reports to stabilize and cancel
2331b115575SJohn Danielson 		 * the timer for this map
2341b115575SJohn Danielson 		 */
2351b115575SJohn Danielson 		(void) damap_sync(damapp);
2361b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
2371b115575SJohn Danielson 		dam_sched_tmo(mapp, 0, NULL);
2381b115575SJohn Danielson 
2391b115575SJohn Danielson 		/*
2401b115575SJohn Danielson 		 * map is at full stop
2411b115575SJohn Danielson 		 * release the contents of the map, invoking the
2421b115575SJohn Danielson 		 * detactivation protocol as addresses are released
2431b115575SJohn Danielson 		 */
2441b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2454c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++) {
2464c06356bSdh142964 			if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
2474c06356bSdh142964 				continue;
2481b115575SJohn Danielson 
2491b115575SJohn Danielson 			ASSERT(DAM_IN_REPORT(mapp, i) == 0);
2501b115575SJohn Danielson 
2511b115575SJohn Danielson 			if (DAM_IS_STABLE(mapp, i)) {
2521b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
2531b115575SJohn Danielson 			} else {
2544c06356bSdh142964 				ddi_strid_free(mapp->dam_addr_hash, i);
2554c06356bSdh142964 				ddi_soft_state_free(mapp->dam_da, i);
2564c06356bSdh142964 			}
2571b115575SJohn Danielson 		}
2584c06356bSdh142964 		ddi_strid_fini(&mapp->dam_addr_hash);
2594c06356bSdh142964 		ddi_soft_state_fini(&mapp->dam_da);
2601b115575SJohn Danielson 		kstat_delete(mapp->dam_kstatsp);
2611b115575SJohn Danielson 	}
2624c06356bSdh142964 	bitset_fini(&mapp->dam_active_set);
2634c06356bSdh142964 	bitset_fini(&mapp->dam_stable_set);
2644c06356bSdh142964 	bitset_fini(&mapp->dam_report_set);
2654c06356bSdh142964 	mutex_destroy(&mapp->dam_lock);
2664c06356bSdh142964 	cv_destroy(&mapp->dam_cv);
2674c06356bSdh142964 	if (mapp->dam_name)
2684c06356bSdh142964 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
2694c06356bSdh142964 	kmem_free(mapp, sizeof (*mapp));
2704c06356bSdh142964 }
2714c06356bSdh142964 
2724c06356bSdh142964 /*
2734c06356bSdh142964  * Wait for map stability.
2744c06356bSdh142964  *
2754c06356bSdh142964  * damapp:	address map
2764c06356bSdh142964  */
2774c06356bSdh142964 int
2784c06356bSdh142964 damap_sync(damap_t *damapp)
2794c06356bSdh142964 {
2801b115575SJohn Danielson #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND)
2814c06356bSdh142964 
2824c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
2834c06356bSdh142964 	int   none_active;
2844c06356bSdh142964 
2854c06356bSdh142964 	ASSERT(mapp);
2864c06356bSdh142964 
2871b115575SJohn Danielson 	DTRACE_PROBE2(damap__map__sync__start, char *, mapp->dam_name,
2881b115575SJohn Danielson 	    dam_t *, mapp);
2894c06356bSdh142964 
2901b115575SJohn Danielson 	/*
2911b115575SJohn Danielson 	 * block where waiting for
2921b115575SJohn Danielson 	 * a) stabilization pending or a fullset update pending
2931b115575SJohn Danielson 	 * b) any scheduled timeouts to fire
2941b115575SJohn Danielson 	 * c) the report set to finalize (bitset is null)
2951b115575SJohn Danielson 	 */
2964c06356bSdh142964 	mutex_enter(&mapp->dam_lock);
2974c06356bSdh142964 	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
2984c06356bSdh142964 	    (!bitset_is_null(&mapp->dam_report_set)) || (mapp->dam_tid != 0)) {
2991b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__sync__waiting, char *, mapp->dam_name,
3001b115575SJohn Danielson 		    dam_t *, mapp);
3014c06356bSdh142964 		cv_wait(&mapp->dam_cv, &mapp->dam_lock);
3024c06356bSdh142964 	}
3034c06356bSdh142964 
3044c06356bSdh142964 	none_active = bitset_is_null(&mapp->dam_active_set);
3054c06356bSdh142964 
3064c06356bSdh142964 	mutex_exit(&mapp->dam_lock);
3071b115575SJohn Danielson 	DTRACE_PROBE3(damap__map__sync__end, char *, mapp->dam_name, int,
3081b115575SJohn Danielson 	    none_active, dam_t *, mapp);
3094c06356bSdh142964 
3104c06356bSdh142964 	return (none_active);
3114c06356bSdh142964 }
3124c06356bSdh142964 
3134c06356bSdh142964 /*
3144c06356bSdh142964  * Get the name of a device address map
3154c06356bSdh142964  *
3164c06356bSdh142964  * damapp:	address map
3174c06356bSdh142964  *
3184c06356bSdh142964  * Returns:	name
3194c06356bSdh142964  */
3204c06356bSdh142964 char *
3214c06356bSdh142964 damap_name(damap_t *damapp)
3224c06356bSdh142964 {
3234c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
3244c06356bSdh142964 
3254c06356bSdh142964 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
3264c06356bSdh142964 }
3274c06356bSdh142964 
3284c06356bSdh142964 /*
3294c06356bSdh142964  * Report an address to per-address report
3304c06356bSdh142964  *
3314c06356bSdh142964  * damapp:	address map handle
3324c06356bSdh142964  * address:	address in ascii string representation
3331b115575SJohn Danielson  * addridp:	address ID
3344c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
3354c06356bSdh142964  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
3364c06356bSdh142964  *
3374c06356bSdh142964  * Returns:	DAM_SUCCESS
3384c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
3394c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
3404c06356bSdh142964  */
3414c06356bSdh142964 int
3421b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp,
3431b115575SJohn Danielson     nvlist_t *nvl, void *addr_priv)
3444c06356bSdh142964 {
3454c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
3464c06356bSdh142964 	id_t addrid;
3474c06356bSdh142964 	dam_da_t *passp;
3484c06356bSdh142964 
3491b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
3504c06356bSdh142964 		return (DAM_EINVAL);
3514c06356bSdh142964 
3521b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__add, char *, mapp->dam_name,
3531b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
3541b115575SJohn Danielson 
3551b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
3561b115575SJohn Danielson 	if ((dam_map_alloc(mapp) != DAM_SUCCESS) ||
3571b115575SJohn Danielson 	    ((addrid = dam_get_addrid(mapp, address)) == 0)) {
3581b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
3594c06356bSdh142964 		return (DAM_MAPFULL);
3604c06356bSdh142964 	}
3614c06356bSdh142964 
3624c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
3634c06356bSdh142964 	ASSERT(passp != NULL);
3644c06356bSdh142964 
3654c06356bSdh142964 	/*
3664c06356bSdh142964 	 * If re-reporting the same address (add or remove) clear
3674c06356bSdh142964 	 * the existing report
3684c06356bSdh142964 	 */
3694c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
3701b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__add__jitter, char *, mapp->dam_name,
3711b115575SJohn Danielson 		    char *, address, dam_t *, mapp);
3721b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
3731b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
3744c06356bSdh142964 		passp->da_jitter++;
3754c06356bSdh142964 	}
3764c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
3774c06356bSdh142964 	if (nvl)
3784c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
3794c06356bSdh142964 
3801b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD);
3811b115575SJohn Danielson 	if (addridp != NULL)
3821b115575SJohn Danielson 		*addridp = (damap_id_t)addrid;
3831b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
3844c06356bSdh142964 	return (DAM_SUCCESS);
3854c06356bSdh142964 }
3864c06356bSdh142964 
3874c06356bSdh142964 /*
3884c06356bSdh142964  * Report removal of address from per-address report
3894c06356bSdh142964  *
3904c06356bSdh142964  * damapp:	address map
3914c06356bSdh142964  * address:	address in ascii string representation
3924c06356bSdh142964  *
3934c06356bSdh142964  * Returns:	DAM_SUCCESS
3944c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
3954c06356bSdh142964  *		DAM_FAILURE	General failure
3964c06356bSdh142964  */
3974c06356bSdh142964 int
3984c06356bSdh142964 damap_addr_del(damap_t *damapp, char *address)
3994c06356bSdh142964 {
4004c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
4014c06356bSdh142964 	id_t addrid;
4024c06356bSdh142964 	dam_da_t *passp;
4034c06356bSdh142964 
4041b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4054c06356bSdh142964 		return (DAM_EINVAL);
4064c06356bSdh142964 
4071b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__del, char *, mapp->dam_name,
4081b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
4091b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4101b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
4111b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4121b115575SJohn Danielson 		return (DAM_MAPFULL);
4131b115575SJohn Danielson 	}
4141b115575SJohn Danielson 
4151b115575SJohn Danielson 	/*
4161b115575SJohn Danielson 	 * if reporting the removal of an address which is not in the map
4171b115575SJohn Danielson 	 * return success
4181b115575SJohn Danielson 	 */
4194c06356bSdh142964 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
4201b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4214c06356bSdh142964 		return (DAM_SUCCESS);
4224c06356bSdh142964 	}
4234c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4244c06356bSdh142964 	ASSERT(passp);
4254c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
4261b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__del__jitter, char *, mapp->dam_name,
4271b115575SJohn Danielson 		    char *, address, dam_t *, mapp);
4281b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4291b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4304c06356bSdh142964 		passp->da_jitter++;
4314c06356bSdh142964 	}
4321b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL);
4331b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4344c06356bSdh142964 	return (DAM_SUCCESS);
4354c06356bSdh142964 }
4364c06356bSdh142964 
4374c06356bSdh142964 /*
4384c06356bSdh142964  * Initiate full-set report
4394c06356bSdh142964  *
4404c06356bSdh142964  * damapp:	address map
4414c06356bSdh142964  *
4424c06356bSdh142964  * Returns:	DAM_SUCCESS
4434c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
4444c06356bSdh142964  */
4454c06356bSdh142964 int
4464c06356bSdh142964 damap_addrset_begin(damap_t *damapp)
4474c06356bSdh142964 {
4484c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
4494c06356bSdh142964 	int i;
4504c06356bSdh142964 
4511b115575SJohn Danielson 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
4524c06356bSdh142964 		return (DAM_EINVAL);
4534c06356bSdh142964 
4541b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__begin, char *, mapp->dam_name, dam_t *,
4551b115575SJohn Danielson 	    mapp);
4561b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4571b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
4581b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4591b115575SJohn Danielson 		return (DAM_MAPFULL);
4601b115575SJohn Danielson 	}
4614c06356bSdh142964 	if (mapp->dam_flags & DAM_SETADD) {
4621b115575SJohn Danielson 		DTRACE_PROBE2(damap__addrset__begin__reset, char *,
4631b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
4644c06356bSdh142964 		/*
4654c06356bSdh142964 		 * cancel stabilization timeout
4664c06356bSdh142964 		 */
4674c06356bSdh142964 		dam_sched_tmo(mapp, 0, NULL);
4681b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4691b115575SJohn Danielson 
4701b115575SJohn Danielson 		/*
4711b115575SJohn Danielson 		 * clear pending reports
4721b115575SJohn Danielson 		 */
4734c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++) {
4744c06356bSdh142964 			if (DAM_IN_REPORT(mapp, i))
4751b115575SJohn Danielson 				dam_addr_report_release(mapp, i);
4764c06356bSdh142964 		}
4774c06356bSdh142964 	}
4784c06356bSdh142964 	bitset_zero(&mapp->dam_report_set);
4791b115575SJohn Danielson 	mapp->dam_flags |= DAM_SETADD;
4801b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4814c06356bSdh142964 	return (DAM_SUCCESS);
4824c06356bSdh142964 }
4834c06356bSdh142964 
4844c06356bSdh142964 /*
4854c06356bSdh142964  * Report address to full-set report
4864c06356bSdh142964  *
4874c06356bSdh142964  * damapp:	address map handle
4884c06356bSdh142964  * address:	address in ascii string representation
4894c06356bSdh142964  * rindx:	index if address stabilizes
4904c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
4914c06356bSdh142964  * addr_priv:	optional provider-private data (passed to activate/release cb)
4924c06356bSdh142964  *
4934c06356bSdh142964  * Returns:	DAM_SUCCESS
4944c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
4954c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
4964c06356bSdh142964  *		DAM_FAILURE	General failure
4974c06356bSdh142964  */
4984c06356bSdh142964 int
4994c06356bSdh142964 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
5004c06356bSdh142964     nvlist_t *nvl, void *addr_priv)
5014c06356bSdh142964 {
5024c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
5034c06356bSdh142964 	id_t addrid;
5044c06356bSdh142964 	dam_da_t *passp;
5054c06356bSdh142964 
5061b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
5074c06356bSdh142964 		return (DAM_EINVAL);
5084c06356bSdh142964 
5091b115575SJohn Danielson 	DTRACE_PROBE3(damap__addrset__add, char *, mapp->dam_name,
5101b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
5114c06356bSdh142964 
5121b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
5131b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
5141b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5151b115575SJohn Danielson 		return (DAM_FAILURE);
5161b115575SJohn Danielson 	}
5171b115575SJohn Danielson 
5184c06356bSdh142964 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
5191b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5204c06356bSdh142964 		return (DAM_MAPFULL);
5214c06356bSdh142964 	}
5224c06356bSdh142964 
5234c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
5244c06356bSdh142964 	ASSERT(passp);
5254c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
5261b115575SJohn Danielson 		DTRACE_PROBE3(damap__addrset__add__jitter, char *,
5271b115575SJohn Danielson 		    mapp->dam_name, char *, address, dam_t *, mapp);
5281b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
5294c06356bSdh142964 		passp->da_jitter++;
5304c06356bSdh142964 	}
5314c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
5324c06356bSdh142964 	if (nvl)
5334c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
5344c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
5354c06356bSdh142964 	if (ridx)
5364c06356bSdh142964 		*ridx = (damap_id_t)addrid;
5371b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
5384c06356bSdh142964 	return (DAM_SUCCESS);
5394c06356bSdh142964 }
5404c06356bSdh142964 
5414c06356bSdh142964 /*
5424c06356bSdh142964  * Commit full-set report for stabilization
5434c06356bSdh142964  *
5444c06356bSdh142964  * damapp:	address map handle
5454c06356bSdh142964  * flags:	(currently 0)
5464c06356bSdh142964  *
5474c06356bSdh142964  * Returns:	DAM_SUCCESS
5484c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
5494c06356bSdh142964  *		DAM_FAILURE	General failure
5504c06356bSdh142964  */
5514c06356bSdh142964 int
5524c06356bSdh142964 damap_addrset_end(damap_t *damapp, int flags)
5534c06356bSdh142964 {
5544c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
5554c06356bSdh142964 	int i;
5564c06356bSdh142964 
5571b115575SJohn Danielson 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
5584c06356bSdh142964 		return (DAM_EINVAL);
5594c06356bSdh142964 
5601b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__end, char *, mapp->dam_name,
5611b115575SJohn Danielson 	    dam_t *, mapp);
5624c06356bSdh142964 
5631b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
5641b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
5651b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5661b115575SJohn Danielson 		return (DAM_FAILURE);
5671b115575SJohn Danielson 	}
5681b115575SJohn Danielson 
5691b115575SJohn Danielson 	if (flags & DAMAP_END_RESET) {
5701b115575SJohn Danielson 		DTRACE_PROBE2(damap__addrset__end__reset, char *,
5711b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
5724c06356bSdh142964 		dam_sched_tmo(mapp, 0, NULL);
5734c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++)
5744c06356bSdh142964 			if (DAM_IN_REPORT(mapp, i))
5751b115575SJohn Danielson 				dam_addr_report_release(mapp, i);
5764c06356bSdh142964 	} else {
5774c06356bSdh142964 		mapp->dam_last_update = gethrtime();
5781b115575SJohn Danielson 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb);
5794c06356bSdh142964 	}
5801b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
5814c06356bSdh142964 	return (DAM_SUCCESS);
5824c06356bSdh142964 }
5834c06356bSdh142964 
5844c06356bSdh142964 /*
5854c06356bSdh142964  * Return nvlist registered with reported address
5864c06356bSdh142964  *
5874c06356bSdh142964  * damapp:	address map handle
5881b115575SJohn Danielson  * addrid:	address ID
5894c06356bSdh142964  *
5904c06356bSdh142964  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
5914c06356bSdh142964  *		NULL
5924c06356bSdh142964  */
5934c06356bSdh142964 nvlist_t *
5944c06356bSdh142964 damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
5954c06356bSdh142964 {
5964c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
5974c06356bSdh142964 	dam_da_t *pass;
5984c06356bSdh142964 
5991b115575SJohn Danielson 	if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) {
6001b115575SJohn Danielson 		if (pass = ddi_get_soft_state(mapp->dam_da, addrid))
6014c06356bSdh142964 			return (pass->da_nvl);
6024c06356bSdh142964 	}
6034c06356bSdh142964 	return (NULL);
6044c06356bSdh142964 }
6054c06356bSdh142964 
6064c06356bSdh142964 /*
6074c06356bSdh142964  * Return address string
6084c06356bSdh142964  *
6094c06356bSdh142964  * damapp:	address map handle
6101b115575SJohn Danielson  * addrid:	address ID
6114c06356bSdh142964  *
6124c06356bSdh142964  * Returns:	char *		Address string
6134c06356bSdh142964  *		NULL
6144c06356bSdh142964  */
6154c06356bSdh142964 char *
6161b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid)
6174c06356bSdh142964 {
6184c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6194c06356bSdh142964 
6201b115575SJohn Danielson 	if (mapp->dam_high)
6211b115575SJohn Danielson 		return (ddi_strid_id2str(mapp->dam_addr_hash, addrid));
6221b115575SJohn Danielson 	else
6231b115575SJohn Danielson 		return (NULL);
6244c06356bSdh142964 }
6254c06356bSdh142964 
6264c06356bSdh142964 /*
6274c06356bSdh142964  * Release address reference in map
6284c06356bSdh142964  *
6294c06356bSdh142964  * damapp:	address map handle
6301b115575SJohn Danielson  * addrid:	address ID
6314c06356bSdh142964  */
6324c06356bSdh142964 void
6334c06356bSdh142964 damap_id_rele(damap_t *damapp, damap_id_t addrid)
6344c06356bSdh142964 {
6354c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6361b115575SJohn Danielson 	dam_da_t *passp;
6371b115575SJohn Danielson 	char *addr;
6384c06356bSdh142964 
6391b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
6401b115575SJohn Danielson 	ASSERT(passp);
6411b115575SJohn Danielson 
6421b115575SJohn Danielson 	addr = damap_id2addr(damapp, addrid);
6431b115575SJohn Danielson 	DTRACE_PROBE4(damap__id__rele, char *, mapp->dam_name, char *, addr,
6441b115575SJohn Danielson 	    dam_t *, mapp, int, passp->da_ref);
6451b115575SJohn Danielson 
6461b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6471b115575SJohn Danielson 
6481b115575SJohn Danielson 	/*
6491b115575SJohn Danielson 	 * teardown address if last outstanding reference
6501b115575SJohn Danielson 	 */
6511b115575SJohn Danielson 	if (--passp->da_ref == 0)
6521b115575SJohn Danielson 		dam_addr_release(mapp, (id_t)addrid);
6531b115575SJohn Danielson 
6541b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6554c06356bSdh142964 }
6564c06356bSdh142964 
6574c06356bSdh142964 /*
6584c06356bSdh142964  * Return current reference count on address reference in map
6594c06356bSdh142964  *
6604c06356bSdh142964  * damapp:	address map handle
6611b115575SJohn Danielson  * addrid:	address ID
6624c06356bSdh142964  *
6634c06356bSdh142964  * Returns:	DAM_SUCCESS
6644c06356bSdh142964  *		DAM_FAILURE
6654c06356bSdh142964  */
6664c06356bSdh142964 int
6671b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid)
6684c06356bSdh142964 {
6694c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6704c06356bSdh142964 	dam_da_t *passp;
6714c06356bSdh142964 	int ref = -1;
6724c06356bSdh142964 
6731b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
6744c06356bSdh142964 	if (passp)
6754c06356bSdh142964 		ref = passp->da_ref;
6761b115575SJohn Danielson 
6774c06356bSdh142964 	return (ref);
6784c06356bSdh142964 }
6794c06356bSdh142964 
6804c06356bSdh142964 /*
6814c06356bSdh142964  * Return next address ID in list
6824c06356bSdh142964  *
6834c06356bSdh142964  * damapp:	address map handle
6844c06356bSdh142964  * damap_list:	address ID list passed to config|unconfig
6854c06356bSdh142964  *		returned by look by lookup_all
6864c06356bSdh142964  * last:	last ID returned, 0 is start of list
6874c06356bSdh142964  *
6884c06356bSdh142964  * Returns:	addrid		Next ID from the list
6894c06356bSdh142964  *		0		End of the list
6904c06356bSdh142964  */
6914c06356bSdh142964 damap_id_t
6924c06356bSdh142964 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
6934c06356bSdh142964 {
6944c06356bSdh142964 	int i, start;
6954c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6964c06356bSdh142964 	bitset_t *dam_list = (bitset_t *)damap_list;
6974c06356bSdh142964 
6984c06356bSdh142964 	if (!mapp || !dam_list)
6994c06356bSdh142964 		return ((damap_id_t)0);
7004c06356bSdh142964 
7014c06356bSdh142964 	start = (int)last + 1;
7021b115575SJohn Danielson 	for (i = start; i < mapp->dam_high; i++) {
7031b115575SJohn Danielson 		if (bitset_in_set(dam_list, i)) {
7044c06356bSdh142964 			return ((damap_id_t)i);
7051b115575SJohn Danielson 		}
7061b115575SJohn Danielson 	}
7074c06356bSdh142964 	return ((damap_id_t)0);
7084c06356bSdh142964 }
7094c06356bSdh142964 
7104c06356bSdh142964 /*
7114c06356bSdh142964  * Set config private data
7124c06356bSdh142964  *
7134c06356bSdh142964  * damapp:	address map handle
7141b115575SJohn Danielson  * addrid:	address ID
7154c06356bSdh142964  * cfg_priv:	configuration private data
7164c06356bSdh142964  *
7174c06356bSdh142964  */
7184c06356bSdh142964 void
7191b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv)
7204c06356bSdh142964 {
7214c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7224c06356bSdh142964 	dam_da_t *passp;
7234c06356bSdh142964 
7241b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7251b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7264c06356bSdh142964 	if (!passp) {
7271b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
7284c06356bSdh142964 		return;
7294c06356bSdh142964 	}
7304c06356bSdh142964 	passp->da_cfg_priv = cfg_priv;
7311b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7324c06356bSdh142964 }
7334c06356bSdh142964 
7344c06356bSdh142964 /*
7354c06356bSdh142964  * Get config private data
7364c06356bSdh142964  *
7374c06356bSdh142964  * damapp:	address map handle
7381b115575SJohn Danielson  * addrid:	address ID
7394c06356bSdh142964  *
7404c06356bSdh142964  * Returns:	configuration private data
7414c06356bSdh142964  */
7424c06356bSdh142964 void *
7431b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid)
7444c06356bSdh142964 {
7454c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7464c06356bSdh142964 	dam_da_t *passp;
7474c06356bSdh142964 	void *rv;
7484c06356bSdh142964 
7491b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7501b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7514c06356bSdh142964 	if (!passp) {
7521b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
7534c06356bSdh142964 		return (NULL);
7544c06356bSdh142964 	}
7554c06356bSdh142964 	rv = passp->da_cfg_priv;
7561b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7574c06356bSdh142964 	return (rv);
7584c06356bSdh142964 }
7594c06356bSdh142964 
7604c06356bSdh142964 /*
7614c06356bSdh142964  * Lookup a single address in the active address map
7624c06356bSdh142964  *
7634c06356bSdh142964  * damapp:	address map handle
7644c06356bSdh142964  * address:	address string
7654c06356bSdh142964  *
7664c06356bSdh142964  * Returns:	ID of active/stable address
7674c06356bSdh142964  *		0	Address not in stable set
7684c06356bSdh142964  *
7694c06356bSdh142964  * Future: Allow the caller to wait for stabilize before returning not found.
7704c06356bSdh142964  */
7714c06356bSdh142964 damap_id_t
7724c06356bSdh142964 damap_lookup(damap_t *damapp, char *address)
7734c06356bSdh142964 {
7744c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7754c06356bSdh142964 	id_t addrid = 0;
7764c06356bSdh142964 	dam_da_t *passp = NULL;
7774c06356bSdh142964 
7781b115575SJohn Danielson 	DTRACE_PROBE3(damap__lookup, char *, mapp->dam_name,
7791b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
7801b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7811b115575SJohn Danielson 	if (!mapp->dam_high)
7821b115575SJohn Danielson 		addrid = 0;
7831b115575SJohn Danielson 	else
7844c06356bSdh142964 		addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
7854c06356bSdh142964 	if (addrid) {
7864c06356bSdh142964 		if (DAM_IS_STABLE(mapp, addrid)) {
7874c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
7884c06356bSdh142964 			ASSERT(passp);
7894c06356bSdh142964 			if (passp) {
7904c06356bSdh142964 				passp->da_ref++;
7914c06356bSdh142964 			} else {
7924c06356bSdh142964 				addrid = 0;
7934c06356bSdh142964 			}
7944c06356bSdh142964 		} else {
7954c06356bSdh142964 			addrid = 0;
7964c06356bSdh142964 		}
7974c06356bSdh142964 	}
7981b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7991b115575SJohn Danielson 	DTRACE_PROBE4(damap__lookup__return, char *, mapp->dam_name,
8001b115575SJohn Danielson 	    char *, address, dam_t *, mapp, int, addrid);
8014c06356bSdh142964 	return ((damap_id_t)addrid);
8024c06356bSdh142964 }
8034c06356bSdh142964 
8044c06356bSdh142964 
8054c06356bSdh142964 /*
8064c06356bSdh142964  * Return the list of stable addresses in the map
8074c06356bSdh142964  *
8084c06356bSdh142964  * damapp:	address map handle
8094c06356bSdh142964  * id_listp:	pointer to list of address IDs in stable map (returned)
8104c06356bSdh142964  *
8114c06356bSdh142964  * Returns:	# of entries returned in alist
8124c06356bSdh142964  */
8134c06356bSdh142964 int
8144c06356bSdh142964 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
8154c06356bSdh142964 {
8164c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8174c06356bSdh142964 	int mapsz = mapp->dam_size;
8184c06356bSdh142964 	int n_ids, i;
8194c06356bSdh142964 	bitset_t *bsp;
8201b115575SJohn Danielson 	char	 *addrp;
8214c06356bSdh142964 	dam_da_t *passp;
8224c06356bSdh142964 
8231b115575SJohn Danielson 	DTRACE_PROBE2(damap__lookup__all, char *, mapp->dam_name,
8241b115575SJohn Danielson 	    dam_t *, mapp);
8251b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8261b115575SJohn Danielson 	if (!mapp->dam_high) {
8271b115575SJohn Danielson 		*id_listp = (damap_id_list_t)NULL;
8281b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8291b115575SJohn Danielson 		DTRACE_PROBE3(damap__lookup__all__nomap, char *,
8301b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp, int, 0);
8311b115575SJohn Danielson 		return (0);
8321b115575SJohn Danielson 	}
8334c06356bSdh142964 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
8344c06356bSdh142964 	bitset_init(bsp);
8354c06356bSdh142964 	bitset_resize(bsp, mapsz);
8364c06356bSdh142964 	bitset_copy(&mapp->dam_active_set, bsp);
8374c06356bSdh142964 	for (n_ids = 0, i = 1; i < mapsz; i++) {
8384c06356bSdh142964 		if (bitset_in_set(bsp, i)) {
8394c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, i);
8404c06356bSdh142964 			ASSERT(passp);
8414c06356bSdh142964 			if (passp) {
8421b115575SJohn Danielson 				addrp = damap_id2addr(damapp, i);
8431b115575SJohn Danielson 				DTRACE_PROBE3(damap__lookup__all__item, char *,
8441b115575SJohn Danielson 				    mapp->dam_name, char *, addrp, dam_t *,
8451b115575SJohn Danielson 				    mapp);
8464c06356bSdh142964 				passp->da_ref++;
8474c06356bSdh142964 				n_ids++;
8484c06356bSdh142964 			}
8494c06356bSdh142964 		}
8504c06356bSdh142964 	}
8514c06356bSdh142964 	if (n_ids) {
8524c06356bSdh142964 		*id_listp = (damap_id_list_t)bsp;
8531b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8544c06356bSdh142964 		return (n_ids);
8554c06356bSdh142964 	} else {
8564c06356bSdh142964 		*id_listp = (damap_id_list_t)NULL;
8574c06356bSdh142964 		bitset_fini(bsp);
8584c06356bSdh142964 		kmem_free(bsp, sizeof (*bsp));
8591b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8604c06356bSdh142964 		return (0);
8614c06356bSdh142964 	}
8624c06356bSdh142964 }
8634c06356bSdh142964 
8644c06356bSdh142964 /*
8654c06356bSdh142964  * Release the address list returned by damap_lookup_all()
8664c06356bSdh142964  *
8674c06356bSdh142964  * mapp:	address map handle
8684c06356bSdh142964  * id_list:	list of address IDs returned in damap_lookup_all()
8694c06356bSdh142964  */
8704c06356bSdh142964 void
8714c06356bSdh142964 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
8724c06356bSdh142964 {
8734c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8744c06356bSdh142964 	int i;
8754c06356bSdh142964 
8764c06356bSdh142964 	if (id_list == NULL)
8774c06356bSdh142964 		return;
8784c06356bSdh142964 
8791b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8804c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
8814c06356bSdh142964 		if (bitset_in_set((bitset_t *)id_list, i))
8821b115575SJohn Danielson 			(void) dam_addr_release(mapp, i);
8834c06356bSdh142964 	}
8841b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8854c06356bSdh142964 	bitset_fini((bitset_t *)id_list);
8864c06356bSdh142964 	kmem_free((void *)id_list, sizeof (bitset_t));
8874c06356bSdh142964 }
8884c06356bSdh142964 
8894c06356bSdh142964 /*
8901b115575SJohn Danielson  * activate an address that has passed the stabilization interval
8914c06356bSdh142964  */
8924c06356bSdh142964 static void
8931b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid)
8944c06356bSdh142964 {
8954c06356bSdh142964 	dam_da_t *passp;
8961b115575SJohn Danielson 	int config_rv;
8974c06356bSdh142964 	char *addrstr;
8984c06356bSdh142964 
8991b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9001b115575SJohn Danielson 	bitset_add(&mapp->dam_active_set, addrid);
9011b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
9024c06356bSdh142964 	ASSERT(passp);
9031b115575SJohn Danielson 
9044c06356bSdh142964 	/*
9054c06356bSdh142964 	 * copy the reported nvlist and provider private data
9064c06356bSdh142964 	 */
9071b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
9081b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__activate__start, char *, mapp->dam_name,
9091b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
9104c06356bSdh142964 	passp->da_nvl = passp->da_nvl_rpt;
9114c06356bSdh142964 	passp->da_ppriv = passp->da_ppriv_rpt;
9124c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
9134c06356bSdh142964 	passp->da_nvl_rpt = NULL;
9144c06356bSdh142964 	passp->da_last_stable = gethrtime();
9154c06356bSdh142964 	passp->da_stable_cnt++;
9161b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
9171b115575SJohn Danielson 	if (mapp->dam_activate_cb) {
9181b115575SJohn Danielson 		(*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr,
9191b115575SJohn Danielson 		    addrid, &passp->da_ppriv_rpt);
9204c06356bSdh142964 	}
9214c06356bSdh142964 
9224c06356bSdh142964 	/*
9231b115575SJohn Danielson 	 * call the address-specific configuration action as part of
9241b115575SJohn Danielson 	 * activation.
9254c06356bSdh142964 	 */
9261b115575SJohn Danielson 	config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp,
9271b115575SJohn Danielson 	    addrid);
9281b115575SJohn Danielson 	if (config_rv != DAM_SUCCESS) {
9291b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
9301b115575SJohn Danielson 		passp->da_flags |= DA_FAILED_CONFIG;
9311b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9321b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__activate__config__failure,
9331b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
934d189c170SReed 		dam_deact_cleanup(mapp, addrid, addrstr,
935d189c170SReed 		    DAMAP_DEACT_RSN_CFG_FAIL);
936d189c170SReed 	} else {
937d189c170SReed 		DTRACE_PROBE3(damap__addr__activate__end, char *,
938d189c170SReed 		    mapp->dam_name, char *, addrstr, dam_t *, mapp);
9394c06356bSdh142964 	}
9404c06356bSdh142964 }
9414c06356bSdh142964 
9424c06356bSdh142964 /*
9431b115575SJohn Danielson  * deactivate a previously stable address
9444c06356bSdh142964  */
9454c06356bSdh142964 static void
9461b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid)
9474c06356bSdh142964 {
9481b115575SJohn Danielson 	char *addrstr;
9494c06356bSdh142964 
9501b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
9511b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__deactivate__start, char *, mapp->dam_name,
9521b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
9531b115575SJohn Danielson 
9541b115575SJohn Danielson 	/*
9551b115575SJohn Danielson 	 * call the unconfiguration callback
9561b115575SJohn Danielson 	 */
9571b115575SJohn Danielson 	(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid);
958d189c170SReed 	dam_deact_cleanup(mapp, addrid, addrstr, DAMAP_DEACT_RSN_GONE);
959d189c170SReed }
960d189c170SReed 
961d189c170SReed static void
962d189c170SReed dam_deact_cleanup(dam_t *mapp, id_t addrid, char *addrstr,
963d189c170SReed     damap_deact_rsn_t deact_rsn)
964d189c170SReed {
965d189c170SReed 	dam_da_t *passp;
966d189c170SReed 
9671b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
9681b115575SJohn Danielson 	ASSERT(passp);
9691b115575SJohn Danielson 	if (mapp->dam_deactivate_cb)
9701b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
9711b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
972d189c170SReed 		    addrid, passp->da_ppriv, deact_rsn);
9731b115575SJohn Danielson 
9741b115575SJohn Danielson 	/*
9751b115575SJohn Danielson 	 * clear the active bit and free the backing info for
9761b115575SJohn Danielson 	 * this address
9771b115575SJohn Danielson 	 */
9781b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9791b115575SJohn Danielson 	bitset_del(&mapp->dam_active_set, addrid);
9801b115575SJohn Danielson 	passp->da_ppriv = NULL;
9811b115575SJohn Danielson 	if (passp->da_nvl)
9821b115575SJohn Danielson 		nvlist_free(passp->da_nvl);
9831b115575SJohn Danielson 	passp->da_nvl = NULL;
9841b115575SJohn Danielson 	passp->da_ppriv_rpt = NULL;
9851b115575SJohn Danielson 	if (passp->da_nvl_rpt)
9861b115575SJohn Danielson 		nvlist_free(passp->da_nvl_rpt);
9871b115575SJohn Danielson 	passp->da_nvl_rpt = NULL;
9881b115575SJohn Danielson 
9891b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__deactivate__end, char *, mapp->dam_name,
9901b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
9911b115575SJohn Danielson 
9921b115575SJohn Danielson 	(void) dam_addr_release(mapp, addrid);
9931b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
9941b115575SJohn Danielson }
9951b115575SJohn Danielson 
9961b115575SJohn Danielson /*
9971b115575SJohn Danielson  * taskq callback for multi-thread activation
9981b115575SJohn Danielson  */
9991b115575SJohn Danielson static void
10001b115575SJohn Danielson dam_tq_config(void *arg)
10011b115575SJohn Danielson {
10021b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
10031b115575SJohn Danielson 
10041b115575SJohn Danielson 	dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id);
10051b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
10061b115575SJohn Danielson }
10071b115575SJohn Danielson 
10081b115575SJohn Danielson /*
10091b115575SJohn Danielson  * taskq callback for multi-thread deactivation
10101b115575SJohn Danielson  */
10111b115575SJohn Danielson static void
10121b115575SJohn Danielson dam_tq_unconfig(void *arg)
10131b115575SJohn Danielson {
10141b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
10151b115575SJohn Danielson 
10161b115575SJohn Danielson 	dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id);
10171b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
10181b115575SJohn Danielson }
10191b115575SJohn Danielson 
10201b115575SJohn Danielson /*
10211b115575SJohn Danielson  * Activate a set of stabilized addresses
10221b115575SJohn Danielson  */
10231b115575SJohn Danielson static void
10241b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate)
10251b115575SJohn Danielson {
10261b115575SJohn Danielson 
10271b115575SJohn Danielson 	int i, nset;
10281b115575SJohn Danielson 	taskq_t *tqp = NULL;
10291b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
10301b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
10311b115575SJohn Danielson 	extern pri_t maxclsyspri;
10321b115575SJohn Danielson 
10331b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
10341b115575SJohn Danielson 		/*
10351b115575SJohn Danielson 		 * calculate the # of taskq threads to create
10361b115575SJohn Danielson 		 */
10371b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
10381b115575SJohn Danielson 			if (bitset_in_set(activate, i))
10391b115575SJohn Danielson 				nset++;
10401b115575SJohn Danielson 		ASSERT(nset);
10411b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name);
10421b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
10431b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
10441b115575SJohn Danielson 	}
10451b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
10461b115575SJohn Danielson 		if (bitset_in_set(activate, i)) {
10471b115575SJohn Danielson 			if (!tqp)
10481b115575SJohn Danielson 				dam_addr_activate(mapp, i);
10491b115575SJohn Danielson 			else {
10501b115575SJohn Danielson 				/*
10511b115575SJohn Danielson 				 * multi-threaded activation
10521b115575SJohn Danielson 				 */
10531b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
10541b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
10551b115575SJohn Danielson 				tqd->tqd_id = i;
10561b115575SJohn Danielson 				(void) taskq_dispatch(tqp, dam_tq_config,
1057*64109744SChris Horne 				    tqd, TQ_SLEEP);
10581b115575SJohn Danielson 			}
10591b115575SJohn Danielson 		}
10601b115575SJohn Danielson 	}
10611b115575SJohn Danielson 	if (tqp) {
10621b115575SJohn Danielson 		taskq_wait(tqp);
10631b115575SJohn Danielson 		taskq_destroy(tqp);
10641b115575SJohn Danielson 	}
10651b115575SJohn Danielson }
10661b115575SJohn Danielson 
10671b115575SJohn Danielson /*
10681b115575SJohn Danielson  * Deactivate a set of stabilized addresses
10691b115575SJohn Danielson  */
10701b115575SJohn Danielson static void
10711b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate)
10721b115575SJohn Danielson {
10731b115575SJohn Danielson 	int i, nset;
10741b115575SJohn Danielson 	taskq_t *tqp = NULL;
10751b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
10761b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
10771b115575SJohn Danielson 
10781b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__deactivate, char *, mapp->dam_name,
10791b115575SJohn Danielson 	    dam_t *, mapp);
10801b115575SJohn Danielson 
10811b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
10821b115575SJohn Danielson 		/*
10831b115575SJohn Danielson 		 * compute the # of taskq threads to dispatch
10841b115575SJohn Danielson 		 */
10851b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
10861b115575SJohn Danielson 			if (bitset_in_set(deactivate, i))
10871b115575SJohn Danielson 				nset++;
10881b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "deactv-%s",
10891b115575SJohn Danielson 		    mapp->dam_name);
10901b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
10911b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
10921b115575SJohn Danielson 	}
10931b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
10941b115575SJohn Danielson 		if (bitset_in_set(deactivate, i)) {
10951b115575SJohn Danielson 			if (!tqp) {
10961b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
10971b115575SJohn Danielson 			} else {
10981b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
10991b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
11001b115575SJohn Danielson 				tqd->tqd_id = i;
11011b115575SJohn Danielson 				(void) taskq_dispatch(tqp,
1102*64109744SChris Horne 				    dam_tq_unconfig, tqd, TQ_SLEEP);
11031b115575SJohn Danielson 			}
11041b115575SJohn Danielson 		}
11051b115575SJohn Danielson 	}
11061b115575SJohn Danielson 
11071b115575SJohn Danielson 	if (tqp) {
11081b115575SJohn Danielson 		taskq_wait(tqp);
11091b115575SJohn Danielson 		taskq_destroy(tqp);
11101b115575SJohn Danielson 	}
11111b115575SJohn Danielson }
11121b115575SJohn Danielson 
11131b115575SJohn Danielson /*
11141b115575SJohn Danielson  * Release a previously activated address
11151b115575SJohn Danielson  */
11161b115575SJohn Danielson static void
11171b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid)
11181b115575SJohn Danielson {
11191b115575SJohn Danielson 	dam_da_t *passp;
11201b115575SJohn Danielson 	char	 *addrstr;
11211b115575SJohn Danielson 
11221b115575SJohn Danielson 
11231b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
11244c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
11254c06356bSdh142964 	ASSERT(passp);
11264c06356bSdh142964 
11271b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
11281b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__release, char *, mapp->dam_name,
11291b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
11304c06356bSdh142964 
11314c06356bSdh142964 	/*
11321b115575SJohn Danielson 	 * defer releasing the address until outstanding references
11331b115575SJohn Danielson 	 * are released
11344c06356bSdh142964 	 */
11351b115575SJohn Danielson 	if (passp->da_ref > 1) {
11361b115575SJohn Danielson 		DTRACE_PROBE4(damap__addr__release__outstanding__refs,
11371b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp,
11381b115575SJohn Danielson 		    int, passp->da_ref);
11394c06356bSdh142964 		return;
11404c06356bSdh142964 	}
11411b115575SJohn Danielson 
11421b115575SJohn Danielson 	/*
11431b115575SJohn Danielson 	 * allow pending reports to stabilize
11441b115575SJohn Danielson 	 */
11451b115575SJohn Danielson 	if (DAM_IN_REPORT(mapp, addrid)) {
11461b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__release__report__pending,
11471b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
11481b115575SJohn Danielson 		return;
11491b115575SJohn Danielson 	}
11501b115575SJohn Danielson 
11514c06356bSdh142964 	ddi_strid_free(mapp->dam_addr_hash, addrid);
11524c06356bSdh142964 	ddi_soft_state_free(mapp->dam_da, addrid);
11534c06356bSdh142964 }
11544c06356bSdh142964 
11554c06356bSdh142964 /*
11564c06356bSdh142964  * process stabilized address reports
11574c06356bSdh142964  */
11584c06356bSdh142964 static void
11591b115575SJohn Danielson dam_stabilize_map(void *arg)
11604c06356bSdh142964 {
11614c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
11624c06356bSdh142964 	bitset_t delta;
11634c06356bSdh142964 	bitset_t cfg;
11644c06356bSdh142964 	bitset_t uncfg;
11654c06356bSdh142964 	int has_cfg, has_uncfg;
11661b115575SJohn Danielson 	uint32_t i, n_active;
11671b115575SJohn Danielson 
11681b115575SJohn Danielson 	DTRACE_PROBE2(damap__stabilize__map, char *, mapp->dam_name,
11691b115575SJohn Danielson 	    dam_t *, mapp);
11704c06356bSdh142964 
11714c06356bSdh142964 	bitset_init(&delta);
11724c06356bSdh142964 	bitset_resize(&delta, mapp->dam_size);
11734c06356bSdh142964 	bitset_init(&cfg);
11744c06356bSdh142964 	bitset_resize(&cfg, mapp->dam_size);
11754c06356bSdh142964 	bitset_init(&uncfg);
11764c06356bSdh142964 	bitset_resize(&uncfg, mapp->dam_size);
11774c06356bSdh142964 
11781b115575SJohn Danielson 	/*
11791b115575SJohn Danielson 	 * determine which addresses have changed during
11801b115575SJohn Danielson 	 * this stabilization cycle
11811b115575SJohn Danielson 	 */
11821b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
11831b115575SJohn Danielson 	ASSERT(mapp->dam_flags & DAM_SPEND);
11844c06356bSdh142964 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
11854c06356bSdh142964 	    &delta)) {
11861b115575SJohn Danielson 		/*
11871b115575SJohn Danielson 		 * no difference
11881b115575SJohn Danielson 		 */
11894c06356bSdh142964 		bitset_zero(&mapp->dam_stable_set);
11901b115575SJohn Danielson 		mapp->dam_flags  &= ~DAM_SPEND;
11911b115575SJohn Danielson 		cv_signal(&mapp->dam_cv);
11921b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
11934c06356bSdh142964 		bitset_fini(&uncfg);
11944c06356bSdh142964 		bitset_fini(&cfg);
11954c06356bSdh142964 		bitset_fini(&delta);
11961b115575SJohn Danielson 		DTRACE_PROBE2(damap__stabilize__map__nochange, char *,
11971b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
11984c06356bSdh142964 		return;
11994c06356bSdh142964 	}
12001b115575SJohn Danielson 
12011b115575SJohn Danielson 	/*
12021b115575SJohn Danielson 	 * compute the sets of addresses to be activated and deactivated
12031b115575SJohn Danielson 	 */
12044c06356bSdh142964 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
12054c06356bSdh142964 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
12061b115575SJohn Danielson 
12071b115575SJohn Danielson 	/*
12081b115575SJohn Danielson 	 * drop map lock while invoking callouts
12091b115575SJohn Danielson 	 */
12101b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
12111b115575SJohn Danielson 
12121b115575SJohn Danielson 	/*
12131b115575SJohn Danielson 	 * activate all newly stable addresss
12141b115575SJohn Danielson 	 */
12151b115575SJohn Danielson 	if (has_cfg)
12164c06356bSdh142964 		dam_addrset_activate(mapp, &cfg);
12171b115575SJohn Danielson 
12181b115575SJohn Danielson 	/*
12191b115575SJohn Danielson 	 * deactivate addresss which are no longer in the map
12201b115575SJohn Danielson 	 */
12211b115575SJohn Danielson 	if (has_uncfg)
12221b115575SJohn Danielson 		dam_addrset_deactivate(mapp, &uncfg);
12231b115575SJohn Danielson 
12241b115575SJohn Danielson 
12251b115575SJohn Danielson 	/*
12261b115575SJohn Danielson 	 * timestamp the last stable time and increment the kstat keeping
12271b115575SJohn Danielson 	 * the # of of stable cycles for the map
12281b115575SJohn Danielson 	 */
12291b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
12304c06356bSdh142964 	bitset_zero(&mapp->dam_stable_set);
12314c06356bSdh142964 	mapp->dam_last_stable = gethrtime();
12324c06356bSdh142964 	mapp->dam_stable_cnt++;
12331b115575SJohn Danielson 	DAM_INCR_STAT(mapp, dam_cycles);
12341b115575SJohn Danielson 
12351b115575SJohn Danielson 	/*
12361b115575SJohn Danielson 	 * determine the number of stable addresses
12371b115575SJohn Danielson 	 * and update the n_active kstat for this map
12381b115575SJohn Danielson 	 */
12391b115575SJohn Danielson 	for (i = 1, n_active = 0; i < mapp->dam_high; i++)
12401b115575SJohn Danielson 		if (bitset_in_set(&mapp->dam_active_set, i))
12411b115575SJohn Danielson 			n_active++;
12421b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_active, n_active);
12431b115575SJohn Danielson 
12441b115575SJohn Danielson 	DTRACE_PROBE3(damap__map__stable__end, char *, mapp->dam_name,
12451b115575SJohn Danielson 	    dam_t *, mapp, int, n_active);
12461b115575SJohn Danielson 
12471b115575SJohn Danielson 	mapp->dam_flags  &= ~DAM_SPEND;
12481b115575SJohn Danielson 	cv_signal(&mapp->dam_cv);
12491b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
12504c06356bSdh142964 	bitset_fini(&uncfg);
12514c06356bSdh142964 	bitset_fini(&cfg);
12524c06356bSdh142964 	bitset_fini(&delta);
12534c06356bSdh142964 }
12544c06356bSdh142964 
12554c06356bSdh142964 /*
12564c06356bSdh142964  * per-address stabilization timeout
12574c06356bSdh142964  */
12584c06356bSdh142964 static void
12594c06356bSdh142964 dam_addr_stable_cb(void *arg)
12604c06356bSdh142964 {
12614c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
12624c06356bSdh142964 	int i;
12634c06356bSdh142964 	dam_da_t *passp;
12644c06356bSdh142964 	int spend = 0;
12654c06356bSdh142964 	int tpend = 0;
12664c06356bSdh142964 	int64_t	next_tmov = mapp->dam_stabletmo;
12674c06356bSdh142964 	int64_t tmo_delta;
1268d3d50737SRafael Vanoni 	int64_t ts = ddi_get_lbolt64();
12694c06356bSdh142964 
12701b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
12714c06356bSdh142964 	if (mapp->dam_tid == 0) {
12721b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addr__stable__cancelled, char *,
12731b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
12741b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
12754c06356bSdh142964 		return;
12764c06356bSdh142964 	}
12774c06356bSdh142964 	mapp->dam_tid = 0;
12781b115575SJohn Danielson 
12794c06356bSdh142964 	/*
12804c06356bSdh142964 	 * If still under stabilization, reschedule timeout,
12811b115575SJohn Danielson 	 * otherwise dispatch the task to activate and deactivate the
12821b115575SJohn Danielson 	 * new stable address
12834c06356bSdh142964 	 */
12844c06356bSdh142964 	if (mapp->dam_flags & DAM_SPEND) {
12851b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
12864c06356bSdh142964 		mapp->dam_stable_overrun++;
12874c06356bSdh142964 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
12881b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addr__stable__overrun, char *,
12891b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
12901b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
12914c06356bSdh142964 		return;
12924c06356bSdh142964 	}
12934c06356bSdh142964 
12941b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
12951b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
12961b115575SJohn Danielson 
12971b115575SJohn Danielson 	/*
12981b115575SJohn Danielson 	 * copy the current active set to the stable map
12991b115575SJohn Danielson 	 * for each address being reported, decrement its
13001b115575SJohn Danielson 	 * stabilize deadline, and if stable, add or remove the
13011b115575SJohn Danielson 	 * address from the stable set
13021b115575SJohn Danielson 	 */
13034c06356bSdh142964 	bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set);
13044c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
13054c06356bSdh142964 		if (!bitset_in_set(&mapp->dam_report_set, i))
13064c06356bSdh142964 			continue;
13074c06356bSdh142964 		passp = ddi_get_soft_state(mapp->dam_da, i);
13084c06356bSdh142964 		ASSERT(passp);
13094c06356bSdh142964 
13104c06356bSdh142964 		/* report has stabilized */
13114c06356bSdh142964 		if (passp->da_deadline <= ts) {
13124c06356bSdh142964 			bitset_del(&mapp->dam_report_set, i);
13131b115575SJohn Danielson 			if (passp->da_flags & DA_RELE)
13144c06356bSdh142964 				bitset_del(&mapp->dam_stable_set, i);
13151b115575SJohn Danielson 			else
13164c06356bSdh142964 				bitset_add(&mapp->dam_stable_set, i);
13174c06356bSdh142964 			spend++;
13184c06356bSdh142964 			continue;
13194c06356bSdh142964 		}
13204c06356bSdh142964 
13214c06356bSdh142964 		/*
13221b115575SJohn Danielson 		 * not stabilized, determine next map timeout
13234c06356bSdh142964 		 */
13244c06356bSdh142964 		tpend++;
13254c06356bSdh142964 		tmo_delta = passp->da_deadline - ts;
13264c06356bSdh142964 		if (tmo_delta < next_tmov)
13274c06356bSdh142964 			next_tmov = tmo_delta;
13284c06356bSdh142964 	}
13294c06356bSdh142964 
13304c06356bSdh142964 	/*
13311b115575SJohn Danielson 	 * schedule system_taskq activation of stabilized reports
13324c06356bSdh142964 	 */
13334c06356bSdh142964 	if (spend) {
13341b115575SJohn Danielson 		if (taskq_dispatch(system_taskq, dam_stabilize_map,
1335*64109744SChris Horne 		    mapp, TQ_NOSLEEP | TQ_NOQUEUE)) {
13361b115575SJohn Danielson 			mapp->dam_flags  |= DAM_SPEND;
13371b115575SJohn Danielson 			DTRACE_PROBE2(damap__map__addr__stable__start, char *,
13381b115575SJohn Danielson 			    mapp->dam_name, dam_t *, mapp);
13391b115575SJohn Danielson 		} else {
13404c06356bSdh142964 			tpend++;
1341*64109744SChris Horne 
1342*64109744SChris Horne 			/*
1343*64109744SChris Horne 			 * Avoid waiting the entire stabalization
1344*64109744SChris Horne 			 * time again if taskq_diskpatch fails.
1345*64109744SChris Horne 			 */
1346*64109744SChris Horne 			tmo_delta = drv_usectohz(
1347*64109744SChris Horne 			    damap_taskq_dispatch_retry_usec);
1348*64109744SChris Horne 			if (tmo_delta < next_tmov)
1349*64109744SChris Horne 				next_tmov = tmo_delta;
13504c06356bSdh142964 		}
13511b115575SJohn Danielson 	}
13524c06356bSdh142964 
13534c06356bSdh142964 	/*
13541b115575SJohn Danielson 	 * reschedule the stabilization timer if there are reports
13551b115575SJohn Danielson 	 * still pending
13564c06356bSdh142964 	 */
13574c06356bSdh142964 	if (tpend)
13584c06356bSdh142964 		dam_sched_tmo(mapp, (clock_t)next_tmov, dam_addr_stable_cb);
13591b115575SJohn Danielson 
13601b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
13614c06356bSdh142964 }
13624c06356bSdh142964 
13634c06356bSdh142964 /*
13641b115575SJohn Danielson  * fullset stabilization timeout callback
13654c06356bSdh142964  */
13664c06356bSdh142964 static void
13671b115575SJohn Danielson dam_addrset_stable_cb(void *arg)
13684c06356bSdh142964 {
13694c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
13704c06356bSdh142964 
13711b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13724c06356bSdh142964 	if (mapp->dam_tid == 0) {
13731b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
13741b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__cancelled,
13751b115575SJohn Danielson 		    char *, mapp->dam_name, dam_t *, mapp);
13764c06356bSdh142964 		return;
13774c06356bSdh142964 	}
13784c06356bSdh142964 	mapp->dam_tid = 0;
13794c06356bSdh142964 
13804c06356bSdh142964 	/*
13811b115575SJohn Danielson 	 * If map still underoing stabilization reschedule timeout,
13821b115575SJohn Danielson 	 * else dispatch the task to configure the new stable set of
13831b115575SJohn Danielson 	 * addresses.
13844c06356bSdh142964 	 */
1385*64109744SChris Horne 	if ((mapp->dam_flags & DAM_SPEND) ||
1386*64109744SChris Horne 	    (taskq_dispatch(system_taskq, dam_stabilize_map, mapp,
1387*64109744SChris Horne 	    TQ_NOSLEEP | TQ_NOQUEUE) == NULL)) {
13881b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
13894c06356bSdh142964 		mapp->dam_stable_overrun++;
1390*64109744SChris Horne 		dam_sched_tmo(mapp,
1391*64109744SChris Horne 		    drv_usectohz(damap_taskq_dispatch_retry_usec),
1392*64109744SChris Horne 		    dam_addrset_stable_cb);
1393*64109744SChris Horne 
13941b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__overrun, char *,
13951b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
13961b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
13971b115575SJohn Danielson 		return;
13981b115575SJohn Danielson 	}
13991b115575SJohn Danielson 
14001b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
14011b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
14024c06356bSdh142964 	bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
14034c06356bSdh142964 	bitset_zero(&mapp->dam_report_set);
14041b115575SJohn Danielson 	mapp->dam_flags |= DAM_SPEND;
14051b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SETADD;
14061b115575SJohn Danielson 	DTRACE_PROBE2(damap__map__addrset__stable__start, char *,
14071b115575SJohn Danielson 	    mapp->dam_name, dam_t *, mapp);
14081b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
14094c06356bSdh142964 }
14104c06356bSdh142964 
14114c06356bSdh142964 /*
14121b115575SJohn Danielson  * schedule map timeout 'tmo_ms' ticks
14131b115575SJohn Danielson  * if map timer is currently running, cancel if tmo_ms == 0
14144c06356bSdh142964  */
14154c06356bSdh142964 static void
14164c06356bSdh142964 dam_sched_tmo(dam_t *mapp, clock_t tmo_ms, void (*tmo_cb)())
14174c06356bSdh142964 {
14184c06356bSdh142964 	timeout_id_t tid;
14194c06356bSdh142964 
14201b115575SJohn Danielson 	DTRACE_PROBE3(damap__sched__tmo, char *, mapp->dam_name, dam_t *, mapp,
14211b115575SJohn Danielson 	    clock_t, tmo_ms);
14224c06356bSdh142964 
14231b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
14241b115575SJohn Danielson 	if ((tid = mapp->dam_tid) != 0) {
14251b115575SJohn Danielson 		if (tmo_ms == 0) {
14261b115575SJohn Danielson 			mapp->dam_tid = 0;
14271b115575SJohn Danielson 			mutex_exit(&mapp->dam_lock);
14281b115575SJohn Danielson 			(void) untimeout(tid);
14291b115575SJohn Danielson 			mutex_enter(&mapp->dam_lock);
14301b115575SJohn Danielson 		}
14311b115575SJohn Danielson 	} else {
14324c06356bSdh142964 		if (tmo_cb && (tmo_ms != 0))
14334c06356bSdh142964 			mapp->dam_tid = timeout(tmo_cb, mapp, tmo_ms);
14344c06356bSdh142964 	}
14351b115575SJohn Danielson }
14364c06356bSdh142964 
14374c06356bSdh142964 /*
14381b115575SJohn Danielson  * report addition or removal of an address
14394c06356bSdh142964  */
14404c06356bSdh142964 static void
14411b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type)
14424c06356bSdh142964 {
14431b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
14441b115575SJohn Danielson 
14451b115575SJohn Danielson 	DTRACE_PROBE4(damap__addr__report, char *, mapp->dam_name,
14461b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp, int, rpt_type);
14471b115575SJohn Danielson 
14481b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
14494c06356bSdh142964 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
14504c06356bSdh142964 	passp->da_last_report = gethrtime();
14514c06356bSdh142964 	mapp->dam_last_update = gethrtime();
14524c06356bSdh142964 	passp->da_report_cnt++;
1453d3d50737SRafael Vanoni 	passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stabletmo;
14541b115575SJohn Danielson 	if (rpt_type == RPT_ADDR_DEL)
14554c06356bSdh142964 		passp->da_flags |= DA_RELE;
14561b115575SJohn Danielson 	else if (rpt_type == RPT_ADDR_ADD)
14574c06356bSdh142964 		passp->da_flags &= ~DA_RELE;
14584c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
14594c06356bSdh142964 	dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
14604c06356bSdh142964 }
14614c06356bSdh142964 
14624c06356bSdh142964 /*
14634c06356bSdh142964  * release an address report
14644c06356bSdh142964  */
14654c06356bSdh142964 static void
14661b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid)
14674c06356bSdh142964 {
14684c06356bSdh142964 	dam_da_t *passp;
14691b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
14704c06356bSdh142964 
14711b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__report__release, char *, mapp->dam_name,
14721b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
14731b115575SJohn Danielson 
14741b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
14754c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
14764c06356bSdh142964 	ASSERT(passp);
14771b115575SJohn Danielson 	/*
14781b115575SJohn Danielson 	 * clear the report bit
14791b115575SJohn Danielson 	 * if the address has a registered deactivation handler and
14809aed1621SDavid Hollister 	 * we are holding a private data pointer and the address has not
14819aed1621SDavid Hollister 	 * stabilized, deactivate the address (private data).
14821b115575SJohn Danielson 	 */
14831b115575SJohn Danielson 	bitset_del(&mapp->dam_report_set, addrid);
14849aed1621SDavid Hollister 	if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb &&
14859aed1621SDavid Hollister 	    passp->da_ppriv_rpt) {
14861b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14871b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
14881b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
14899aed1621SDavid Hollister 		    addrid, passp->da_ppriv_rpt, DAMAP_DEACT_RSN_UNSTBL);
14901b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
14911b115575SJohn Danielson 	}
14924c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
14934c06356bSdh142964 	if (passp->da_nvl_rpt)
14944c06356bSdh142964 		nvlist_free(passp->da_nvl_rpt);
14954c06356bSdh142964 }
14964c06356bSdh142964 
14974c06356bSdh142964 /*
14984c06356bSdh142964  * return the map ID of an address
14994c06356bSdh142964  */
15004c06356bSdh142964 static id_t
15014c06356bSdh142964 dam_get_addrid(dam_t *mapp, char *address)
15024c06356bSdh142964 {
15034c06356bSdh142964 	damap_id_t addrid;
15044c06356bSdh142964 	dam_da_t *passp;
15054c06356bSdh142964 
15061b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15074c06356bSdh142964 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
15081b115575SJohn Danielson 		if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash,
15094c06356bSdh142964 		    address)) == (damap_id_t)0) {
15104c06356bSdh142964 			return (0);
15114c06356bSdh142964 		}
15124c06356bSdh142964 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
15134c06356bSdh142964 		    DDI_SUCCESS) {
15144c06356bSdh142964 			ddi_strid_free(mapp->dam_addr_hash, addrid);
15154c06356bSdh142964 			return (0);
15164c06356bSdh142964 		}
15171b115575SJohn Danielson 
15184c06356bSdh142964 		if (addrid >= mapp->dam_high)
15194c06356bSdh142964 			mapp->dam_high = addrid + 1;
15201b115575SJohn Danielson 
15211b115575SJohn Danielson 		/*
15221b115575SJohn Danielson 		 * expand bitmaps if ID has outgrown old map size
15231b115575SJohn Danielson 		 */
15241b115575SJohn Danielson 		if (mapp->dam_high > mapp->dam_size) {
15251b115575SJohn Danielson 			mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP;
15261b115575SJohn Danielson 			bitset_resize(&mapp->dam_active_set, mapp->dam_size);
15271b115575SJohn Danielson 			bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
15281b115575SJohn Danielson 			bitset_resize(&mapp->dam_report_set, mapp->dam_size);
15294c06356bSdh142964 		}
15301b115575SJohn Danielson 
15314c06356bSdh142964 		passp = ddi_get_soft_state(mapp->dam_da, addrid);
15321b115575SJohn Danielson 		passp->da_ref = 1;
15331b115575SJohn Danielson 		passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash,
15341b115575SJohn Danielson 		    addrid); /* for mdb */
15351b115575SJohn Danielson 	}
15364c06356bSdh142964 	return (addrid);
15374c06356bSdh142964 }
15384c06356bSdh142964 
15394c06356bSdh142964 /*
15404c06356bSdh142964  * create and install map statistics
15414c06356bSdh142964  */
15424c06356bSdh142964 static int
15434c06356bSdh142964 dam_kstat_create(dam_t *mapp)
15444c06356bSdh142964 {
15454c06356bSdh142964 	kstat_t			*mapsp;
15464c06356bSdh142964 	struct dam_kstats	*statsp;
15474c06356bSdh142964 
15484c06356bSdh142964 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
15494c06356bSdh142964 	    KSTAT_TYPE_NAMED,
15504c06356bSdh142964 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
15511b115575SJohn Danielson 
15521b115575SJohn Danielson 	if (mapsp == NULL)
15534c06356bSdh142964 		return (DDI_FAILURE);
15544c06356bSdh142964 
15554c06356bSdh142964 	statsp = (struct dam_kstats *)mapsp->ks_data;
15561b115575SJohn Danielson 	kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32);
15571b115575SJohn Danielson 	kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32);
15581b115575SJohn Danielson 	kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32);
15591b115575SJohn Danielson 	kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32);
15604c06356bSdh142964 	kstat_install(mapsp);
15614c06356bSdh142964 	mapp->dam_kstatsp = mapsp;
15624c06356bSdh142964 	return (DDI_SUCCESS);
15634c06356bSdh142964 }
1564