xref: /titanic_51/usr/src/uts/common/os/damap.c (revision aab83bb83be7342f6cfccaed8d5fe0b2f404855d)
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 /*
2360aabb4cSChris 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>
37*a288e5a9SJoshua M. Clulow #include <sys/ddi_periodic.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 *);
5860aabb4cSChris 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,
12260aabb4cSChris 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 
1334c06356bSdh142964 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
1341b115575SJohn Danielson 	mapp->dam_options = map_opts;
13560aabb4cSChris Horne 	mapp->dam_stable_ticks = drv_usectohz(stable_usec);
1361b115575SJohn Danielson 	mapp->dam_size = 0;
1371b115575SJohn Danielson 	mapp->dam_rptmode = mode;
1384c06356bSdh142964 	mapp->dam_activate_arg = activate_arg;
1394c06356bSdh142964 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
1404c06356bSdh142964 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
1414c06356bSdh142964 	mapp->dam_config_arg = config_arg;
1424c06356bSdh142964 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
1434c06356bSdh142964 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
1441b115575SJohn Danielson 	mapp->dam_name = i_ddi_strdup(name, KM_SLEEP);
1454c06356bSdh142964 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
14660aabb4cSChris Horne 	cv_init(&mapp->dam_sync_cv, NULL, CV_DRIVER, NULL);
1471b115575SJohn Danielson 	bitset_init(&mapp->dam_active_set);
1481b115575SJohn Danielson 	bitset_init(&mapp->dam_stable_set);
1491b115575SJohn Danielson 	bitset_init(&mapp->dam_report_set);
1504c06356bSdh142964 	*damapp = (damap_t *)mapp;
1511b94a41bSChris Horne 
1521b94a41bSChris Horne 	DTRACE_PROBE5(damap__create,
1531b94a41bSChris Horne 	    char *, mapp->dam_name, damap_t *, mapp,
1541b94a41bSChris Horne 	    damap_rptmode_t, mode, int, map_opts, int, stable_usec);
1551b94a41bSChris Horne 
1564c06356bSdh142964 	return (DAM_SUCCESS);
1574c06356bSdh142964 }
1584c06356bSdh142964 
1594c06356bSdh142964 /*
1601b115575SJohn Danielson  * Allocate backing resources
1611b115575SJohn Danielson  *
1621b115575SJohn Danielson  * DAMs are lightly backed on create - major allocations occur
1631b115575SJohn Danielson  * at the time a report is made to the map, and are extended on
1641b115575SJohn Danielson  * a demand basis.
1651b115575SJohn Danielson  */
1661b115575SJohn Danielson static int
1671b115575SJohn Danielson dam_map_alloc(dam_t *mapp)
1681b115575SJohn Danielson {
1691b115575SJohn Danielson 	void *softstate_p;
1701b115575SJohn Danielson 
1711b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
1721b115575SJohn Danielson 	if (mapp->dam_flags & DAM_DESTROYPEND)
1731b115575SJohn Danielson 		return (DAM_FAILURE);
1741b115575SJohn Danielson 
1751b115575SJohn Danielson 	/*
1761b115575SJohn Danielson 	 * dam_high > 0 signals map allocation complete
1771b115575SJohn Danielson 	 */
1781b115575SJohn Danielson 	if (mapp->dam_high)
1791b115575SJohn Danielson 		return (DAM_SUCCESS);
1801b115575SJohn Danielson 
1811b115575SJohn Danielson 	mapp->dam_size = DAM_SIZE_BUMP;
1821b115575SJohn Danielson 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t),
1831b115575SJohn Danielson 	    mapp->dam_size) != DDI_SUCCESS)
1841b115575SJohn Danielson 		return (DAM_FAILURE);
1851b115575SJohn Danielson 
1861b115575SJohn Danielson 	if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) !=
1871b115575SJohn Danielson 	    DDI_SUCCESS) {
1881b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1891b115575SJohn Danielson 		return (DAM_FAILURE);
1901b115575SJohn Danielson 	}
1911b115575SJohn Danielson 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
1921b115575SJohn Danielson 		ddi_soft_state_fini(softstate_p);
1931b115575SJohn Danielson 		ddi_strid_fini(&mapp->dam_addr_hash);
1941b115575SJohn Danielson 		return (DAM_FAILURE);
1951b115575SJohn Danielson 	}
1961b115575SJohn Danielson 	mapp->dam_da = softstate_p;
1971b115575SJohn Danielson 	mapp->dam_high = 1;
1981b115575SJohn Danielson 	bitset_resize(&mapp->dam_active_set, mapp->dam_size);
1991b115575SJohn Danielson 	bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
2001b115575SJohn Danielson 	bitset_resize(&mapp->dam_report_set, mapp->dam_size);
2011b115575SJohn Danielson 	return (DAM_SUCCESS);
2021b115575SJohn Danielson }
2031b115575SJohn Danielson 
2041b115575SJohn Danielson /*
2051b115575SJohn Danielson  * Destroy address map
2064c06356bSdh142964  *
2074c06356bSdh142964  * damapp:	address map
2084c06356bSdh142964  *
2094c06356bSdh142964  * Returns:	DAM_SUCCESS
2104c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
2114c06356bSdh142964  *		DAM_FAILURE	General failure
2124c06356bSdh142964  */
2134c06356bSdh142964 void
2144c06356bSdh142964 damap_destroy(damap_t *damapp)
2154c06356bSdh142964 {
2164c06356bSdh142964 	int i;
2174c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
2184c06356bSdh142964 
2194c06356bSdh142964 	ASSERT(mapp);
2204c06356bSdh142964 
2211b94a41bSChris Horne 	DTRACE_PROBE2(damap__destroy,
2221b94a41bSChris Horne 	    char *, mapp->dam_name, damap_t *, mapp);
2234c06356bSdh142964 
2241b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
2254c06356bSdh142964 
2264c06356bSdh142964 	/*
2271b115575SJohn Danielson 	 * prevent new reports from being added to the map
2284c06356bSdh142964 	 */
2291b115575SJohn Danielson 	mapp->dam_flags |= DAM_DESTROYPEND;
2304c06356bSdh142964 
2311b115575SJohn Danielson 	if (mapp->dam_high) {
2321b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2331b115575SJohn Danielson 		/*
2341b115575SJohn Danielson 		 * wait for outstanding reports to stabilize and cancel
2351b115575SJohn Danielson 		 * the timer for this map
2361b115575SJohn Danielson 		 */
23760aabb4cSChris Horne 		(void) damap_sync(damapp, 0);
2381b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
23960aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
2401b115575SJohn Danielson 
2411b115575SJohn Danielson 		/*
2421b115575SJohn Danielson 		 * map is at full stop
2431b115575SJohn Danielson 		 * release the contents of the map, invoking the
2441b115575SJohn Danielson 		 * detactivation protocol as addresses are released
2451b115575SJohn Danielson 		 */
2461b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2474c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++) {
2484c06356bSdh142964 			if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
2494c06356bSdh142964 				continue;
2501b115575SJohn Danielson 
2511b115575SJohn Danielson 			ASSERT(DAM_IN_REPORT(mapp, i) == 0);
2521b115575SJohn Danielson 
2531b115575SJohn Danielson 			if (DAM_IS_STABLE(mapp, i)) {
2541b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
2551b115575SJohn Danielson 			} else {
2564c06356bSdh142964 				ddi_strid_free(mapp->dam_addr_hash, i);
2574c06356bSdh142964 				ddi_soft_state_free(mapp->dam_da, i);
2584c06356bSdh142964 			}
2591b115575SJohn Danielson 		}
2604c06356bSdh142964 		ddi_strid_fini(&mapp->dam_addr_hash);
2614c06356bSdh142964 		ddi_soft_state_fini(&mapp->dam_da);
2621b115575SJohn Danielson 		kstat_delete(mapp->dam_kstatsp);
26360aabb4cSChris Horne 	} else
26460aabb4cSChris Horne 		mutex_exit(&mapp->dam_lock);
26560aabb4cSChris Horne 
2664c06356bSdh142964 	bitset_fini(&mapp->dam_active_set);
2674c06356bSdh142964 	bitset_fini(&mapp->dam_stable_set);
2684c06356bSdh142964 	bitset_fini(&mapp->dam_report_set);
2694c06356bSdh142964 	mutex_destroy(&mapp->dam_lock);
27060aabb4cSChris Horne 	cv_destroy(&mapp->dam_sync_cv);
2714c06356bSdh142964 	if (mapp->dam_name)
2724c06356bSdh142964 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
2734c06356bSdh142964 	kmem_free(mapp, sizeof (*mapp));
2744c06356bSdh142964 }
2754c06356bSdh142964 
2764c06356bSdh142964 /*
27760aabb4cSChris Horne  * Wait for map stability.  If sync was successfull then return 1.
27860aabb4cSChris Horne  * If called with a non-zero sync_usec, then a return value of 0 means a
27960aabb4cSChris Horne  * timeout occurred prior to sync completion. NOTE: if sync_usec is
28060aabb4cSChris Horne  * non-zero, it should be much longer than dam_stable_ticks.
2814c06356bSdh142964  *
2824c06356bSdh142964  * damapp:	address map
28360aabb4cSChris Horne  * sync_usec:	micorseconds until we give up on sync completion.
2844c06356bSdh142964  */
2851b115575SJohn Danielson #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND)
28660aabb4cSChris Horne int
28760aabb4cSChris Horne damap_sync(damap_t *damapp, int sync_usec)
28860aabb4cSChris Horne {
2894c06356bSdh142964 	dam_t	*mapp = (dam_t *)damapp;
29060aabb4cSChris Horne 	int	rv;
2914c06356bSdh142964 
2924c06356bSdh142964 	ASSERT(mapp);
2931b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__sync__start,
2941b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
2951b94a41bSChris Horne 	    int, sync_usec);
2964c06356bSdh142964 
2971b115575SJohn Danielson 	/*
29860aabb4cSChris Horne 	 * Block when waiting for
2991b115575SJohn Danielson 	 *	a) stabilization pending or a fullset update pending
30060aabb4cSChris Horne 	 *	b) the report set to finalize (bitset is null)
30160aabb4cSChris Horne 	 *	c) any scheduled timeouts to fire
3021b115575SJohn Danielson 	 */
30360aabb4cSChris Horne 	rv = 1;					/* return synced */
3044c06356bSdh142964 	mutex_enter(&mapp->dam_lock);
30560aabb4cSChris Horne again:	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
30660aabb4cSChris Horne 	    (!bitset_is_null(&mapp->dam_report_set)) ||
30760aabb4cSChris Horne 	    (mapp->dam_tid != 0)) {
3081b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__sync__waiting,
3091b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
31060aabb4cSChris Horne 
31160aabb4cSChris Horne 		/* Wait for condition relayed via timeout */
31260aabb4cSChris Horne 		if (sync_usec) {
31360aabb4cSChris Horne 			if (cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
31460aabb4cSChris Horne 			    drv_usectohz(sync_usec), TR_MICROSEC) == -1) {
31560aabb4cSChris Horne 				mapp->dam_sync_to_cnt++;
31660aabb4cSChris Horne 				rv = 0;		/* return timeout */
31760aabb4cSChris Horne 				break;
31860aabb4cSChris Horne 			}
31960aabb4cSChris Horne 		} else
32060aabb4cSChris Horne 			cv_wait(&mapp->dam_sync_cv, &mapp->dam_lock);
3214c06356bSdh142964 	}
3224c06356bSdh142964 
32360aabb4cSChris Horne 	if (rv) {
32460aabb4cSChris Horne 		/*
32560aabb4cSChris Horne 		 * Delay one stabilization time after the apparent sync above
32660aabb4cSChris Horne 		 * and verify accuracy - resync if not accurate.
32760aabb4cSChris Horne 		 */
32860aabb4cSChris Horne 		(void) cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
32960aabb4cSChris Horne 		    mapp->dam_stable_ticks, TR_MICROSEC);
33060aabb4cSChris Horne 		if (rv && ((mapp->dam_flags & WAITFOR_FLAGS) ||
33160aabb4cSChris Horne 		    (!bitset_is_null(&mapp->dam_report_set)) ||
33260aabb4cSChris Horne 		    (mapp->dam_tid != 0)))
33360aabb4cSChris Horne 			goto again;
33460aabb4cSChris Horne 	}
3354c06356bSdh142964 	mutex_exit(&mapp->dam_lock);
3364c06356bSdh142964 
3371b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__sync__end,
3381b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
3391b94a41bSChris Horne 	    int, rv);
34060aabb4cSChris Horne 	return (rv);
34160aabb4cSChris Horne }
34260aabb4cSChris Horne 
34360aabb4cSChris Horne /*
34460aabb4cSChris Horne  * Return 1 if active set is empty
34560aabb4cSChris Horne  */
34660aabb4cSChris Horne int
34760aabb4cSChris Horne damap_is_empty(damap_t *damapp)
34860aabb4cSChris Horne {
34960aabb4cSChris Horne 	dam_t	*mapp = (dam_t *)damapp;
35060aabb4cSChris Horne 	int	rv;
35160aabb4cSChris Horne 
35260aabb4cSChris Horne 	mutex_enter(&mapp->dam_lock);
35360aabb4cSChris Horne 	rv = bitset_is_null(&mapp->dam_active_set);
35460aabb4cSChris Horne 	mutex_exit(&mapp->dam_lock);
35560aabb4cSChris Horne 	return (rv);
3564c06356bSdh142964 }
3574c06356bSdh142964 
3584c06356bSdh142964 /*
3594c06356bSdh142964  * Get the name of a device address map
3604c06356bSdh142964  *
3614c06356bSdh142964  * damapp:	address map
3624c06356bSdh142964  *
3634c06356bSdh142964  * Returns:	name
3644c06356bSdh142964  */
3654c06356bSdh142964 char *
3664c06356bSdh142964 damap_name(damap_t *damapp)
3674c06356bSdh142964 {
3684c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
3694c06356bSdh142964 
3704c06356bSdh142964 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
3714c06356bSdh142964 }
3724c06356bSdh142964 
3734c06356bSdh142964 /*
37460aabb4cSChris Horne  * Get the current size of the device address map
37560aabb4cSChris Horne  *
37660aabb4cSChris Horne  * damapp:	address map
37760aabb4cSChris Horne  *
37860aabb4cSChris Horne  * Returns:	size
37960aabb4cSChris Horne  */
38060aabb4cSChris Horne int
38160aabb4cSChris Horne damap_size(damap_t *damapp)
38260aabb4cSChris Horne {
38360aabb4cSChris Horne 	dam_t *mapp = (dam_t *)damapp;
38460aabb4cSChris Horne 
38560aabb4cSChris Horne 	return (mapp->dam_size);
38660aabb4cSChris Horne }
38760aabb4cSChris Horne 
38860aabb4cSChris Horne /*
3894c06356bSdh142964  * Report an address to per-address report
3904c06356bSdh142964  *
3914c06356bSdh142964  * damapp:	address map handle
3924c06356bSdh142964  * address:	address in ascii string representation
3931b115575SJohn Danielson  * addridp:	address ID
3944c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
3954c06356bSdh142964  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
3964c06356bSdh142964  *
3974c06356bSdh142964  * Returns:	DAM_SUCCESS
3984c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
3994c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
4004c06356bSdh142964  */
4014c06356bSdh142964 int
4021b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp,
4031b115575SJohn Danielson     nvlist_t *nvl, void *addr_priv)
4044c06356bSdh142964 {
4054c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
4064c06356bSdh142964 	id_t addrid;
4074c06356bSdh142964 	dam_da_t *passp;
4084c06356bSdh142964 
4091b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4104c06356bSdh142964 		return (DAM_EINVAL);
4114c06356bSdh142964 
4121b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__add,
4131b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
4141b94a41bSChris Horne 	    char *, address);
4151b115575SJohn Danielson 
4161b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4171b115575SJohn Danielson 	if ((dam_map_alloc(mapp) != DAM_SUCCESS) ||
4181b115575SJohn Danielson 	    ((addrid = dam_get_addrid(mapp, address)) == 0)) {
4191b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4204c06356bSdh142964 		return (DAM_MAPFULL);
4214c06356bSdh142964 	}
4224c06356bSdh142964 
4234c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4244c06356bSdh142964 	ASSERT(passp != NULL);
4254c06356bSdh142964 
4264c06356bSdh142964 	/*
4274c06356bSdh142964 	 * If re-reporting the same address (add or remove) clear
4284c06356bSdh142964 	 * the existing report
4294c06356bSdh142964 	 */
4304c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
4311b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__add__jitter,
4321b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
4331b94a41bSChris Horne 		    char *, address);
4341b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4351b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4364c06356bSdh142964 		passp->da_jitter++;
4374c06356bSdh142964 	}
4384c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
4394c06356bSdh142964 	if (nvl)
4404c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
4414c06356bSdh142964 
4421b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD);
4431b115575SJohn Danielson 	if (addridp != NULL)
4441b115575SJohn Danielson 		*addridp = (damap_id_t)addrid;
4451b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4464c06356bSdh142964 	return (DAM_SUCCESS);
4474c06356bSdh142964 }
4484c06356bSdh142964 
4494c06356bSdh142964 /*
4504c06356bSdh142964  * Report removal of address from per-address report
4514c06356bSdh142964  *
4524c06356bSdh142964  * damapp:	address map
4534c06356bSdh142964  * address:	address in ascii string representation
4544c06356bSdh142964  *
4554c06356bSdh142964  * Returns:	DAM_SUCCESS
4564c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
4574c06356bSdh142964  *		DAM_FAILURE	General failure
4584c06356bSdh142964  */
4594c06356bSdh142964 int
4604c06356bSdh142964 damap_addr_del(damap_t *damapp, char *address)
4614c06356bSdh142964 {
4624c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
4634c06356bSdh142964 	id_t addrid;
4644c06356bSdh142964 	dam_da_t *passp;
4654c06356bSdh142964 
4661b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4674c06356bSdh142964 		return (DAM_EINVAL);
4684c06356bSdh142964 
4691b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__del,
4701b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
4711b94a41bSChris Horne 	    char *, address);
4721b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4731b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
4741b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4751b115575SJohn Danielson 		return (DAM_MAPFULL);
4761b115575SJohn Danielson 	}
4771b115575SJohn Danielson 
4781b115575SJohn Danielson 	/*
4791b115575SJohn Danielson 	 * if reporting the removal of an address which is not in the map
4801b115575SJohn Danielson 	 * return success
4811b115575SJohn Danielson 	 */
4824c06356bSdh142964 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
4831b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4844c06356bSdh142964 		return (DAM_SUCCESS);
4854c06356bSdh142964 	}
4864c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4874c06356bSdh142964 	ASSERT(passp);
4884c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
4891b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__del__jitter,
4901b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
4911b94a41bSChris Horne 		    char *, address);
4921b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4931b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4944c06356bSdh142964 		passp->da_jitter++;
4954c06356bSdh142964 	}
4961b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL);
4971b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4984c06356bSdh142964 	return (DAM_SUCCESS);
4994c06356bSdh142964 }
5004c06356bSdh142964 
5010b53804eSReed static int
5020b53804eSReed damap_addrset_flush_locked(damap_t *damapp)
5030b53804eSReed {
5040b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
5050b53804eSReed 	int	idx;
5060b53804eSReed 
5070b53804eSReed 	ASSERT(mapp);
5080b53804eSReed 	ASSERT(mutex_owned(&mapp->dam_lock));
5090b53804eSReed 	if (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) {
5100b53804eSReed 		return (DAM_EINVAL);
5110b53804eSReed 	}
5120b53804eSReed 
5131b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__flush__locked__enter,
5141b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
5150b53804eSReed 	if (mapp->dam_flags & DAM_SETADD) {
5161b94a41bSChris Horne 		DTRACE_PROBE2(damap__addrset__flush__locked__reset,
5171b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
5180b53804eSReed 
5190b53804eSReed 		/*
5200b53804eSReed 		 * cancel stabilization timeout
5210b53804eSReed 		 */
52260aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
5230b53804eSReed 		DAM_INCR_STAT(mapp, dam_jitter);
5240b53804eSReed 
5250b53804eSReed 		/*
5260b53804eSReed 		 * clear pending reports
5270b53804eSReed 		 */
5280b53804eSReed 		for (idx = 1; idx < mapp->dam_high; idx++) {
5290b53804eSReed 			if (DAM_IN_REPORT(mapp, idx)) {
5300b53804eSReed 				dam_addr_report_release(mapp, idx);
5310b53804eSReed 			}
5320b53804eSReed 		}
5330b53804eSReed 
5340b53804eSReed 		bitset_zero(&mapp->dam_report_set);
5350b53804eSReed 		mapp->dam_flags &= ~DAM_SETADD;
53660aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
5370b53804eSReed 	}
5380b53804eSReed 
5390b53804eSReed 	return (DAM_SUCCESS);
5400b53804eSReed }
5410b53804eSReed 
5424c06356bSdh142964 /*
5434c06356bSdh142964  * Initiate full-set report
5444c06356bSdh142964  *
5454c06356bSdh142964  * damapp:	address map
5464c06356bSdh142964  *
5474c06356bSdh142964  * Returns:	DAM_SUCCESS
5484c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
5494c06356bSdh142964  */
5504c06356bSdh142964 int
5514c06356bSdh142964 damap_addrset_begin(damap_t *damapp)
5524c06356bSdh142964 {
5534c06356bSdh142964 	dam_t	*mapp = (dam_t *)damapp;
5540b53804eSReed 	int	rv;
5554c06356bSdh142964 
5560b53804eSReed 	if (mapp == NULL) {
5574c06356bSdh142964 		return (DAM_EINVAL);
5580b53804eSReed 	}
5594c06356bSdh142964 
5601b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__begin,
5611b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
5620b53804eSReed 
5631b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
5641b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
5651b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5660b53804eSReed 
5671b115575SJohn Danielson 		return (DAM_MAPFULL);
5681b115575SJohn Danielson 	}
5690b53804eSReed 
5700b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
5710b53804eSReed 	if (rv == DAM_SUCCESS) {
5720b53804eSReed 		mapp->dam_flags |= DAM_SETADD;
5730b53804eSReed 	}
5740b53804eSReed 	mutex_exit(&mapp->dam_lock);
5750b53804eSReed 
5760b53804eSReed 	return (rv);
5770b53804eSReed }
5781b115575SJohn Danielson 
5791b115575SJohn Danielson /*
5800b53804eSReed  * Cancel full-set report
5810b53804eSReed  *
5820b53804eSReed  * damapp:	address map
5830b53804eSReed  *
5840b53804eSReed  * Returns:	DAM_SUCCESS
5850b53804eSReed  *		DAM_EINVAL	Invalid argument(s)
5861b115575SJohn Danielson  */
5870b53804eSReed int
5880b53804eSReed damap_addrset_flush(damap_t *damapp)
5890b53804eSReed {
5900b53804eSReed 	int	rv;
5910b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
5920b53804eSReed 
5930b53804eSReed 	if (mapp == NULL) {
5940b53804eSReed 		return (DAM_EINVAL);
5954c06356bSdh142964 	}
5960b53804eSReed 
5971b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__flush,
5981b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
5990b53804eSReed 
6000b53804eSReed 	mutex_enter(&mapp->dam_lock);
6010b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
6021b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6030b53804eSReed 
6040b53804eSReed 	return (rv);
6054c06356bSdh142964 }
6064c06356bSdh142964 
6074c06356bSdh142964 /*
6084c06356bSdh142964  * Report address to full-set report
6094c06356bSdh142964  *
6104c06356bSdh142964  * damapp:	address map handle
6114c06356bSdh142964  * address:	address in ascii string representation
6124c06356bSdh142964  * rindx:	index if address stabilizes
6134c06356bSdh142964  * nvl:		optional nvlist of configuration-private data
6144c06356bSdh142964  * addr_priv:	optional provider-private data (passed to activate/release cb)
6154c06356bSdh142964  *
6164c06356bSdh142964  * Returns:	DAM_SUCCESS
6174c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
6184c06356bSdh142964  *		DAM_MAPFULL	address map exhausted
6194c06356bSdh142964  *		DAM_FAILURE	General failure
6204c06356bSdh142964  */
6214c06356bSdh142964 int
6224c06356bSdh142964 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
6234c06356bSdh142964     nvlist_t *nvl, void *addr_priv)
6244c06356bSdh142964 {
6254c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6264c06356bSdh142964 	id_t addrid;
6274c06356bSdh142964 	dam_da_t *passp;
6284c06356bSdh142964 
6291b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6304c06356bSdh142964 		return (DAM_EINVAL);
6314c06356bSdh142964 
6321b94a41bSChris Horne 	DTRACE_PROBE3(damap__addrset__add,
6331b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp, char *, address);
6344c06356bSdh142964 
6351b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6361b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6371b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6381b115575SJohn Danielson 		return (DAM_FAILURE);
6391b115575SJohn Danielson 	}
6401b115575SJohn Danielson 
6414c06356bSdh142964 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
6421b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6434c06356bSdh142964 		return (DAM_MAPFULL);
6444c06356bSdh142964 	}
6454c06356bSdh142964 
6464c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
6474c06356bSdh142964 	ASSERT(passp);
6484c06356bSdh142964 	if (DAM_IN_REPORT(mapp, addrid)) {
6491b94a41bSChris Horne 		DTRACE_PROBE3(damap__addrset__add__jitter,
6501b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
6511b94a41bSChris Horne 		    char *, address);
6521b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
6534c06356bSdh142964 		passp->da_jitter++;
6544c06356bSdh142964 	}
6554c06356bSdh142964 	passp->da_ppriv_rpt = addr_priv;
6564c06356bSdh142964 	if (nvl)
6574c06356bSdh142964 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
6584c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
6594c06356bSdh142964 	if (ridx)
6604c06356bSdh142964 		*ridx = (damap_id_t)addrid;
6611b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6624c06356bSdh142964 	return (DAM_SUCCESS);
6634c06356bSdh142964 }
6644c06356bSdh142964 
6654c06356bSdh142964 /*
6664c06356bSdh142964  * Commit full-set report for stabilization
6674c06356bSdh142964  *
6684c06356bSdh142964  * damapp:	address map handle
6694c06356bSdh142964  * flags:	(currently 0)
6704c06356bSdh142964  *
6714c06356bSdh142964  * Returns:	DAM_SUCCESS
6724c06356bSdh142964  *		DAM_EINVAL	Invalid argument(s)
6734c06356bSdh142964  *		DAM_FAILURE	General failure
6744c06356bSdh142964  */
6754c06356bSdh142964 int
6764c06356bSdh142964 damap_addrset_end(damap_t *damapp, int flags)
6774c06356bSdh142964 {
6784c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
6794c06356bSdh142964 	int i;
6804c06356bSdh142964 
6811b115575SJohn Danielson 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6824c06356bSdh142964 		return (DAM_EINVAL);
6834c06356bSdh142964 
6841b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__end,
6851b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
6864c06356bSdh142964 
6871b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6881b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6891b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6901b115575SJohn Danielson 		return (DAM_FAILURE);
6911b115575SJohn Danielson 	}
6921b115575SJohn Danielson 
6931b115575SJohn Danielson 	if (flags & DAMAP_END_RESET) {
6941b94a41bSChris Horne 		DTRACE_PROBE2(damap__addrset__end__reset,
6951b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
69660aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
6974c06356bSdh142964 		for (i = 1; i < mapp->dam_high; i++)
6984c06356bSdh142964 			if (DAM_IN_REPORT(mapp, i))
6991b115575SJohn Danielson 				dam_addr_report_release(mapp, i);
7004c06356bSdh142964 	} else {
7014c06356bSdh142964 		mapp->dam_last_update = gethrtime();
70260aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
70360aabb4cSChris Horne 		    mapp->dam_stable_ticks);
7044c06356bSdh142964 	}
7051b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7064c06356bSdh142964 	return (DAM_SUCCESS);
7074c06356bSdh142964 }
7084c06356bSdh142964 
7094c06356bSdh142964 /*
7104c06356bSdh142964  * Return nvlist registered with reported address
7114c06356bSdh142964  *
7124c06356bSdh142964  * damapp:	address map handle
7131b115575SJohn Danielson  * addrid:	address ID
7144c06356bSdh142964  *
7154c06356bSdh142964  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
7164c06356bSdh142964  *		NULL
7174c06356bSdh142964  */
7184c06356bSdh142964 nvlist_t *
7194c06356bSdh142964 damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
7204c06356bSdh142964 {
7214c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7224c06356bSdh142964 	dam_da_t *pass;
7234c06356bSdh142964 
7241b115575SJohn Danielson 	if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) {
7251b115575SJohn Danielson 		if (pass = ddi_get_soft_state(mapp->dam_da, addrid))
7264c06356bSdh142964 			return (pass->da_nvl);
7274c06356bSdh142964 	}
7284c06356bSdh142964 	return (NULL);
7294c06356bSdh142964 }
7304c06356bSdh142964 
7314c06356bSdh142964 /*
7324c06356bSdh142964  * Return address string
7334c06356bSdh142964  *
7344c06356bSdh142964  * damapp:	address map handle
7351b115575SJohn Danielson  * addrid:	address ID
7364c06356bSdh142964  *
7374c06356bSdh142964  * Returns:	char *		Address string
7384c06356bSdh142964  *		NULL
7394c06356bSdh142964  */
7404c06356bSdh142964 char *
7411b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid)
7424c06356bSdh142964 {
7434c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7444c06356bSdh142964 
7451b115575SJohn Danielson 	if (mapp->dam_high)
7461b115575SJohn Danielson 		return (ddi_strid_id2str(mapp->dam_addr_hash, addrid));
7471b115575SJohn Danielson 	else
7481b115575SJohn Danielson 		return (NULL);
7494c06356bSdh142964 }
7504c06356bSdh142964 
7514c06356bSdh142964 /*
7524c06356bSdh142964  * Release address reference in map
7534c06356bSdh142964  *
7544c06356bSdh142964  * damapp:	address map handle
7551b115575SJohn Danielson  * addrid:	address ID
7564c06356bSdh142964  */
7574c06356bSdh142964 void
7584c06356bSdh142964 damap_id_rele(damap_t *damapp, damap_id_t addrid)
7594c06356bSdh142964 {
7604c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7611b115575SJohn Danielson 	dam_da_t *passp;
7621b115575SJohn Danielson 	char *addr;
7634c06356bSdh142964 
7641b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7651b115575SJohn Danielson 	ASSERT(passp);
7661b115575SJohn Danielson 
7671b115575SJohn Danielson 	addr = damap_id2addr(damapp, addrid);
7681b94a41bSChris Horne 	DTRACE_PROBE4(damap__id__rele,
7691b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
7701b94a41bSChris Horne 	    char *, addr, int, passp->da_ref);
7711b115575SJohn Danielson 
7721b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7731b115575SJohn Danielson 
7741b115575SJohn Danielson 	/*
7751b115575SJohn Danielson 	 * teardown address if last outstanding reference
7761b115575SJohn Danielson 	 */
7771b115575SJohn Danielson 	if (--passp->da_ref == 0)
7781b115575SJohn Danielson 		dam_addr_release(mapp, (id_t)addrid);
7791b115575SJohn Danielson 
7801b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7814c06356bSdh142964 }
7824c06356bSdh142964 
7834c06356bSdh142964 /*
7844c06356bSdh142964  * Return current reference count on address reference in map
7854c06356bSdh142964  *
7864c06356bSdh142964  * damapp:	address map handle
7871b115575SJohn Danielson  * addrid:	address ID
7884c06356bSdh142964  *
7894c06356bSdh142964  * Returns:	DAM_SUCCESS
7904c06356bSdh142964  *		DAM_FAILURE
7914c06356bSdh142964  */
7924c06356bSdh142964 int
7931b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid)
7944c06356bSdh142964 {
7954c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
7964c06356bSdh142964 	dam_da_t *passp;
7974c06356bSdh142964 	int ref = -1;
7984c06356bSdh142964 
7991b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8004c06356bSdh142964 	if (passp)
8014c06356bSdh142964 		ref = passp->da_ref;
8021b115575SJohn Danielson 
8034c06356bSdh142964 	return (ref);
8044c06356bSdh142964 }
8054c06356bSdh142964 
8064c06356bSdh142964 /*
8074c06356bSdh142964  * Return next address ID in list
8084c06356bSdh142964  *
8094c06356bSdh142964  * damapp:	address map handle
8104c06356bSdh142964  * damap_list:	address ID list passed to config|unconfig
8114c06356bSdh142964  *		returned by look by lookup_all
8124c06356bSdh142964  * last:	last ID returned, 0 is start of list
8134c06356bSdh142964  *
8144c06356bSdh142964  * Returns:	addrid		Next ID from the list
8154c06356bSdh142964  *		0		End of the list
8164c06356bSdh142964  */
8174c06356bSdh142964 damap_id_t
8184c06356bSdh142964 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
8194c06356bSdh142964 {
8204c06356bSdh142964 	int i, start;
8214c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8224c06356bSdh142964 	bitset_t *dam_list = (bitset_t *)damap_list;
8234c06356bSdh142964 
8244c06356bSdh142964 	if (!mapp || !dam_list)
8254c06356bSdh142964 		return ((damap_id_t)0);
8264c06356bSdh142964 
8274c06356bSdh142964 	start = (int)last + 1;
8281b115575SJohn Danielson 	for (i = start; i < mapp->dam_high; i++) {
8291b115575SJohn Danielson 		if (bitset_in_set(dam_list, i)) {
8304c06356bSdh142964 			return ((damap_id_t)i);
8311b115575SJohn Danielson 		}
8321b115575SJohn Danielson 	}
8334c06356bSdh142964 	return ((damap_id_t)0);
8344c06356bSdh142964 }
8354c06356bSdh142964 
8364c06356bSdh142964 /*
8374c06356bSdh142964  * Set config private data
8384c06356bSdh142964  *
8394c06356bSdh142964  * damapp:	address map handle
8401b115575SJohn Danielson  * addrid:	address ID
8414c06356bSdh142964  * cfg_priv:	configuration private data
8424c06356bSdh142964  *
8434c06356bSdh142964  */
8444c06356bSdh142964 void
8451b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv)
8464c06356bSdh142964 {
8474c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8484c06356bSdh142964 	dam_da_t *passp;
8494c06356bSdh142964 
8501b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8511b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8524c06356bSdh142964 	if (!passp) {
8531b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8544c06356bSdh142964 		return;
8554c06356bSdh142964 	}
8564c06356bSdh142964 	passp->da_cfg_priv = cfg_priv;
8571b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8584c06356bSdh142964 }
8594c06356bSdh142964 
8604c06356bSdh142964 /*
8614c06356bSdh142964  * Get config private data
8624c06356bSdh142964  *
8634c06356bSdh142964  * damapp:	address map handle
8641b115575SJohn Danielson  * addrid:	address ID
8654c06356bSdh142964  *
8664c06356bSdh142964  * Returns:	configuration private data
8674c06356bSdh142964  */
8684c06356bSdh142964 void *
8691b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid)
8704c06356bSdh142964 {
8714c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
8724c06356bSdh142964 	dam_da_t *passp;
8734c06356bSdh142964 	void *rv;
8744c06356bSdh142964 
8751b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8761b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8774c06356bSdh142964 	if (!passp) {
8781b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8794c06356bSdh142964 		return (NULL);
8804c06356bSdh142964 	}
8814c06356bSdh142964 	rv = passp->da_cfg_priv;
8821b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8834c06356bSdh142964 	return (rv);
8844c06356bSdh142964 }
8854c06356bSdh142964 
8864c06356bSdh142964 /*
8874c06356bSdh142964  * Lookup a single address in the active address map
8884c06356bSdh142964  *
8894c06356bSdh142964  * damapp:	address map handle
8904c06356bSdh142964  * address:	address string
8914c06356bSdh142964  *
8924c06356bSdh142964  * Returns:	ID of active/stable address
8934c06356bSdh142964  *		0	Address not in stable set
8944c06356bSdh142964  *
8954c06356bSdh142964  * Future: Allow the caller to wait for stabilize before returning not found.
8964c06356bSdh142964  */
8974c06356bSdh142964 damap_id_t
8984c06356bSdh142964 damap_lookup(damap_t *damapp, char *address)
8994c06356bSdh142964 {
9004c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
9014c06356bSdh142964 	id_t addrid = 0;
9024c06356bSdh142964 	dam_da_t *passp = NULL;
9034c06356bSdh142964 
9041b94a41bSChris Horne 	DTRACE_PROBE3(damap__lookup,
9051b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
9061b94a41bSChris Horne 	    char *, address);
9071b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9081b115575SJohn Danielson 	if (!mapp->dam_high)
9091b115575SJohn Danielson 		addrid = 0;
9101b115575SJohn Danielson 	else
9114c06356bSdh142964 		addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
9124c06356bSdh142964 	if (addrid) {
9134c06356bSdh142964 		if (DAM_IS_STABLE(mapp, addrid)) {
9144c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
9154c06356bSdh142964 			ASSERT(passp);
9164c06356bSdh142964 			if (passp) {
9174c06356bSdh142964 				passp->da_ref++;
9184c06356bSdh142964 			} else {
9194c06356bSdh142964 				addrid = 0;
9204c06356bSdh142964 			}
9214c06356bSdh142964 		} else {
9224c06356bSdh142964 			addrid = 0;
9234c06356bSdh142964 		}
9244c06356bSdh142964 	}
9251b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
9261b94a41bSChris Horne 	DTRACE_PROBE4(damap__lookup__return,
9271b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
9281b94a41bSChris Horne 	    char *, address, int, addrid);
9294c06356bSdh142964 	return ((damap_id_t)addrid);
9304c06356bSdh142964 }
9314c06356bSdh142964 
9324c06356bSdh142964 
9334c06356bSdh142964 /*
9344c06356bSdh142964  * Return the list of stable addresses in the map
9354c06356bSdh142964  *
9364c06356bSdh142964  * damapp:	address map handle
9374c06356bSdh142964  * id_listp:	pointer to list of address IDs in stable map (returned)
9384c06356bSdh142964  *
9394c06356bSdh142964  * Returns:	# of entries returned in alist
9404c06356bSdh142964  */
9414c06356bSdh142964 int
9424c06356bSdh142964 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
9434c06356bSdh142964 {
9444c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
9454c06356bSdh142964 	int mapsz = mapp->dam_size;
9464c06356bSdh142964 	int n_ids, i;
9474c06356bSdh142964 	bitset_t *bsp;
9481b115575SJohn Danielson 	char	 *addrp;
9494c06356bSdh142964 	dam_da_t *passp;
9504c06356bSdh142964 
9511b94a41bSChris Horne 	DTRACE_PROBE2(damap__lookup__all,
9521b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
9531b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9541b115575SJohn Danielson 	if (!mapp->dam_high) {
9551b115575SJohn Danielson 		*id_listp = (damap_id_list_t)NULL;
9561b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9571b94a41bSChris Horne 		DTRACE_PROBE2(damap__lookup__all__nomap,
9581b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
9591b115575SJohn Danielson 		return (0);
9601b115575SJohn Danielson 	}
9614c06356bSdh142964 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
9624c06356bSdh142964 	bitset_init(bsp);
9634c06356bSdh142964 	bitset_resize(bsp, mapsz);
9644c06356bSdh142964 	bitset_copy(&mapp->dam_active_set, bsp);
9654c06356bSdh142964 	for (n_ids = 0, i = 1; i < mapsz; i++) {
9664c06356bSdh142964 		if (bitset_in_set(bsp, i)) {
9674c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, i);
9684c06356bSdh142964 			ASSERT(passp);
9694c06356bSdh142964 			if (passp) {
9701b115575SJohn Danielson 				addrp = damap_id2addr(damapp, i);
9711b94a41bSChris Horne 				DTRACE_PROBE3(damap__lookup__all__item,
9721b94a41bSChris Horne 				    char *, mapp->dam_name, dam_t *, mapp,
9731b94a41bSChris Horne 				    char *, addrp);
9744c06356bSdh142964 				passp->da_ref++;
9754c06356bSdh142964 				n_ids++;
9764c06356bSdh142964 			}
9774c06356bSdh142964 		}
9784c06356bSdh142964 	}
9794c06356bSdh142964 	if (n_ids) {
9804c06356bSdh142964 		*id_listp = (damap_id_list_t)bsp;
9811b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9824c06356bSdh142964 		return (n_ids);
9834c06356bSdh142964 	} else {
9844c06356bSdh142964 		*id_listp = (damap_id_list_t)NULL;
9854c06356bSdh142964 		bitset_fini(bsp);
9864c06356bSdh142964 		kmem_free(bsp, sizeof (*bsp));
9871b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9884c06356bSdh142964 		return (0);
9894c06356bSdh142964 	}
9904c06356bSdh142964 }
9914c06356bSdh142964 
9924c06356bSdh142964 /*
9934c06356bSdh142964  * Release the address list returned by damap_lookup_all()
9944c06356bSdh142964  *
9954c06356bSdh142964  * mapp:	address map handle
9964c06356bSdh142964  * id_list:	list of address IDs returned in damap_lookup_all()
9974c06356bSdh142964  */
9984c06356bSdh142964 void
9994c06356bSdh142964 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
10004c06356bSdh142964 {
10014c06356bSdh142964 	dam_t *mapp = (dam_t *)damapp;
10024c06356bSdh142964 	int i;
10034c06356bSdh142964 
10044c06356bSdh142964 	if (id_list == NULL)
10054c06356bSdh142964 		return;
10064c06356bSdh142964 
10071b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10084c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
10094c06356bSdh142964 		if (bitset_in_set((bitset_t *)id_list, i))
10101b115575SJohn Danielson 			(void) dam_addr_release(mapp, i);
10114c06356bSdh142964 	}
10121b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10134c06356bSdh142964 	bitset_fini((bitset_t *)id_list);
10144c06356bSdh142964 	kmem_free((void *)id_list, sizeof (bitset_t));
10154c06356bSdh142964 }
10164c06356bSdh142964 
10174c06356bSdh142964 /*
10181b115575SJohn Danielson  * activate an address that has passed the stabilization interval
10194c06356bSdh142964  */
10204c06356bSdh142964 static void
10211b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid)
10224c06356bSdh142964 {
10234c06356bSdh142964 	dam_da_t *passp;
10241b115575SJohn Danielson 	int config_rv;
10254c06356bSdh142964 	char *addrstr;
10264c06356bSdh142964 
10271b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10281b115575SJohn Danielson 	bitset_add(&mapp->dam_active_set, addrid);
10291b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
10304c06356bSdh142964 	ASSERT(passp);
10311b115575SJohn Danielson 
10324c06356bSdh142964 	/*
10334c06356bSdh142964 	 * copy the reported nvlist and provider private data
10344c06356bSdh142964 	 */
10351b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10361b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__activate__start,
10371b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
10381b94a41bSChris Horne 	    char *, addrstr);
10394c06356bSdh142964 	passp->da_nvl = passp->da_nvl_rpt;
10404c06356bSdh142964 	passp->da_ppriv = passp->da_ppriv_rpt;
10414c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
10424c06356bSdh142964 	passp->da_nvl_rpt = NULL;
10434c06356bSdh142964 	passp->da_last_stable = gethrtime();
10444c06356bSdh142964 	passp->da_stable_cnt++;
10451b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10461b115575SJohn Danielson 	if (mapp->dam_activate_cb) {
10471b115575SJohn Danielson 		(*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr,
10481b115575SJohn Danielson 		    addrid, &passp->da_ppriv_rpt);
10494c06356bSdh142964 	}
10504c06356bSdh142964 
10514c06356bSdh142964 	/*
10521b115575SJohn Danielson 	 * call the address-specific configuration action as part of
10531b115575SJohn Danielson 	 * activation.
10544c06356bSdh142964 	 */
10551b115575SJohn Danielson 	config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp,
10561b115575SJohn Danielson 	    addrid);
10571b115575SJohn Danielson 	if (config_rv != DAM_SUCCESS) {
10581b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
10591b115575SJohn Danielson 		passp->da_flags |= DA_FAILED_CONFIG;
10601b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
10611b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__activate__config__failure,
10621b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
10631b94a41bSChris Horne 		    char *, addrstr);
1064d189c170SReed 		dam_deact_cleanup(mapp, addrid, addrstr,
1065d189c170SReed 		    DAMAP_DEACT_RSN_CFG_FAIL);
1066d189c170SReed 	} else {
10671b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__activate__end,
10681b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
10691b94a41bSChris Horne 		    char *, addrstr);
10704c06356bSdh142964 	}
10714c06356bSdh142964 }
10724c06356bSdh142964 
10734c06356bSdh142964 /*
10741b115575SJohn Danielson  * deactivate a previously stable address
10754c06356bSdh142964  */
10764c06356bSdh142964 static void
10771b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid)
10784c06356bSdh142964 {
10791b115575SJohn Danielson 	char *addrstr;
10804c06356bSdh142964 
10811b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10821b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__deactivate__start,
10831b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
10841b94a41bSChris Horne 	    char *, addrstr);
10851b115575SJohn Danielson 
10861b115575SJohn Danielson 	/*
10871b115575SJohn Danielson 	 * call the unconfiguration callback
10881b115575SJohn Danielson 	 */
10891b115575SJohn Danielson 	(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid);
1090d189c170SReed 	dam_deact_cleanup(mapp, addrid, addrstr, DAMAP_DEACT_RSN_GONE);
1091d189c170SReed }
1092d189c170SReed 
1093d189c170SReed static void
1094d189c170SReed dam_deact_cleanup(dam_t *mapp, id_t addrid, char *addrstr,
1095d189c170SReed     damap_deact_rsn_t deact_rsn)
1096d189c170SReed {
1097d189c170SReed 	dam_da_t *passp;
1098d189c170SReed 
10991b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
11001b115575SJohn Danielson 	ASSERT(passp);
11011b115575SJohn Danielson 	if (mapp->dam_deactivate_cb)
11021b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
11031b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
1104d189c170SReed 		    addrid, passp->da_ppriv, deact_rsn);
11051b115575SJohn Danielson 
11061b115575SJohn Danielson 	/*
11071b115575SJohn Danielson 	 * clear the active bit and free the backing info for
11081b115575SJohn Danielson 	 * this address
11091b115575SJohn Danielson 	 */
11101b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
11111b115575SJohn Danielson 	bitset_del(&mapp->dam_active_set, addrid);
11121b115575SJohn Danielson 	passp->da_ppriv = NULL;
11131b115575SJohn Danielson 	nvlist_free(passp->da_nvl);
11141b115575SJohn Danielson 	passp->da_nvl = NULL;
11151b115575SJohn Danielson 	passp->da_ppriv_rpt = NULL;
11161b115575SJohn Danielson 	nvlist_free(passp->da_nvl_rpt);
11171b115575SJohn Danielson 	passp->da_nvl_rpt = NULL;
11181b115575SJohn Danielson 
11191b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__deactivate__end,
11201b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
11211b94a41bSChris Horne 	    char *, addrstr);
11221b115575SJohn Danielson 
11231b115575SJohn Danielson 	(void) dam_addr_release(mapp, addrid);
11241b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
11251b115575SJohn Danielson }
11261b115575SJohn Danielson 
11271b115575SJohn Danielson /*
11281b115575SJohn Danielson  * taskq callback for multi-thread activation
11291b115575SJohn Danielson  */
11301b115575SJohn Danielson static void
11311b115575SJohn Danielson dam_tq_config(void *arg)
11321b115575SJohn Danielson {
11331b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11341b115575SJohn Danielson 
11351b115575SJohn Danielson 	dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id);
11361b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11371b115575SJohn Danielson }
11381b115575SJohn Danielson 
11391b115575SJohn Danielson /*
11401b115575SJohn Danielson  * taskq callback for multi-thread deactivation
11411b115575SJohn Danielson  */
11421b115575SJohn Danielson static void
11431b115575SJohn Danielson dam_tq_unconfig(void *arg)
11441b115575SJohn Danielson {
11451b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11461b115575SJohn Danielson 
11471b115575SJohn Danielson 	dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id);
11481b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11491b115575SJohn Danielson }
11501b115575SJohn Danielson 
11511b115575SJohn Danielson /*
11521b115575SJohn Danielson  * Activate a set of stabilized addresses
11531b115575SJohn Danielson  */
11541b115575SJohn Danielson static void
11551b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate)
11561b115575SJohn Danielson {
11571b115575SJohn Danielson 
11581b115575SJohn Danielson 	int i, nset;
11591b115575SJohn Danielson 	taskq_t *tqp = NULL;
11601b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
11611b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
11621b115575SJohn Danielson 	extern pri_t maxclsyspri;
11631b115575SJohn Danielson 
11641b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
11651b115575SJohn Danielson 		/*
11661b115575SJohn Danielson 		 * calculate the # of taskq threads to create
11671b115575SJohn Danielson 		 */
11681b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
11691b115575SJohn Danielson 			if (bitset_in_set(activate, i))
11701b115575SJohn Danielson 				nset++;
11711b115575SJohn Danielson 		ASSERT(nset);
11721b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name);
11731b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
11741b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
11751b115575SJohn Danielson 	}
11761b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
11771b115575SJohn Danielson 		if (bitset_in_set(activate, i)) {
11781b115575SJohn Danielson 			if (!tqp)
11791b115575SJohn Danielson 				dam_addr_activate(mapp, i);
11801b115575SJohn Danielson 			else {
11811b115575SJohn Danielson 				/*
11821b115575SJohn Danielson 				 * multi-threaded activation
11831b115575SJohn Danielson 				 */
11841b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
11851b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
11861b115575SJohn Danielson 				tqd->tqd_id = i;
11871b115575SJohn Danielson 				(void) taskq_dispatch(tqp, dam_tq_config,
118864109744SChris Horne 				    tqd, TQ_SLEEP);
11891b115575SJohn Danielson 			}
11901b115575SJohn Danielson 		}
11911b115575SJohn Danielson 	}
11921b115575SJohn Danielson 	if (tqp) {
11931b115575SJohn Danielson 		taskq_wait(tqp);
11941b115575SJohn Danielson 		taskq_destroy(tqp);
11951b115575SJohn Danielson 	}
11961b115575SJohn Danielson }
11971b115575SJohn Danielson 
11981b115575SJohn Danielson /*
11991b115575SJohn Danielson  * Deactivate a set of stabilized addresses
12001b115575SJohn Danielson  */
12011b115575SJohn Danielson static void
12021b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate)
12031b115575SJohn Danielson {
12041b115575SJohn Danielson 	int i, nset;
12051b115575SJohn Danielson 	taskq_t *tqp = NULL;
12061b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
12071b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
12081b115575SJohn Danielson 
12091b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__deactivate,
12101b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
12111b115575SJohn Danielson 
12121b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
12131b115575SJohn Danielson 		/*
12141b115575SJohn Danielson 		 * compute the # of taskq threads to dispatch
12151b115575SJohn Danielson 		 */
12161b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
12171b115575SJohn Danielson 			if (bitset_in_set(deactivate, i))
12181b115575SJohn Danielson 				nset++;
12191b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "deactv-%s",
12201b115575SJohn Danielson 		    mapp->dam_name);
12211b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
12221b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
12231b115575SJohn Danielson 	}
12241b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
12251b115575SJohn Danielson 		if (bitset_in_set(deactivate, i)) {
12261b115575SJohn Danielson 			if (!tqp) {
12271b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
12281b115575SJohn Danielson 			} else {
12291b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
12301b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
12311b115575SJohn Danielson 				tqd->tqd_id = i;
12321b115575SJohn Danielson 				(void) taskq_dispatch(tqp,
123364109744SChris Horne 				    dam_tq_unconfig, tqd, TQ_SLEEP);
12341b115575SJohn Danielson 			}
12351b115575SJohn Danielson 		}
12361b115575SJohn Danielson 	}
12371b115575SJohn Danielson 
12381b115575SJohn Danielson 	if (tqp) {
12391b115575SJohn Danielson 		taskq_wait(tqp);
12401b115575SJohn Danielson 		taskq_destroy(tqp);
12411b115575SJohn Danielson 	}
12421b115575SJohn Danielson }
12431b115575SJohn Danielson 
12441b115575SJohn Danielson /*
12451b115575SJohn Danielson  * Release a previously activated address
12461b115575SJohn Danielson  */
12471b115575SJohn Danielson static void
12481b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid)
12491b115575SJohn Danielson {
12501b115575SJohn Danielson 	dam_da_t *passp;
12511b115575SJohn Danielson 	char	 *addrstr;
12521b115575SJohn Danielson 
12531b115575SJohn Danielson 
12541b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
12554c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
12564c06356bSdh142964 	ASSERT(passp);
12574c06356bSdh142964 
12581b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
12591b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__release,
12601b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
12611b94a41bSChris Horne 	    char *, addrstr);
12624c06356bSdh142964 
12634c06356bSdh142964 	/*
12641b115575SJohn Danielson 	 * defer releasing the address until outstanding references
12651b115575SJohn Danielson 	 * are released
12664c06356bSdh142964 	 */
12671b115575SJohn Danielson 	if (passp->da_ref > 1) {
12681b115575SJohn Danielson 		DTRACE_PROBE4(damap__addr__release__outstanding__refs,
12691b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
12701b94a41bSChris Horne 		    char *, addrstr, int, passp->da_ref);
12714c06356bSdh142964 		return;
12724c06356bSdh142964 	}
12731b115575SJohn Danielson 
12741b115575SJohn Danielson 	/*
12751b115575SJohn Danielson 	 * allow pending reports to stabilize
12761b115575SJohn Danielson 	 */
12771b115575SJohn Danielson 	if (DAM_IN_REPORT(mapp, addrid)) {
12781b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__release__report__pending,
12791b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
12801b94a41bSChris Horne 		    char *, addrstr);
12811b115575SJohn Danielson 		return;
12821b115575SJohn Danielson 	}
12831b115575SJohn Danielson 
12844c06356bSdh142964 	ddi_strid_free(mapp->dam_addr_hash, addrid);
12854c06356bSdh142964 	ddi_soft_state_free(mapp->dam_da, addrid);
12864c06356bSdh142964 }
12874c06356bSdh142964 
12884c06356bSdh142964 /*
12894c06356bSdh142964  * process stabilized address reports
12904c06356bSdh142964  */
12914c06356bSdh142964 static void
12921b115575SJohn Danielson dam_stabilize_map(void *arg)
12934c06356bSdh142964 {
12944c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
12954c06356bSdh142964 	bitset_t delta;
12964c06356bSdh142964 	bitset_t cfg;
12974c06356bSdh142964 	bitset_t uncfg;
12984c06356bSdh142964 	int has_cfg, has_uncfg;
12991b115575SJohn Danielson 	uint32_t i, n_active;
13001b115575SJohn Danielson 
13011b94a41bSChris Horne 	DTRACE_PROBE2(damap__stabilize__map,
13021b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
13034c06356bSdh142964 
13044c06356bSdh142964 	bitset_init(&delta);
13054c06356bSdh142964 	bitset_resize(&delta, mapp->dam_size);
13064c06356bSdh142964 	bitset_init(&cfg);
13074c06356bSdh142964 	bitset_resize(&cfg, mapp->dam_size);
13084c06356bSdh142964 	bitset_init(&uncfg);
13094c06356bSdh142964 	bitset_resize(&uncfg, mapp->dam_size);
13104c06356bSdh142964 
13111b115575SJohn Danielson 	/*
13121b115575SJohn Danielson 	 * determine which addresses have changed during
13131b115575SJohn Danielson 	 * this stabilization cycle
13141b115575SJohn Danielson 	 */
13151b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13161b115575SJohn Danielson 	ASSERT(mapp->dam_flags & DAM_SPEND);
13174c06356bSdh142964 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
13184c06356bSdh142964 	    &delta)) {
13191b115575SJohn Danielson 		/*
13201b115575SJohn Danielson 		 * no difference
13211b115575SJohn Danielson 		 */
13224c06356bSdh142964 		bitset_zero(&mapp->dam_stable_set);
13231b115575SJohn Danielson 		mapp->dam_flags &= ~DAM_SPEND;
132460aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
13251b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
132660aabb4cSChris Horne 
13274c06356bSdh142964 		bitset_fini(&uncfg);
13284c06356bSdh142964 		bitset_fini(&cfg);
13294c06356bSdh142964 		bitset_fini(&delta);
13301b94a41bSChris Horne 		DTRACE_PROBE2(damap__stabilize__map__nochange,
13311b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
13324c06356bSdh142964 		return;
13334c06356bSdh142964 	}
13341b115575SJohn Danielson 
13351b115575SJohn Danielson 	/*
13361b115575SJohn Danielson 	 * compute the sets of addresses to be activated and deactivated
13371b115575SJohn Danielson 	 */
13384c06356bSdh142964 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
13394c06356bSdh142964 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
13401b115575SJohn Danielson 
13411b115575SJohn Danielson 	/*
13421b115575SJohn Danielson 	 * drop map lock while invoking callouts
13431b115575SJohn Danielson 	 */
13441b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
13451b115575SJohn Danielson 
13461b115575SJohn Danielson 	/*
13471b115575SJohn Danielson 	 * activate all newly stable addresss
13481b115575SJohn Danielson 	 */
13491b115575SJohn Danielson 	if (has_cfg)
13504c06356bSdh142964 		dam_addrset_activate(mapp, &cfg);
13511b115575SJohn Danielson 
13521b115575SJohn Danielson 	/*
13531b115575SJohn Danielson 	 * deactivate addresss which are no longer in the map
13541b115575SJohn Danielson 	 */
13551b115575SJohn Danielson 	if (has_uncfg)
13561b115575SJohn Danielson 		dam_addrset_deactivate(mapp, &uncfg);
13571b115575SJohn Danielson 
13581b115575SJohn Danielson 
13591b115575SJohn Danielson 	/*
13601b115575SJohn Danielson 	 * timestamp the last stable time and increment the kstat keeping
13611b115575SJohn Danielson 	 * the # of of stable cycles for the map
13621b115575SJohn Danielson 	 */
13631b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13644c06356bSdh142964 	bitset_zero(&mapp->dam_stable_set);
13654c06356bSdh142964 	mapp->dam_last_stable = gethrtime();
13664c06356bSdh142964 	mapp->dam_stable_cnt++;
13671b115575SJohn Danielson 	DAM_INCR_STAT(mapp, dam_cycles);
13681b115575SJohn Danielson 
13691b115575SJohn Danielson 	/*
13701b115575SJohn Danielson 	 * determine the number of stable addresses
13711b115575SJohn Danielson 	 * and update the n_active kstat for this map
13721b115575SJohn Danielson 	 */
13731b115575SJohn Danielson 	for (i = 1, n_active = 0; i < mapp->dam_high; i++)
13741b115575SJohn Danielson 		if (bitset_in_set(&mapp->dam_active_set, i))
13751b115575SJohn Danielson 			n_active++;
13761b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_active, n_active);
13771b115575SJohn Danielson 
13781b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__stable__end,
13791b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
13801b94a41bSChris Horne 	    int, n_active);
13811b115575SJohn Danielson 
13821b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SPEND;
138360aabb4cSChris Horne 	cv_signal(&mapp->dam_sync_cv);
13841b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
138560aabb4cSChris Horne 
13864c06356bSdh142964 	bitset_fini(&uncfg);
13874c06356bSdh142964 	bitset_fini(&cfg);
13884c06356bSdh142964 	bitset_fini(&delta);
13894c06356bSdh142964 }
13904c06356bSdh142964 
13914c06356bSdh142964 /*
13924c06356bSdh142964  * per-address stabilization timeout
13934c06356bSdh142964  */
13944c06356bSdh142964 static void
13954c06356bSdh142964 dam_addr_stable_cb(void *arg)
13964c06356bSdh142964 {
13974c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
13984c06356bSdh142964 	int i;
13994c06356bSdh142964 	dam_da_t *passp;
14004c06356bSdh142964 	int spend = 0;
14014c06356bSdh142964 	int tpend = 0;
140260aabb4cSChris Horne 	int64_t ts, next_ticks, delta_ticks;
14034c06356bSdh142964 
14041b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
14054c06356bSdh142964 	if (mapp->dam_tid == 0) {
14061b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__cancelled,
14071b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
14081b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14094c06356bSdh142964 		return;
14104c06356bSdh142964 	}
14114c06356bSdh142964 	mapp->dam_tid = 0;
14121b115575SJohn Danielson 
14134c06356bSdh142964 	/*
14144c06356bSdh142964 	 * If still under stabilization, reschedule timeout,
14151b115575SJohn Danielson 	 * otherwise dispatch the task to activate and deactivate the
14161b115575SJohn Danielson 	 * new stable address
14174c06356bSdh142964 	 */
14184c06356bSdh142964 	if (mapp->dam_flags & DAM_SPEND) {
14191b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
14204c06356bSdh142964 		mapp->dam_stable_overrun++;
14211b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__overrun,
14221b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
142360aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
142460aabb4cSChris Horne 		    mapp->dam_stable_ticks);
14251b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14264c06356bSdh142964 		return;
14274c06356bSdh142964 	}
14284c06356bSdh142964 
14291b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
14301b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
14311b115575SJohn Danielson 
14321b94a41bSChris Horne 	/* See if any reports stabalized and compute next timeout. */
143360aabb4cSChris Horne 	ts = ddi_get_lbolt64();
143460aabb4cSChris Horne 	next_ticks = mapp->dam_stable_ticks;
14354c06356bSdh142964 	for (i = 1; i < mapp->dam_high; i++) {
14361b94a41bSChris Horne 		if (bitset_in_set(&mapp->dam_report_set, i)) {
14374c06356bSdh142964 			passp = ddi_get_soft_state(mapp->dam_da, i);
14384c06356bSdh142964 			ASSERT(passp);
14394c06356bSdh142964 
14401b94a41bSChris Horne 			if (passp->da_deadline <= ts)
14411b94a41bSChris Horne 				spend++;	/* report has stabilized */
14421b94a41bSChris Horne 			else {
14431b94a41bSChris Horne 				/* not stabilized, determine next map timeout */
14444c06356bSdh142964 				tpend++;
144560aabb4cSChris Horne 				delta_ticks = passp->da_deadline - ts;
144660aabb4cSChris Horne 				if (delta_ticks < next_ticks)
144760aabb4cSChris Horne 					next_ticks = delta_ticks;
14484c06356bSdh142964 			}
14491b94a41bSChris Horne 		}
14501b94a41bSChris Horne 	}
14514c06356bSdh142964 
14524c06356bSdh142964 	/*
14531b115575SJohn Danielson 	 * schedule system_taskq activation of stabilized reports
14544c06356bSdh142964 	 */
14554c06356bSdh142964 	if (spend) {
14561b115575SJohn Danielson 		if (taskq_dispatch(system_taskq, dam_stabilize_map,
145764109744SChris Horne 		    mapp, TQ_NOSLEEP | TQ_NOQUEUE)) {
14581b94a41bSChris Horne 			DTRACE_PROBE2(damap__map__addr__stable__start,
14591b94a41bSChris Horne 			    char *, mapp->dam_name, dam_t *, mapp);
14601b94a41bSChris Horne 
14611b94a41bSChris Horne 			/*
14621b94a41bSChris Horne 			 * The stable_set we compute below stays pending until
14631b94a41bSChris Horne 			 * processed by dam_stabilize_map. We can't set
14641b94a41bSChris Horne 			 * DAM_SPEND (or bitset_del things from the
14651b94a41bSChris Horne 			 * report_set) until we *know* that we can handoff the
14661b94a41bSChris Horne 			 * result to dam_stabilize_map. If dam_stabilize_map
14671b94a41bSChris Horne 			 * starts executing before we are complete, it will
14681b94a41bSChris Horne 			 * block on the dam_lock mutex until we are ready.
14691b94a41bSChris Horne 			 */
14701b115575SJohn Danielson 			mapp->dam_flags |= DAM_SPEND;
14711b94a41bSChris Horne 
14721b94a41bSChris Horne 			/*
14731b94a41bSChris Horne 			 * Copy the current active_set to the stable_set, then
14741b94a41bSChris Horne 			 * add or remove stabilized report_set address from
14751b94a41bSChris Horne 			 * the stable set (and delete them from the report_set).
14761b94a41bSChris Horne 			 */
14771b94a41bSChris Horne 			bitset_copy(&mapp->dam_active_set,
14781b94a41bSChris Horne 			    &mapp->dam_stable_set);
14791b94a41bSChris Horne 			for (i = 1; i < mapp->dam_high; i++) {
14801b94a41bSChris Horne 				if (!bitset_in_set(&mapp->dam_report_set, i))
14811b94a41bSChris Horne 					continue;
14821b94a41bSChris Horne 
14831b94a41bSChris Horne 				passp = ddi_get_soft_state(mapp->dam_da, i);
14841b94a41bSChris Horne 				if (passp->da_deadline > ts)
14851b94a41bSChris Horne 					continue; /* report not stabilized */
14861b94a41bSChris Horne 
14871b94a41bSChris Horne 				/* report has stabilized */
14881b94a41bSChris Horne 				if (passp->da_flags & DA_RELE)
14891b94a41bSChris Horne 					bitset_del(&mapp->dam_stable_set, i);
14901b94a41bSChris Horne 				else
14911b94a41bSChris Horne 					bitset_add(&mapp->dam_stable_set, i);
14921b94a41bSChris Horne 
14931b94a41bSChris Horne 				bitset_del(&mapp->dam_report_set, i);
14941b94a41bSChris Horne 			}
14951b115575SJohn Danielson 		} else {
14961b94a41bSChris Horne 			DTRACE_PROBE2(damap__map__addr__stable__spendfail,
14971b94a41bSChris Horne 			    char *, mapp->dam_name, dam_t *, mapp);
149864109744SChris Horne 
149964109744SChris Horne 			/*
150064109744SChris Horne 			 * Avoid waiting the entire stabalization
150164109744SChris Horne 			 * time again if taskq_diskpatch fails.
150264109744SChris Horne 			 */
15031b94a41bSChris Horne 			tpend++;
150460aabb4cSChris Horne 			delta_ticks = drv_usectohz(
150564109744SChris Horne 			    damap_taskq_dispatch_retry_usec);
150660aabb4cSChris Horne 			if (delta_ticks < next_ticks)
150760aabb4cSChris Horne 				next_ticks = delta_ticks;
15084c06356bSdh142964 		}
15091b115575SJohn Danielson 	}
15104c06356bSdh142964 
15114c06356bSdh142964 	/*
15121b115575SJohn Danielson 	 * reschedule the stabilization timer if there are reports
15131b115575SJohn Danielson 	 * still pending
15144c06356bSdh142964 	 */
15151b94a41bSChris Horne 	if (tpend) {
15161b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__tpend, char *,
15171b94a41bSChris Horne 		    mapp->dam_name, dam_t *, mapp);
151860aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
151960aabb4cSChris Horne 		    (clock_t)next_ticks);
15201b94a41bSChris Horne 	}
15211b115575SJohn Danielson 
15221b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
15234c06356bSdh142964 }
15244c06356bSdh142964 
15254c06356bSdh142964 /*
15261b115575SJohn Danielson  * fullset stabilization timeout callback
15274c06356bSdh142964  */
15284c06356bSdh142964 static void
15291b115575SJohn Danielson dam_addrset_stable_cb(void *arg)
15304c06356bSdh142964 {
15314c06356bSdh142964 	dam_t *mapp = (dam_t *)arg;
15324c06356bSdh142964 
15331b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
15344c06356bSdh142964 	if (mapp->dam_tid == 0) {
15351b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
15361b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__cancelled,
15371b115575SJohn Danielson 		    char *, mapp->dam_name, dam_t *, mapp);
15384c06356bSdh142964 		return;
15394c06356bSdh142964 	}
15404c06356bSdh142964 	mapp->dam_tid = 0;
15414c06356bSdh142964 
15424c06356bSdh142964 	/*
15431b115575SJohn Danielson 	 * If map still underoing stabilization reschedule timeout,
15441b115575SJohn Danielson 	 * else dispatch the task to configure the new stable set of
15451b115575SJohn Danielson 	 * addresses.
15464c06356bSdh142964 	 */
154764109744SChris Horne 	if ((mapp->dam_flags & DAM_SPEND) ||
154864109744SChris Horne 	    (taskq_dispatch(system_taskq, dam_stabilize_map, mapp,
154964109744SChris Horne 	    TQ_NOSLEEP | TQ_NOQUEUE) == NULL)) {
15501b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
15514c06356bSdh142964 		mapp->dam_stable_overrun++;
155260aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
155360aabb4cSChris Horne 		    drv_usectohz(damap_taskq_dispatch_retry_usec));
155464109744SChris Horne 
15551b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addrset__stable__overrun,
15561b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
15571b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
15581b115575SJohn Danielson 		return;
15591b115575SJohn Danielson 	}
15601b115575SJohn Danielson 
15611b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
15621b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
15634c06356bSdh142964 	bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
15644c06356bSdh142964 	bitset_zero(&mapp->dam_report_set);
15651b115575SJohn Danielson 	mapp->dam_flags |= DAM_SPEND;
15661b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SETADD;
156760aabb4cSChris Horne 	/* NOTE: don't need cv_signal since DAM_SPEND is still set */
156860aabb4cSChris Horne 
15691b94a41bSChris Horne 	DTRACE_PROBE2(damap__map__addrset__stable__start,
15701b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
15711b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
15724c06356bSdh142964 }
15734c06356bSdh142964 
15744c06356bSdh142964 /*
157560aabb4cSChris Horne  * schedule map timeout in 'ticks' ticks
157660aabb4cSChris Horne  * if map timer is currently running, cancel if ticks == 0
15774c06356bSdh142964  */
15784c06356bSdh142964 static void
157960aabb4cSChris Horne dam_sched_timeout(void (*timeout_cb)(), dam_t *mapp, clock_t ticks)
15804c06356bSdh142964 {
15814c06356bSdh142964 	timeout_id_t tid;
15824c06356bSdh142964 
15831b94a41bSChris Horne 	DTRACE_PROBE4(damap__sched__timeout,
15841b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
15851b94a41bSChris Horne 	    int, ticks, timeout_id_t, mapp->dam_tid);
15864c06356bSdh142964 
15871b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15881b115575SJohn Danielson 	if ((tid = mapp->dam_tid) != 0) {
158960aabb4cSChris Horne 		if (ticks == 0) {
15901b115575SJohn Danielson 			mapp->dam_tid = 0;
15911b115575SJohn Danielson 			mutex_exit(&mapp->dam_lock);
15921b115575SJohn Danielson 			(void) untimeout(tid);
15931b115575SJohn Danielson 			mutex_enter(&mapp->dam_lock);
15941b115575SJohn Danielson 		}
15951b115575SJohn Danielson 	} else {
159660aabb4cSChris Horne 		if (timeout_cb && (ticks != 0))
159760aabb4cSChris Horne 			mapp->dam_tid = timeout(timeout_cb, mapp, ticks);
15984c06356bSdh142964 	}
15991b115575SJohn Danielson }
16004c06356bSdh142964 
16014c06356bSdh142964 /*
16021b115575SJohn Danielson  * report addition or removal of an address
16034c06356bSdh142964  */
16044c06356bSdh142964 static void
16051b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type)
16064c06356bSdh142964 {
16071b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
16081b115575SJohn Danielson 
16091b94a41bSChris Horne 	DTRACE_PROBE4(damap__addr__report,
16101b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
16111b94a41bSChris Horne 	    char *, addrstr, int, rpt_type);
16121b115575SJohn Danielson 
16131b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16144c06356bSdh142964 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
16154c06356bSdh142964 	passp->da_last_report = gethrtime();
16164c06356bSdh142964 	mapp->dam_last_update = gethrtime();
16174c06356bSdh142964 	passp->da_report_cnt++;
161860aabb4cSChris Horne 	passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stable_ticks;
16191b115575SJohn Danielson 	if (rpt_type == RPT_ADDR_DEL)
16204c06356bSdh142964 		passp->da_flags |= DA_RELE;
16211b115575SJohn Danielson 	else if (rpt_type == RPT_ADDR_ADD)
16224c06356bSdh142964 		passp->da_flags &= ~DA_RELE;
16234c06356bSdh142964 	bitset_add(&mapp->dam_report_set, addrid);
162460aabb4cSChris Horne 	dam_sched_timeout(dam_addr_stable_cb, mapp, mapp->dam_stable_ticks);
16254c06356bSdh142964 }
16264c06356bSdh142964 
16274c06356bSdh142964 /*
16284c06356bSdh142964  * release an address report
16294c06356bSdh142964  */
16304c06356bSdh142964 static void
16311b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid)
16324c06356bSdh142964 {
16334c06356bSdh142964 	dam_da_t *passp;
16341b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
16354c06356bSdh142964 
16361b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__report__release,
16371b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
16381b94a41bSChris Horne 	    char *, addrstr);
16391b115575SJohn Danielson 
16401b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16414c06356bSdh142964 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
16424c06356bSdh142964 	ASSERT(passp);
16431b115575SJohn Danielson 	/*
16441b115575SJohn Danielson 	 * clear the report bit
16451b115575SJohn Danielson 	 * if the address has a registered deactivation handler and
16469aed1621SDavid Hollister 	 * we are holding a private data pointer and the address has not
16479aed1621SDavid Hollister 	 * stabilized, deactivate the address (private data).
16481b115575SJohn Danielson 	 */
16491b115575SJohn Danielson 	bitset_del(&mapp->dam_report_set, addrid);
16509aed1621SDavid Hollister 	if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb &&
16519aed1621SDavid Hollister 	    passp->da_ppriv_rpt) {
16521b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
16531b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
16541b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
16559aed1621SDavid Hollister 		    addrid, passp->da_ppriv_rpt, DAMAP_DEACT_RSN_UNSTBL);
16561b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
16571b115575SJohn Danielson 	}
16584c06356bSdh142964 	passp->da_ppriv_rpt = NULL;
16594c06356bSdh142964 	nvlist_free(passp->da_nvl_rpt);
16604c06356bSdh142964 }
16614c06356bSdh142964 
16624c06356bSdh142964 /*
16634c06356bSdh142964  * return the map ID of an address
16644c06356bSdh142964  */
16654c06356bSdh142964 static id_t
16664c06356bSdh142964 dam_get_addrid(dam_t *mapp, char *address)
16674c06356bSdh142964 {
16684c06356bSdh142964 	damap_id_t addrid;
16694c06356bSdh142964 	dam_da_t *passp;
16704c06356bSdh142964 
16711b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16724c06356bSdh142964 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
16731b115575SJohn Danielson 		if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash,
16744c06356bSdh142964 		    address)) == (damap_id_t)0) {
16754c06356bSdh142964 			return (0);
16764c06356bSdh142964 		}
16774c06356bSdh142964 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
16784c06356bSdh142964 		    DDI_SUCCESS) {
16794c06356bSdh142964 			ddi_strid_free(mapp->dam_addr_hash, addrid);
16804c06356bSdh142964 			return (0);
16814c06356bSdh142964 		}
16821b115575SJohn Danielson 
16834c06356bSdh142964 		if (addrid >= mapp->dam_high)
16844c06356bSdh142964 			mapp->dam_high = addrid + 1;
16851b115575SJohn Danielson 
16861b115575SJohn Danielson 		/*
16871b115575SJohn Danielson 		 * expand bitmaps if ID has outgrown old map size
16881b115575SJohn Danielson 		 */
16891b115575SJohn Danielson 		if (mapp->dam_high > mapp->dam_size) {
16901b115575SJohn Danielson 			mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP;
16911b115575SJohn Danielson 			bitset_resize(&mapp->dam_active_set, mapp->dam_size);
16921b115575SJohn Danielson 			bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
16931b115575SJohn Danielson 			bitset_resize(&mapp->dam_report_set, mapp->dam_size);
16944c06356bSdh142964 		}
16951b115575SJohn Danielson 
16964c06356bSdh142964 		passp = ddi_get_soft_state(mapp->dam_da, addrid);
16971b115575SJohn Danielson 		passp->da_ref = 1;
16981b115575SJohn Danielson 		passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash,
16991b115575SJohn Danielson 		    addrid); /* for mdb */
17001b115575SJohn Danielson 	}
17014c06356bSdh142964 	return (addrid);
17024c06356bSdh142964 }
17034c06356bSdh142964 
17044c06356bSdh142964 /*
17054c06356bSdh142964  * create and install map statistics
17064c06356bSdh142964  */
17074c06356bSdh142964 static int
17084c06356bSdh142964 dam_kstat_create(dam_t *mapp)
17094c06356bSdh142964 {
17104c06356bSdh142964 	kstat_t			*mapsp;
17114c06356bSdh142964 	struct dam_kstats	*statsp;
17124c06356bSdh142964 
17134c06356bSdh142964 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
17144c06356bSdh142964 	    KSTAT_TYPE_NAMED,
17154c06356bSdh142964 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
17161b115575SJohn Danielson 
17171b115575SJohn Danielson 	if (mapsp == NULL)
17184c06356bSdh142964 		return (DDI_FAILURE);
17194c06356bSdh142964 
17204c06356bSdh142964 	statsp = (struct dam_kstats *)mapsp->ks_data;
17211b115575SJohn Danielson 	kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32);
17221b115575SJohn Danielson 	kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32);
17231b115575SJohn Danielson 	kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32);
17241b115575SJohn Danielson 	kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32);
17254c06356bSdh142964 	kstat_install(mapsp);
17264c06356bSdh142964 	mapp->dam_kstatsp = mapsp;
17274c06356bSdh142964 	return (DDI_SUCCESS);
17284c06356bSdh142964 }
1729