xref: /titanic_54/usr/src/uts/common/os/damap.c (revision 60aabb4ce92352f01733c518d6b6bb69e60b9113)
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 /*
23*60aabb4cSChris Horne  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
244c06356bSdh142964  */
254c06356bSdh142964 
264c06356bSdh142964 #include <sys/note.h>
274c06356bSdh142964 #include <sys/types.h>
284c06356bSdh142964 #include <sys/param.h>
294c06356bSdh142964 #include <sys/systm.h>
304c06356bSdh142964 #include <sys/buf.h>
314c06356bSdh142964 #include <sys/kmem.h>
324c06356bSdh142964 #include <sys/cmn_err.h>
334c06356bSdh142964 #include <sys/debug.h>
344c06356bSdh142964 #include <sys/sunndi.h>
354c06356bSdh142964 #include <sys/kstat.h>
364c06356bSdh142964 #include <sys/conf.h>
374c06356bSdh142964 #include <sys/ddi_timer.h>
384c06356bSdh142964 #include <sys/devctl.h>
394c06356bSdh142964 #include <sys/callb.h>
404c06356bSdh142964 #include <sys/sysevent.h>
414c06356bSdh142964 #include <sys/taskq.h>
424c06356bSdh142964 #include <sys/ddi.h>
434c06356bSdh142964 #include <sys/bitset.h>
444c06356bSdh142964 #include <sys/damap.h>
454c06356bSdh142964 #include <sys/damap_impl.h>
464c06356bSdh142964 
474c06356bSdh142964 #ifdef DEBUG
484c06356bSdh142964 static int damap_debug = 0;
494c06356bSdh142964 #endif /* DEBUG */
504c06356bSdh142964 
511b115575SJohn Danielson extern taskq_t *system_taskq;
521b115575SJohn Danielson 
534c06356bSdh142964 static void dam_addrset_activate(dam_t *, bitset_t *);
541b115575SJohn Danielson static void dam_addrset_deactivate(dam_t *, bitset_t *);
551b115575SJohn Danielson static void dam_stabilize_map(void *);
564c06356bSdh142964 static void dam_addr_stable_cb(void *);
571b115575SJohn Danielson static void dam_addrset_stable_cb(void *);
58*60aabb4cSChris Horne static void dam_sched_timeout(void (*timeout_cb)(), dam_t *, clock_t);
591b115575SJohn Danielson static void dam_addr_report(dam_t *, dam_da_t *, id_t, int);
601b115575SJohn Danielson static void dam_addr_release(dam_t *, id_t);
611b115575SJohn Danielson static void dam_addr_report_release(dam_t *, id_t);
621b115575SJohn Danielson static void dam_addr_deactivate(dam_t *, id_t);
63d189c170SReed static void dam_deact_cleanup(dam_t *, id_t, char *, damap_deact_rsn_t);
644c06356bSdh142964 static id_t dam_get_addrid(dam_t *, char *);
654c06356bSdh142964 static int dam_kstat_create(dam_t *);
661b115575SJohn Danielson static int dam_map_alloc(dam_t *);
674c06356bSdh142964 
684c06356bSdh142964 #define	DAM_INCR_STAT(mapp, stat)				\
694c06356bSdh142964 	if ((mapp)->dam_kstatsp) {				\
704c06356bSdh142964 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
714c06356bSdh142964 		stp->stat.value.ui32++;				\
724c06356bSdh142964 	}
734c06356bSdh142964 
744c06356bSdh142964 #define	DAM_SET_STAT(mapp, stat, val)				\
754c06356bSdh142964 	if ((mapp)->dam_kstatsp) {				\
764c06356bSdh142964 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
774c06356bSdh142964 		stp->stat.value.ui32 = (val);			\
784c06356bSdh142964 	}
794c06356bSdh142964 
801b115575SJohn Danielson 
811b115575SJohn Danielson /*
821b115575SJohn Danielson  * increase damap size by 64 entries at a time
831b115575SJohn Danielson  */
841b115575SJohn Danielson #define	DAM_SIZE_BUMP	64
851b115575SJohn Danielson 
8664109744SChris Horne int	damap_taskq_dispatch_retry_usec = 1000;
8764109744SChris Horne 
881b115575SJohn Danielson /*
891b115575SJohn Danielson  * config/unconfig taskq data
901b115575SJohn Danielson  */
911b115575SJohn Danielson typedef struct {
921b115575SJohn Danielson 	dam_t *tqd_mapp;
931b115575SJohn Danielson 	id_t tqd_id;
941b115575SJohn Danielson } cfg_tqd_t;
951b115575SJohn Danielson 
961b115575SJohn Danielson extern pri_t maxclsyspri;
971b115575SJohn Danielson 
984c06356bSdh142964 /*
994c06356bSdh142964  * Create new device address map
1004c06356bSdh142964  *
1011b115575SJohn Danielson  * name:		map name (kstat unique)
1024c06356bSdh142964  * size:		max # of map entries
1031b115575SJohn Danielson  * mode:		style of address reports: per-address or fullset
1044c06356bSdh142964  * stable_usec:		# of quiescent microseconds before report/map is stable
1054c06356bSdh142964  *
1064c06356bSdh142964  * activate_arg:	address provider activation-callout private
1074c06356bSdh142964  * activate_cb:		address provider activation callback handler
1084c06356bSdh142964  * deactivate_cb:	address provider deactivation callback handler
1094c06356bSdh142964  *
1104c06356bSdh142964  * config_arg:		configuration-callout private
1114c06356bSdh142964  * config_cb:		class configuration callout
1124c06356bSdh142964  * unconfig_cb:		class unconfiguration callout
1134c06356bSdh142964  *
1144c06356bSdh142964  * damapp:		pointer to map handle (return)
1154c06356bSdh142964  *
1164c06356bSdh142964  * Returns:	DAM_SUCCESS
1174c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
1184c06356bSdh142964  *		DAM_FAILURE	General failure
1194c06356bSdh142964  */
1204c06356bSdh142964 int
1211b115575SJohn Danielson damap_create(char *name, damap_rptmode_t mode, int map_opts,
122*60aabb4cSChris Horne     int stable_usec, void *activate_arg, damap_activate_cb_t activate_cb,
1234c06356bSdh142964     damap_deactivate_cb_t deactivate_cb,
1244c06356bSdh142964     void *config_arg, damap_configure_cb_t configure_cb,
1254c06356bSdh142964     damap_unconfig_cb_t unconfig_cb,
1264c06356bSdh142964     damap_t **damapp)
1274c06356bSdh142964 {
1284c06356bSdh142964 	dam_t *mapp;
1294c06356bSdh142964 
1301b115575SJohn Danielson 	if (configure_cb == NULL || unconfig_cb == NULL || name == NULL)
1314c06356bSdh142964 		return (DAM_EINVAL);
1324c06356bSdh142964 
1331b115575SJohn Danielson 	DTRACE_PROBE3(damap__create, char *, name,
134*60aabb4cSChris Horne 	    damap_rptmode_t, mode, int, stable_usec);
1354c06356bSdh142964 
1364c06356bSdh142964 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
1371b115575SJohn Danielson 	mapp->dam_options = map_opts;
138*60aabb4cSChris Horne 	mapp->dam_stable_ticks = drv_usectohz(stable_usec);
1391b115575SJohn Danielson 	mapp->dam_size = 0;
1401b115575SJohn Danielson 	mapp->dam_rptmode = mode;
1414c06356bSdh142964 	mapp->dam_activate_arg = activate_arg;
1424c06356bSdh142964 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
1434c06356bSdh142964 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
1444c06356bSdh142964 	mapp->dam_config_arg = config_arg;
1454c06356bSdh142964 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
1464c06356bSdh142964 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
1471b115575SJohn Danielson 	mapp->dam_name = i_ddi_strdup(name, KM_SLEEP);
1484c06356bSdh142964 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
149*60aabb4cSChris Horne 	cv_init(&mapp->dam_sync_cv, NULL, CV_DRIVER, NULL);
1501b115575SJohn Danielson 	bitset_init(&mapp->dam_active_set);
1511b115575SJohn Danielson 	bitset_init(&mapp->dam_stable_set);
1521b115575SJohn Danielson 	bitset_init(&mapp->dam_report_set);
1534c06356bSdh142964 	*damapp = (damap_t *)mapp;
1544c06356bSdh142964 	return (DAM_SUCCESS);
1554c06356bSdh142964 }
1564c06356bSdh142964 
1574c06356bSdh142964 /*
1581b115575SJohn Danielson  * Allocate backing resources
1591b115575SJohn Danielson  *
1601b115575SJohn Danielson  * DAMs are lightly backed on create - major allocations occur
1611b115575SJohn Danielson  * at the time a report is made to the map, and are extended on
1621b115575SJohn Danielson  * a demand basis.
1631b115575SJohn Danielson  */
1641b115575SJohn Danielson static int
1651b115575SJohn Danielson dam_map_alloc(dam_t *mapp)
1661b115575SJohn Danielson {
1671b115575SJohn Danielson 	void *softstate_p;
1681b115575SJohn Danielson 
1691b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
1701b115575SJohn Danielson 	if (mapp->dam_flags & DAM_DESTROYPEND)
1711b115575SJohn Danielson 		return (DAM_FAILURE);
1721b115575SJohn Danielson 
1731b115575SJohn Danielson 	/*
1741b115575SJohn Danielson 	 * dam_high > 0 signals map allocation complete
1751b115575SJohn Danielson 	 */
1761b115575SJohn Danielson 	if (mapp->dam_high)
1771b115575SJohn Danielson 		return (DAM_SUCCESS);
1781b115575SJohn Danielson 
1791b115575SJohn Danielson 	mapp->dam_size = DAM_SIZE_BUMP;
1801b115575SJohn Danielson 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t),
1811b115575SJohn Danielson 	    mapp->dam_size) != DDI_SUCCESS)
1821b115575SJohn Danielson 		return (DAM_FAILURE);
1831b115575SJohn Danielson 
1841b115575SJohn Danielson 	if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) !=
1851b115575SJohn Danielson 	    DDI_SUCCESS) {
1861b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1871b115575SJohn Danielson 		return (DAM_FAILURE);
1881b115575SJohn Danielson 	}
1891b115575SJohn Danielson 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
1901b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1911b115575SJohn Danielson 		ddi_strid_fini(&mapp->dam_addr_hash);
1921b115575SJohn Danielson 		return (DAM_FAILURE);
1931b115575SJohn Danielson 	}
1941b115575SJohn Danielson 	mapp->dam_da = softstate_p;
1951b115575SJohn Danielson 	mapp->dam_high = 1;
1961b115575SJohn Danielson 	bitset_resize(&mapp->dam_active_set, mapp->dam_size);
1971b115575SJohn Danielson 	bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
1981b115575SJohn Danielson 	bitset_resize(&mapp->dam_report_set, mapp->dam_size);
1991b115575SJohn Danielson 	return (DAM_SUCCESS);
2001b115575SJohn Danielson }
2011b115575SJohn Danielson 
2021b115575SJohn Danielson /*
2031b115575SJohn Danielson  * Destroy address map
2044c06356bSdh142964  *
2054c06356bSdh142964  * damapp:	address map
2064c06356bSdh142964  *
2074c06356bSdh142964  * Returns:	DAM_SUCCESS
2084c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
2094c06356bSdh142964  *		DAM_FAILURE	General failure
2104c06356bSdh142964  */
2114c06356bSdh142964 void
2124c06356bSdh142964 damap_destroy(damap_t *damapp)
2134c06356bSdh142964 {
2144c06356bSdh142964 	int i;
2154c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
2164c06356bSdh142964 
2174c06356bSdh142964 	ASSERT(mapp);
2184c06356bSdh142964 
2191b115575SJohn Danielson 	DTRACE_PROBE1(damap__destroy, char *, mapp->dam_name);
2204c06356bSdh142964 
2211b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
2224c06356bSdh142964 
2234c06356bSdh142964 	/*
2241b115575SJohn Danielson 	 * prevent new reports from being added to the map
2254c06356bSdh142964 	 */
2261b115575SJohn Danielson 	mapp->dam_flags |= DAM_DESTROYPEND;
2274c06356bSdh142964 
2281b115575SJohn Danielson 	if (mapp->dam_high) {
2291b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2301b115575SJohn Danielson 		/*
2311b115575SJohn Danielson 		 * wait for outstanding reports to stabilize and cancel
2321b115575SJohn Danielson 		 * the timer for this map
2331b115575SJohn Danielson 		 */
234*60aabb4cSChris Horne 		(void) damap_sync(damapp, 0);
2351b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
236*60aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
2371b115575SJohn Danielson 
2381b115575SJohn Danielson 		/*
2391b115575SJohn Danielson 		 * map is at full stop
2401b115575SJohn Danielson 		 * release the contents of the map, invoking the
2411b115575SJohn Danielson 		 * detactivation protocol as addresses are released
2421b115575SJohn Danielson 		 */
2431b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2444c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++) {
2454c06356bSdh142964 			if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
2464c06356bSdh142964 				continue;
2471b115575SJohn Danielson 
2481b115575SJohn Danielson 			ASSERT(DAM_IN_REPORT(mapp, i) == 0);
2491b115575SJohn Danielson 
2501b115575SJohn Danielson 			if (DAM_IS_STABLE(mapp, i)) {
2511b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
2521b115575SJohn Danielson 			} else {
2534c06356bSdh142964 				ddi_strid_free(mapp->dam_addr_hash, i);
2544c06356bSdh142964 				ddi_soft_state_free(mapp->dam_da, i);
2554c06356bSdh142964 			}
2561b115575SJohn Danielson 		}
2574c06356bSdh142964 		ddi_strid_fini(&mapp->dam_addr_hash);
2584c06356bSdh142964 		ddi_soft_state_fini(&mapp->dam_da);
2591b115575SJohn Danielson 		kstat_delete(mapp->dam_kstatsp);
260*60aabb4cSChris Horne 	} else
261*60aabb4cSChris Horne 		mutex_exit(&mapp->dam_lock);
262*60aabb4cSChris Horne 
2634c06356bSdh142964 	bitset_fini(&mapp->dam_active_set);
2644c06356bSdh142964 	bitset_fini(&mapp->dam_stable_set);
2654c06356bSdh142964 	bitset_fini(&mapp->dam_report_set);
2664c06356bSdh142964 	mutex_destroy(&mapp->dam_lock);
267*60aabb4cSChris Horne 	cv_destroy(&mapp->dam_sync_cv);
2684c06356bSdh142964 	if (mapp->dam_name)
2694c06356bSdh142964 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
2704c06356bSdh142964 	kmem_free(mapp, sizeof (*mapp));
2714c06356bSdh142964 }
2724c06356bSdh142964 
2734c06356bSdh142964 /*
274*60aabb4cSChris Horne  * Wait for map stability.  If sync was successfull then return 1.
275*60aabb4cSChris Horne  * If called with a non-zero sync_usec, then a return value of 0 means a
276*60aabb4cSChris Horne  * timeout occurred prior to sync completion. NOTE: if sync_usec is
277*60aabb4cSChris Horne  * non-zero, it should be much longer than dam_stable_ticks.
2784c06356bSdh142964  *
2794c06356bSdh142964  * damapp:	address map
280*60aabb4cSChris Horne  * sync_usec:	micorseconds until we give up on sync completion.
2814c06356bSdh142964  */
2821b115575SJohn Danielson #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND)
283*60aabb4cSChris Horne int
284*60aabb4cSChris Horne damap_sync(damap_t *damapp, int sync_usec)
285*60aabb4cSChris Horne {
2864c06356bSdh142964 	dam_t	*mapp = (dam_t *)damapp;
287*60aabb4cSChris Horne 	int	rv;
2884c06356bSdh142964 
2894c06356bSdh142964 	ASSERT(mapp);
2901b115575SJohn Danielson 	DTRACE_PROBE2(damap__map__sync__start, char *, mapp->dam_name,
2911b115575SJohn Danielson 	    dam_t *, mapp);
2924c06356bSdh142964 
2931b115575SJohn Danielson 	/*
294*60aabb4cSChris Horne 	 * Block when waiting for
2951b115575SJohn Danielson 	 *	a) stabilization pending or a fullset update pending
296*60aabb4cSChris Horne 	 *	b) the report set to finalize (bitset is null)
297*60aabb4cSChris Horne 	 *	c) any scheduled timeouts to fire
2981b115575SJohn Danielson 	 */
299*60aabb4cSChris Horne 	rv = 1;					/* return synced */
3004c06356bSdh142964 	mutex_enter(&mapp->dam_lock);
301*60aabb4cSChris Horne again:	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
302*60aabb4cSChris Horne 	    (!bitset_is_null(&mapp->dam_report_set)) ||
303*60aabb4cSChris Horne 	    (mapp->dam_tid != 0)) {
3041b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__sync__waiting, char *, mapp->dam_name,
3051b115575SJohn Danielson 		    dam_t *, mapp);
306*60aabb4cSChris Horne 
307*60aabb4cSChris Horne 		/* Wait for condition relayed via timeout */
308*60aabb4cSChris Horne 		if (sync_usec) {
309*60aabb4cSChris Horne 			if (cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
310*60aabb4cSChris Horne 			    drv_usectohz(sync_usec), TR_MICROSEC) == -1) {
311*60aabb4cSChris Horne 				mapp->dam_sync_to_cnt++;
312*60aabb4cSChris Horne 				rv = 0;		/* return timeout */
313*60aabb4cSChris Horne 				break;
314*60aabb4cSChris Horne 			}
315*60aabb4cSChris Horne 		} else
316*60aabb4cSChris Horne 			cv_wait(&mapp->dam_sync_cv, &mapp->dam_lock);
3174c06356bSdh142964 	}
3184c06356bSdh142964 
319*60aabb4cSChris Horne 	if (rv) {
320*60aabb4cSChris Horne 		/*
321*60aabb4cSChris Horne 		 * Delay one stabilization time after the apparent sync above
322*60aabb4cSChris Horne 		 * and verify accuracy - resync if not accurate.
323*60aabb4cSChris Horne 		 */
324*60aabb4cSChris Horne 		(void) cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
325*60aabb4cSChris Horne 		    mapp->dam_stable_ticks, TR_MICROSEC);
326*60aabb4cSChris Horne 		if (rv && ((mapp->dam_flags & WAITFOR_FLAGS) ||
327*60aabb4cSChris Horne 		    (!bitset_is_null(&mapp->dam_report_set)) ||
328*60aabb4cSChris Horne 		    (mapp->dam_tid != 0)))
329*60aabb4cSChris Horne 			goto again;
330*60aabb4cSChris Horne 	}
3314c06356bSdh142964 	mutex_exit(&mapp->dam_lock);
3324c06356bSdh142964 
333*60aabb4cSChris Horne 	DTRACE_PROBE3(damap__map__sync__end, char *, mapp->dam_name,
334*60aabb4cSChris Horne 	    int, rv, dam_t *, mapp);
335*60aabb4cSChris Horne 	return (rv);
336*60aabb4cSChris Horne }
337*60aabb4cSChris Horne 
338*60aabb4cSChris Horne /*
339*60aabb4cSChris Horne  * Return 1 if active set is empty
340*60aabb4cSChris Horne  */
341*60aabb4cSChris Horne int
342*60aabb4cSChris Horne damap_is_empty(damap_t *damapp)
343*60aabb4cSChris Horne {
344*60aabb4cSChris Horne 	dam_t	*mapp = (dam_t *)damapp;
345*60aabb4cSChris Horne 	int	rv;
346*60aabb4cSChris Horne 
347*60aabb4cSChris Horne 	mutex_enter(&mapp->dam_lock);
348*60aabb4cSChris Horne 	rv = bitset_is_null(&mapp->dam_active_set);
349*60aabb4cSChris Horne 	mutex_exit(&mapp->dam_lock);
350*60aabb4cSChris Horne 	return (rv);
3514c06356bSdh142964 }
3524c06356bSdh142964 
3534c06356bSdh142964 /*
3544c06356bSdh142964  * Get the name of a device address map
3554c06356bSdh142964  *
3564c06356bSdh142964  * damapp:	address map
3574c06356bSdh142964  *
3584c06356bSdh142964  * Returns:	name
3594c06356bSdh142964  */
3604c06356bSdh142964 char *
3614c06356bSdh142964 damap_name(damap_t *damapp)
3624c06356bSdh142964 {
3634c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
3644c06356bSdh142964 
3654c06356bSdh142964 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
3664c06356bSdh142964 }
3674c06356bSdh142964 
3684c06356bSdh142964 /*
369*60aabb4cSChris Horne  * Get the current size of the device address map
370*60aabb4cSChris Horne  *
371*60aabb4cSChris Horne  * damapp:	address map
372*60aabb4cSChris Horne  *
373*60aabb4cSChris Horne  * Returns:	size
374*60aabb4cSChris Horne  */
375*60aabb4cSChris Horne int
376*60aabb4cSChris Horne damap_size(damap_t *damapp)
377*60aabb4cSChris Horne {
378*60aabb4cSChris Horne 	dam_t *mapp = (dam_t *)damapp;
379*60aabb4cSChris Horne 
380*60aabb4cSChris Horne 	return (mapp->dam_size);
381*60aabb4cSChris Horne }
382*60aabb4cSChris Horne 
383*60aabb4cSChris Horne /*
3844c06356bSdh142964  * Report an address to per-address report
3854c06356bSdh142964  *
3864c06356bSdh142964  * damapp:	address map handle
3874c06356bSdh142964  * address:	address in ascii string representation
3881b115575SJohn Danielson  * addridp:	address ID
3894c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
3904c06356bSdh142964  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
3914c06356bSdh142964  *
3924c06356bSdh142964  * Returns:	DAM_SUCCESS
3934c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
3944c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
3954c06356bSdh142964  */
3964c06356bSdh142964 int
3971b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp,
3981b115575SJohn Danielson     nvlist_t *nvl, void *addr_priv)
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__add, char *, mapp->dam_name,
4081b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
4091b115575SJohn Danielson 
4101b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4111b115575SJohn Danielson 	if ((dam_map_alloc(mapp) != DAM_SUCCESS) ||
4121b115575SJohn Danielson 	    ((addrid = dam_get_addrid(mapp, address)) == 0)) {
4131b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4144c06356bSdh142964 		return (DAM_MAPFULL);
4154c06356bSdh142964 	}
4164c06356bSdh142964 
4174c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4184c06356bSdh142964 	ASSERT(passp != NULL);
4194c06356bSdh142964 
4204c06356bSdh142964 	/*
4214c06356bSdh142964 	 * If re-reporting the same address (add or remove) clear
4224c06356bSdh142964 	 * the existing report
4234c06356bSdh142964 	 */
4244c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
4251b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__add__jitter, char *, mapp->dam_name,
4261b115575SJohn Danielson 		    char *, address, dam_t *, mapp);
4271b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4281b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4294c06356bSdh142964 		passp->da_jitter++;
4304c06356bSdh142964 	}
4314c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
4324c06356bSdh142964 	if (nvl)
4334c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
4344c06356bSdh142964 
4351b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD);
4361b115575SJohn Danielson 	if (addridp != NULL)
4371b115575SJohn Danielson 		*addridp = (damap_id_t)addrid;
4381b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4394c06356bSdh142964 	return (DAM_SUCCESS);
4404c06356bSdh142964 }
4414c06356bSdh142964 
4424c06356bSdh142964 /*
4434c06356bSdh142964  * Report removal of address from per-address report
4444c06356bSdh142964  *
4454c06356bSdh142964  * damapp:	address map
4464c06356bSdh142964  * address:	address in ascii string representation
4474c06356bSdh142964  *
4484c06356bSdh142964  * Returns:	DAM_SUCCESS
4494c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
4504c06356bSdh142964  *		DAM_FAILURE	General failure
4514c06356bSdh142964  */
4524c06356bSdh142964 int
4534c06356bSdh142964 damap_addr_del(damap_t *damapp, char *address)
4544c06356bSdh142964 {
4554c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
4564c06356bSdh142964 	id_t addrid;
4574c06356bSdh142964 	dam_da_t *passp;
4584c06356bSdh142964 
4591b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4604c06356bSdh142964 		return (DAM_EINVAL);
4614c06356bSdh142964 
4621b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__del, char *, mapp->dam_name,
4631b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
4641b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4651b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
4661b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4671b115575SJohn Danielson 		return (DAM_MAPFULL);
4681b115575SJohn Danielson 	}
4691b115575SJohn Danielson 
4701b115575SJohn Danielson 	/*
4711b115575SJohn Danielson 	 * if reporting the removal of an address which is not in the map
4721b115575SJohn Danielson 	 * return success
4731b115575SJohn Danielson 	 */
4744c06356bSdh142964 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
4751b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4764c06356bSdh142964 		return (DAM_SUCCESS);
4774c06356bSdh142964 	}
4784c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4794c06356bSdh142964 	ASSERT(passp);
4804c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
4811b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__del__jitter, char *, mapp->dam_name,
4821b115575SJohn Danielson 		    char *, address, dam_t *, mapp);
4831b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4841b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4854c06356bSdh142964 		passp->da_jitter++;
4864c06356bSdh142964 	}
4871b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL);
4881b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4894c06356bSdh142964 	return (DAM_SUCCESS);
4904c06356bSdh142964 }
4914c06356bSdh142964 
4920b53804eSReed static int
4930b53804eSReed damap_addrset_flush_locked(damap_t *damapp)
4940b53804eSReed {
4950b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
4960b53804eSReed 	int	idx;
4970b53804eSReed 
4980b53804eSReed 	ASSERT(mapp);
4990b53804eSReed 	ASSERT(mutex_owned(&mapp->dam_lock));
5000b53804eSReed 	if (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) {
5010b53804eSReed 		return (DAM_EINVAL);
5020b53804eSReed 	}
5030b53804eSReed 
5040b53804eSReed 	DTRACE_PROBE2(damap__addrset__flush__locked__enter, char *,
5050b53804eSReed 	    mapp->dam_name, dam_t *, mapp);
5060b53804eSReed 	if (mapp->dam_flags & DAM_SETADD) {
5070b53804eSReed 		DTRACE_PROBE2(damap__addrset__flush__locked__reset, char *,
5080b53804eSReed 		    mapp->dam_name, dam_t *, mapp);
5090b53804eSReed 
5100b53804eSReed 		/*
5110b53804eSReed 		 * cancel stabilization timeout
5120b53804eSReed 		 */
513*60aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
5140b53804eSReed 		DAM_INCR_STAT(mapp, dam_jitter);
5150b53804eSReed 
5160b53804eSReed 		/*
5170b53804eSReed 		 * clear pending reports
5180b53804eSReed 		 */
5190b53804eSReed 		for (idx = 1; idx < mapp->dam_high; idx++) {
5200b53804eSReed 			if (DAM_IN_REPORT(mapp, idx)) {
5210b53804eSReed 				dam_addr_report_release(mapp, idx);
5220b53804eSReed 			}
5230b53804eSReed 		}
5240b53804eSReed 
5250b53804eSReed 		bitset_zero(&mapp->dam_report_set);
5260b53804eSReed 		mapp->dam_flags &= ~DAM_SETADD;
527*60aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
5280b53804eSReed 	}
5290b53804eSReed 
5300b53804eSReed 	return (DAM_SUCCESS);
5310b53804eSReed }
5320b53804eSReed 
5334c06356bSdh142964 /*
5344c06356bSdh142964  * Initiate full-set report
5354c06356bSdh142964  *
5364c06356bSdh142964  * damapp:	address map
5374c06356bSdh142964  *
5384c06356bSdh142964  * Returns:	DAM_SUCCESS
5394c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
5404c06356bSdh142964  */
5414c06356bSdh142964 int
5424c06356bSdh142964 damap_addrset_begin(damap_t *damapp)
5434c06356bSdh142964 {
5444c06356bSdh142964 	dam_t	*mapp = (dam_t *)damapp;
5450b53804eSReed 	int	rv;
5464c06356bSdh142964 
5470b53804eSReed 	if (mapp == NULL) {
5484c06356bSdh142964 		return (DAM_EINVAL);
5490b53804eSReed 	}
5504c06356bSdh142964 
5511b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__begin, char *, mapp->dam_name, dam_t *,
5521b115575SJohn Danielson 	    mapp);
5530b53804eSReed 
5541b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
5551b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
5561b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5570b53804eSReed 
5581b115575SJohn Danielson 		return (DAM_MAPFULL);
5591b115575SJohn Danielson 	}
5600b53804eSReed 
5610b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
5620b53804eSReed 	if (rv == DAM_SUCCESS) {
5630b53804eSReed 		mapp->dam_flags |= DAM_SETADD;
5640b53804eSReed 	}
5650b53804eSReed 	mutex_exit(&mapp->dam_lock);
5660b53804eSReed 
5670b53804eSReed 	return (rv);
5680b53804eSReed }
5691b115575SJohn Danielson 
5701b115575SJohn Danielson /*
5710b53804eSReed  * Cancel full-set report
5720b53804eSReed  *
5730b53804eSReed  * damapp:	address map
5740b53804eSReed  *
5750b53804eSReed  * Returns:	DAM_SUCCESS
5760b53804eSReed  *		DAM_EINVAL	Invalid argument(s)
5771b115575SJohn Danielson  */
5780b53804eSReed int
5790b53804eSReed damap_addrset_flush(damap_t *damapp)
5800b53804eSReed {
5810b53804eSReed 	int	rv;
5820b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
5830b53804eSReed 
5840b53804eSReed 	if (mapp == NULL) {
5850b53804eSReed 		return (DAM_EINVAL);
5864c06356bSdh142964 	}
5870b53804eSReed 
5880b53804eSReed 	DTRACE_PROBE2(damap__addrset__flush, char *, mapp->dam_name,
5890b53804eSReed 	    dam_t *, mapp);
5900b53804eSReed 
5910b53804eSReed 	mutex_enter(&mapp->dam_lock);
5920b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
5931b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
5940b53804eSReed 
5950b53804eSReed 	return (rv);
5964c06356bSdh142964 }
5974c06356bSdh142964 
5984c06356bSdh142964 /*
5994c06356bSdh142964  * Report address to full-set report
6004c06356bSdh142964  *
6014c06356bSdh142964  * damapp:	address map handle
6024c06356bSdh142964  * address:	address in ascii string representation
6034c06356bSdh142964  * rindx:	index if address stabilizes
6044c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
6054c06356bSdh142964  * addr_priv:	optional provider-private data (passed to activate/release cb)
6064c06356bSdh142964  *
6074c06356bSdh142964  * Returns:	DAM_SUCCESS
6084c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
6094c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
6104c06356bSdh142964  *		DAM_FAILURE	General failure
6114c06356bSdh142964  */
6124c06356bSdh142964 int
6134c06356bSdh142964 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
6144c06356bSdh142964     nvlist_t *nvl, void *addr_priv)
6154c06356bSdh142964 {
6164c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6174c06356bSdh142964 	id_t addrid;
6184c06356bSdh142964 	dam_da_t *passp;
6194c06356bSdh142964 
6201b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6214c06356bSdh142964 		return (DAM_EINVAL);
6224c06356bSdh142964 
6231b115575SJohn Danielson 	DTRACE_PROBE3(damap__addrset__add, char *, mapp->dam_name,
6241b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
6254c06356bSdh142964 
6261b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6271b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6281b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6291b115575SJohn Danielson 		return (DAM_FAILURE);
6301b115575SJohn Danielson 	}
6311b115575SJohn Danielson 
6324c06356bSdh142964 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
6331b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6344c06356bSdh142964 		return (DAM_MAPFULL);
6354c06356bSdh142964 	}
6364c06356bSdh142964 
6374c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
6384c06356bSdh142964 	ASSERT(passp);
6394c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
6401b115575SJohn Danielson 		DTRACE_PROBE3(damap__addrset__add__jitter, char *,
6411b115575SJohn Danielson 		    mapp->dam_name, char *, address, dam_t *, mapp);
6421b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
6434c06356bSdh142964 		passp->da_jitter++;
6444c06356bSdh142964 	}
6454c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
6464c06356bSdh142964 	if (nvl)
6474c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
6484c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
6494c06356bSdh142964 	if (ridx)
6504c06356bSdh142964 		*ridx = (damap_id_t)addrid;
6511b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6524c06356bSdh142964 	return (DAM_SUCCESS);
6534c06356bSdh142964 }
6544c06356bSdh142964 
6554c06356bSdh142964 /*
6564c06356bSdh142964  * Commit full-set report for stabilization
6574c06356bSdh142964  *
6584c06356bSdh142964  * damapp:	address map handle
6594c06356bSdh142964  * flags:	(currently 0)
6604c06356bSdh142964  *
6614c06356bSdh142964  * Returns:	DAM_SUCCESS
6624c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
6634c06356bSdh142964  *		DAM_FAILURE	General failure
6644c06356bSdh142964  */
6654c06356bSdh142964 int
6664c06356bSdh142964 damap_addrset_end(damap_t *damapp, int flags)
6674c06356bSdh142964 {
6684c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6694c06356bSdh142964 	int i;
6704c06356bSdh142964 
6711b115575SJohn Danielson 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6724c06356bSdh142964 		return (DAM_EINVAL);
6734c06356bSdh142964 
6741b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__end, char *, mapp->dam_name,
6751b115575SJohn Danielson 	    dam_t *, mapp);
6764c06356bSdh142964 
6771b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6781b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6791b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6801b115575SJohn Danielson 		return (DAM_FAILURE);
6811b115575SJohn Danielson 	}
6821b115575SJohn Danielson 
6831b115575SJohn Danielson 	if (flags & DAMAP_END_RESET) {
6841b115575SJohn Danielson 		DTRACE_PROBE2(damap__addrset__end__reset, char *,
6851b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
686*60aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
6874c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++)
6884c06356bSdh142964 			if (DAM_IN_REPORT(mapp, i))
6891b115575SJohn Danielson 				dam_addr_report_release(mapp, i);
6904c06356bSdh142964 	} else {
6914c06356bSdh142964 		mapp->dam_last_update = gethrtime();
692*60aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
693*60aabb4cSChris Horne 		    mapp->dam_stable_ticks);
6944c06356bSdh142964 	}
6951b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6964c06356bSdh142964 	return (DAM_SUCCESS);
6974c06356bSdh142964 }
6984c06356bSdh142964 
6994c06356bSdh142964 /*
7004c06356bSdh142964  * Return nvlist registered with reported address
7014c06356bSdh142964  *
7024c06356bSdh142964  * damapp:	address map handle
7031b115575SJohn Danielson  * addrid:	address ID
7044c06356bSdh142964  *
7054c06356bSdh142964  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
7064c06356bSdh142964  *		NULL
7074c06356bSdh142964  */
7084c06356bSdh142964 nvlist_t *
7094c06356bSdh142964 damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
7104c06356bSdh142964 {
7114c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7124c06356bSdh142964 	dam_da_t *pass;
7134c06356bSdh142964 
7141b115575SJohn Danielson 	if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) {
7151b115575SJohn Danielson 		if (pass = ddi_get_soft_state(mapp->dam_da, addrid))
7164c06356bSdh142964 			return (pass->da_nvl);
7174c06356bSdh142964 	}
7184c06356bSdh142964 	return (NULL);
7194c06356bSdh142964 }
7204c06356bSdh142964 
7214c06356bSdh142964 /*
7224c06356bSdh142964  * Return address string
7234c06356bSdh142964  *
7244c06356bSdh142964  * damapp:	address map handle
7251b115575SJohn Danielson  * addrid:	address ID
7264c06356bSdh142964  *
7274c06356bSdh142964  * Returns:	char *		Address string
7284c06356bSdh142964  *		NULL
7294c06356bSdh142964  */
7304c06356bSdh142964 char *
7311b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid)
7324c06356bSdh142964 {
7334c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7344c06356bSdh142964 
7351b115575SJohn Danielson 	if (mapp->dam_high)
7361b115575SJohn Danielson 		return (ddi_strid_id2str(mapp->dam_addr_hash, addrid));
7371b115575SJohn Danielson 	else
7381b115575SJohn Danielson 		return (NULL);
7394c06356bSdh142964 }
7404c06356bSdh142964 
7414c06356bSdh142964 /*
7424c06356bSdh142964  * Release address reference in map
7434c06356bSdh142964  *
7444c06356bSdh142964  * damapp:	address map handle
7451b115575SJohn Danielson  * addrid:	address ID
7464c06356bSdh142964  */
7474c06356bSdh142964 void
7484c06356bSdh142964 damap_id_rele(damap_t *damapp, damap_id_t addrid)
7494c06356bSdh142964 {
7504c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7511b115575SJohn Danielson 	dam_da_t *passp;
7521b115575SJohn Danielson 	char *addr;
7534c06356bSdh142964 
7541b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7551b115575SJohn Danielson 	ASSERT(passp);
7561b115575SJohn Danielson 
7571b115575SJohn Danielson 	addr = damap_id2addr(damapp, addrid);
7581b115575SJohn Danielson 	DTRACE_PROBE4(damap__id__rele, char *, mapp->dam_name, char *, addr,
7591b115575SJohn Danielson 	    dam_t *, mapp, int, passp->da_ref);
7601b115575SJohn Danielson 
7611b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7621b115575SJohn Danielson 
7631b115575SJohn Danielson 	/*
7641b115575SJohn Danielson 	 * teardown address if last outstanding reference
7651b115575SJohn Danielson 	 */
7661b115575SJohn Danielson 	if (--passp->da_ref == 0)
7671b115575SJohn Danielson 		dam_addr_release(mapp, (id_t)addrid);
7681b115575SJohn Danielson 
7691b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7704c06356bSdh142964 }
7714c06356bSdh142964 
7724c06356bSdh142964 /*
7734c06356bSdh142964  * Return current reference count on address reference in map
7744c06356bSdh142964  *
7754c06356bSdh142964  * damapp:	address map handle
7761b115575SJohn Danielson  * addrid:	address ID
7774c06356bSdh142964  *
7784c06356bSdh142964  * Returns:	DAM_SUCCESS
7794c06356bSdh142964  *		DAM_FAILURE
7804c06356bSdh142964  */
7814c06356bSdh142964 int
7821b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid)
7834c06356bSdh142964 {
7844c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7854c06356bSdh142964 	dam_da_t *passp;
7864c06356bSdh142964 	int ref = -1;
7874c06356bSdh142964 
7881b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7894c06356bSdh142964 	if (passp)
7904c06356bSdh142964 		ref = passp->da_ref;
7911b115575SJohn Danielson 
7924c06356bSdh142964 	return (ref);
7934c06356bSdh142964 }
7944c06356bSdh142964 
7954c06356bSdh142964 /*
7964c06356bSdh142964  * Return next address ID in list
7974c06356bSdh142964  *
7984c06356bSdh142964  * damapp:	address map handle
7994c06356bSdh142964  * damap_list:	address ID list passed to config|unconfig
8004c06356bSdh142964  *		returned by look by lookup_all
8014c06356bSdh142964  * last:	last ID returned, 0 is start of list
8024c06356bSdh142964  *
8034c06356bSdh142964  * Returns:	addrid		Next ID from the list
8044c06356bSdh142964  *		0		End of the list
8054c06356bSdh142964  */
8064c06356bSdh142964 damap_id_t
8074c06356bSdh142964 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
8084c06356bSdh142964 {
8094c06356bSdh142964 	int i, start;
8104c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8114c06356bSdh142964 	bitset_t *dam_list = (bitset_t *)damap_list;
8124c06356bSdh142964 
8134c06356bSdh142964 	if (!mapp || !dam_list)
8144c06356bSdh142964 		return ((damap_id_t)0);
8154c06356bSdh142964 
8164c06356bSdh142964 	start = (int)last + 1;
8171b115575SJohn Danielson 	for (i = start; i < mapp->dam_high; i++) {
8181b115575SJohn Danielson 		if (bitset_in_set(dam_list, i)) {
8194c06356bSdh142964 			return ((damap_id_t)i);
8201b115575SJohn Danielson 		}
8211b115575SJohn Danielson 	}
8224c06356bSdh142964 	return ((damap_id_t)0);
8234c06356bSdh142964 }
8244c06356bSdh142964 
8254c06356bSdh142964 /*
8264c06356bSdh142964  * Set config private data
8274c06356bSdh142964  *
8284c06356bSdh142964  * damapp:	address map handle
8291b115575SJohn Danielson  * addrid:	address ID
8304c06356bSdh142964  * cfg_priv:	configuration private data
8314c06356bSdh142964  *
8324c06356bSdh142964  */
8334c06356bSdh142964 void
8341b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv)
8354c06356bSdh142964 {
8364c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8374c06356bSdh142964 	dam_da_t *passp;
8384c06356bSdh142964 
8391b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8401b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8414c06356bSdh142964 	if (!passp) {
8421b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8434c06356bSdh142964 		return;
8444c06356bSdh142964 	}
8454c06356bSdh142964 	passp->da_cfg_priv = cfg_priv;
8461b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8474c06356bSdh142964 }
8484c06356bSdh142964 
8494c06356bSdh142964 /*
8504c06356bSdh142964  * Get config private data
8514c06356bSdh142964  *
8524c06356bSdh142964  * damapp:	address map handle
8531b115575SJohn Danielson  * addrid:	address ID
8544c06356bSdh142964  *
8554c06356bSdh142964  * Returns:	configuration private data
8564c06356bSdh142964  */
8574c06356bSdh142964 void *
8581b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid)
8594c06356bSdh142964 {
8604c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8614c06356bSdh142964 	dam_da_t *passp;
8624c06356bSdh142964 	void *rv;
8634c06356bSdh142964 
8641b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8651b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8664c06356bSdh142964 	if (!passp) {
8671b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8684c06356bSdh142964 		return (NULL);
8694c06356bSdh142964 	}
8704c06356bSdh142964 	rv = passp->da_cfg_priv;
8711b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8724c06356bSdh142964 	return (rv);
8734c06356bSdh142964 }
8744c06356bSdh142964 
8754c06356bSdh142964 /*
8764c06356bSdh142964  * Lookup a single address in the active address map
8774c06356bSdh142964  *
8784c06356bSdh142964  * damapp:	address map handle
8794c06356bSdh142964  * address:	address string
8804c06356bSdh142964  *
8814c06356bSdh142964  * Returns:	ID of active/stable address
8824c06356bSdh142964  *		0	Address not in stable set
8834c06356bSdh142964  *
8844c06356bSdh142964  * Future: Allow the caller to wait for stabilize before returning not found.
8854c06356bSdh142964  */
8864c06356bSdh142964 damap_id_t
8874c06356bSdh142964 damap_lookup(damap_t *damapp, char *address)
8884c06356bSdh142964 {
8894c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8904c06356bSdh142964 	id_t addrid = 0;
8914c06356bSdh142964 	dam_da_t *passp = NULL;
8924c06356bSdh142964 
8931b115575SJohn Danielson 	DTRACE_PROBE3(damap__lookup, char *, mapp->dam_name,
8941b115575SJohn Danielson 	    char *, address, dam_t *, mapp);
8951b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8961b115575SJohn Danielson 	if (!mapp->dam_high)
8971b115575SJohn Danielson 		addrid = 0;
8981b115575SJohn Danielson 	else
8994c06356bSdh142964 		addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
9004c06356bSdh142964 	if (addrid) {
9014c06356bSdh142964 		if (DAM_IS_STABLE(mapp, addrid)) {
9024c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
9034c06356bSdh142964 			ASSERT(passp);
9044c06356bSdh142964 			if (passp) {
9054c06356bSdh142964 				passp->da_ref++;
9064c06356bSdh142964 			} else {
9074c06356bSdh142964 				addrid = 0;
9084c06356bSdh142964 			}
9094c06356bSdh142964 		} else {
9104c06356bSdh142964 			addrid = 0;
9114c06356bSdh142964 		}
9124c06356bSdh142964 	}
9131b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
9141b115575SJohn Danielson 	DTRACE_PROBE4(damap__lookup__return, char *, mapp->dam_name,
9151b115575SJohn Danielson 	    char *, address, dam_t *, mapp, int, addrid);
9164c06356bSdh142964 	return ((damap_id_t)addrid);
9174c06356bSdh142964 }
9184c06356bSdh142964 
9194c06356bSdh142964 
9204c06356bSdh142964 /*
9214c06356bSdh142964  * Return the list of stable addresses in the map
9224c06356bSdh142964  *
9234c06356bSdh142964  * damapp:	address map handle
9244c06356bSdh142964  * id_listp:	pointer to list of address IDs in stable map (returned)
9254c06356bSdh142964  *
9264c06356bSdh142964  * Returns:	# of entries returned in alist
9274c06356bSdh142964  */
9284c06356bSdh142964 int
9294c06356bSdh142964 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
9304c06356bSdh142964 {
9314c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
9324c06356bSdh142964 	int mapsz = mapp->dam_size;
9334c06356bSdh142964 	int n_ids, i;
9344c06356bSdh142964 	bitset_t *bsp;
9351b115575SJohn Danielson 	char	 *addrp;
9364c06356bSdh142964 	dam_da_t *passp;
9374c06356bSdh142964 
9381b115575SJohn Danielson 	DTRACE_PROBE2(damap__lookup__all, char *, mapp->dam_name,
9391b115575SJohn Danielson 	    dam_t *, mapp);
9401b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9411b115575SJohn Danielson 	if (!mapp->dam_high) {
9421b115575SJohn Danielson 		*id_listp = (damap_id_list_t)NULL;
9431b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9441b115575SJohn Danielson 		DTRACE_PROBE3(damap__lookup__all__nomap, char *,
9451b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp, int, 0);
9461b115575SJohn Danielson 		return (0);
9471b115575SJohn Danielson 	}
9484c06356bSdh142964 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
9494c06356bSdh142964 	bitset_init(bsp);
9504c06356bSdh142964 	bitset_resize(bsp, mapsz);
9514c06356bSdh142964 	bitset_copy(&mapp->dam_active_set, bsp);
9524c06356bSdh142964 	for (n_ids = 0, i = 1; i < mapsz; i++) {
9534c06356bSdh142964 		if (bitset_in_set(bsp, i)) {
9544c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, i);
9554c06356bSdh142964 			ASSERT(passp);
9564c06356bSdh142964 			if (passp) {
9571b115575SJohn Danielson 				addrp = damap_id2addr(damapp, i);
9581b115575SJohn Danielson 				DTRACE_PROBE3(damap__lookup__all__item, char *,
9591b115575SJohn Danielson 				    mapp->dam_name, char *, addrp, dam_t *,
9601b115575SJohn Danielson 				    mapp);
9614c06356bSdh142964 				passp->da_ref++;
9624c06356bSdh142964 				n_ids++;
9634c06356bSdh142964 			}
9644c06356bSdh142964 		}
9654c06356bSdh142964 	}
9664c06356bSdh142964 	if (n_ids) {
9674c06356bSdh142964 		*id_listp = (damap_id_list_t)bsp;
9681b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9694c06356bSdh142964 		return (n_ids);
9704c06356bSdh142964 	} else {
9714c06356bSdh142964 		*id_listp = (damap_id_list_t)NULL;
9724c06356bSdh142964 		bitset_fini(bsp);
9734c06356bSdh142964 		kmem_free(bsp, sizeof (*bsp));
9741b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9754c06356bSdh142964 		return (0);
9764c06356bSdh142964 	}
9774c06356bSdh142964 }
9784c06356bSdh142964 
9794c06356bSdh142964 /*
9804c06356bSdh142964  * Release the address list returned by damap_lookup_all()
9814c06356bSdh142964  *
9824c06356bSdh142964  * mapp:	address map handle
9834c06356bSdh142964  * id_list:	list of address IDs returned in damap_lookup_all()
9844c06356bSdh142964  */
9854c06356bSdh142964 void
9864c06356bSdh142964 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
9874c06356bSdh142964 {
9884c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
9894c06356bSdh142964 	int i;
9904c06356bSdh142964 
9914c06356bSdh142964 	if (id_list == NULL)
9924c06356bSdh142964 		return;
9934c06356bSdh142964 
9941b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9954c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
9964c06356bSdh142964 		if (bitset_in_set((bitset_t *)id_list, i))
9971b115575SJohn Danielson 			(void) dam_addr_release(mapp, i);
9984c06356bSdh142964 	}
9991b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10004c06356bSdh142964 	bitset_fini((bitset_t *)id_list);
10014c06356bSdh142964 	kmem_free((void *)id_list, sizeof (bitset_t));
10024c06356bSdh142964 }
10034c06356bSdh142964 
10044c06356bSdh142964 /*
10051b115575SJohn Danielson  * activate an address that has passed the stabilization interval
10064c06356bSdh142964  */
10074c06356bSdh142964 static void
10081b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid)
10094c06356bSdh142964 {
10104c06356bSdh142964 	dam_da_t *passp;
10111b115575SJohn Danielson 	int config_rv;
10124c06356bSdh142964 	char *addrstr;
10134c06356bSdh142964 
10141b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10151b115575SJohn Danielson 	bitset_add(&mapp->dam_active_set, addrid);
10161b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
10174c06356bSdh142964 	ASSERT(passp);
10181b115575SJohn Danielson 
10194c06356bSdh142964 	/*
10204c06356bSdh142964 	 * copy the reported nvlist and provider private data
10214c06356bSdh142964 	 */
10221b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10231b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__activate__start, char *, mapp->dam_name,
10241b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
10254c06356bSdh142964 	passp->da_nvl = passp->da_nvl_rpt;
10264c06356bSdh142964 	passp->da_ppriv = passp->da_ppriv_rpt;
10274c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
10284c06356bSdh142964 	passp->da_nvl_rpt = NULL;
10294c06356bSdh142964 	passp->da_last_stable = gethrtime();
10304c06356bSdh142964 	passp->da_stable_cnt++;
10311b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10321b115575SJohn Danielson 	if (mapp->dam_activate_cb) {
10331b115575SJohn Danielson 		(*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr,
10341b115575SJohn Danielson 		    addrid, &passp->da_ppriv_rpt);
10354c06356bSdh142964 	}
10364c06356bSdh142964 
10374c06356bSdh142964 	/*
10381b115575SJohn Danielson 	 * call the address-specific configuration action as part of
10391b115575SJohn Danielson 	 * activation.
10404c06356bSdh142964 	 */
10411b115575SJohn Danielson 	config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp,
10421b115575SJohn Danielson 	    addrid);
10431b115575SJohn Danielson 	if (config_rv != DAM_SUCCESS) {
10441b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
10451b115575SJohn Danielson 		passp->da_flags |= DA_FAILED_CONFIG;
10461b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
10471b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__activate__config__failure,
10481b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
1049d189c170SReed 		dam_deact_cleanup(mapp, addrid, addrstr,
1050d189c170SReed 		    DAMAP_DEACT_RSN_CFG_FAIL);
1051d189c170SReed 	} else {
1052d189c170SReed 		DTRACE_PROBE3(damap__addr__activate__end, char *,
1053d189c170SReed 		    mapp->dam_name, char *, addrstr, dam_t *, mapp);
10544c06356bSdh142964 	}
10554c06356bSdh142964 }
10564c06356bSdh142964 
10574c06356bSdh142964 /*
10581b115575SJohn Danielson  * deactivate a previously stable address
10594c06356bSdh142964  */
10604c06356bSdh142964 static void
10611b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid)
10624c06356bSdh142964 {
10631b115575SJohn Danielson 	char *addrstr;
10644c06356bSdh142964 
10651b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10661b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__deactivate__start, char *, mapp->dam_name,
10671b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
10681b115575SJohn Danielson 
10691b115575SJohn Danielson 	/*
10701b115575SJohn Danielson 	 * call the unconfiguration callback
10711b115575SJohn Danielson 	 */
10721b115575SJohn Danielson 	(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid);
1073d189c170SReed 	dam_deact_cleanup(mapp, addrid, addrstr, DAMAP_DEACT_RSN_GONE);
1074d189c170SReed }
1075d189c170SReed 
1076d189c170SReed static void
1077d189c170SReed dam_deact_cleanup(dam_t *mapp, id_t addrid, char *addrstr,
1078d189c170SReed     damap_deact_rsn_t deact_rsn)
1079d189c170SReed {
1080d189c170SReed 	dam_da_t *passp;
1081d189c170SReed 
10821b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
10831b115575SJohn Danielson 	ASSERT(passp);
10841b115575SJohn Danielson 	if (mapp->dam_deactivate_cb)
10851b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
10861b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
1087d189c170SReed 		    addrid, passp->da_ppriv, deact_rsn);
10881b115575SJohn Danielson 
10891b115575SJohn Danielson 	/*
10901b115575SJohn Danielson 	 * clear the active bit and free the backing info for
10911b115575SJohn Danielson 	 * this address
10921b115575SJohn Danielson 	 */
10931b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10941b115575SJohn Danielson 	bitset_del(&mapp->dam_active_set, addrid);
10951b115575SJohn Danielson 	passp->da_ppriv = NULL;
10961b115575SJohn Danielson 	if (passp->da_nvl)
10971b115575SJohn Danielson 		nvlist_free(passp->da_nvl);
10981b115575SJohn Danielson 	passp->da_nvl = NULL;
10991b115575SJohn Danielson 	passp->da_ppriv_rpt = NULL;
11001b115575SJohn Danielson 	if (passp->da_nvl_rpt)
11011b115575SJohn Danielson 		nvlist_free(passp->da_nvl_rpt);
11021b115575SJohn Danielson 	passp->da_nvl_rpt = NULL;
11031b115575SJohn Danielson 
11041b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__deactivate__end, char *, mapp->dam_name,
11051b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
11061b115575SJohn Danielson 
11071b115575SJohn Danielson 	(void) dam_addr_release(mapp, addrid);
11081b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
11091b115575SJohn Danielson }
11101b115575SJohn Danielson 
11111b115575SJohn Danielson /*
11121b115575SJohn Danielson  * taskq callback for multi-thread activation
11131b115575SJohn Danielson  */
11141b115575SJohn Danielson static void
11151b115575SJohn Danielson dam_tq_config(void *arg)
11161b115575SJohn Danielson {
11171b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11181b115575SJohn Danielson 
11191b115575SJohn Danielson 	dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id);
11201b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11211b115575SJohn Danielson }
11221b115575SJohn Danielson 
11231b115575SJohn Danielson /*
11241b115575SJohn Danielson  * taskq callback for multi-thread deactivation
11251b115575SJohn Danielson  */
11261b115575SJohn Danielson static void
11271b115575SJohn Danielson dam_tq_unconfig(void *arg)
11281b115575SJohn Danielson {
11291b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11301b115575SJohn Danielson 
11311b115575SJohn Danielson 	dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id);
11321b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11331b115575SJohn Danielson }
11341b115575SJohn Danielson 
11351b115575SJohn Danielson /*
11361b115575SJohn Danielson  * Activate a set of stabilized addresses
11371b115575SJohn Danielson  */
11381b115575SJohn Danielson static void
11391b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate)
11401b115575SJohn Danielson {
11411b115575SJohn Danielson 
11421b115575SJohn Danielson 	int i, nset;
11431b115575SJohn Danielson 	taskq_t *tqp = NULL;
11441b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
11451b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
11461b115575SJohn Danielson 	extern pri_t maxclsyspri;
11471b115575SJohn Danielson 
11481b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
11491b115575SJohn Danielson 		/*
11501b115575SJohn Danielson 		 * calculate the # of taskq threads to create
11511b115575SJohn Danielson 		 */
11521b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
11531b115575SJohn Danielson 			if (bitset_in_set(activate, i))
11541b115575SJohn Danielson 				nset++;
11551b115575SJohn Danielson 		ASSERT(nset);
11561b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name);
11571b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
11581b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
11591b115575SJohn Danielson 	}
11601b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
11611b115575SJohn Danielson 		if (bitset_in_set(activate, i)) {
11621b115575SJohn Danielson 			if (!tqp)
11631b115575SJohn Danielson 				dam_addr_activate(mapp, i);
11641b115575SJohn Danielson 			else {
11651b115575SJohn Danielson 				/*
11661b115575SJohn Danielson 				 * multi-threaded activation
11671b115575SJohn Danielson 				 */
11681b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
11691b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
11701b115575SJohn Danielson 				tqd->tqd_id = i;
11711b115575SJohn Danielson 				(void) taskq_dispatch(tqp, dam_tq_config,
117264109744SChris Horne 				    tqd, TQ_SLEEP);
11731b115575SJohn Danielson 			}
11741b115575SJohn Danielson 		}
11751b115575SJohn Danielson 	}
11761b115575SJohn Danielson 	if (tqp) {
11771b115575SJohn Danielson 		taskq_wait(tqp);
11781b115575SJohn Danielson 		taskq_destroy(tqp);
11791b115575SJohn Danielson 	}
11801b115575SJohn Danielson }
11811b115575SJohn Danielson 
11821b115575SJohn Danielson /*
11831b115575SJohn Danielson  * Deactivate a set of stabilized addresses
11841b115575SJohn Danielson  */
11851b115575SJohn Danielson static void
11861b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate)
11871b115575SJohn Danielson {
11881b115575SJohn Danielson 	int i, nset;
11891b115575SJohn Danielson 	taskq_t *tqp = NULL;
11901b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
11911b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
11921b115575SJohn Danielson 
11931b115575SJohn Danielson 	DTRACE_PROBE2(damap__addrset__deactivate, char *, mapp->dam_name,
11941b115575SJohn Danielson 	    dam_t *, mapp);
11951b115575SJohn Danielson 
11961b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
11971b115575SJohn Danielson 		/*
11981b115575SJohn Danielson 		 * compute the # of taskq threads to dispatch
11991b115575SJohn Danielson 		 */
12001b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
12011b115575SJohn Danielson 			if (bitset_in_set(deactivate, i))
12021b115575SJohn Danielson 				nset++;
12031b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "deactv-%s",
12041b115575SJohn Danielson 		    mapp->dam_name);
12051b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
12061b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
12071b115575SJohn Danielson 	}
12081b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
12091b115575SJohn Danielson 		if (bitset_in_set(deactivate, i)) {
12101b115575SJohn Danielson 			if (!tqp) {
12111b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
12121b115575SJohn Danielson 			} else {
12131b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
12141b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
12151b115575SJohn Danielson 				tqd->tqd_id = i;
12161b115575SJohn Danielson 				(void) taskq_dispatch(tqp,
121764109744SChris Horne 				    dam_tq_unconfig, tqd, TQ_SLEEP);
12181b115575SJohn Danielson 			}
12191b115575SJohn Danielson 		}
12201b115575SJohn Danielson 	}
12211b115575SJohn Danielson 
12221b115575SJohn Danielson 	if (tqp) {
12231b115575SJohn Danielson 		taskq_wait(tqp);
12241b115575SJohn Danielson 		taskq_destroy(tqp);
12251b115575SJohn Danielson 	}
12261b115575SJohn Danielson }
12271b115575SJohn Danielson 
12281b115575SJohn Danielson /*
12291b115575SJohn Danielson  * Release a previously activated address
12301b115575SJohn Danielson  */
12311b115575SJohn Danielson static void
12321b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid)
12331b115575SJohn Danielson {
12341b115575SJohn Danielson 	dam_da_t *passp;
12351b115575SJohn Danielson 	char	 *addrstr;
12361b115575SJohn Danielson 
12371b115575SJohn Danielson 
12381b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
12394c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
12404c06356bSdh142964 	ASSERT(passp);
12414c06356bSdh142964 
12421b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
12431b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__release, char *, mapp->dam_name,
12441b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
12454c06356bSdh142964 
12464c06356bSdh142964 	/*
12471b115575SJohn Danielson 	 * defer releasing the address until outstanding references
12481b115575SJohn Danielson 	 * are released
12494c06356bSdh142964 	 */
12501b115575SJohn Danielson 	if (passp->da_ref > 1) {
12511b115575SJohn Danielson 		DTRACE_PROBE4(damap__addr__release__outstanding__refs,
12521b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp,
12531b115575SJohn Danielson 		    int, passp->da_ref);
12544c06356bSdh142964 		return;
12554c06356bSdh142964 	}
12561b115575SJohn Danielson 
12571b115575SJohn Danielson 	/*
12581b115575SJohn Danielson 	 * allow pending reports to stabilize
12591b115575SJohn Danielson 	 */
12601b115575SJohn Danielson 	if (DAM_IN_REPORT(mapp, addrid)) {
12611b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__release__report__pending,
12621b115575SJohn Danielson 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
12631b115575SJohn Danielson 		return;
12641b115575SJohn Danielson 	}
12651b115575SJohn Danielson 
12664c06356bSdh142964 	ddi_strid_free(mapp->dam_addr_hash, addrid);
12674c06356bSdh142964 	ddi_soft_state_free(mapp->dam_da, addrid);
12684c06356bSdh142964 }
12694c06356bSdh142964 
12704c06356bSdh142964 /*
12714c06356bSdh142964  * process stabilized address reports
12724c06356bSdh142964  */
12734c06356bSdh142964 static void
12741b115575SJohn Danielson dam_stabilize_map(void *arg)
12754c06356bSdh142964 {
12764c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
12774c06356bSdh142964 	bitset_t delta;
12784c06356bSdh142964 	bitset_t cfg;
12794c06356bSdh142964 	bitset_t uncfg;
12804c06356bSdh142964 	int has_cfg, has_uncfg;
12811b115575SJohn Danielson 	uint32_t i, n_active;
12821b115575SJohn Danielson 
12831b115575SJohn Danielson 	DTRACE_PROBE2(damap__stabilize__map, char *, mapp->dam_name,
12841b115575SJohn Danielson 	    dam_t *, mapp);
12854c06356bSdh142964 
12864c06356bSdh142964 	bitset_init(&delta);
12874c06356bSdh142964 	bitset_resize(&delta, mapp->dam_size);
12884c06356bSdh142964 	bitset_init(&cfg);
12894c06356bSdh142964 	bitset_resize(&cfg, mapp->dam_size);
12904c06356bSdh142964 	bitset_init(&uncfg);
12914c06356bSdh142964 	bitset_resize(&uncfg, mapp->dam_size);
12924c06356bSdh142964 
12931b115575SJohn Danielson 	/*
12941b115575SJohn Danielson 	 * determine which addresses have changed during
12951b115575SJohn Danielson 	 * this stabilization cycle
12961b115575SJohn Danielson 	 */
12971b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
12981b115575SJohn Danielson 	ASSERT(mapp->dam_flags & DAM_SPEND);
12994c06356bSdh142964 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
13004c06356bSdh142964 	    &delta)) {
13011b115575SJohn Danielson 		/*
13021b115575SJohn Danielson 		 * no difference
13031b115575SJohn Danielson 		 */
13044c06356bSdh142964 		bitset_zero(&mapp->dam_stable_set);
13051b115575SJohn Danielson 		mapp->dam_flags &= ~DAM_SPEND;
1306*60aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
13071b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
1308*60aabb4cSChris Horne 
13094c06356bSdh142964 		bitset_fini(&uncfg);
13104c06356bSdh142964 		bitset_fini(&cfg);
13114c06356bSdh142964 		bitset_fini(&delta);
13121b115575SJohn Danielson 		DTRACE_PROBE2(damap__stabilize__map__nochange, char *,
13131b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
13144c06356bSdh142964 		return;
13154c06356bSdh142964 	}
13161b115575SJohn Danielson 
13171b115575SJohn Danielson 	/*
13181b115575SJohn Danielson 	 * compute the sets of addresses to be activated and deactivated
13191b115575SJohn Danielson 	 */
13204c06356bSdh142964 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
13214c06356bSdh142964 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
13221b115575SJohn Danielson 
13231b115575SJohn Danielson 	/*
13241b115575SJohn Danielson 	 * drop map lock while invoking callouts
13251b115575SJohn Danielson 	 */
13261b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
13271b115575SJohn Danielson 
13281b115575SJohn Danielson 	/*
13291b115575SJohn Danielson 	 * activate all newly stable addresss
13301b115575SJohn Danielson 	 */
13311b115575SJohn Danielson 	if (has_cfg)
13324c06356bSdh142964 		dam_addrset_activate(mapp, &cfg);
13331b115575SJohn Danielson 
13341b115575SJohn Danielson 	/*
13351b115575SJohn Danielson 	 * deactivate addresss which are no longer in the map
13361b115575SJohn Danielson 	 */
13371b115575SJohn Danielson 	if (has_uncfg)
13381b115575SJohn Danielson 		dam_addrset_deactivate(mapp, &uncfg);
13391b115575SJohn Danielson 
13401b115575SJohn Danielson 
13411b115575SJohn Danielson 	/*
13421b115575SJohn Danielson 	 * timestamp the last stable time and increment the kstat keeping
13431b115575SJohn Danielson 	 * the # of of stable cycles for the map
13441b115575SJohn Danielson 	 */
13451b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13464c06356bSdh142964 	bitset_zero(&mapp->dam_stable_set);
13474c06356bSdh142964 	mapp->dam_last_stable = gethrtime();
13484c06356bSdh142964 	mapp->dam_stable_cnt++;
13491b115575SJohn Danielson 	DAM_INCR_STAT(mapp, dam_cycles);
13501b115575SJohn Danielson 
13511b115575SJohn Danielson 	/*
13521b115575SJohn Danielson 	 * determine the number of stable addresses
13531b115575SJohn Danielson 	 * and update the n_active kstat for this map
13541b115575SJohn Danielson 	 */
13551b115575SJohn Danielson 	for (i = 1, n_active = 0; i < mapp->dam_high; i++)
13561b115575SJohn Danielson 		if (bitset_in_set(&mapp->dam_active_set, i))
13571b115575SJohn Danielson 			n_active++;
13581b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_active, n_active);
13591b115575SJohn Danielson 
13601b115575SJohn Danielson 	DTRACE_PROBE3(damap__map__stable__end, char *, mapp->dam_name,
13611b115575SJohn Danielson 	    dam_t *, mapp, int, n_active);
13621b115575SJohn Danielson 
13631b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SPEND;
1364*60aabb4cSChris Horne 	cv_signal(&mapp->dam_sync_cv);
13651b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
1366*60aabb4cSChris Horne 
13674c06356bSdh142964 	bitset_fini(&uncfg);
13684c06356bSdh142964 	bitset_fini(&cfg);
13694c06356bSdh142964 	bitset_fini(&delta);
13704c06356bSdh142964 }
13714c06356bSdh142964 
13724c06356bSdh142964 /*
13734c06356bSdh142964  * per-address stabilization timeout
13744c06356bSdh142964  */
13754c06356bSdh142964 static void
13764c06356bSdh142964 dam_addr_stable_cb(void *arg)
13774c06356bSdh142964 {
13784c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
13794c06356bSdh142964 	int i;
13804c06356bSdh142964 	dam_da_t *passp;
13814c06356bSdh142964 	int spend = 0;
13824c06356bSdh142964 	int tpend = 0;
1383*60aabb4cSChris Horne 	int64_t ts, next_ticks, delta_ticks;
13844c06356bSdh142964 
13851b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13864c06356bSdh142964 	if (mapp->dam_tid == 0) {
13871b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addr__stable__cancelled, char *,
13881b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
13891b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
13904c06356bSdh142964 		return;
13914c06356bSdh142964 	}
13924c06356bSdh142964 	mapp->dam_tid = 0;
13931b115575SJohn Danielson 
13944c06356bSdh142964 	/*
13954c06356bSdh142964 	 * If still under stabilization, reschedule timeout,
13961b115575SJohn Danielson 	 * otherwise dispatch the task to activate and deactivate the
13971b115575SJohn Danielson 	 * new stable address
13984c06356bSdh142964 	 */
13994c06356bSdh142964 	if (mapp->dam_flags & DAM_SPEND) {
14001b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
14014c06356bSdh142964 		mapp->dam_stable_overrun++;
1402*60aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
1403*60aabb4cSChris Horne 		    mapp->dam_stable_ticks);
14041b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addr__stable__overrun, char *,
14051b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
14061b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14074c06356bSdh142964 		return;
14084c06356bSdh142964 	}
14094c06356bSdh142964 
14101b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
14111b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
14121b115575SJohn Danielson 
14131b115575SJohn Danielson 	/*
14141b115575SJohn Danielson 	 * copy the current active set to the stable map
14151b115575SJohn Danielson 	 * for each address being reported, decrement its
14161b115575SJohn Danielson 	 * stabilize deadline, and if stable, add or remove the
14171b115575SJohn Danielson 	 * address from the stable set
14181b115575SJohn Danielson 	 */
14194c06356bSdh142964 	bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set);
1420*60aabb4cSChris Horne 	ts = ddi_get_lbolt64();
1421*60aabb4cSChris Horne 	next_ticks = mapp->dam_stable_ticks;
14224c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
14234c06356bSdh142964 		if (!bitset_in_set(&mapp->dam_report_set, i))
14244c06356bSdh142964 			continue;
14254c06356bSdh142964 		passp = ddi_get_soft_state(mapp->dam_da, i);
14264c06356bSdh142964 		ASSERT(passp);
14274c06356bSdh142964 
14284c06356bSdh142964 		/* report has stabilized */
14294c06356bSdh142964 		if (passp->da_deadline <= ts) {
14304c06356bSdh142964 			bitset_del(&mapp->dam_report_set, i);
14311b115575SJohn Danielson 			if (passp->da_flags & DA_RELE)
14324c06356bSdh142964 				bitset_del(&mapp->dam_stable_set, i);
14331b115575SJohn Danielson 			else
14344c06356bSdh142964 				bitset_add(&mapp->dam_stable_set, i);
14354c06356bSdh142964 			spend++;
14364c06356bSdh142964 			continue;
14374c06356bSdh142964 		}
14384c06356bSdh142964 
14394c06356bSdh142964 		/*
14401b115575SJohn Danielson 		 * not stabilized, determine next map timeout
14414c06356bSdh142964 		 */
14424c06356bSdh142964 		tpend++;
1443*60aabb4cSChris Horne 		delta_ticks = passp->da_deadline - ts;
1444*60aabb4cSChris Horne 		if (delta_ticks < next_ticks)
1445*60aabb4cSChris Horne 			next_ticks = delta_ticks;
14464c06356bSdh142964 	}
14474c06356bSdh142964 
14484c06356bSdh142964 	/*
14491b115575SJohn Danielson 	 * schedule system_taskq activation of stabilized reports
14504c06356bSdh142964 	 */
14514c06356bSdh142964 	if (spend) {
14521b115575SJohn Danielson 		if (taskq_dispatch(system_taskq, dam_stabilize_map,
145364109744SChris Horne 		    mapp, TQ_NOSLEEP | TQ_NOQUEUE)) {
14541b115575SJohn Danielson 			mapp->dam_flags |= DAM_SPEND;
14551b115575SJohn Danielson 			DTRACE_PROBE2(damap__map__addr__stable__start, char *,
14561b115575SJohn Danielson 			    mapp->dam_name, dam_t *, mapp);
14571b115575SJohn Danielson 		} else {
14584c06356bSdh142964 			tpend++;
145964109744SChris Horne 
146064109744SChris Horne 			/*
146164109744SChris Horne 			 * Avoid waiting the entire stabalization
146264109744SChris Horne 			 * time again if taskq_diskpatch fails.
146364109744SChris Horne 			 */
1464*60aabb4cSChris Horne 			delta_ticks = drv_usectohz(
146564109744SChris Horne 			    damap_taskq_dispatch_retry_usec);
1466*60aabb4cSChris Horne 			if (delta_ticks < next_ticks)
1467*60aabb4cSChris Horne 				next_ticks = delta_ticks;
14684c06356bSdh142964 		}
14691b115575SJohn Danielson 	}
14704c06356bSdh142964 
14714c06356bSdh142964 	/*
14721b115575SJohn Danielson 	 * reschedule the stabilization timer if there are reports
14731b115575SJohn Danielson 	 * still pending
14744c06356bSdh142964 	 */
14754c06356bSdh142964 	if (tpend)
1476*60aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
1477*60aabb4cSChris Horne 		    (clock_t)next_ticks);
14781b115575SJohn Danielson 
14791b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
14804c06356bSdh142964 }
14814c06356bSdh142964 
14824c06356bSdh142964 /*
14831b115575SJohn Danielson  * fullset stabilization timeout callback
14844c06356bSdh142964  */
14854c06356bSdh142964 static void
14861b115575SJohn Danielson dam_addrset_stable_cb(void *arg)
14874c06356bSdh142964 {
14884c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
14894c06356bSdh142964 
14901b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
14914c06356bSdh142964 	if (mapp->dam_tid == 0) {
14921b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14931b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__cancelled,
14941b115575SJohn Danielson 		    char *, mapp->dam_name, dam_t *, mapp);
14954c06356bSdh142964 		return;
14964c06356bSdh142964 	}
14974c06356bSdh142964 	mapp->dam_tid = 0;
14984c06356bSdh142964 
14994c06356bSdh142964 	/*
15001b115575SJohn Danielson 	 * If map still underoing stabilization reschedule timeout,
15011b115575SJohn Danielson 	 * else dispatch the task to configure the new stable set of
15021b115575SJohn Danielson 	 * addresses.
15034c06356bSdh142964 	 */
150464109744SChris Horne 	if ((mapp->dam_flags & DAM_SPEND) ||
150564109744SChris Horne 	    (taskq_dispatch(system_taskq, dam_stabilize_map, mapp,
150664109744SChris Horne 	    TQ_NOSLEEP | TQ_NOQUEUE) == NULL)) {
15071b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
15084c06356bSdh142964 		mapp->dam_stable_overrun++;
1509*60aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
1510*60aabb4cSChris Horne 		    drv_usectohz(damap_taskq_dispatch_retry_usec));
151164109744SChris Horne 
15121b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__overrun, char *,
15131b115575SJohn Danielson 		    mapp->dam_name, dam_t *, mapp);
15141b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
15151b115575SJohn Danielson 		return;
15161b115575SJohn Danielson 	}
15171b115575SJohn Danielson 
15181b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
15191b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
15204c06356bSdh142964 	bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
15214c06356bSdh142964 	bitset_zero(&mapp->dam_report_set);
15221b115575SJohn Danielson 	mapp->dam_flags |= DAM_SPEND;
15231b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SETADD;
1524*60aabb4cSChris Horne 	/* NOTE: don't need cv_signal since DAM_SPEND is still set */
1525*60aabb4cSChris Horne 
15261b115575SJohn Danielson 	DTRACE_PROBE2(damap__map__addrset__stable__start, char *,
15271b115575SJohn Danielson 	    mapp->dam_name, dam_t *, mapp);
15281b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
15294c06356bSdh142964 }
15304c06356bSdh142964 
15314c06356bSdh142964 /*
1532*60aabb4cSChris Horne  * schedule map timeout in 'ticks' ticks
1533*60aabb4cSChris Horne  * if map timer is currently running, cancel if ticks == 0
15344c06356bSdh142964  */
15354c06356bSdh142964 static void
1536*60aabb4cSChris Horne dam_sched_timeout(void (*timeout_cb)(), dam_t *mapp, clock_t ticks)
15374c06356bSdh142964 {
15384c06356bSdh142964 	timeout_id_t tid;
15394c06356bSdh142964 
1540*60aabb4cSChris Horne 	DTRACE_PROBE3(damap__sched__timeout, char *, mapp->dam_name,
1541*60aabb4cSChris Horne 	    dam_t *, mapp, int, ticks);
15424c06356bSdh142964 
15431b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15441b115575SJohn Danielson 	if ((tid = mapp->dam_tid) != 0) {
1545*60aabb4cSChris Horne 		if (ticks == 0) {
15461b115575SJohn Danielson 			mapp->dam_tid = 0;
15471b115575SJohn Danielson 			mutex_exit(&mapp->dam_lock);
15481b115575SJohn Danielson 			(void) untimeout(tid);
15491b115575SJohn Danielson 			mutex_enter(&mapp->dam_lock);
15501b115575SJohn Danielson 		}
15511b115575SJohn Danielson 	} else {
1552*60aabb4cSChris Horne 		if (timeout_cb && (ticks != 0))
1553*60aabb4cSChris Horne 			mapp->dam_tid = timeout(timeout_cb, mapp, ticks);
15544c06356bSdh142964 	}
15551b115575SJohn Danielson }
15564c06356bSdh142964 
15574c06356bSdh142964 /*
15581b115575SJohn Danielson  * report addition or removal of an address
15594c06356bSdh142964  */
15604c06356bSdh142964 static void
15611b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type)
15624c06356bSdh142964 {
15631b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
15641b115575SJohn Danielson 
15651b115575SJohn Danielson 	DTRACE_PROBE4(damap__addr__report, char *, mapp->dam_name,
15661b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp, int, rpt_type);
15671b115575SJohn Danielson 
15681b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15694c06356bSdh142964 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
15704c06356bSdh142964 	passp->da_last_report = gethrtime();
15714c06356bSdh142964 	mapp->dam_last_update = gethrtime();
15724c06356bSdh142964 	passp->da_report_cnt++;
1573*60aabb4cSChris Horne 	passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stable_ticks;
15741b115575SJohn Danielson 	if (rpt_type == RPT_ADDR_DEL)
15754c06356bSdh142964 		passp->da_flags |= DA_RELE;
15761b115575SJohn Danielson 	else if (rpt_type == RPT_ADDR_ADD)
15774c06356bSdh142964 		passp->da_flags &= ~DA_RELE;
15784c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
1579*60aabb4cSChris Horne 	dam_sched_timeout(dam_addr_stable_cb, mapp, mapp->dam_stable_ticks);
15804c06356bSdh142964 }
15814c06356bSdh142964 
15824c06356bSdh142964 /*
15834c06356bSdh142964  * release an address report
15844c06356bSdh142964  */
15854c06356bSdh142964 static void
15861b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid)
15874c06356bSdh142964 {
15884c06356bSdh142964 	dam_da_t *passp;
15891b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
15904c06356bSdh142964 
15911b115575SJohn Danielson 	DTRACE_PROBE3(damap__addr__report__release, char *, mapp->dam_name,
15921b115575SJohn Danielson 	    char *, addrstr, dam_t *, mapp);
15931b115575SJohn Danielson 
15941b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15954c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
15964c06356bSdh142964 	ASSERT(passp);
15971b115575SJohn Danielson 	/*
15981b115575SJohn Danielson 	 * clear the report bit
15991b115575SJohn Danielson 	 * if the address has a registered deactivation handler and
16009aed1621SDavid Hollister 	 * we are holding a private data pointer and the address has not
16019aed1621SDavid Hollister 	 * stabilized, deactivate the address (private data).
16021b115575SJohn Danielson 	 */
16031b115575SJohn Danielson 	bitset_del(&mapp->dam_report_set, addrid);
16049aed1621SDavid Hollister 	if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb &&
16059aed1621SDavid Hollister 	    passp->da_ppriv_rpt) {
16061b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
16071b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
16081b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
16099aed1621SDavid Hollister 		    addrid, passp->da_ppriv_rpt, DAMAP_DEACT_RSN_UNSTBL);
16101b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
16111b115575SJohn Danielson 	}
16124c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
16134c06356bSdh142964 	if (passp->da_nvl_rpt)
16144c06356bSdh142964 		nvlist_free(passp->da_nvl_rpt);
16154c06356bSdh142964 }
16164c06356bSdh142964 
16174c06356bSdh142964 /*
16184c06356bSdh142964  * return the map ID of an address
16194c06356bSdh142964  */
16204c06356bSdh142964 static id_t
16214c06356bSdh142964 dam_get_addrid(dam_t *mapp, char *address)
16224c06356bSdh142964 {
16234c06356bSdh142964 	damap_id_t addrid;
16244c06356bSdh142964 	dam_da_t *passp;
16254c06356bSdh142964 
16261b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16274c06356bSdh142964 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
16281b115575SJohn Danielson 		if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash,
16294c06356bSdh142964 		    address)) == (damap_id_t)0) {
16304c06356bSdh142964 			return (0);
16314c06356bSdh142964 		}
16324c06356bSdh142964 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
16334c06356bSdh142964 		    DDI_SUCCESS) {
16344c06356bSdh142964 			ddi_strid_free(mapp->dam_addr_hash, addrid);
16354c06356bSdh142964 			return (0);
16364c06356bSdh142964 		}
16371b115575SJohn Danielson 
16384c06356bSdh142964 		if (addrid >= mapp->dam_high)
16394c06356bSdh142964 			mapp->dam_high = addrid + 1;
16401b115575SJohn Danielson 
16411b115575SJohn Danielson 		/*
16421b115575SJohn Danielson 		 * expand bitmaps if ID has outgrown old map size
16431b115575SJohn Danielson 		 */
16441b115575SJohn Danielson 		if (mapp->dam_high > mapp->dam_size) {
16451b115575SJohn Danielson 			mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP;
16461b115575SJohn Danielson 			bitset_resize(&mapp->dam_active_set, mapp->dam_size);
16471b115575SJohn Danielson 			bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
16481b115575SJohn Danielson 			bitset_resize(&mapp->dam_report_set, mapp->dam_size);
16494c06356bSdh142964 		}
16501b115575SJohn Danielson 
16514c06356bSdh142964 		passp = ddi_get_soft_state(mapp->dam_da, addrid);
16521b115575SJohn Danielson 		passp->da_ref = 1;
16531b115575SJohn Danielson 		passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash,
16541b115575SJohn Danielson 		    addrid); /* for mdb */
16551b115575SJohn Danielson 	}
16564c06356bSdh142964 	return (addrid);
16574c06356bSdh142964 }
16584c06356bSdh142964 
16594c06356bSdh142964 /*
16604c06356bSdh142964  * create and install map statistics
16614c06356bSdh142964  */
16624c06356bSdh142964 static int
16634c06356bSdh142964 dam_kstat_create(dam_t *mapp)
16644c06356bSdh142964 {
16654c06356bSdh142964 	kstat_t			*mapsp;
16664c06356bSdh142964 	struct dam_kstats	*statsp;
16674c06356bSdh142964 
16684c06356bSdh142964 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
16694c06356bSdh142964 	    KSTAT_TYPE_NAMED,
16704c06356bSdh142964 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
16711b115575SJohn Danielson 
16721b115575SJohn Danielson 	if (mapsp == NULL)
16734c06356bSdh142964 		return (DDI_FAILURE);
16744c06356bSdh142964 
16754c06356bSdh142964 	statsp = (struct dam_kstats *)mapsp->ks_data;
16761b115575SJohn Danielson 	kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32);
16771b115575SJohn Danielson 	kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32);
16781b115575SJohn Danielson 	kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32);
16791b115575SJohn Danielson 	kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32);
16804c06356bSdh142964 	kstat_install(mapsp);
16814c06356bSdh142964 	mapp->dam_kstatsp = mapsp;
16824c06356bSdh142964 	return (DDI_SUCCESS);
16834c06356bSdh142964 }
1684