xref: /illumos-gate/usr/src/uts/common/os/damap.c (revision ccac1493)
14c06356bSdh /*
24c06356bSdh  * CDDL HEADER START
34c06356bSdh  *
44c06356bSdh  * The contents of this file are subject to the terms of the
54c06356bSdh  * Common Development and Distribution License (the "License").
64c06356bSdh  * You may not use this file except in compliance with the License.
74c06356bSdh  *
84c06356bSdh  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94c06356bSdh  * or http://www.opensolaris.org/os/licensing.
104c06356bSdh  * See the License for the specific language governing permissions
114c06356bSdh  * and limitations under the License.
124c06356bSdh  *
134c06356bSdh  * When distributing Covered Code, include this CDDL HEADER in each
144c06356bSdh  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154c06356bSdh  * If applicable, add the following below this CDDL HEADER, with the
164c06356bSdh  * fields enclosed by brackets "[]" replaced with your own identifying
174c06356bSdh  * information: Portions Copyright [yyyy] [name of copyright owner]
184c06356bSdh  *
194c06356bSdh  * CDDL HEADER END
204c06356bSdh  */
214c06356bSdh 
224c06356bSdh /*
2360aabb4cSChris Horne  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2478427917SHans Rosenfeld  * Copyright 2023 Racktop Systems, Inc.
254c06356bSdh  */
264c06356bSdh 
274c06356bSdh #include <sys/note.h>
284c06356bSdh #include <sys/types.h>
294c06356bSdh #include <sys/param.h>
304c06356bSdh #include <sys/systm.h>
314c06356bSdh #include <sys/buf.h>
324c06356bSdh #include <sys/kmem.h>
334c06356bSdh #include <sys/cmn_err.h>
344c06356bSdh #include <sys/debug.h>
354c06356bSdh #include <sys/sunndi.h>
364c06356bSdh #include <sys/kstat.h>
374c06356bSdh #include <sys/conf.h>
38a288e5a9SJoshua M. Clulow #include <sys/ddi_periodic.h>
394c06356bSdh #include <sys/devctl.h>
404c06356bSdh #include <sys/callb.h>
414c06356bSdh #include <sys/sysevent.h>
424c06356bSdh #include <sys/taskq.h>
434c06356bSdh #include <sys/ddi.h>
444c06356bSdh #include <sys/bitset.h>
454c06356bSdh #include <sys/damap.h>
464c06356bSdh #include <sys/damap_impl.h>
474c06356bSdh 
484c06356bSdh #ifdef DEBUG
494c06356bSdh static int damap_debug = 0;
504c06356bSdh #endif /* DEBUG */
514c06356bSdh 
521b115575SJohn Danielson extern taskq_t *system_taskq;
531b115575SJohn Danielson 
544c06356bSdh static void dam_addrset_activate(dam_t *, bitset_t *);
551b115575SJohn Danielson static void dam_addrset_deactivate(dam_t *, bitset_t *);
561b115575SJohn Danielson static void dam_stabilize_map(void *);
574c06356bSdh static void dam_addr_stable_cb(void *);
581b115575SJohn Danielson static void dam_addrset_stable_cb(void *);
5960aabb4cSChris Horne static void dam_sched_timeout(void (*timeout_cb)(), dam_t *, clock_t);
601b115575SJohn Danielson static void dam_addr_report(dam_t *, dam_da_t *, id_t, int);
611b115575SJohn Danielson static void dam_addr_release(dam_t *, id_t);
621b115575SJohn Danielson static void dam_addr_report_release(dam_t *, id_t);
631b115575SJohn Danielson static void dam_addr_deactivate(dam_t *, id_t);
64d189c170SReed static void dam_deact_cleanup(dam_t *, id_t, char *, damap_deact_rsn_t);
654c06356bSdh static id_t dam_get_addrid(dam_t *, char *);
664c06356bSdh static int dam_kstat_create(dam_t *);
671b115575SJohn Danielson static int dam_map_alloc(dam_t *);
684c06356bSdh 
694c06356bSdh #define	DAM_INCR_STAT(mapp, stat)				\
704c06356bSdh 	if ((mapp)->dam_kstatsp) {				\
714c06356bSdh 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
724c06356bSdh 		stp->stat.value.ui32++;				\
734c06356bSdh 	}
744c06356bSdh 
754c06356bSdh #define	DAM_SET_STAT(mapp, stat, val)				\
764c06356bSdh 	if ((mapp)->dam_kstatsp) {				\
774c06356bSdh 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
784c06356bSdh 		stp->stat.value.ui32 = (val);			\
794c06356bSdh 	}
804c06356bSdh 
811b115575SJohn Danielson 
821b115575SJohn Danielson /*
831b115575SJohn Danielson  * increase damap size by 64 entries at a time
841b115575SJohn Danielson  */
851b115575SJohn Danielson #define	DAM_SIZE_BUMP	64
861b115575SJohn Danielson 
8764109744SChris Horne int	damap_taskq_dispatch_retry_usec = 1000;
8864109744SChris Horne 
891b115575SJohn Danielson /*
901b115575SJohn Danielson  * config/unconfig taskq data
911b115575SJohn Danielson  */
921b115575SJohn Danielson typedef struct {
931b115575SJohn Danielson 	dam_t *tqd_mapp;
941b115575SJohn Danielson 	id_t tqd_id;
951b115575SJohn Danielson } cfg_tqd_t;
961b115575SJohn Danielson 
971b115575SJohn Danielson extern pri_t maxclsyspri;
981b115575SJohn Danielson 
994c06356bSdh /*
1004c06356bSdh  * Create new device address map
1014c06356bSdh  *
1021b115575SJohn Danielson  * name:		map name (kstat unique)
1034c06356bSdh  * size:		max # of map entries
1041b115575SJohn Danielson  * mode:		style of address reports: per-address or fullset
1054c06356bSdh  * stable_usec:		# of quiescent microseconds before report/map is stable
1064c06356bSdh  *
1074c06356bSdh  * activate_arg:	address provider activation-callout private
1084c06356bSdh  * activate_cb:		address provider activation callback handler
1094c06356bSdh  * deactivate_cb:	address provider deactivation callback handler
1104c06356bSdh  *
1114c06356bSdh  * config_arg:		configuration-callout private
1124c06356bSdh  * config_cb:		class configuration callout
1134c06356bSdh  * unconfig_cb:		class unconfiguration callout
1144c06356bSdh  *
1154c06356bSdh  * damapp:		pointer to map handle (return)
1164c06356bSdh  *
1174c06356bSdh  * Returns:	DAM_SUCCESS
1184c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
1194c06356bSdh  *		DAM_FAILURE	General failure
1204c06356bSdh  */
1214c06356bSdh int
damap_create(char * name,damap_rptmode_t mode,int map_opts,int stable_usec,void * activate_arg,damap_activate_cb_t activate_cb,damap_deactivate_cb_t deactivate_cb,void * config_arg,damap_configure_cb_t configure_cb,damap_unconfig_cb_t unconfig_cb,damap_t ** damapp)1221b115575SJohn Danielson damap_create(char *name, damap_rptmode_t mode, int map_opts,
12360aabb4cSChris Horne     int stable_usec, void *activate_arg, damap_activate_cb_t activate_cb,
1244c06356bSdh     damap_deactivate_cb_t deactivate_cb,
1254c06356bSdh     void *config_arg, damap_configure_cb_t configure_cb,
1264c06356bSdh     damap_unconfig_cb_t unconfig_cb,
1274c06356bSdh     damap_t **damapp)
1284c06356bSdh {
1294c06356bSdh 	dam_t *mapp;
1304c06356bSdh 
1311b115575SJohn Danielson 	if (configure_cb == NULL || unconfig_cb == NULL || name == NULL)
1324c06356bSdh 		return (DAM_EINVAL);
1334c06356bSdh 
1344c06356bSdh 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
1351b115575SJohn Danielson 	mapp->dam_options = map_opts;
13660aabb4cSChris Horne 	mapp->dam_stable_ticks = drv_usectohz(stable_usec);
1371b115575SJohn Danielson 	mapp->dam_size = 0;
1381b115575SJohn Danielson 	mapp->dam_rptmode = mode;
1394c06356bSdh 	mapp->dam_activate_arg = activate_arg;
1404c06356bSdh 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
1414c06356bSdh 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
1424c06356bSdh 	mapp->dam_config_arg = config_arg;
1434c06356bSdh 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
1444c06356bSdh 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
1451b115575SJohn Danielson 	mapp->dam_name = i_ddi_strdup(name, KM_SLEEP);
1461b115575SJohn Danielson 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
14760aabb4cSChris Horne 	cv_init(&mapp->dam_sync_cv, NULL, CV_DRIVER, NULL);
1484c06356bSdh 	bitset_init(&mapp->dam_active_set);
1494c06356bSdh 	bitset_init(&mapp->dam_stable_set);
1504c06356bSdh 	bitset_init(&mapp->dam_report_set);
1514c06356bSdh 	*damapp = (damap_t *)mapp;
1521b94a41bSChris Horne 
1531b94a41bSChris Horne 	DTRACE_PROBE5(damap__create,
1541b94a41bSChris Horne 	    char *, mapp->dam_name, damap_t *, mapp,
1551b94a41bSChris Horne 	    damap_rptmode_t, mode, int, map_opts, int, stable_usec);
1561b94a41bSChris Horne 
1571b115575SJohn Danielson 	return (DAM_SUCCESS);
1581b115575SJohn Danielson }
1591b115575SJohn Danielson 
1601b115575SJohn Danielson /*
1611b115575SJohn Danielson  * Allocate backing resources
1621b115575SJohn Danielson  *
1631b115575SJohn Danielson  * DAMs are lightly backed on create - major allocations occur
1641b115575SJohn Danielson  * at the time a report is made to the map, and are extended on
1651b115575SJohn Danielson  * a demand basis.
1661b115575SJohn Danielson  */
1671b115575SJohn Danielson static int
dam_map_alloc(dam_t * mapp)1681b115575SJohn Danielson dam_map_alloc(dam_t *mapp)
1691b115575SJohn Danielson {
1701b115575SJohn Danielson 	void *softstate_p;
1711b115575SJohn Danielson 
1721b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
1731b115575SJohn Danielson 	if (mapp->dam_flags & DAM_DESTROYPEND)
1741b115575SJohn Danielson 		return (DAM_FAILURE);
1751b115575SJohn Danielson 
1761b115575SJohn Danielson 	/*
1771b115575SJohn Danielson 	 * dam_high > 0 signals map allocation complete
1781b115575SJohn Danielson 	 */
1791b115575SJohn Danielson 	if (mapp->dam_high)
1801b115575SJohn Danielson 		return (DAM_SUCCESS);
1811b115575SJohn Danielson 
1821b115575SJohn Danielson 	mapp->dam_size = DAM_SIZE_BUMP;
1831b115575SJohn Danielson 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t),
1841b115575SJohn Danielson 	    mapp->dam_size) != DDI_SUCCESS)
1851b115575SJohn Danielson 		return (DAM_FAILURE);
1861b115575SJohn Danielson 
1871b115575SJohn Danielson 	if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) !=
1881b115575SJohn Danielson 	    DDI_SUCCESS) {
189*ccac1493SHans Rosenfeld 		ddi_soft_state_fini(&softstate_p);
1901b115575SJohn Danielson 		return (DAM_FAILURE);
1911b115575SJohn Danielson 	}
1924c06356bSdh 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
193*ccac1493SHans Rosenfeld 		ddi_soft_state_fini(&softstate_p);
1941b115575SJohn Danielson 		ddi_strid_fini(&mapp->dam_addr_hash);
1954c06356bSdh 		return (DAM_FAILURE);
1964c06356bSdh 	}
1971b115575SJohn Danielson 	mapp->dam_da = softstate_p;
1981b115575SJohn Danielson 	mapp->dam_high = 1;
1991b115575SJohn Danielson 	bitset_resize(&mapp->dam_active_set, mapp->dam_size);
2001b115575SJohn Danielson 	bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
2011b115575SJohn Danielson 	bitset_resize(&mapp->dam_report_set, mapp->dam_size);
2024c06356bSdh 	return (DAM_SUCCESS);
2034c06356bSdh }
2044c06356bSdh 
2054c06356bSdh /*
2061b115575SJohn Danielson  * Destroy address map
2074c06356bSdh  *
2084c06356bSdh  * damapp:	address map
2094c06356bSdh  *
2104c06356bSdh  * Returns:	DAM_SUCCESS
2114c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
2124c06356bSdh  *		DAM_FAILURE	General failure
2134c06356bSdh  */
2144c06356bSdh void
damap_destroy(damap_t * damapp)2154c06356bSdh damap_destroy(damap_t *damapp)
2164c06356bSdh {
2174c06356bSdh 	int i;
2184c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
2194c06356bSdh 
2204c06356bSdh 	ASSERT(mapp);
2214c06356bSdh 
2221b94a41bSChris Horne 	DTRACE_PROBE2(damap__destroy,
2231b94a41bSChris Horne 	    char *, mapp->dam_name, damap_t *, mapp);
2244c06356bSdh 
2251b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
2264c06356bSdh 
2274c06356bSdh 	/*
2281b115575SJohn Danielson 	 * prevent new reports from being added to the map
2294c06356bSdh 	 */
2301b115575SJohn Danielson 	mapp->dam_flags |= DAM_DESTROYPEND;
2314c06356bSdh 
2321b115575SJohn Danielson 	if (mapp->dam_high) {
2331b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2341b115575SJohn Danielson 		/*
2351b115575SJohn Danielson 		 * wait for outstanding reports to stabilize and cancel
2361b115575SJohn Danielson 		 * the timer for this map
2371b115575SJohn Danielson 		 */
23860aabb4cSChris Horne 		(void) damap_sync(damapp, 0);
2391b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
24060aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
2411b115575SJohn Danielson 
2421b115575SJohn Danielson 		/*
2431b115575SJohn Danielson 		 * map is at full stop
2441b115575SJohn Danielson 		 * release the contents of the map, invoking the
2451b115575SJohn Danielson 		 * detactivation protocol as addresses are released
2461b115575SJohn Danielson 		 */
2471b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
2481b115575SJohn Danielson 		for (i = 1; i < mapp->dam_high; i++) {
2491b115575SJohn Danielson 			if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
2501b115575SJohn Danielson 				continue;
2511b115575SJohn Danielson 
2521b115575SJohn Danielson 			ASSERT(DAM_IN_REPORT(mapp, i) == 0);
2531b115575SJohn Danielson 
2541b115575SJohn Danielson 			if (DAM_IS_STABLE(mapp, i)) {
2551b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
2561b115575SJohn Danielson 			} else {
2571b115575SJohn Danielson 				ddi_strid_free(mapp->dam_addr_hash, i);
2581b115575SJohn Danielson 				ddi_soft_state_free(mapp->dam_da, i);
2591b115575SJohn Danielson 			}
2601b115575SJohn Danielson 		}
2611b115575SJohn Danielson 		ddi_strid_fini(&mapp->dam_addr_hash);
2621b115575SJohn Danielson 		ddi_soft_state_fini(&mapp->dam_da);
2631b115575SJohn Danielson 		kstat_delete(mapp->dam_kstatsp);
26460aabb4cSChris Horne 	} else
26560aabb4cSChris Horne 		mutex_exit(&mapp->dam_lock);
26660aabb4cSChris Horne 
2674c06356bSdh 	bitset_fini(&mapp->dam_active_set);
2684c06356bSdh 	bitset_fini(&mapp->dam_stable_set);
2694c06356bSdh 	bitset_fini(&mapp->dam_report_set);
2704c06356bSdh 	mutex_destroy(&mapp->dam_lock);
27160aabb4cSChris Horne 	cv_destroy(&mapp->dam_sync_cv);
2724c06356bSdh 	if (mapp->dam_name)
2734c06356bSdh 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
2744c06356bSdh 	kmem_free(mapp, sizeof (*mapp));
2754c06356bSdh }
2764c06356bSdh 
2774c06356bSdh /*
27860aabb4cSChris Horne  * Wait for map stability.  If sync was successfull then return 1.
27960aabb4cSChris Horne  * If called with a non-zero sync_usec, then a return value of 0 means a
28060aabb4cSChris Horne  * timeout occurred prior to sync completion. NOTE: if sync_usec is
28160aabb4cSChris Horne  * non-zero, it should be much longer than dam_stable_ticks.
2824c06356bSdh  *
2834c06356bSdh  * damapp:	address map
28460aabb4cSChris Horne  * sync_usec:	micorseconds until we give up on sync completion.
2854c06356bSdh  */
28660aabb4cSChris Horne #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND)
2874c06356bSdh int
damap_sync(damap_t * damapp,int sync_usec)28860aabb4cSChris Horne damap_sync(damap_t *damapp, int sync_usec)
2894c06356bSdh {
29060aabb4cSChris Horne 	dam_t	*mapp = (dam_t *)damapp;
29160aabb4cSChris Horne 	int	rv;
2924c06356bSdh 
2934c06356bSdh 	ASSERT(mapp);
2941b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__sync__start,
2951b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
2961b94a41bSChris Horne 	    int, sync_usec);
2974c06356bSdh 
2981b115575SJohn Danielson 	/*
29960aabb4cSChris Horne 	 * Block when waiting for
30060aabb4cSChris Horne 	 *	a) stabilization pending or a fullset update pending
30160aabb4cSChris Horne 	 *	b) the report set to finalize (bitset is null)
30260aabb4cSChris Horne 	 *	c) any scheduled timeouts to fire
3031b115575SJohn Danielson 	 */
30460aabb4cSChris Horne 	rv = 1;					/* return synced */
3054c06356bSdh 	mutex_enter(&mapp->dam_lock);
30660aabb4cSChris Horne again:	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
30760aabb4cSChris Horne 	    (!bitset_is_null(&mapp->dam_report_set)) ||
30860aabb4cSChris Horne 	    (mapp->dam_tid != 0)) {
3091b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__sync__waiting,
3101b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
3114c06356bSdh 
31260aabb4cSChris Horne 		/* Wait for condition relayed via timeout */
31360aabb4cSChris Horne 		if (sync_usec) {
31460aabb4cSChris Horne 			if (cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
31560aabb4cSChris Horne 			    drv_usectohz(sync_usec), TR_MICROSEC) == -1) {
31660aabb4cSChris Horne 				mapp->dam_sync_to_cnt++;
31760aabb4cSChris Horne 				rv = 0;		/* return timeout */
31860aabb4cSChris Horne 				break;
31960aabb4cSChris Horne 			}
32060aabb4cSChris Horne 		} else
32160aabb4cSChris Horne 			cv_wait(&mapp->dam_sync_cv, &mapp->dam_lock);
32260aabb4cSChris Horne 	}
3234c06356bSdh 
32460aabb4cSChris Horne 	if (rv) {
32560aabb4cSChris Horne 		/*
32660aabb4cSChris Horne 		 * Delay one stabilization time after the apparent sync above
32760aabb4cSChris Horne 		 * and verify accuracy - resync if not accurate.
32860aabb4cSChris Horne 		 */
32960aabb4cSChris Horne 		(void) cv_reltimedwait(&mapp->dam_sync_cv, &mapp->dam_lock,
33060aabb4cSChris Horne 		    mapp->dam_stable_ticks, TR_MICROSEC);
33160aabb4cSChris Horne 		if (rv && ((mapp->dam_flags & WAITFOR_FLAGS) ||
33260aabb4cSChris Horne 		    (!bitset_is_null(&mapp->dam_report_set)) ||
33360aabb4cSChris Horne 		    (mapp->dam_tid != 0)))
33460aabb4cSChris Horne 			goto again;
33560aabb4cSChris Horne 	}
3364c06356bSdh 	mutex_exit(&mapp->dam_lock);
3374c06356bSdh 
3381b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__sync__end,
3391b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
3401b94a41bSChris Horne 	    int, rv);
34160aabb4cSChris Horne 	return (rv);
34260aabb4cSChris Horne }
34360aabb4cSChris Horne 
34460aabb4cSChris Horne /*
34560aabb4cSChris Horne  * Return 1 if active set is empty
34660aabb4cSChris Horne  */
34760aabb4cSChris Horne int
damap_is_empty(damap_t * damapp)34860aabb4cSChris Horne damap_is_empty(damap_t *damapp)
34960aabb4cSChris Horne {
35060aabb4cSChris Horne 	dam_t	*mapp = (dam_t *)damapp;
35160aabb4cSChris Horne 	int	rv;
35260aabb4cSChris Horne 
35360aabb4cSChris Horne 	mutex_enter(&mapp->dam_lock);
35460aabb4cSChris Horne 	rv = bitset_is_null(&mapp->dam_active_set);
35560aabb4cSChris Horne 	mutex_exit(&mapp->dam_lock);
35660aabb4cSChris Horne 	return (rv);
3574c06356bSdh }
3584c06356bSdh 
3594c06356bSdh /*
3604c06356bSdh  * Get the name of a device address map
3614c06356bSdh  *
3624c06356bSdh  * damapp:	address map
3634c06356bSdh  *
3644c06356bSdh  * Returns:	name
3654c06356bSdh  */
3664c06356bSdh char *
damap_name(damap_t * damapp)3674c06356bSdh damap_name(damap_t *damapp)
3684c06356bSdh {
3694c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
3704c06356bSdh 
3714c06356bSdh 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
3724c06356bSdh }
3734c06356bSdh 
37460aabb4cSChris Horne /*
37560aabb4cSChris Horne  * Get the current size of the device address map
37660aabb4cSChris Horne  *
37760aabb4cSChris Horne  * damapp:	address map
37860aabb4cSChris Horne  *
37960aabb4cSChris Horne  * Returns:	size
38060aabb4cSChris Horne  */
38160aabb4cSChris Horne int
damap_size(damap_t * damapp)38260aabb4cSChris Horne damap_size(damap_t *damapp)
38360aabb4cSChris Horne {
38460aabb4cSChris Horne 	dam_t *mapp = (dam_t *)damapp;
38560aabb4cSChris Horne 
38660aabb4cSChris Horne 	return (mapp->dam_size);
38760aabb4cSChris Horne }
38860aabb4cSChris Horne 
3894c06356bSdh /*
3904c06356bSdh  * Report an address to per-address report
3914c06356bSdh  *
3924c06356bSdh  * damapp:	address map handle
3934c06356bSdh  * address:	address in ascii string representation
3941b115575SJohn Danielson  * addridp:	address ID
3954c06356bSdh  * nvl:		optional nvlist of configuration-private data
3964c06356bSdh  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
3974c06356bSdh  *
3984c06356bSdh  * Returns:	DAM_SUCCESS
3994c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
4004c06356bSdh  *		DAM_MAPFULL	address map exhausted
4014c06356bSdh  */
4024c06356bSdh int
damap_addr_add(damap_t * damapp,char * address,damap_id_t * addridp,nvlist_t * nvl,void * addr_priv)4031b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp,
4041b115575SJohn Danielson     nvlist_t *nvl, void *addr_priv)
4054c06356bSdh {
4064c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
4074c06356bSdh 	id_t addrid;
4084c06356bSdh 	dam_da_t *passp;
4094c06356bSdh 
4101b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4114c06356bSdh 		return (DAM_EINVAL);
4124c06356bSdh 
4131b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__add,
4141b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
4151b94a41bSChris Horne 	    char *, address);
4161b115575SJohn Danielson 
4171b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4181b115575SJohn Danielson 	if ((dam_map_alloc(mapp) != DAM_SUCCESS) ||
4191b115575SJohn Danielson 	    ((addrid = dam_get_addrid(mapp, address)) == 0)) {
4201b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4214c06356bSdh 		return (DAM_MAPFULL);
4224c06356bSdh 	}
4234c06356bSdh 
4244c06356bSdh 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4254c06356bSdh 	ASSERT(passp != NULL);
4264c06356bSdh 
4274c06356bSdh 	/*
4284c06356bSdh 	 * If re-reporting the same address (add or remove) clear
4294c06356bSdh 	 * the existing report
4304c06356bSdh 	 */
4314c06356bSdh 	if (DAM_IN_REPORT(mapp, addrid)) {
4321b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__add__jitter,
4331b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
4341b94a41bSChris Horne 		    char *, address);
4351b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4361b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4374c06356bSdh 		passp->da_jitter++;
4384c06356bSdh 	}
43978427917SHans Rosenfeld 	passp->da_ppriv = addr_priv;
4404c06356bSdh 	if (nvl)
4414c06356bSdh 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
4424c06356bSdh 
4431b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD);
4441b115575SJohn Danielson 	if (addridp != NULL)
4451b115575SJohn Danielson 		*addridp = (damap_id_t)addrid;
4461b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4474c06356bSdh 	return (DAM_SUCCESS);
4484c06356bSdh }
4494c06356bSdh 
4504c06356bSdh /*
4514c06356bSdh  * Report removal of address from per-address report
4524c06356bSdh  *
4534c06356bSdh  * damapp:	address map
4544c06356bSdh  * address:	address in ascii string representation
4554c06356bSdh  *
4564c06356bSdh  * Returns:	DAM_SUCCESS
4574c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
4584c06356bSdh  *		DAM_FAILURE	General failure
4594c06356bSdh  */
4604c06356bSdh int
damap_addr_del(damap_t * damapp,char * address)4614c06356bSdh damap_addr_del(damap_t *damapp, char *address)
4624c06356bSdh {
4634c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
4644c06356bSdh 	id_t addrid;
4654c06356bSdh 	dam_da_t *passp;
4664c06356bSdh 
4671b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
4684c06356bSdh 		return (DAM_EINVAL);
4694c06356bSdh 
4701b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__del,
4711b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
4721b94a41bSChris Horne 	    char *, address);
4731b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
4741b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
4751b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4761b115575SJohn Danielson 		return (DAM_MAPFULL);
4771b115575SJohn Danielson 	}
4781b115575SJohn Danielson 
4791b115575SJohn Danielson 	/*
4801b115575SJohn Danielson 	 * if reporting the removal of an address which is not in the map
4811b115575SJohn Danielson 	 * return success
4821b115575SJohn Danielson 	 */
4834c06356bSdh 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
4841b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
4854c06356bSdh 		return (DAM_SUCCESS);
4864c06356bSdh 	}
4874c06356bSdh 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
4884c06356bSdh 	ASSERT(passp);
4894c06356bSdh 	if (DAM_IN_REPORT(mapp, addrid)) {
4901b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__del__jitter,
4911b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
4921b94a41bSChris Horne 		    char *, address);
4931b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_jitter);
4941b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
4954c06356bSdh 		passp->da_jitter++;
4964c06356bSdh 	}
4971b115575SJohn Danielson 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL);
4981b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
4994c06356bSdh 	return (DAM_SUCCESS);
5004c06356bSdh }
5014c06356bSdh 
5020b53804eSReed static int
damap_addrset_flush_locked(damap_t * damapp)5030b53804eSReed damap_addrset_flush_locked(damap_t *damapp)
5040b53804eSReed {
50560aabb4cSChris Horne 	dam_t	*mapp = (dam_t *)damapp;
5060b53804eSReed 	int	idx;
5070b53804eSReed 
5080b53804eSReed 	ASSERT(mapp);
5090b53804eSReed 	ASSERT(mutex_owned(&mapp->dam_lock));
5100b53804eSReed 	if (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) {
5110b53804eSReed 		return (DAM_EINVAL);
5120b53804eSReed 	}
5130b53804eSReed 
5141b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__flush__locked__enter,
5151b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
5160b53804eSReed 	if (mapp->dam_flags & DAM_SETADD) {
5171b94a41bSChris Horne 		DTRACE_PROBE2(damap__addrset__flush__locked__reset,
5181b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
5190b53804eSReed 
5200b53804eSReed 		/*
5210b53804eSReed 		 * cancel stabilization timeout
5220b53804eSReed 		 */
52360aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
5240b53804eSReed 		DAM_INCR_STAT(mapp, dam_jitter);
5250b53804eSReed 
5260b53804eSReed 		/*
5270b53804eSReed 		 * clear pending reports
5280b53804eSReed 		 */
5290b53804eSReed 		for (idx = 1; idx < mapp->dam_high; idx++) {
5300b53804eSReed 			if (DAM_IN_REPORT(mapp, idx)) {
5310b53804eSReed 				dam_addr_report_release(mapp, idx);
5320b53804eSReed 			}
5330b53804eSReed 		}
5340b53804eSReed 
5350b53804eSReed 		bitset_zero(&mapp->dam_report_set);
5360b53804eSReed 		mapp->dam_flags &= ~DAM_SETADD;
53760aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
5380b53804eSReed 	}
5390b53804eSReed 
5400b53804eSReed 	return (DAM_SUCCESS);
5410b53804eSReed }
5420b53804eSReed 
5434c06356bSdh /*
5444c06356bSdh  * Initiate full-set report
5454c06356bSdh  *
5464c06356bSdh  * damapp:	address map
5474c06356bSdh  *
5484c06356bSdh  * Returns:	DAM_SUCCESS
5494c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
5504c06356bSdh  */
5514c06356bSdh int
damap_addrset_begin(damap_t * damapp)5524c06356bSdh damap_addrset_begin(damap_t *damapp)
5534c06356bSdh {
5540b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
5550b53804eSReed 	int	rv;
5564c06356bSdh 
5570b53804eSReed 	if (mapp == NULL) {
5584c06356bSdh 		return (DAM_EINVAL);
5590b53804eSReed 	}
5604c06356bSdh 
5611b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__begin,
5621b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
5630b53804eSReed 
5641b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
5651b115575SJohn Danielson 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
5661b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
5670b53804eSReed 
5681b115575SJohn Danielson 		return (DAM_MAPFULL);
5691b115575SJohn Danielson 	}
5701b115575SJohn Danielson 
5710b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
5720b53804eSReed 	if (rv == DAM_SUCCESS) {
5730b53804eSReed 		mapp->dam_flags |= DAM_SETADD;
5744c06356bSdh 	}
5751b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
5760b53804eSReed 
5770b53804eSReed 	return (rv);
5780b53804eSReed }
5790b53804eSReed 
5800b53804eSReed /*
5810b53804eSReed  * Cancel full-set report
5820b53804eSReed  *
58360aabb4cSChris Horne  * damapp:	address map
5840b53804eSReed  *
58560aabb4cSChris Horne  * Returns:	DAM_SUCCESS
58660aabb4cSChris Horne  *		DAM_EINVAL	Invalid argument(s)
5870b53804eSReed  */
5880b53804eSReed int
damap_addrset_flush(damap_t * damapp)5890b53804eSReed damap_addrset_flush(damap_t *damapp)
5900b53804eSReed {
5910b53804eSReed 	int	rv;
5920b53804eSReed 	dam_t	*mapp = (dam_t *)damapp;
5930b53804eSReed 
5940b53804eSReed 	if (mapp == NULL) {
5950b53804eSReed 		return (DAM_EINVAL);
5960b53804eSReed 	}
5970b53804eSReed 
5981b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__flush,
5991b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
6000b53804eSReed 
6010b53804eSReed 	mutex_enter(&mapp->dam_lock);
6020b53804eSReed 	rv = damap_addrset_flush_locked(damapp);
6030b53804eSReed 	mutex_exit(&mapp->dam_lock);
6040b53804eSReed 
6050b53804eSReed 	return (rv);
6064c06356bSdh }
6074c06356bSdh 
6084c06356bSdh /*
6094c06356bSdh  * Report address to full-set report
6104c06356bSdh  *
6114c06356bSdh  * damapp:	address map handle
6124c06356bSdh  * address:	address in ascii string representation
6134c06356bSdh  * rindx:	index if address stabilizes
6144c06356bSdh  * nvl:		optional nvlist of configuration-private data
6154c06356bSdh  * addr_priv:	optional provider-private data (passed to activate/release cb)
6164c06356bSdh  *
6174c06356bSdh  * Returns:	DAM_SUCCESS
6184c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
6194c06356bSdh  *		DAM_MAPFULL	address map exhausted
6204c06356bSdh  *		DAM_FAILURE	General failure
6214c06356bSdh  */
6224c06356bSdh int
damap_addrset_add(damap_t * damapp,char * address,damap_id_t * ridx,nvlist_t * nvl,void * addr_priv)6234c06356bSdh damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
6244c06356bSdh     nvlist_t *nvl, void *addr_priv)
6254c06356bSdh {
6264c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
6274c06356bSdh 	id_t addrid;
6284c06356bSdh 	dam_da_t *passp;
6294c06356bSdh 
6301b115575SJohn Danielson 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6314c06356bSdh 		return (DAM_EINVAL);
6324c06356bSdh 
6331b94a41bSChris Horne 	DTRACE_PROBE3(damap__addrset__add,
6341b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp, char *, address);
6351b115575SJohn Danielson 
6361b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6371b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6381b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6394c06356bSdh 		return (DAM_FAILURE);
6401b115575SJohn Danielson 	}
6414c06356bSdh 
6424c06356bSdh 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
6431b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6444c06356bSdh 		return (DAM_MAPFULL);
6454c06356bSdh 	}
6464c06356bSdh 
6474c06356bSdh 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
6484c06356bSdh 	ASSERT(passp);
6494c06356bSdh 	if (DAM_IN_REPORT(mapp, addrid)) {
6501b94a41bSChris Horne 		DTRACE_PROBE3(damap__addrset__add__jitter,
6511b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
6521b94a41bSChris Horne 		    char *, address);
6531b115575SJohn Danielson 		dam_addr_report_release(mapp, addrid);
6544c06356bSdh 		passp->da_jitter++;
6554c06356bSdh 	}
65678427917SHans Rosenfeld 	passp->da_ppriv = addr_priv;
6574c06356bSdh 	if (nvl)
6584c06356bSdh 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
6594c06356bSdh 	bitset_add(&mapp->dam_report_set, addrid);
6604c06356bSdh 	if (ridx)
6614c06356bSdh 		*ridx = (damap_id_t)addrid;
6621b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
6634c06356bSdh 	return (DAM_SUCCESS);
6644c06356bSdh }
6654c06356bSdh 
6664c06356bSdh /*
6674c06356bSdh  * Commit full-set report for stabilization
6684c06356bSdh  *
6694c06356bSdh  * damapp:	address map handle
6704c06356bSdh  * flags:	(currently 0)
6714c06356bSdh  *
6724c06356bSdh  * Returns:	DAM_SUCCESS
6734c06356bSdh  *		DAM_EINVAL	Invalid argument(s)
6744c06356bSdh  *		DAM_FAILURE	General failure
6754c06356bSdh  */
6764c06356bSdh int
damap_addrset_end(damap_t * damapp,int flags)6774c06356bSdh damap_addrset_end(damap_t *damapp, int flags)
6784c06356bSdh {
6794c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
6804c06356bSdh 	int i;
6814c06356bSdh 
6821b115575SJohn Danielson 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
6834c06356bSdh 		return (DAM_EINVAL);
6844c06356bSdh 
6851b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__end,
6861b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
6871b115575SJohn Danielson 
6881b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
6891b115575SJohn Danielson 	if (!(mapp->dam_flags & DAM_SETADD)) {
6901b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
6914c06356bSdh 		return (DAM_FAILURE);
6921b115575SJohn Danielson 	}
6934c06356bSdh 
6941b115575SJohn Danielson 	if (flags & DAMAP_END_RESET) {
6951b94a41bSChris Horne 		DTRACE_PROBE2(damap__addrset__end__reset,
6961b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
69760aabb4cSChris Horne 		dam_sched_timeout(NULL, mapp, 0);
6984c06356bSdh 		for (i = 1; i < mapp->dam_high; i++)
6994c06356bSdh 			if (DAM_IN_REPORT(mapp, i))
7001b115575SJohn Danielson 				dam_addr_report_release(mapp, i);
7014c06356bSdh 	} else {
7024c06356bSdh 		mapp->dam_last_update = gethrtime();
70360aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
70460aabb4cSChris Horne 		    mapp->dam_stable_ticks);
7054c06356bSdh 	}
7061b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7074c06356bSdh 	return (DAM_SUCCESS);
7084c06356bSdh }
7094c06356bSdh 
7104c06356bSdh /*
7114c06356bSdh  * Return nvlist registered with reported address
7124c06356bSdh  *
7134c06356bSdh  * damapp:	address map handle
7141b115575SJohn Danielson  * addrid:	address ID
7154c06356bSdh  *
7164c06356bSdh  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
7174c06356bSdh  *		NULL
7184c06356bSdh  */
7194c06356bSdh nvlist_t *
damap_id2nvlist(damap_t * damapp,damap_id_t addrid)7204c06356bSdh damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
7214c06356bSdh {
7224c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
7234c06356bSdh 	dam_da_t *pass;
7244c06356bSdh 
7251b115575SJohn Danielson 	if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) {
7261b115575SJohn Danielson 		if (pass = ddi_get_soft_state(mapp->dam_da, addrid))
7274c06356bSdh 			return (pass->da_nvl);
7284c06356bSdh 	}
7294c06356bSdh 	return (NULL);
7304c06356bSdh }
7314c06356bSdh 
7324c06356bSdh /*
7334c06356bSdh  * Return address string
7344c06356bSdh  *
7354c06356bSdh  * damapp:	address map handle
7361b115575SJohn Danielson  * addrid:	address ID
7374c06356bSdh  *
7384c06356bSdh  * Returns:	char *		Address string
7394c06356bSdh  *		NULL
7404c06356bSdh  */
7414c06356bSdh char *
damap_id2addr(damap_t * damapp,damap_id_t addrid)7421b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid)
7434c06356bSdh {
7444c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
7454c06356bSdh 
7461b115575SJohn Danielson 	if (mapp->dam_high)
7471b115575SJohn Danielson 		return (ddi_strid_id2str(mapp->dam_addr_hash, addrid));
7481b115575SJohn Danielson 	else
7491b115575SJohn Danielson 		return (NULL);
7504c06356bSdh }
7514c06356bSdh 
7524c06356bSdh /*
7531b115575SJohn Danielson  * Release address reference in map
7544c06356bSdh  *
7554c06356bSdh  * damapp:	address map handle
7561b115575SJohn Danielson  * addrid:	address ID
7574c06356bSdh  */
7581b115575SJohn Danielson void
damap_id_rele(damap_t * damapp,damap_id_t addrid)7591b115575SJohn Danielson damap_id_rele(damap_t *damapp, damap_id_t addrid)
7604c06356bSdh {
7614c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
7624c06356bSdh 	dam_da_t *passp;
7631b115575SJohn Danielson 	char *addr;
7644c06356bSdh 
7651b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
7661b115575SJohn Danielson 	ASSERT(passp);
7674c06356bSdh 
7681b115575SJohn Danielson 	addr = damap_id2addr(damapp, addrid);
7691b94a41bSChris Horne 	DTRACE_PROBE4(damap__id__rele,
7701b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
7711b94a41bSChris Horne 	    char *, addr, int, passp->da_ref);
7724c06356bSdh 
7731b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
7741b115575SJohn Danielson 
7751b115575SJohn Danielson 	/*
7761b115575SJohn Danielson 	 * teardown address if last outstanding reference
7771b115575SJohn Danielson 	 */
7781b115575SJohn Danielson 	if (--passp->da_ref == 0)
7791b115575SJohn Danielson 		dam_addr_release(mapp, (id_t)addrid);
7804c06356bSdh 
7811b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
7824c06356bSdh }
7834c06356bSdh 
7844c06356bSdh /*
7854c06356bSdh  * Return current reference count on address reference in map
7864c06356bSdh  *
7874c06356bSdh  * damapp:	address map handle
7881b115575SJohn Danielson  * addrid:	address ID
7894c06356bSdh  *
7904c06356bSdh  * Returns:	DAM_SUCCESS
7914c06356bSdh  *		DAM_FAILURE
7924c06356bSdh  */
7934c06356bSdh int
damap_id_ref(damap_t * damapp,damap_id_t addrid)7941b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid)
7954c06356bSdh {
7964c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
7974c06356bSdh 	dam_da_t *passp;
7984c06356bSdh 	int ref = -1;
7994c06356bSdh 
8001b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8014c06356bSdh 	if (passp)
8024c06356bSdh 		ref = passp->da_ref;
8031b115575SJohn Danielson 
8044c06356bSdh 	return (ref);
8054c06356bSdh }
8064c06356bSdh 
8074c06356bSdh /*
8084c06356bSdh  * Return next address ID in list
8094c06356bSdh  *
8104c06356bSdh  * damapp:	address map handle
8114c06356bSdh  * damap_list:	address ID list passed to config|unconfig
8124c06356bSdh  *		returned by look by lookup_all
8134c06356bSdh  * last:	last ID returned, 0 is start of list
8144c06356bSdh  *
8154c06356bSdh  * Returns:	addrid		Next ID from the list
8164c06356bSdh  *		0		End of the list
8174c06356bSdh  */
8184c06356bSdh damap_id_t
damap_id_next(damap_t * damapp,damap_id_list_t damap_list,damap_id_t last)8194c06356bSdh damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
8204c06356bSdh {
8214c06356bSdh 	int i, start;
8224c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
8234c06356bSdh 	bitset_t *dam_list = (bitset_t *)damap_list;
8244c06356bSdh 
8254c06356bSdh 	if (!mapp || !dam_list)
8264c06356bSdh 		return ((damap_id_t)0);
8274c06356bSdh 
8284c06356bSdh 	start = (int)last + 1;
8291b115575SJohn Danielson 	for (i = start; i < mapp->dam_high; i++) {
8301b115575SJohn Danielson 		if (bitset_in_set(dam_list, i)) {
8314c06356bSdh 			return ((damap_id_t)i);
8321b115575SJohn Danielson 		}
8331b115575SJohn Danielson 	}
8344c06356bSdh 	return ((damap_id_t)0);
8354c06356bSdh }
8364c06356bSdh 
8374c06356bSdh /*
8384c06356bSdh  * Set config private data
8394c06356bSdh  *
8404c06356bSdh  * damapp:	address map handle
8411b115575SJohn Danielson  * addrid:	address ID
8424c06356bSdh  * cfg_priv:	configuration private data
8434c06356bSdh  *
8444c06356bSdh  */
8454c06356bSdh void
damap_id_priv_set(damap_t * damapp,damap_id_t addrid,void * cfg_priv)8461b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv)
8474c06356bSdh {
8484c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
8494c06356bSdh 	dam_da_t *passp;
8504c06356bSdh 
8511b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8521b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8534c06356bSdh 	if (!passp) {
8541b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8554c06356bSdh 		return;
8564c06356bSdh 	}
8574c06356bSdh 	passp->da_cfg_priv = cfg_priv;
8581b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8594c06356bSdh }
8604c06356bSdh 
8614c06356bSdh /*
8624c06356bSdh  * Get config private data
8634c06356bSdh  *
8644c06356bSdh  * damapp:	address map handle
8651b115575SJohn Danielson  * addrid:	address ID
8664c06356bSdh  *
8674c06356bSdh  * Returns:	configuration private data
8684c06356bSdh  */
8694c06356bSdh void *
damap_id_priv_get(damap_t * damapp,damap_id_t addrid)8701b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid)
8714c06356bSdh {
8724c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
8734c06356bSdh 	dam_da_t *passp;
8744c06356bSdh 	void *rv;
8754c06356bSdh 
8761b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
8771b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
8784c06356bSdh 	if (!passp) {
8791b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
8804c06356bSdh 		return (NULL);
8814c06356bSdh 	}
8824c06356bSdh 	rv = passp->da_cfg_priv;
8831b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
8844c06356bSdh 	return (rv);
8854c06356bSdh }
8864c06356bSdh 
8874c06356bSdh /*
8884c06356bSdh  * Lookup a single address in the active address map
8894c06356bSdh  *
8904c06356bSdh  * damapp:	address map handle
8914c06356bSdh  * address:	address string
8924c06356bSdh  *
8934c06356bSdh  * Returns:	ID of active/stable address
8944c06356bSdh  *		0	Address not in stable set
8954c06356bSdh  *
8964c06356bSdh  * Future: Allow the caller to wait for stabilize before returning not found.
8974c06356bSdh  */
8984c06356bSdh damap_id_t
damap_lookup(damap_t * damapp,char * address)8994c06356bSdh damap_lookup(damap_t *damapp, char *address)
9004c06356bSdh {
9014c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
9024c06356bSdh 	id_t addrid = 0;
9034c06356bSdh 	dam_da_t *passp = NULL;
9044c06356bSdh 
9051b94a41bSChris Horne 	DTRACE_PROBE3(damap__lookup,
9061b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
9071b94a41bSChris Horne 	    char *, address);
9081b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9091b115575SJohn Danielson 	if (!mapp->dam_high)
9101b115575SJohn Danielson 		addrid = 0;
9111b115575SJohn Danielson 	else
9121b115575SJohn Danielson 		addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
9134c06356bSdh 	if (addrid) {
9144c06356bSdh 		if (DAM_IS_STABLE(mapp, addrid)) {
9154c06356bSdh 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
9164c06356bSdh 			ASSERT(passp);
9174c06356bSdh 			if (passp) {
9184c06356bSdh 				passp->da_ref++;
9194c06356bSdh 			} else {
9204c06356bSdh 				addrid = 0;
9214c06356bSdh 			}
9224c06356bSdh 		} else {
9234c06356bSdh 			addrid = 0;
9244c06356bSdh 		}
9254c06356bSdh 	}
9261b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
9271b94a41bSChris Horne 	DTRACE_PROBE4(damap__lookup__return,
9281b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
9291b94a41bSChris Horne 	    char *, address, int, addrid);
9304c06356bSdh 	return ((damap_id_t)addrid);
9314c06356bSdh }
9324c06356bSdh 
9334c06356bSdh 
9344c06356bSdh /*
9354c06356bSdh  * Return the list of stable addresses in the map
9364c06356bSdh  *
9374c06356bSdh  * damapp:	address map handle
9384c06356bSdh  * id_listp:	pointer to list of address IDs in stable map (returned)
9394c06356bSdh  *
9404c06356bSdh  * Returns:	# of entries returned in alist
9414c06356bSdh  */
9424c06356bSdh int
damap_lookup_all(damap_t * damapp,damap_id_list_t * id_listp)9434c06356bSdh damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
9444c06356bSdh {
9454c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
9464c06356bSdh 	int mapsz = mapp->dam_size;
9474c06356bSdh 	int n_ids, i;
9484c06356bSdh 	bitset_t *bsp;
9491b115575SJohn Danielson 	char	 *addrp;
9504c06356bSdh 	dam_da_t *passp;
9514c06356bSdh 
9521b94a41bSChris Horne 	DTRACE_PROBE2(damap__lookup__all,
9531b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
9541b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
9551b115575SJohn Danielson 	if (!mapp->dam_high) {
9561b115575SJohn Danielson 		*id_listp = (damap_id_list_t)NULL;
9571b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9581b94a41bSChris Horne 		DTRACE_PROBE2(damap__lookup__all__nomap,
9591b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
9601b115575SJohn Danielson 		return (0);
9611b115575SJohn Danielson 	}
9624c06356bSdh 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
9634c06356bSdh 	bitset_init(bsp);
9644c06356bSdh 	bitset_resize(bsp, mapsz);
9654c06356bSdh 	bitset_copy(&mapp->dam_active_set, bsp);
9664c06356bSdh 	for (n_ids = 0, i = 1; i < mapsz; i++) {
9674c06356bSdh 		if (bitset_in_set(bsp, i)) {
9684c06356bSdh 			passp = ddi_get_soft_state(mapp->dam_da, i);
9694c06356bSdh 			ASSERT(passp);
9704c06356bSdh 			if (passp) {
9711b115575SJohn Danielson 				addrp = damap_id2addr(damapp, i);
9721b94a41bSChris Horne 				DTRACE_PROBE3(damap__lookup__all__item,
9731b94a41bSChris Horne 				    char *, mapp->dam_name, dam_t *, mapp,
9741b94a41bSChris Horne 				    char *, addrp);
9754c06356bSdh 				passp->da_ref++;
9764c06356bSdh 				n_ids++;
9774c06356bSdh 			}
9784c06356bSdh 		}
9794c06356bSdh 	}
9804c06356bSdh 	if (n_ids) {
9814c06356bSdh 		*id_listp = (damap_id_list_t)bsp;
9821b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9834c06356bSdh 		return (n_ids);
9844c06356bSdh 	} else {
9854c06356bSdh 		*id_listp = (damap_id_list_t)NULL;
9864c06356bSdh 		bitset_fini(bsp);
9874c06356bSdh 		kmem_free(bsp, sizeof (*bsp));
9881b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
9894c06356bSdh 		return (0);
9904c06356bSdh 	}
9914c06356bSdh }
9924c06356bSdh 
9934c06356bSdh /*
9944c06356bSdh  * Release the address list returned by damap_lookup_all()
9954c06356bSdh  *
9964c06356bSdh  * mapp:	address map handle
9974c06356bSdh  * id_list:	list of address IDs returned in damap_lookup_all()
9984c06356bSdh  */
9994c06356bSdh void
damap_id_list_rele(damap_t * damapp,damap_id_list_t id_list)10004c06356bSdh damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
10014c06356bSdh {
10024c06356bSdh 	dam_t *mapp = (dam_t *)damapp;
10034c06356bSdh 	int i;
10044c06356bSdh 
10054c06356bSdh 	if (id_list == NULL)
10064c06356bSdh 		return;
10074c06356bSdh 
10081b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10094c06356bSdh 	for (i = 1; i < mapp->dam_high; i++) {
10104c06356bSdh 		if (bitset_in_set((bitset_t *)id_list, i))
10111b115575SJohn Danielson 			(void) dam_addr_release(mapp, i);
10124c06356bSdh 	}
10131b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10144c06356bSdh 	bitset_fini((bitset_t *)id_list);
10154c06356bSdh 	kmem_free((void *)id_list, sizeof (bitset_t));
10164c06356bSdh }
10174c06356bSdh 
10184c06356bSdh /*
10191b115575SJohn Danielson  * activate an address that has passed the stabilization interval
10204c06356bSdh  */
10214c06356bSdh static void
dam_addr_activate(dam_t * mapp,id_t addrid)10221b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid)
10234c06356bSdh {
10244c06356bSdh 	dam_da_t *passp;
10251b115575SJohn Danielson 	int config_rv;
10264c06356bSdh 	char *addrstr;
10274c06356bSdh 
10281b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
10291b115575SJohn Danielson 	bitset_add(&mapp->dam_active_set, addrid);
10301b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
10311b115575SJohn Danielson 	ASSERT(passp);
10321b115575SJohn Danielson 
10331b115575SJohn Danielson 	/*
10341b115575SJohn Danielson 	 * copy the reported nvlist and provider private data
10351b115575SJohn Danielson 	 */
10361b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10371b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__activate__start,
10381b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
10391b94a41bSChris Horne 	    char *, addrstr);
10401b115575SJohn Danielson 	passp->da_nvl = passp->da_nvl_rpt;
10411b115575SJohn Danielson 	passp->da_nvl_rpt = NULL;
10421b115575SJohn Danielson 	passp->da_last_stable = gethrtime();
10431b115575SJohn Danielson 	passp->da_stable_cnt++;
10441b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
10451b115575SJohn Danielson 	if (mapp->dam_activate_cb) {
10461b115575SJohn Danielson 		(*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr,
104778427917SHans Rosenfeld 		    addrid, &passp->da_ppriv);
10481b115575SJohn Danielson 	}
10491b115575SJohn Danielson 
10501b115575SJohn Danielson 	/*
10511b115575SJohn Danielson 	 * call the address-specific configuration action as part of
10521b115575SJohn Danielson 	 * activation.
10531b115575SJohn Danielson 	 */
10541b115575SJohn Danielson 	config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp,
10551b115575SJohn Danielson 	    addrid);
10561b115575SJohn Danielson 	if (config_rv != DAM_SUCCESS) {
10571b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
10581b115575SJohn Danielson 		passp->da_flags |= DA_FAILED_CONFIG;
10591b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
10601b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__activate__config__failure,
10611b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
10621b94a41bSChris Horne 		    char *, addrstr);
1063d189c170SReed 		dam_deact_cleanup(mapp, addrid, addrstr,
1064d189c170SReed 		    DAMAP_DEACT_RSN_CFG_FAIL);
1065d189c170SReed 	} else {
10661b94a41bSChris Horne 		DTRACE_PROBE3(damap__addr__activate__end,
10671b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
10681b94a41bSChris Horne 		    char *, addrstr);
10691b115575SJohn Danielson 	}
10701b115575SJohn Danielson }
10711b115575SJohn Danielson 
10721b115575SJohn Danielson /*
10731b115575SJohn Danielson  * deactivate a previously stable address
10741b115575SJohn Danielson  */
10751b115575SJohn Danielson static void
dam_addr_deactivate(dam_t * mapp,id_t addrid)10761b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid)
10771b115575SJohn Danielson {
10781b115575SJohn Danielson 	char *addrstr;
10791b115575SJohn Danielson 
10801b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
10811b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__deactivate__start,
10821b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
10831b94a41bSChris Horne 	    char *, addrstr);
10841b115575SJohn Danielson 
10851b115575SJohn Danielson 	/*
10861b115575SJohn Danielson 	 * call the unconfiguration callback
10871b115575SJohn Danielson 	 */
10881b115575SJohn Danielson 	(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid);
1089d189c170SReed 	dam_deact_cleanup(mapp, addrid, addrstr, DAMAP_DEACT_RSN_GONE);
1090d189c170SReed }
1091d189c170SReed 
1092d189c170SReed static void
dam_deact_cleanup(dam_t * mapp,id_t addrid,char * addrstr,damap_deact_rsn_t deact_rsn)1093d189c170SReed dam_deact_cleanup(dam_t *mapp, id_t addrid, char *addrstr,
1094d189c170SReed     damap_deact_rsn_t deact_rsn)
1095d189c170SReed {
1096d189c170SReed 	dam_da_t *passp;
1097d189c170SReed 
10981b115575SJohn Danielson 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
10991b115575SJohn Danielson 	ASSERT(passp);
11001b115575SJohn Danielson 	if (mapp->dam_deactivate_cb)
11011b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
11021b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
1103d189c170SReed 		    addrid, passp->da_ppriv, deact_rsn);
11041b115575SJohn Danielson 
11051b115575SJohn Danielson 	/*
11061b115575SJohn Danielson 	 * clear the active bit and free the backing info for
11071b115575SJohn Danielson 	 * this address
11081b115575SJohn Danielson 	 */
11091b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
11101b115575SJohn Danielson 	bitset_del(&mapp->dam_active_set, addrid);
11111b115575SJohn Danielson 	passp->da_ppriv = NULL;
1112aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(passp->da_nvl);
11131b115575SJohn Danielson 	passp->da_nvl = NULL;
1114aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(passp->da_nvl_rpt);
11151b115575SJohn Danielson 	passp->da_nvl_rpt = NULL;
11161b115575SJohn Danielson 
11171b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__deactivate__end,
11181b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
11191b94a41bSChris Horne 	    char *, addrstr);
11201b115575SJohn Danielson 
11211b115575SJohn Danielson 	(void) dam_addr_release(mapp, addrid);
11221b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
11231b115575SJohn Danielson }
11241b115575SJohn Danielson 
11251b115575SJohn Danielson /*
11261b115575SJohn Danielson  * taskq callback for multi-thread activation
11271b115575SJohn Danielson  */
11281b115575SJohn Danielson static void
dam_tq_config(void * arg)11291b115575SJohn Danielson dam_tq_config(void *arg)
11301b115575SJohn Danielson {
11311b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11321b115575SJohn Danielson 
11331b115575SJohn Danielson 	dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id);
11341b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11351b115575SJohn Danielson }
11361b115575SJohn Danielson 
11371b115575SJohn Danielson /*
11381b115575SJohn Danielson  * taskq callback for multi-thread deactivation
11391b115575SJohn Danielson  */
11401b115575SJohn Danielson static void
dam_tq_unconfig(void * arg)11411b115575SJohn Danielson dam_tq_unconfig(void *arg)
11421b115575SJohn Danielson {
11431b115575SJohn Danielson 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
11441b115575SJohn Danielson 
11451b115575SJohn Danielson 	dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id);
11461b115575SJohn Danielson 	kmem_free(tqd, sizeof (*tqd));
11471b115575SJohn Danielson }
11481b115575SJohn Danielson 
11491b115575SJohn Danielson /*
11501b115575SJohn Danielson  * Activate a set of stabilized addresses
11511b115575SJohn Danielson  */
11521b115575SJohn Danielson static void
dam_addrset_activate(dam_t * mapp,bitset_t * activate)11531b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate)
11541b115575SJohn Danielson {
11551b115575SJohn Danielson 
11561b115575SJohn Danielson 	int i, nset;
11571b115575SJohn Danielson 	taskq_t *tqp = NULL;
11581b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
11591b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
11601b115575SJohn Danielson 	extern pri_t maxclsyspri;
11611b115575SJohn Danielson 
11621b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
11634c06356bSdh 		/*
11641b115575SJohn Danielson 		 * calculate the # of taskq threads to create
11654c06356bSdh 		 */
11661b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
11671b115575SJohn Danielson 			if (bitset_in_set(activate, i))
11681b115575SJohn Danielson 				nset++;
11691b115575SJohn Danielson 		ASSERT(nset);
11701b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name);
11711b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
11721b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
11731b115575SJohn Danielson 	}
11741b115575SJohn Danielson 	for (i = 1; i < mapp->dam_high; i++) {
11751b115575SJohn Danielson 		if (bitset_in_set(activate, i)) {
11761b115575SJohn Danielson 			if (!tqp)
11771b115575SJohn Danielson 				dam_addr_activate(mapp, i);
11781b115575SJohn Danielson 			else {
11791b115575SJohn Danielson 				/*
11801b115575SJohn Danielson 				 * multi-threaded activation
11811b115575SJohn Danielson 				 */
11821b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
11831b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
11841b115575SJohn Danielson 				tqd->tqd_id = i;
11851b115575SJohn Danielson 				(void) taskq_dispatch(tqp, dam_tq_config,
118664109744SChris Horne 				    tqd, TQ_SLEEP);
11871b115575SJohn Danielson 			}
11881b115575SJohn Danielson 		}
11891b115575SJohn Danielson 	}
11901b115575SJohn Danielson 	if (tqp) {
11911b115575SJohn Danielson 		taskq_wait(tqp);
11921b115575SJohn Danielson 		taskq_destroy(tqp);
11934c06356bSdh 	}
11944c06356bSdh }
11954c06356bSdh 
11964c06356bSdh /*
11971b115575SJohn Danielson  * Deactivate a set of stabilized addresses
11984c06356bSdh  */
11994c06356bSdh static void
dam_addrset_deactivate(dam_t * mapp,bitset_t * deactivate)12001b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate)
12014c06356bSdh {
12021b115575SJohn Danielson 	int i, nset;
12031b115575SJohn Danielson 	taskq_t *tqp = NULL;
12041b115575SJohn Danielson 	cfg_tqd_t *tqd = NULL;
12051b115575SJohn Danielson 	char tqn[TASKQ_NAMELEN];
12061b115575SJohn Danielson 
12071b94a41bSChris Horne 	DTRACE_PROBE2(damap__addrset__deactivate,
12081b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
12094c06356bSdh 
12101b115575SJohn Danielson 	if (mapp->dam_options & DAMAP_MTCONFIG) {
12111b115575SJohn Danielson 		/*
12121b115575SJohn Danielson 		 * compute the # of taskq threads to dispatch
12131b115575SJohn Danielson 		 */
12141b115575SJohn Danielson 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
12151b115575SJohn Danielson 			if (bitset_in_set(deactivate, i))
12161b115575SJohn Danielson 				nset++;
12171b115575SJohn Danielson 		(void) snprintf(tqn, sizeof (tqn), "deactv-%s",
12181b115575SJohn Danielson 		    mapp->dam_name);
12191b115575SJohn Danielson 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
12201b115575SJohn Danielson 		    INT_MAX, TASKQ_PREPOPULATE);
12211b115575SJohn Danielson 	}
12224c06356bSdh 	for (i = 1; i < mapp->dam_high; i++) {
12231b115575SJohn Danielson 		if (bitset_in_set(deactivate, i)) {
12241b115575SJohn Danielson 			if (!tqp) {
12251b115575SJohn Danielson 				dam_addr_deactivate(mapp, i);
12261b115575SJohn Danielson 			} else {
12271b115575SJohn Danielson 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
12281b115575SJohn Danielson 				tqd->tqd_mapp = mapp;
12291b115575SJohn Danielson 				tqd->tqd_id = i;
12301b115575SJohn Danielson 				(void) taskq_dispatch(tqp,
123164109744SChris Horne 				    dam_tq_unconfig, tqd, TQ_SLEEP);
12321b115575SJohn Danielson 			}
12334c06356bSdh 		}
12344c06356bSdh 	}
12351b115575SJohn Danielson 
12361b115575SJohn Danielson 	if (tqp) {
12371b115575SJohn Danielson 		taskq_wait(tqp);
12381b115575SJohn Danielson 		taskq_destroy(tqp);
12391b115575SJohn Danielson 	}
12404c06356bSdh }
12414c06356bSdh 
12424c06356bSdh /*
12431b115575SJohn Danielson  * Release a previously activated address
12444c06356bSdh  */
12454c06356bSdh static void
dam_addr_release(dam_t * mapp,id_t addrid)12461b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid)
12474c06356bSdh {
12484c06356bSdh 	dam_da_t *passp;
12491b115575SJohn Danielson 	char	 *addrstr;
12501b115575SJohn Danielson 
12514c06356bSdh 
12521b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
12534c06356bSdh 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
12544c06356bSdh 	ASSERT(passp);
12554c06356bSdh 
12561b115575SJohn Danielson 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
12571b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__release,
12581b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
12591b94a41bSChris Horne 	    char *, addrstr);
12604c06356bSdh 
12614c06356bSdh 	/*
12621b115575SJohn Danielson 	 * defer releasing the address until outstanding references
12631b115575SJohn Danielson 	 * are released
12644c06356bSdh 	 */
12651b115575SJohn Danielson 	if (passp->da_ref > 1) {
12661b115575SJohn Danielson 		DTRACE_PROBE4(damap__addr__release__outstanding__refs,
12671b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
12681b94a41bSChris Horne 		    char *, addrstr, int, passp->da_ref);
12694c06356bSdh 		return;
12701b115575SJohn Danielson 	}
12714c06356bSdh 
12724c06356bSdh 	/*
12731b115575SJohn Danielson 	 * allow pending reports to stabilize
12744c06356bSdh 	 */
12751b115575SJohn Danielson 	if (DAM_IN_REPORT(mapp, addrid)) {
12761b115575SJohn Danielson 		DTRACE_PROBE3(damap__addr__release__report__pending,
12771b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp,
12781b94a41bSChris Horne 		    char *, addrstr);
12794c06356bSdh 		return;
12804c06356bSdh 	}
12811b115575SJohn Danielson 
12824c06356bSdh 	ddi_strid_free(mapp->dam_addr_hash, addrid);
12834c06356bSdh 	ddi_soft_state_free(mapp->dam_da, addrid);
12844c06356bSdh }
12854c06356bSdh 
12864c06356bSdh /*
12874c06356bSdh  * process stabilized address reports
12884c06356bSdh  */
12894c06356bSdh static void
dam_stabilize_map(void * arg)12901b115575SJohn Danielson dam_stabilize_map(void *arg)
12914c06356bSdh {
12924c06356bSdh 	dam_t *mapp = (dam_t *)arg;
12934c06356bSdh 	bitset_t delta;
12944c06356bSdh 	bitset_t cfg;
12954c06356bSdh 	bitset_t uncfg;
12964c06356bSdh 	int has_cfg, has_uncfg;
12971b115575SJohn Danielson 	uint32_t i, n_active;
12981b115575SJohn Danielson 
12991b94a41bSChris Horne 	DTRACE_PROBE2(damap__stabilize__map,
13001b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
13014c06356bSdh 
13024c06356bSdh 	bitset_init(&delta);
13034c06356bSdh 	bitset_resize(&delta, mapp->dam_size);
13044c06356bSdh 	bitset_init(&cfg);
13054c06356bSdh 	bitset_resize(&cfg, mapp->dam_size);
13064c06356bSdh 	bitset_init(&uncfg);
13074c06356bSdh 	bitset_resize(&uncfg, mapp->dam_size);
13084c06356bSdh 
13091b115575SJohn Danielson 	/*
13101b115575SJohn Danielson 	 * determine which addresses have changed during
13111b115575SJohn Danielson 	 * this stabilization cycle
13121b115575SJohn Danielson 	 */
13131b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13141b115575SJohn Danielson 	ASSERT(mapp->dam_flags & DAM_SPEND);
13154c06356bSdh 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
13164c06356bSdh 	    &delta)) {
13171b115575SJohn Danielson 		/*
13181b115575SJohn Danielson 		 * no difference
13191b115575SJohn Danielson 		 */
13204c06356bSdh 		bitset_zero(&mapp->dam_stable_set);
132160aabb4cSChris Horne 		mapp->dam_flags &= ~DAM_SPEND;
132260aabb4cSChris Horne 		cv_signal(&mapp->dam_sync_cv);
13231b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
132460aabb4cSChris Horne 
13254c06356bSdh 		bitset_fini(&uncfg);
13264c06356bSdh 		bitset_fini(&cfg);
13274c06356bSdh 		bitset_fini(&delta);
13281b94a41bSChris Horne 		DTRACE_PROBE2(damap__stabilize__map__nochange,
13291b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
13304c06356bSdh 		return;
13314c06356bSdh 	}
13321b115575SJohn Danielson 
13331b115575SJohn Danielson 	/*
13341b115575SJohn Danielson 	 * compute the sets of addresses to be activated and deactivated
13351b115575SJohn Danielson 	 */
13364c06356bSdh 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
13374c06356bSdh 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
13381b115575SJohn Danielson 
13391b115575SJohn Danielson 	/*
13401b115575SJohn Danielson 	 * drop map lock while invoking callouts
13411b115575SJohn Danielson 	 */
13421b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
13431b115575SJohn Danielson 
13441b115575SJohn Danielson 	/*
13451b115575SJohn Danielson 	 * activate all newly stable addresss
13461b115575SJohn Danielson 	 */
13471b115575SJohn Danielson 	if (has_cfg)
13484c06356bSdh 		dam_addrset_activate(mapp, &cfg);
13491b115575SJohn Danielson 
13501b115575SJohn Danielson 	/*
13511b115575SJohn Danielson 	 * deactivate addresss which are no longer in the map
13521b115575SJohn Danielson 	 */
13531b115575SJohn Danielson 	if (has_uncfg)
13541b115575SJohn Danielson 		dam_addrset_deactivate(mapp, &uncfg);
13551b115575SJohn Danielson 
13561b115575SJohn Danielson 
13571b115575SJohn Danielson 	/*
13581b115575SJohn Danielson 	 * timestamp the last stable time and increment the kstat keeping
13591b115575SJohn Danielson 	 * the # of of stable cycles for the map
13601b115575SJohn Danielson 	 */
13611b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
13624c06356bSdh 	bitset_zero(&mapp->dam_stable_set);
13634c06356bSdh 	mapp->dam_last_stable = gethrtime();
13644c06356bSdh 	mapp->dam_stable_cnt++;
13651b115575SJohn Danielson 	DAM_INCR_STAT(mapp, dam_cycles);
13661b115575SJohn Danielson 
13671b115575SJohn Danielson 	/*
13681b115575SJohn Danielson 	 * determine the number of stable addresses
13691b115575SJohn Danielson 	 * and update the n_active kstat for this map
13701b115575SJohn Danielson 	 */
13711b115575SJohn Danielson 	for (i = 1, n_active = 0; i < mapp->dam_high; i++)
13721b115575SJohn Danielson 		if (bitset_in_set(&mapp->dam_active_set, i))
13731b115575SJohn Danielson 			n_active++;
13741b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_active, n_active);
13751b115575SJohn Danielson 
13761b94a41bSChris Horne 	DTRACE_PROBE3(damap__map__stable__end,
13771b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
13781b94a41bSChris Horne 	    int, n_active);
13791b115575SJohn Danielson 
138060aabb4cSChris Horne 	mapp->dam_flags &= ~DAM_SPEND;
138160aabb4cSChris Horne 	cv_signal(&mapp->dam_sync_cv);
13821b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
138360aabb4cSChris Horne 
13844c06356bSdh 	bitset_fini(&uncfg);
13854c06356bSdh 	bitset_fini(&cfg);
13864c06356bSdh 	bitset_fini(&delta);
13874c06356bSdh }
13884c06356bSdh 
13894c06356bSdh /*
13904c06356bSdh  * per-address stabilization timeout
13914c06356bSdh  */
13924c06356bSdh static void
dam_addr_stable_cb(void * arg)13934c06356bSdh dam_addr_stable_cb(void *arg)
13944c06356bSdh {
13954c06356bSdh 	dam_t *mapp = (dam_t *)arg;
13964c06356bSdh 	int i;
13974c06356bSdh 	dam_da_t *passp;
13984c06356bSdh 	int spend = 0;
13994c06356bSdh 	int tpend = 0;
140060aabb4cSChris Horne 	int64_t ts, next_ticks, delta_ticks;
14014c06356bSdh 
14021b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
14034c06356bSdh 	if (mapp->dam_tid == 0) {
14041b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__cancelled,
14051b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
14061b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14074c06356bSdh 		return;
14084c06356bSdh 	}
14094c06356bSdh 	mapp->dam_tid = 0;
14101b115575SJohn Danielson 
14114c06356bSdh 	/*
14124c06356bSdh 	 * If still under stabilization, reschedule timeout,
14131b115575SJohn Danielson 	 * otherwise dispatch the task to activate and deactivate the
14141b115575SJohn Danielson 	 * new stable address
14154c06356bSdh 	 */
14164c06356bSdh 	if (mapp->dam_flags & DAM_SPEND) {
14171b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
14184c06356bSdh 		mapp->dam_stable_overrun++;
14191b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__overrun,
14201b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
142160aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
142260aabb4cSChris Horne 		    mapp->dam_stable_ticks);
14231b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
14244c06356bSdh 		return;
14254c06356bSdh 	}
14264c06356bSdh 
14271b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
14281b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
14291b115575SJohn Danielson 
14301b94a41bSChris Horne 	/* See if any reports stabalized and compute next timeout. */
143160aabb4cSChris Horne 	ts = ddi_get_lbolt64();
143260aabb4cSChris Horne 	next_ticks = mapp->dam_stable_ticks;
14334c06356bSdh 	for (i = 1; i < mapp->dam_high; i++) {
14341b94a41bSChris Horne 		if (bitset_in_set(&mapp->dam_report_set, i)) {
14351b94a41bSChris Horne 			passp = ddi_get_soft_state(mapp->dam_da, i);
14361b94a41bSChris Horne 			ASSERT(passp);
14374c06356bSdh 
14381b94a41bSChris Horne 			if (passp->da_deadline <= ts)
14391b94a41bSChris Horne 				spend++;	/* report has stabilized */
14401b94a41bSChris Horne 			else {
14411b94a41bSChris Horne 				/* not stabilized, determine next map timeout */
14421b94a41bSChris Horne 				tpend++;
14431b94a41bSChris Horne 				delta_ticks = passp->da_deadline - ts;
14441b94a41bSChris Horne 				if (delta_ticks < next_ticks)
14451b94a41bSChris Horne 					next_ticks = delta_ticks;
14461b94a41bSChris Horne 			}
14471b94a41bSChris Horne 		}
14484c06356bSdh 	}
14494c06356bSdh 
14504c06356bSdh 	/*
14511b115575SJohn Danielson 	 * schedule system_taskq activation of stabilized reports
14524c06356bSdh 	 */
14534c06356bSdh 	if (spend) {
14541b115575SJohn Danielson 		if (taskq_dispatch(system_taskq, dam_stabilize_map,
1455fc8ae2ecSToomas Soome 		    mapp, TQ_NOSLEEP | TQ_NOQUEUE) != TASKQID_INVALID) {
14561b94a41bSChris Horne 			DTRACE_PROBE2(damap__map__addr__stable__start,
14571b94a41bSChris Horne 			    char *, mapp->dam_name, dam_t *, mapp);
14581b94a41bSChris Horne 
14591b94a41bSChris Horne 			/*
14601b94a41bSChris Horne 			 * The stable_set we compute below stays pending until
14611b94a41bSChris Horne 			 * processed by dam_stabilize_map. We can't set
14621b94a41bSChris Horne 			 * DAM_SPEND (or bitset_del things from the
14631b94a41bSChris Horne 			 * report_set) until we *know* that we can handoff the
14641b94a41bSChris Horne 			 * result to dam_stabilize_map. If dam_stabilize_map
14651b94a41bSChris Horne 			 * starts executing before we are complete, it will
14661b94a41bSChris Horne 			 * block on the dam_lock mutex until we are ready.
14671b94a41bSChris Horne 			 */
146860aabb4cSChris Horne 			mapp->dam_flags |= DAM_SPEND;
14691b94a41bSChris Horne 
14701b94a41bSChris Horne 			/*
14711b94a41bSChris Horne 			 * Copy the current active_set to the stable_set, then
14721b94a41bSChris Horne 			 * add or remove stabilized report_set address from
14731b94a41bSChris Horne 			 * the stable set (and delete them from the report_set).
14741b94a41bSChris Horne 			 */
14751b94a41bSChris Horne 			bitset_copy(&mapp->dam_active_set,
14761b94a41bSChris Horne 			    &mapp->dam_stable_set);
14771b94a41bSChris Horne 			for (i = 1; i < mapp->dam_high; i++) {
14781b94a41bSChris Horne 				if (!bitset_in_set(&mapp->dam_report_set, i))
14791b94a41bSChris Horne 					continue;
14801b94a41bSChris Horne 
14811b94a41bSChris Horne 				passp = ddi_get_soft_state(mapp->dam_da, i);
14821b94a41bSChris Horne 				if (passp->da_deadline > ts)
14831b94a41bSChris Horne 					continue; /* report not stabilized */
14841b94a41bSChris Horne 
14851b94a41bSChris Horne 				/* report has stabilized */
14861b94a41bSChris Horne 				if (passp->da_flags & DA_RELE)
14871b94a41bSChris Horne 					bitset_del(&mapp->dam_stable_set, i);
14881b94a41bSChris Horne 				else
14891b94a41bSChris Horne 					bitset_add(&mapp->dam_stable_set, i);
14901b94a41bSChris Horne 
14911b94a41bSChris Horne 				bitset_del(&mapp->dam_report_set, i);
14921b94a41bSChris Horne 			}
14931b115575SJohn Danielson 		} else {
14941b94a41bSChris Horne 			DTRACE_PROBE2(damap__map__addr__stable__spendfail,
14951b94a41bSChris Horne 			    char *, mapp->dam_name, dam_t *, mapp);
149664109744SChris Horne 
149764109744SChris Horne 			/*
149864109744SChris Horne 			 * Avoid waiting the entire stabalization
149964109744SChris Horne 			 * time again if taskq_diskpatch fails.
150064109744SChris Horne 			 */
15011b94a41bSChris Horne 			tpend++;
150260aabb4cSChris Horne 			delta_ticks = drv_usectohz(
150364109744SChris Horne 			    damap_taskq_dispatch_retry_usec);
150460aabb4cSChris Horne 			if (delta_ticks < next_ticks)
150560aabb4cSChris Horne 				next_ticks = delta_ticks;
15061b115575SJohn Danielson 		}
15074c06356bSdh 	}
15084c06356bSdh 
15094c06356bSdh 	/*
15101b115575SJohn Danielson 	 * reschedule the stabilization timer if there are reports
15111b115575SJohn Danielson 	 * still pending
15124c06356bSdh 	 */
15131b94a41bSChris Horne 	if (tpend) {
15141b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addr__stable__tpend, char *,
15151b94a41bSChris Horne 		    mapp->dam_name, dam_t *, mapp);
151660aabb4cSChris Horne 		dam_sched_timeout(dam_addr_stable_cb, mapp,
151760aabb4cSChris Horne 		    (clock_t)next_ticks);
15181b94a41bSChris Horne 	}
15191b115575SJohn Danielson 
15201b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
15214c06356bSdh }
15224c06356bSdh 
15234c06356bSdh /*
15241b115575SJohn Danielson  * fullset stabilization timeout callback
15254c06356bSdh  */
15264c06356bSdh static void
dam_addrset_stable_cb(void * arg)15271b115575SJohn Danielson dam_addrset_stable_cb(void *arg)
15284c06356bSdh {
15294c06356bSdh 	dam_t *mapp = (dam_t *)arg;
15304c06356bSdh 
15311b115575SJohn Danielson 	mutex_enter(&mapp->dam_lock);
15324c06356bSdh 	if (mapp->dam_tid == 0) {
15331b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
15341b115575SJohn Danielson 		DTRACE_PROBE2(damap__map__addrset__stable__cancelled,
15351b115575SJohn Danielson 		    char *, mapp->dam_name, dam_t *, mapp);
15364c06356bSdh 		return;
15374c06356bSdh 	}
15384c06356bSdh 	mapp->dam_tid = 0;
15394c06356bSdh 
15404c06356bSdh 	/*
15411b115575SJohn Danielson 	 * If map still underoing stabilization reschedule timeout,
15421b115575SJohn Danielson 	 * else dispatch the task to configure the new stable set of
15431b115575SJohn Danielson 	 * addresses.
15444c06356bSdh 	 */
154564109744SChris Horne 	if ((mapp->dam_flags & DAM_SPEND) ||
154664109744SChris Horne 	    (taskq_dispatch(system_taskq, dam_stabilize_map, mapp,
1547fc8ae2ecSToomas Soome 	    TQ_NOSLEEP | TQ_NOQUEUE) == TASKQID_INVALID)) {
15481b115575SJohn Danielson 		DAM_INCR_STAT(mapp, dam_overrun);
15494c06356bSdh 		mapp->dam_stable_overrun++;
155060aabb4cSChris Horne 		dam_sched_timeout(dam_addrset_stable_cb, mapp,
155160aabb4cSChris Horne 		    drv_usectohz(damap_taskq_dispatch_retry_usec));
155264109744SChris Horne 
15531b94a41bSChris Horne 		DTRACE_PROBE2(damap__map__addrset__stable__overrun,
15541b94a41bSChris Horne 		    char *, mapp->dam_name, dam_t *, mapp);
15551b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
15561b115575SJohn Danielson 		return;
15574c06356bSdh 	}
15581b115575SJohn Danielson 
15591b115575SJohn Danielson 	DAM_SET_STAT(mapp, dam_overrun, 0);
15601b115575SJohn Danielson 	mapp->dam_stable_overrun = 0;
15611b115575SJohn Danielson 	bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
15621b115575SJohn Danielson 	bitset_zero(&mapp->dam_report_set);
15631b115575SJohn Danielson 	mapp->dam_flags |= DAM_SPEND;
15641b115575SJohn Danielson 	mapp->dam_flags &= ~DAM_SETADD;
156560aabb4cSChris Horne 	/* NOTE: don't need cv_signal since DAM_SPEND is still set */
156660aabb4cSChris Horne 
15671b94a41bSChris Horne 	DTRACE_PROBE2(damap__map__addrset__stable__start,
15681b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp);
15691b115575SJohn Danielson 	mutex_exit(&mapp->dam_lock);
15704c06356bSdh }
15714c06356bSdh 
15724c06356bSdh /*
157360aabb4cSChris Horne  * schedule map timeout in 'ticks' ticks
157460aabb4cSChris Horne  * if map timer is currently running, cancel if ticks == 0
15754c06356bSdh  */
15764c06356bSdh static void
dam_sched_timeout(void (* timeout_cb)(),dam_t * mapp,clock_t ticks)157760aabb4cSChris Horne dam_sched_timeout(void (*timeout_cb)(), dam_t *mapp, clock_t ticks)
15784c06356bSdh {
15794c06356bSdh 	timeout_id_t tid;
15804c06356bSdh 
15811b94a41bSChris Horne 	DTRACE_PROBE4(damap__sched__timeout,
15821b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
15831b94a41bSChris Horne 	    int, ticks, timeout_id_t, mapp->dam_tid);
15841b115575SJohn Danielson 
15851b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
15864c06356bSdh 	if ((tid = mapp->dam_tid) != 0) {
158760aabb4cSChris Horne 		if (ticks == 0) {
15881b115575SJohn Danielson 			mapp->dam_tid = 0;
15891b115575SJohn Danielson 			mutex_exit(&mapp->dam_lock);
15901b115575SJohn Danielson 			(void) untimeout(tid);
15911b115575SJohn Danielson 			mutex_enter(&mapp->dam_lock);
15921b115575SJohn Danielson 		}
15931b115575SJohn Danielson 	} else {
159460aabb4cSChris Horne 		if (timeout_cb && (ticks != 0))
159560aabb4cSChris Horne 			mapp->dam_tid = timeout(timeout_cb, mapp, ticks);
15964c06356bSdh 	}
15974c06356bSdh }
15984c06356bSdh 
15994c06356bSdh /*
16001b115575SJohn Danielson  * report addition or removal of an address
16014c06356bSdh  */
16024c06356bSdh static void
dam_addr_report(dam_t * mapp,dam_da_t * passp,id_t addrid,int rpt_type)16031b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type)
16044c06356bSdh {
16051b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
16061b115575SJohn Danielson 
16071b94a41bSChris Horne 	DTRACE_PROBE4(damap__addr__report,
16081b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
16091b94a41bSChris Horne 	    char *, addrstr, int, rpt_type);
16101b115575SJohn Danielson 
16111b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16124c06356bSdh 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
16134c06356bSdh 	passp->da_last_report = gethrtime();
16144c06356bSdh 	mapp->dam_last_update = gethrtime();
16154c06356bSdh 	passp->da_report_cnt++;
161660aabb4cSChris Horne 	passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stable_ticks;
16171b115575SJohn Danielson 	if (rpt_type == RPT_ADDR_DEL)
16184c06356bSdh 		passp->da_flags |= DA_RELE;
16191b115575SJohn Danielson 	else if (rpt_type == RPT_ADDR_ADD)
16204c06356bSdh 		passp->da_flags &= ~DA_RELE;
16214c06356bSdh 	bitset_add(&mapp->dam_report_set, addrid);
162260aabb4cSChris Horne 	dam_sched_timeout(dam_addr_stable_cb, mapp, mapp->dam_stable_ticks);
16234c06356bSdh }
16244c06356bSdh 
16254c06356bSdh /*
16264c06356bSdh  * release an address report
16274c06356bSdh  */
16284c06356bSdh static void
dam_addr_report_release(dam_t * mapp,id_t addrid)16291b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid)
16304c06356bSdh {
16314c06356bSdh 	dam_da_t *passp;
16321b115575SJohn Danielson 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
16334c06356bSdh 
16341b94a41bSChris Horne 	DTRACE_PROBE3(damap__addr__report__release,
16351b94a41bSChris Horne 	    char *, mapp->dam_name, dam_t *, mapp,
16361b94a41bSChris Horne 	    char *, addrstr);
16371b115575SJohn Danielson 
16381b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16394c06356bSdh 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
16404c06356bSdh 	ASSERT(passp);
16411b115575SJohn Danielson 	/*
16421b115575SJohn Danielson 	 * clear the report bit
16431b115575SJohn Danielson 	 * if the address has a registered deactivation handler and
16449aed1621SDavid Hollister 	 * we are holding a private data pointer and the address has not
16459aed1621SDavid Hollister 	 * stabilized, deactivate the address (private data).
16461b115575SJohn Danielson 	 */
16471b115575SJohn Danielson 	bitset_del(&mapp->dam_report_set, addrid);
16489aed1621SDavid Hollister 	if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb &&
164978427917SHans Rosenfeld 	    passp->da_ppriv) {
16501b115575SJohn Danielson 		mutex_exit(&mapp->dam_lock);
16511b115575SJohn Danielson 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
16521b115575SJohn Danielson 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
165378427917SHans Rosenfeld 		    addrid, passp->da_ppriv, DAMAP_DEACT_RSN_UNSTBL);
16541b115575SJohn Danielson 		mutex_enter(&mapp->dam_lock);
16551b115575SJohn Danielson 	}
165678427917SHans Rosenfeld 	passp->da_ppriv = NULL;
1657aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(passp->da_nvl_rpt);
16584c06356bSdh }
16594c06356bSdh 
16604c06356bSdh /*
16614c06356bSdh  * return the map ID of an address
16624c06356bSdh  */
16634c06356bSdh static id_t
dam_get_addrid(dam_t * mapp,char * address)16644c06356bSdh dam_get_addrid(dam_t *mapp, char *address)
16654c06356bSdh {
16664c06356bSdh 	damap_id_t addrid;
16674c06356bSdh 	dam_da_t *passp;
16684c06356bSdh 
16691b115575SJohn Danielson 	ASSERT(mutex_owned(&mapp->dam_lock));
16704c06356bSdh 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
16711b115575SJohn Danielson 		if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash,
16724c06356bSdh 		    address)) == (damap_id_t)0) {
16734c06356bSdh 			return (0);
16744c06356bSdh 		}
16754c06356bSdh 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
16764c06356bSdh 		    DDI_SUCCESS) {
16774c06356bSdh 			ddi_strid_free(mapp->dam_addr_hash, addrid);
16784c06356bSdh 			return (0);
16794c06356bSdh 		}
16801b115575SJohn Danielson 
16814c06356bSdh 		if (addrid >= mapp->dam_high)
16824c06356bSdh 			mapp->dam_high = addrid + 1;
16831b115575SJohn Danielson 
16841b115575SJohn Danielson 		/*
16851b115575SJohn Danielson 		 * expand bitmaps if ID has outgrown old map size
16861b115575SJohn Danielson 		 */
16871b115575SJohn Danielson 		if (mapp->dam_high > mapp->dam_size) {
16881b115575SJohn Danielson 			mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP;
16891b115575SJohn Danielson 			bitset_resize(&mapp->dam_active_set, mapp->dam_size);
16901b115575SJohn Danielson 			bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
16911b115575SJohn Danielson 			bitset_resize(&mapp->dam_report_set, mapp->dam_size);
16921b115575SJohn Danielson 		}
16931b115575SJohn Danielson 
16941b115575SJohn Danielson 		passp = ddi_get_soft_state(mapp->dam_da, addrid);
16951b115575SJohn Danielson 		passp->da_ref = 1;
16961b115575SJohn Danielson 		passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash,
16971b115575SJohn Danielson 		    addrid); /* for mdb */
16984c06356bSdh 	}
16994c06356bSdh 	return (addrid);
17004c06356bSdh }
17014c06356bSdh 
17024c06356bSdh /*
17034c06356bSdh  * create and install map statistics
17044c06356bSdh  */
17054c06356bSdh static int
dam_kstat_create(dam_t * mapp)17064c06356bSdh dam_kstat_create(dam_t *mapp)
17074c06356bSdh {
17084c06356bSdh 	kstat_t			*mapsp;
17094c06356bSdh 	struct dam_kstats	*statsp;
17104c06356bSdh 
17114c06356bSdh 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
17124c06356bSdh 	    KSTAT_TYPE_NAMED,
17134c06356bSdh 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
17141b115575SJohn Danielson 
17151b115575SJohn Danielson 	if (mapsp == NULL)
17164c06356bSdh 		return (DDI_FAILURE);
17174c06356bSdh 
17184c06356bSdh 	statsp = (struct dam_kstats *)mapsp->ks_data;
17191b115575SJohn Danielson 	kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32);
17201b115575SJohn Danielson 	kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32);
17211b115575SJohn Danielson 	kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32);
17221b115575SJohn Danielson 	kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32);
17234c06356bSdh 	kstat_install(mapsp);
17244c06356bSdh 	mapp->dam_kstatsp = mapsp;
17254c06356bSdh 	return (DDI_SUCCESS);
17264c06356bSdh }
1727