Home | History | Annotate | Download | only in os
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/note.h>
     28 #include <sys/types.h>
     29 #include <sys/param.h>
     30 #include <sys/systm.h>
     31 #include <sys/buf.h>
     32 #include <sys/kmem.h>
     33 #include <sys/cmn_err.h>
     34 #include <sys/debug.h>
     35 #include <sys/sunndi.h>
     36 #include <sys/kstat.h>
     37 #include <sys/conf.h>
     38 #include <sys/ddi_timer.h>
     39 #include <sys/devctl.h>
     40 #include <sys/callb.h>
     41 #include <sys/sysevent.h>
     42 #include <sys/taskq.h>
     43 #include <sys/ddi.h>
     44 #include <sys/bitset.h>
     45 #include <sys/damap.h>
     46 #include <sys/damap_impl.h>
     47 
     48 #ifdef DEBUG
     49 static int damap_debug = 0;
     50 #endif /* DEBUG */
     51 
     52 extern taskq_t *system_taskq;
     53 
     54 static void dam_addrset_activate(dam_t *, bitset_t *);
     55 static void dam_addrset_deactivate(dam_t *, bitset_t *);
     56 static void dam_stabilize_map(void *);
     57 static void dam_addr_stable_cb(void *);
     58 static void dam_addrset_stable_cb(void *);
     59 static void dam_sched_tmo(dam_t *, clock_t, void (*tmo_cb)());
     60 static void dam_addr_report(dam_t *, dam_da_t *, id_t, int);
     61 static void dam_addr_release(dam_t *, id_t);
     62 static void dam_addr_report_release(dam_t *, id_t);
     63 static void dam_addr_deactivate(dam_t *, id_t);
     64 static id_t dam_get_addrid(dam_t *, char *);
     65 static int dam_kstat_create(dam_t *);
     66 static int dam_map_alloc(dam_t *);
     67 
     68 #define	DAM_INCR_STAT(mapp, stat)				\
     69 	if ((mapp)->dam_kstatsp) {				\
     70 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
     71 		stp->stat.value.ui32++;				\
     72 	}
     73 
     74 #define	DAM_SET_STAT(mapp, stat, val)				\
     75 	if ((mapp)->dam_kstatsp) {				\
     76 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
     77 		stp->stat.value.ui32 = (val);			\
     78 	}
     79 
     80 
     81 /*
     82  * increase damap size by 64 entries at a time
     83  */
     84 #define	DAM_SIZE_BUMP	64
     85 
     86 /*
     87  * config/unconfig taskq data
     88  */
     89 typedef struct {
     90 	dam_t *tqd_mapp;
     91 	id_t tqd_id;
     92 } cfg_tqd_t;
     93 
     94 extern pri_t maxclsyspri;
     95 
     96 /*
     97  * Create new device address map
     98  *
     99  * name:		map name (kstat unique)
    100  * size:		max # of map entries
    101  * mode:		style of address reports: per-address or fullset
    102  * stable_usec:		# of quiescent microseconds before report/map is stable
    103  *
    104  * activate_arg:	address provider activation-callout private
    105  * activate_cb:		address provider activation callback handler
    106  * deactivate_cb:	address provider deactivation callback handler
    107  *
    108  * config_arg:		configuration-callout private
    109  * config_cb:		class configuration callout
    110  * unconfig_cb:		class unconfiguration callout
    111  *
    112  * damapp:		pointer to map handle (return)
    113  *
    114  * Returns:	DAM_SUCCESS
    115  *		DAM_EINVAL	Invalid argument(s)
    116  *		DAM_FAILURE	General failure
    117  */
    118 int
    119 damap_create(char *name, damap_rptmode_t mode, int map_opts,
    120     clock_t stable_usec, void *activate_arg, damap_activate_cb_t activate_cb,
    121     damap_deactivate_cb_t deactivate_cb,
    122     void *config_arg, damap_configure_cb_t configure_cb,
    123     damap_unconfig_cb_t unconfig_cb,
    124     damap_t **damapp)
    125 {
    126 	dam_t *mapp;
    127 
    128 	if (configure_cb == NULL || unconfig_cb == NULL || name == NULL)
    129 		return (DAM_EINVAL);
    130 
    131 	DTRACE_PROBE3(damap__create, char *, name,
    132 	    damap_rptmode_t, mode, clock_t, stable_usec);
    133 
    134 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
    135 	mapp->dam_options = map_opts;
    136 	mapp->dam_stabletmo = drv_usectohz(stable_usec);
    137 	mapp->dam_size = 0;
    138 	mapp->dam_rptmode = mode;
    139 	mapp->dam_activate_arg = activate_arg;
    140 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
    141 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
    142 	mapp->dam_config_arg = config_arg;
    143 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
    144 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
    145 	mapp->dam_name = i_ddi_strdup(name, KM_SLEEP);
    146 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
    147 	cv_init(&mapp->dam_cv, NULL, CV_DRIVER, NULL);
    148 	bitset_init(&mapp->dam_active_set);
    149 	bitset_init(&mapp->dam_stable_set);
    150 	bitset_init(&mapp->dam_report_set);
    151 	*damapp = (damap_t *)mapp;
    152 	return (DAM_SUCCESS);
    153 }
    154 
    155 /*
    156  * Allocate backing resources
    157  *
    158  * DAMs are lightly backed on create - major allocations occur
    159  * at the time a report is made to the map, and are extended on
    160  * a demand basis.
    161  */
    162 static int
    163 dam_map_alloc(dam_t *mapp)
    164 {
    165 	void *softstate_p;
    166 
    167 	ASSERT(mutex_owned(&mapp->dam_lock));
    168 	if (mapp->dam_flags & DAM_DESTROYPEND)
    169 		return (DAM_FAILURE);
    170 
    171 	/*
    172 	 * dam_high > 0 signals map allocation complete
    173 	 */
    174 	if (mapp->dam_high)
    175 		return (DAM_SUCCESS);
    176 
    177 	mapp->dam_size = DAM_SIZE_BUMP;
    178 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t),
    179 	    mapp->dam_size) != DDI_SUCCESS)
    180 		return (DAM_FAILURE);
    181 
    182 	if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) !=
    183 	    DDI_SUCCESS) {
    184 		ddi_soft_state_fini(softstate_p);
    185 		return (DAM_FAILURE);
    186 	}
    187 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
    188 		ddi_soft_state_fini(softstate_p);
    189 		ddi_strid_fini(&mapp->dam_addr_hash);
    190 		return (DAM_FAILURE);
    191 	}
    192 	mapp->dam_da = softstate_p;
    193 	mapp->dam_high = 1;
    194 	bitset_resize(&mapp->dam_active_set, mapp->dam_size);
    195 	bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
    196 	bitset_resize(&mapp->dam_report_set, mapp->dam_size);
    197 	return (DAM_SUCCESS);
    198 }
    199 
    200 /*
    201  * Destroy address map
    202  *
    203  * damapp:	address map
    204  *
    205  * Returns:	DAM_SUCCESS
    206  *		DAM_EINVAL	Invalid argument(s)
    207  *		DAM_FAILURE	General failure
    208  */
    209 void
    210 damap_destroy(damap_t *damapp)
    211 {
    212 	int i;
    213 	dam_t *mapp = (dam_t *)damapp;
    214 
    215 	ASSERT(mapp);
    216 
    217 	DTRACE_PROBE1(damap__destroy, char *, mapp->dam_name);
    218 
    219 	mutex_enter(&mapp->dam_lock);
    220 
    221 	/*
    222 	 * prevent new reports from being added to the map
    223 	 */
    224 	mapp->dam_flags |= DAM_DESTROYPEND;
    225 
    226 	if (mapp->dam_high) {
    227 		mutex_exit(&mapp->dam_lock);
    228 		/*
    229 		 * wait for outstanding reports to stabilize and cancel
    230 		 * the timer for this map
    231 		 */
    232 		(void) damap_sync(damapp);
    233 		mutex_enter(&mapp->dam_lock);
    234 		dam_sched_tmo(mapp, 0, NULL);
    235 
    236 		/*
    237 		 * map is at full stop
    238 		 * release the contents of the map, invoking the
    239 		 * detactivation protocol as addresses are released
    240 		 */
    241 		mutex_exit(&mapp->dam_lock);
    242 		for (i = 1; i < mapp->dam_high; i++) {
    243 			if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
    244 				continue;
    245 
    246 			ASSERT(DAM_IN_REPORT(mapp, i) == 0);
    247 
    248 			if (DAM_IS_STABLE(mapp, i)) {
    249 				dam_addr_deactivate(mapp, i);
    250 			} else {
    251 				ddi_strid_free(mapp->dam_addr_hash, i);
    252 				ddi_soft_state_free(mapp->dam_da, i);
    253 			}
    254 		}
    255 		ddi_strid_fini(&mapp->dam_addr_hash);
    256 		ddi_soft_state_fini(&mapp->dam_da);
    257 		kstat_delete(mapp->dam_kstatsp);
    258 	}
    259 	bitset_fini(&mapp->dam_active_set);
    260 	bitset_fini(&mapp->dam_stable_set);
    261 	bitset_fini(&mapp->dam_report_set);
    262 	mutex_destroy(&mapp->dam_lock);
    263 	cv_destroy(&mapp->dam_cv);
    264 	if (mapp->dam_name)
    265 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
    266 	kmem_free(mapp, sizeof (*mapp));
    267 }
    268 
    269 /*
    270  * Wait for map stability.
    271  *
    272  * damapp:	address map
    273  */
    274 int
    275 damap_sync(damap_t *damapp)
    276 {
    277 #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND)
    278 
    279 	dam_t *mapp = (dam_t *)damapp;
    280 	int   none_active;
    281 
    282 	ASSERT(mapp);
    283 
    284 	DTRACE_PROBE2(damap__map__sync__start, char *, mapp->dam_name,
    285 	    dam_t *, mapp);
    286 
    287 	/*
    288 	 * block where waiting for
    289 	 * a) stabilization pending or a fullset update pending
    290 	 * b) any scheduled timeouts to fire
    291 	 * c) the report set to finalize (bitset is null)
    292 	 */
    293 	mutex_enter(&mapp->dam_lock);
    294 	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
    295 	    (!bitset_is_null(&mapp->dam_report_set)) || (mapp->dam_tid != 0)) {
    296 		DTRACE_PROBE2(damap__map__sync__waiting, char *, mapp->dam_name,
    297 		    dam_t *, mapp);
    298 		cv_wait(&mapp->dam_cv, &mapp->dam_lock);
    299 	}
    300 
    301 	none_active = bitset_is_null(&mapp->dam_active_set);
    302 
    303 	mutex_exit(&mapp->dam_lock);
    304 	DTRACE_PROBE3(damap__map__sync__end, char *, mapp->dam_name, int,
    305 	    none_active, dam_t *, mapp);
    306 
    307 	return (none_active);
    308 }
    309 
    310 /*
    311  * Get the name of a device address map
    312  *
    313  * damapp:	address map
    314  *
    315  * Returns:	name
    316  */
    317 char *
    318 damap_name(damap_t *damapp)
    319 {
    320 	dam_t *mapp = (dam_t *)damapp;
    321 
    322 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
    323 }
    324 
    325 /*
    326  * Report an address to per-address report
    327  *
    328  * damapp:	address map handle
    329  * address:	address in ascii string representation
    330  * addridp:	address ID
    331  * nvl:		optional nvlist of configuration-private data
    332  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
    333  *
    334  * Returns:	DAM_SUCCESS
    335  *		DAM_EINVAL	Invalid argument(s)
    336  *		DAM_MAPFULL	address map exhausted
    337  */
    338 int
    339 damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp,
    340     nvlist_t *nvl, void *addr_priv)
    341 {
    342 	dam_t *mapp = (dam_t *)damapp;
    343 	id_t addrid;
    344 	dam_da_t *passp;
    345 
    346 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
    347 		return (DAM_EINVAL);
    348 
    349 	DTRACE_PROBE3(damap__addr__add, char *, mapp->dam_name,
    350 	    char *, address, dam_t *, mapp);
    351 
    352 	mutex_enter(&mapp->dam_lock);
    353 	if ((dam_map_alloc(mapp) != DAM_SUCCESS) ||
    354 	    ((addrid = dam_get_addrid(mapp, address)) == 0)) {
    355 		mutex_exit(&mapp->dam_lock);
    356 		return (DAM_MAPFULL);
    357 	}
    358 
    359 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
    360 	ASSERT(passp != NULL);
    361 
    362 	/*
    363 	 * If re-reporting the same address (add or remove) clear
    364 	 * the existing report
    365 	 */
    366 	if (DAM_IN_REPORT(mapp, addrid)) {
    367 		DTRACE_PROBE3(damap__addr__add__jitter, char *, mapp->dam_name,
    368 		    char *, address, dam_t *, mapp);
    369 		DAM_INCR_STAT(mapp, dam_jitter);
    370 		dam_addr_report_release(mapp, addrid);
    371 		passp->da_jitter++;
    372 	}
    373 	passp->da_ppriv_rpt = addr_priv;
    374 	if (nvl)
    375 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
    376 
    377 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD);
    378 	if (addridp != NULL)
    379 		*addridp = (damap_id_t)addrid;
    380 	mutex_exit(&mapp->dam_lock);
    381 	return (DAM_SUCCESS);
    382 }
    383 
    384 /*
    385  * Report removal of address from per-address report
    386  *
    387  * damapp:	address map
    388  * address:	address in ascii string representation
    389  *
    390  * Returns:	DAM_SUCCESS
    391  *		DAM_EINVAL	Invalid argument(s)
    392  *		DAM_FAILURE	General failure
    393  */
    394 int
    395 damap_addr_del(damap_t *damapp, char *address)
    396 {
    397 	dam_t *mapp = (dam_t *)damapp;
    398 	id_t addrid;
    399 	dam_da_t *passp;
    400 
    401 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR))
    402 		return (DAM_EINVAL);
    403 
    404 	DTRACE_PROBE3(damap__addr__del, char *, mapp->dam_name,
    405 	    char *, address, dam_t *, mapp);
    406 	mutex_enter(&mapp->dam_lock);
    407 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
    408 		mutex_exit(&mapp->dam_lock);
    409 		return (DAM_MAPFULL);
    410 	}
    411 
    412 	/*
    413 	 * if reporting the removal of an address which is not in the map
    414 	 * return success
    415 	 */
    416 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
    417 		mutex_exit(&mapp->dam_lock);
    418 		return (DAM_SUCCESS);
    419 	}
    420 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
    421 	ASSERT(passp);
    422 	if (DAM_IN_REPORT(mapp, addrid)) {
    423 		DTRACE_PROBE3(damap__addr__del__jitter, char *, mapp->dam_name,
    424 		    char *, address, dam_t *, mapp);
    425 		DAM_INCR_STAT(mapp, dam_jitter);
    426 		dam_addr_report_release(mapp, addrid);
    427 		passp->da_jitter++;
    428 	}
    429 	dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL);
    430 	mutex_exit(&mapp->dam_lock);
    431 	return (DAM_SUCCESS);
    432 }
    433 
    434 /*
    435  * Initiate full-set report
    436  *
    437  * damapp:	address map
    438  *
    439  * Returns:	DAM_SUCCESS
    440  *		DAM_EINVAL	Invalid argument(s)
    441  */
    442 int
    443 damap_addrset_begin(damap_t *damapp)
    444 {
    445 	dam_t *mapp = (dam_t *)damapp;
    446 	int i;
    447 
    448 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
    449 		return (DAM_EINVAL);
    450 
    451 	DTRACE_PROBE2(damap__addrset__begin, char *, mapp->dam_name, dam_t *,
    452 	    mapp);
    453 	mutex_enter(&mapp->dam_lock);
    454 	if (dam_map_alloc(mapp) != DAM_SUCCESS) {
    455 		mutex_exit(&mapp->dam_lock);
    456 		return (DAM_MAPFULL);
    457 	}
    458 	if (mapp->dam_flags & DAM_SETADD) {
    459 		DTRACE_PROBE2(damap__addrset__begin__reset, char *,
    460 		    mapp->dam_name, dam_t *, mapp);
    461 		/*
    462 		 * cancel stabilization timeout
    463 		 */
    464 		dam_sched_tmo(mapp, 0, NULL);
    465 		DAM_INCR_STAT(mapp, dam_jitter);
    466 
    467 		/*
    468 		 * clear pending reports
    469 		 */
    470 		for (i = 1; i < mapp->dam_high; i++) {
    471 			if (DAM_IN_REPORT(mapp, i))
    472 				dam_addr_report_release(mapp, i);
    473 		}
    474 	}
    475 	bitset_zero(&mapp->dam_report_set);
    476 	mapp->dam_flags |= DAM_SETADD;
    477 	mutex_exit(&mapp->dam_lock);
    478 	return (DAM_SUCCESS);
    479 }
    480 
    481 /*
    482  * Report address to full-set report
    483  *
    484  * damapp:	address map handle
    485  * address:	address in ascii string representation
    486  * rindx:	index if address stabilizes
    487  * nvl:		optional nvlist of configuration-private data
    488  * addr_priv:	optional provider-private data (passed to activate/release cb)
    489  *
    490  * Returns:	DAM_SUCCESS
    491  *		DAM_EINVAL	Invalid argument(s)
    492  *		DAM_MAPFULL	address map exhausted
    493  *		DAM_FAILURE	General failure
    494  */
    495 int
    496 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
    497     nvlist_t *nvl, void *addr_priv)
    498 {
    499 	dam_t *mapp = (dam_t *)damapp;
    500 	id_t addrid;
    501 	dam_da_t *passp;
    502 
    503 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
    504 		return (DAM_EINVAL);
    505 
    506 	DTRACE_PROBE3(damap__addrset__add, char *, mapp->dam_name,
    507 	    char *, address, dam_t *, mapp);
    508 
    509 	mutex_enter(&mapp->dam_lock);
    510 	if (!(mapp->dam_flags & DAM_SETADD)) {
    511 		mutex_exit(&mapp->dam_lock);
    512 		return (DAM_FAILURE);
    513 	}
    514 
    515 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
    516 		mutex_exit(&mapp->dam_lock);
    517 		return (DAM_MAPFULL);
    518 	}
    519 
    520 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
    521 	ASSERT(passp);
    522 	if (DAM_IN_REPORT(mapp, addrid)) {
    523 		DTRACE_PROBE3(damap__addrset__add__jitter, char *,
    524 		    mapp->dam_name, char *, address, dam_t *, mapp);
    525 		dam_addr_report_release(mapp, addrid);
    526 		passp->da_jitter++;
    527 	}
    528 	passp->da_ppriv_rpt = addr_priv;
    529 	if (nvl)
    530 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
    531 	bitset_add(&mapp->dam_report_set, addrid);
    532 	if (ridx)
    533 		*ridx = (damap_id_t)addrid;
    534 	mutex_exit(&mapp->dam_lock);
    535 	return (DAM_SUCCESS);
    536 }
    537 
    538 /*
    539  * Commit full-set report for stabilization
    540  *
    541  * damapp:	address map handle
    542  * flags:	(currently 0)
    543  *
    544  * Returns:	DAM_SUCCESS
    545  *		DAM_EINVAL	Invalid argument(s)
    546  *		DAM_FAILURE	General failure
    547  */
    548 int
    549 damap_addrset_end(damap_t *damapp, int flags)
    550 {
    551 	dam_t *mapp = (dam_t *)damapp;
    552 	int i;
    553 
    554 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET))
    555 		return (DAM_EINVAL);
    556 
    557 	DTRACE_PROBE2(damap__addrset__end, char *, mapp->dam_name,
    558 	    dam_t *, mapp);
    559 
    560 	mutex_enter(&mapp->dam_lock);
    561 	if (!(mapp->dam_flags & DAM_SETADD)) {
    562 		mutex_exit(&mapp->dam_lock);
    563 		return (DAM_FAILURE);
    564 	}
    565 
    566 	if (flags & DAMAP_END_RESET) {
    567 		DTRACE_PROBE2(damap__addrset__end__reset, char *,
    568 		    mapp->dam_name, dam_t *, mapp);
    569 		dam_sched_tmo(mapp, 0, NULL);
    570 		for (i = 1; i < mapp->dam_high; i++)
    571 			if (DAM_IN_REPORT(mapp, i))
    572 				dam_addr_report_release(mapp, i);
    573 	} else {
    574 		mapp->dam_last_update = gethrtime();
    575 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb);
    576 	}
    577 	mutex_exit(&mapp->dam_lock);
    578 	return (DAM_SUCCESS);
    579 }
    580 
    581 /*
    582  * Return nvlist registered with reported address
    583  *
    584  * damapp:	address map handle
    585  * addrid:	address ID
    586  *
    587  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
    588  *		NULL
    589  */
    590 nvlist_t *
    591 damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
    592 {
    593 	dam_t *mapp = (dam_t *)damapp;
    594 	dam_da_t *pass;
    595 
    596 	if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) {
    597 		if (pass = ddi_get_soft_state(mapp->dam_da, addrid))
    598 			return (pass->da_nvl);
    599 	}
    600 	return (NULL);
    601 }
    602 
    603 /*
    604  * Return address string
    605  *
    606  * damapp:	address map handle
    607  * addrid:	address ID
    608  *
    609  * Returns:	char *		Address string
    610  *		NULL
    611  */
    612 char *
    613 damap_id2addr(damap_t *damapp, damap_id_t addrid)
    614 {
    615 	dam_t *mapp = (dam_t *)damapp;
    616 
    617 	if (mapp->dam_high)
    618 		return (ddi_strid_id2str(mapp->dam_addr_hash, addrid));
    619 	else
    620 		return (NULL);
    621 }
    622 
    623 /*
    624  * Release address reference in map
    625  *
    626  * damapp:	address map handle
    627  * addrid:	address ID
    628  */
    629 void
    630 damap_id_rele(damap_t *damapp, damap_id_t addrid)
    631 {
    632 	dam_t *mapp = (dam_t *)damapp;
    633 	dam_da_t *passp;
    634 	char *addr;
    635 
    636 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
    637 	ASSERT(passp);
    638 
    639 	addr = damap_id2addr(damapp, addrid);
    640 	DTRACE_PROBE4(damap__id__rele, char *, mapp->dam_name, char *, addr,
    641 	    dam_t *, mapp, int, passp->da_ref);
    642 
    643 	mutex_enter(&mapp->dam_lock);
    644 
    645 	/*
    646 	 * teardown address if last outstanding reference
    647 	 */
    648 	if (--passp->da_ref == 0)
    649 		dam_addr_release(mapp, (id_t)addrid);
    650 
    651 	mutex_exit(&mapp->dam_lock);
    652 }
    653 
    654 /*
    655  * Return current reference count on address reference in map
    656  *
    657  * damapp:	address map handle
    658  * addrid:	address ID
    659  *
    660  * Returns:	DAM_SUCCESS
    661  *		DAM_FAILURE
    662  */
    663 int
    664 damap_id_ref(damap_t *damapp, damap_id_t addrid)
    665 {
    666 	dam_t *mapp = (dam_t *)damapp;
    667 	dam_da_t *passp;
    668 	int ref = -1;
    669 
    670 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
    671 	if (passp)
    672 		ref = passp->da_ref;
    673 
    674 	return (ref);
    675 }
    676 
    677 /*
    678  * Return next address ID in list
    679  *
    680  * damapp:	address map handle
    681  * damap_list:	address ID list passed to config|unconfig
    682  *		returned by look by lookup_all
    683  * last:	last ID returned, 0 is start of list
    684  *
    685  * Returns:	addrid		Next ID from the list
    686  *		0		End of the list
    687  */
    688 damap_id_t
    689 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
    690 {
    691 	int i, start;
    692 	dam_t *mapp = (dam_t *)damapp;
    693 	bitset_t *dam_list = (bitset_t *)damap_list;
    694 
    695 	if (!mapp || !dam_list)
    696 		return ((damap_id_t)0);
    697 
    698 	start = (int)last + 1;
    699 	for (i = start; i < mapp->dam_high; i++) {
    700 		if (bitset_in_set(dam_list, i)) {
    701 			return ((damap_id_t)i);
    702 		}
    703 	}
    704 	return ((damap_id_t)0);
    705 }
    706 
    707 /*
    708  * Set config private data
    709  *
    710  * damapp:	address map handle
    711  * addrid:	address ID
    712  * cfg_priv:	configuration private data
    713  *
    714  */
    715 void
    716 damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv)
    717 {
    718 	dam_t *mapp = (dam_t *)damapp;
    719 	dam_da_t *passp;
    720 
    721 	mutex_enter(&mapp->dam_lock);
    722 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
    723 	if (!passp) {
    724 		mutex_exit(&mapp->dam_lock);
    725 		return;
    726 	}
    727 	passp->da_cfg_priv = cfg_priv;
    728 	mutex_exit(&mapp->dam_lock);
    729 }
    730 
    731 /*
    732  * Get config private data
    733  *
    734  * damapp:	address map handle
    735  * addrid:	address ID
    736  *
    737  * Returns:	configuration private data
    738  */
    739 void *
    740 damap_id_priv_get(damap_t *damapp, damap_id_t addrid)
    741 {
    742 	dam_t *mapp = (dam_t *)damapp;
    743 	dam_da_t *passp;
    744 	void *rv;
    745 
    746 	mutex_enter(&mapp->dam_lock);
    747 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid);
    748 	if (!passp) {
    749 		mutex_exit(&mapp->dam_lock);
    750 		return (NULL);
    751 	}
    752 	rv = passp->da_cfg_priv;
    753 	mutex_exit(&mapp->dam_lock);
    754 	return (rv);
    755 }
    756 
    757 /*
    758  * Lookup a single address in the active address map
    759  *
    760  * damapp:	address map handle
    761  * address:	address string
    762  *
    763  * Returns:	ID of active/stable address
    764  *		0	Address not in stable set
    765  *
    766  * Future: Allow the caller to wait for stabilize before returning not found.
    767  */
    768 damap_id_t
    769 damap_lookup(damap_t *damapp, char *address)
    770 {
    771 	dam_t *mapp = (dam_t *)damapp;
    772 	id_t addrid = 0;
    773 	dam_da_t *passp = NULL;
    774 
    775 	DTRACE_PROBE3(damap__lookup, char *, mapp->dam_name,
    776 	    char *, address, dam_t *, mapp);
    777 	mutex_enter(&mapp->dam_lock);
    778 	if (!mapp->dam_high)
    779 		addrid = 0;
    780 	else
    781 		addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
    782 	if (addrid) {
    783 		if (DAM_IS_STABLE(mapp, addrid)) {
    784 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
    785 			ASSERT(passp);
    786 			if (passp) {
    787 				passp->da_ref++;
    788 			} else {
    789 				addrid = 0;
    790 			}
    791 		} else {
    792 			addrid = 0;
    793 		}
    794 	}
    795 	mutex_exit(&mapp->dam_lock);
    796 	DTRACE_PROBE4(damap__lookup__return, char *, mapp->dam_name,
    797 	    char *, address, dam_t *, mapp, int, addrid);
    798 	return ((damap_id_t)addrid);
    799 }
    800 
    801 
    802 /*
    803  * Return the list of stable addresses in the map
    804  *
    805  * damapp:	address map handle
    806  * id_listp:	pointer to list of address IDs in stable map (returned)
    807  *
    808  * Returns:	# of entries returned in alist
    809  */
    810 int
    811 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
    812 {
    813 	dam_t *mapp = (dam_t *)damapp;
    814 	int mapsz = mapp->dam_size;
    815 	int n_ids, i;
    816 	bitset_t *bsp;
    817 	char	 *addrp;
    818 	dam_da_t *passp;
    819 
    820 	DTRACE_PROBE2(damap__lookup__all, char *, mapp->dam_name,
    821 	    dam_t *, mapp);
    822 	mutex_enter(&mapp->dam_lock);
    823 	if (!mapp->dam_high) {
    824 		*id_listp = (damap_id_list_t)NULL;
    825 		mutex_exit(&mapp->dam_lock);
    826 		DTRACE_PROBE3(damap__lookup__all__nomap, char *,
    827 		    mapp->dam_name, dam_t *, mapp, int, 0);
    828 		return (0);
    829 	}
    830 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
    831 	bitset_init(bsp);
    832 	bitset_resize(bsp, mapsz);
    833 	bitset_copy(&mapp->dam_active_set, bsp);
    834 	for (n_ids = 0, i = 1; i < mapsz; i++) {
    835 		if (bitset_in_set(bsp, i)) {
    836 			passp = ddi_get_soft_state(mapp->dam_da, i);
    837 			ASSERT(passp);
    838 			if (passp) {
    839 				addrp = damap_id2addr(damapp, i);
    840 				DTRACE_PROBE3(damap__lookup__all__item, char *,
    841 				    mapp->dam_name, char *, addrp, dam_t *,
    842 				    mapp);
    843 				passp->da_ref++;
    844 				n_ids++;
    845 			}
    846 		}
    847 	}
    848 	if (n_ids) {
    849 		*id_listp = (damap_id_list_t)bsp;
    850 		mutex_exit(&mapp->dam_lock);
    851 		return (n_ids);
    852 	} else {
    853 		*id_listp = (damap_id_list_t)NULL;
    854 		bitset_fini(bsp);
    855 		kmem_free(bsp, sizeof (*bsp));
    856 		mutex_exit(&mapp->dam_lock);
    857 		return (0);
    858 	}
    859 }
    860 
    861 /*
    862  * Release the address list returned by damap_lookup_all()
    863  *
    864  * mapp:	address map handle
    865  * id_list:	list of address IDs returned in damap_lookup_all()
    866  */
    867 void
    868 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
    869 {
    870 	dam_t *mapp = (dam_t *)damapp;
    871 	int i;
    872 
    873 	if (id_list == NULL)
    874 		return;
    875 
    876 	mutex_enter(&mapp->dam_lock);
    877 	for (i = 1; i < mapp->dam_high; i++) {
    878 		if (bitset_in_set((bitset_t *)id_list, i))
    879 			(void) dam_addr_release(mapp, i);
    880 	}
    881 	mutex_exit(&mapp->dam_lock);
    882 	bitset_fini((bitset_t *)id_list);
    883 	kmem_free((void *)id_list, sizeof (bitset_t));
    884 }
    885 
    886 /*
    887  * activate an address that has passed the stabilization interval
    888  */
    889 static void
    890 dam_addr_activate(dam_t *mapp, id_t addrid)
    891 {
    892 	dam_da_t *passp;
    893 	int config_rv;
    894 	char *addrstr;
    895 
    896 	mutex_enter(&mapp->dam_lock);
    897 	bitset_add(&mapp->dam_active_set, addrid);
    898 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
    899 	ASSERT(passp);
    900 
    901 	/*
    902 	 * copy the reported nvlist and provider private data
    903 	 */
    904 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
    905 	DTRACE_PROBE3(damap__addr__activate__start, char *, mapp->dam_name,
    906 	    char *, addrstr, dam_t *, mapp);
    907 	passp->da_nvl = passp->da_nvl_rpt;
    908 	passp->da_ppriv = passp->da_ppriv_rpt;
    909 	passp->da_ppriv_rpt = NULL;
    910 	passp->da_nvl_rpt = NULL;
    911 	passp->da_last_stable = gethrtime();
    912 	passp->da_stable_cnt++;
    913 	mutex_exit(&mapp->dam_lock);
    914 	if (mapp->dam_activate_cb) {
    915 		(*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr,
    916 		    addrid, &passp->da_ppriv_rpt);
    917 	}
    918 
    919 	/*
    920 	 * call the address-specific configuration action as part of
    921 	 * activation.
    922 	 */
    923 	config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp,
    924 	    addrid);
    925 	if (config_rv != DAM_SUCCESS) {
    926 		mutex_enter(&mapp->dam_lock);
    927 		passp->da_flags |= DA_FAILED_CONFIG;
    928 		mutex_exit(&mapp->dam_lock);
    929 		DTRACE_PROBE3(damap__addr__activate__config__failure,
    930 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
    931 	}
    932 	DTRACE_PROBE3(damap__addr__activate__end, char *, mapp->dam_name,
    933 	    char *, addrstr, dam_t *, mapp);
    934 }
    935 
    936 /*
    937  * deactivate a previously stable address
    938  */
    939 static void
    940 dam_addr_deactivate(dam_t *mapp, id_t addrid)
    941 {
    942 	dam_da_t *passp;
    943 	char *addrstr;
    944 
    945 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
    946 	DTRACE_PROBE3(damap__addr__deactivate__start, char *, mapp->dam_name,
    947 	    char *, addrstr, dam_t *, mapp);
    948 
    949 	/*
    950 	 * call the unconfiguration callback
    951 	 */
    952 	(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid);
    953 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
    954 	ASSERT(passp);
    955 	if (mapp->dam_deactivate_cb)
    956 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
    957 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
    958 		    addrid, passp->da_ppriv);
    959 
    960 	/*
    961 	 * clear the active bit and free the backing info for
    962 	 * this address
    963 	 */
    964 	mutex_enter(&mapp->dam_lock);
    965 	bitset_del(&mapp->dam_active_set, addrid);
    966 	passp->da_ppriv = NULL;
    967 	if (passp->da_nvl)
    968 		nvlist_free(passp->da_nvl);
    969 	passp->da_nvl = NULL;
    970 	passp->da_ppriv_rpt = NULL;
    971 	if (passp->da_nvl_rpt)
    972 		nvlist_free(passp->da_nvl_rpt);
    973 	passp->da_nvl_rpt = NULL;
    974 
    975 	DTRACE_PROBE3(damap__addr__deactivate__end, char *, mapp->dam_name,
    976 	    char *, addrstr, dam_t *, mapp);
    977 
    978 	(void) dam_addr_release(mapp, addrid);
    979 	mutex_exit(&mapp->dam_lock);
    980 }
    981 
    982 /*
    983  * taskq callback for multi-thread activation
    984  */
    985 static void
    986 dam_tq_config(void *arg)
    987 {
    988 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
    989 
    990 	dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id);
    991 	kmem_free(tqd, sizeof (*tqd));
    992 }
    993 
    994 /*
    995  * taskq callback for multi-thread deactivation
    996  */
    997 static void
    998 dam_tq_unconfig(void *arg)
    999 {
   1000 	cfg_tqd_t *tqd = (cfg_tqd_t *)arg;
   1001 
   1002 	dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id);
   1003 	kmem_free(tqd, sizeof (*tqd));
   1004 }
   1005 
   1006 /*
   1007  * Activate a set of stabilized addresses
   1008  */
   1009 static void
   1010 dam_addrset_activate(dam_t *mapp, bitset_t *activate)
   1011 {
   1012 
   1013 	int i, nset;
   1014 	taskq_t *tqp = NULL;
   1015 	cfg_tqd_t *tqd = NULL;
   1016 	char tqn[TASKQ_NAMELEN];
   1017 	extern pri_t maxclsyspri;
   1018 
   1019 	if (mapp->dam_options & DAMAP_MTCONFIG) {
   1020 		/*
   1021 		 * calculate the # of taskq threads to create
   1022 		 */
   1023 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
   1024 			if (bitset_in_set(activate, i))
   1025 				nset++;
   1026 		ASSERT(nset);
   1027 		(void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name);
   1028 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
   1029 		    INT_MAX, TASKQ_PREPOPULATE);
   1030 	}
   1031 	for (i = 1; i < mapp->dam_high; i++) {
   1032 		if (bitset_in_set(activate, i)) {
   1033 			if (!tqp)
   1034 				dam_addr_activate(mapp, i);
   1035 			else {
   1036 				/*
   1037 				 * multi-threaded activation
   1038 				 */
   1039 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
   1040 				tqd->tqd_mapp = mapp;
   1041 				tqd->tqd_id = i;
   1042 				(void) taskq_dispatch(tqp, dam_tq_config,
   1043 				    tqd, KM_SLEEP);
   1044 			}
   1045 		}
   1046 	}
   1047 	if (tqp) {
   1048 		taskq_wait(tqp);
   1049 		taskq_destroy(tqp);
   1050 	}
   1051 }
   1052 
   1053 /*
   1054  * Deactivate a set of stabilized addresses
   1055  */
   1056 static void
   1057 dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate)
   1058 {
   1059 	int i, nset;
   1060 	taskq_t *tqp = NULL;
   1061 	cfg_tqd_t *tqd = NULL;
   1062 	char tqn[TASKQ_NAMELEN];
   1063 
   1064 	DTRACE_PROBE2(damap__addrset__deactivate, char *, mapp->dam_name,
   1065 	    dam_t *, mapp);
   1066 
   1067 	if (mapp->dam_options & DAMAP_MTCONFIG) {
   1068 		/*
   1069 		 * compute the # of taskq threads to dispatch
   1070 		 */
   1071 		for (i = 1, nset = 0; i < mapp->dam_high; i++)
   1072 			if (bitset_in_set(deactivate, i))
   1073 				nset++;
   1074 		(void) snprintf(tqn, sizeof (tqn), "deactv-%s",
   1075 		    mapp->dam_name);
   1076 		tqp = taskq_create(tqn, nset, maxclsyspri, 1,
   1077 		    INT_MAX, TASKQ_PREPOPULATE);
   1078 	}
   1079 	for (i = 1; i < mapp->dam_high; i++) {
   1080 		if (bitset_in_set(deactivate, i)) {
   1081 			if (!tqp) {
   1082 				dam_addr_deactivate(mapp, i);
   1083 			} else {
   1084 				tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP);
   1085 				tqd->tqd_mapp = mapp;
   1086 				tqd->tqd_id = i;
   1087 				(void) taskq_dispatch(tqp,
   1088 				    dam_tq_unconfig, tqd, KM_SLEEP);
   1089 			}
   1090 		}
   1091 	}
   1092 
   1093 	if (tqp) {
   1094 		taskq_wait(tqp);
   1095 		taskq_destroy(tqp);
   1096 	}
   1097 }
   1098 
   1099 /*
   1100  * Release a previously activated address
   1101  */
   1102 static void
   1103 dam_addr_release(dam_t *mapp, id_t addrid)
   1104 {
   1105 	dam_da_t *passp;
   1106 	char	 *addrstr;
   1107 
   1108 
   1109 	ASSERT(mutex_owned(&mapp->dam_lock));
   1110 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
   1111 	ASSERT(passp);
   1112 
   1113 	addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid);
   1114 	DTRACE_PROBE3(damap__addr__release, char *, mapp->dam_name,
   1115 	    char *, addrstr, dam_t *, mapp);
   1116 
   1117 	/*
   1118 	 * defer releasing the address until outstanding references
   1119 	 * are released
   1120 	 */
   1121 	if (passp->da_ref > 1) {
   1122 		DTRACE_PROBE4(damap__addr__release__outstanding__refs,
   1123 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp,
   1124 		    int, passp->da_ref);
   1125 		return;
   1126 	}
   1127 
   1128 	/*
   1129 	 * allow pending reports to stabilize
   1130 	 */
   1131 	if (DAM_IN_REPORT(mapp, addrid)) {
   1132 		DTRACE_PROBE3(damap__addr__release__report__pending,
   1133 		    char *, mapp->dam_name, char *, addrstr, dam_t *, mapp);
   1134 		return;
   1135 	}
   1136 
   1137 	ddi_strid_free(mapp->dam_addr_hash, addrid);
   1138 	ddi_soft_state_free(mapp->dam_da, addrid);
   1139 }
   1140 
   1141 /*
   1142  * process stabilized address reports
   1143  */
   1144 static void
   1145 dam_stabilize_map(void *arg)
   1146 {
   1147 	dam_t *mapp = (dam_t *)arg;
   1148 	bitset_t delta;
   1149 	bitset_t cfg;
   1150 	bitset_t uncfg;
   1151 	int has_cfg, has_uncfg;
   1152 	uint32_t i, n_active;
   1153 
   1154 	DTRACE_PROBE2(damap__stabilize__map, char *, mapp->dam_name,
   1155 	    dam_t *, mapp);
   1156 
   1157 	bitset_init(&delta);
   1158 	bitset_resize(&delta, mapp->dam_size);
   1159 	bitset_init(&cfg);
   1160 	bitset_resize(&cfg, mapp->dam_size);
   1161 	bitset_init(&uncfg);
   1162 	bitset_resize(&uncfg, mapp->dam_size);
   1163 
   1164 	/*
   1165 	 * determine which addresses have changed during
   1166 	 * this stabilization cycle
   1167 	 */
   1168 	mutex_enter(&mapp->dam_lock);
   1169 	ASSERT(mapp->dam_flags & DAM_SPEND);
   1170 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
   1171 	    &delta)) {
   1172 		/*
   1173 		 * no difference
   1174 		 */
   1175 		bitset_zero(&mapp->dam_stable_set);
   1176 		mapp->dam_flags  &= ~DAM_SPEND;
   1177 		cv_signal(&mapp->dam_cv);
   1178 		mutex_exit(&mapp->dam_lock);
   1179 		bitset_fini(&uncfg);
   1180 		bitset_fini(&cfg);
   1181 		bitset_fini(&delta);
   1182 		DTRACE_PROBE2(damap__stabilize__map__nochange, char *,
   1183 		    mapp->dam_name, dam_t *, mapp);
   1184 		return;
   1185 	}
   1186 
   1187 	/*
   1188 	 * compute the sets of addresses to be activated and deactivated
   1189 	 */
   1190 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
   1191 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
   1192 
   1193 	/*
   1194 	 * drop map lock while invoking callouts
   1195 	 */
   1196 	mutex_exit(&mapp->dam_lock);
   1197 
   1198 	/*
   1199 	 * activate all newly stable addresss
   1200 	 */
   1201 	if (has_cfg)
   1202 		dam_addrset_activate(mapp, &cfg);
   1203 
   1204 	/*
   1205 	 * deactivate addresss which are no longer in the map
   1206 	 */
   1207 	if (has_uncfg)
   1208 		dam_addrset_deactivate(mapp, &uncfg);
   1209 
   1210 
   1211 	/*
   1212 	 * timestamp the last stable time and increment the kstat keeping
   1213 	 * the # of of stable cycles for the map
   1214 	 */
   1215 	mutex_enter(&mapp->dam_lock);
   1216 	bitset_zero(&mapp->dam_stable_set);
   1217 	mapp->dam_last_stable = gethrtime();
   1218 	mapp->dam_stable_cnt++;
   1219 	DAM_INCR_STAT(mapp, dam_cycles);
   1220 
   1221 	/*
   1222 	 * determine the number of stable addresses
   1223 	 * and update the n_active kstat for this map
   1224 	 */
   1225 	for (i = 1, n_active = 0; i < mapp->dam_high; i++)
   1226 		if (bitset_in_set(&mapp->dam_active_set, i))
   1227 			n_active++;
   1228 	DAM_SET_STAT(mapp, dam_active, n_active);
   1229 
   1230 	DTRACE_PROBE3(damap__map__stable__end, char *, mapp->dam_name,
   1231 	    dam_t *, mapp, int, n_active);
   1232 
   1233 	mapp->dam_flags  &= ~DAM_SPEND;
   1234 	cv_signal(&mapp->dam_cv);
   1235 	mutex_exit(&mapp->dam_lock);
   1236 	bitset_fini(&uncfg);
   1237 	bitset_fini(&cfg);
   1238 	bitset_fini(&delta);
   1239 }
   1240 
   1241 /*
   1242  * per-address stabilization timeout
   1243  */
   1244 static void
   1245 dam_addr_stable_cb(void *arg)
   1246 {
   1247 	dam_t *mapp = (dam_t *)arg;
   1248 	int i;
   1249 	dam_da_t *passp;
   1250 	int spend = 0;
   1251 	int tpend = 0;
   1252 	int64_t	next_tmov = mapp->dam_stabletmo;
   1253 	int64_t tmo_delta;
   1254 	int64_t ts = ddi_get_lbolt64();
   1255 
   1256 	mutex_enter(&mapp->dam_lock);
   1257 	if (mapp->dam_tid == 0) {
   1258 		DTRACE_PROBE2(damap__map__addr__stable__cancelled, char *,
   1259 		    mapp->dam_name, dam_t *, mapp);
   1260 		mutex_exit(&mapp->dam_lock);
   1261 		return;
   1262 	}
   1263 	mapp->dam_tid = 0;
   1264 
   1265 	/*
   1266 	 * If still under stabilization, reschedule timeout,
   1267 	 * otherwise dispatch the task to activate and deactivate the
   1268 	 * new stable address
   1269 	 */
   1270 	if (mapp->dam_flags & DAM_SPEND) {
   1271 		DAM_INCR_STAT(mapp, dam_overrun);
   1272 		mapp->dam_stable_overrun++;
   1273 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
   1274 		DTRACE_PROBE2(damap__map__addr__stable__overrun, char *,
   1275 		    mapp->dam_name, dam_t *, mapp);
   1276 		mutex_exit(&mapp->dam_lock);
   1277 		return;
   1278 	}
   1279 
   1280 	DAM_SET_STAT(mapp, dam_overrun, 0);
   1281 	mapp->dam_stable_overrun = 0;
   1282 
   1283 	/*
   1284 	 * copy the current active set to the stable map
   1285 	 * for each address being reported, decrement its
   1286 	 * stabilize deadline, and if stable, add or remove the
   1287 	 * address from the stable set
   1288 	 */
   1289 	bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set);
   1290 	for (i = 1; i < mapp->dam_high; i++) {
   1291 		if (!bitset_in_set(&mapp->dam_report_set, i))
   1292 			continue;
   1293 		passp = ddi_get_soft_state(mapp->dam_da, i);
   1294 		ASSERT(passp);
   1295 
   1296 		/* report has stabilized */
   1297 		if (passp->da_deadline <= ts) {
   1298 			bitset_del(&mapp->dam_report_set, i);
   1299 			if (passp->da_flags & DA_RELE)
   1300 				bitset_del(&mapp->dam_stable_set, i);
   1301 			else
   1302 				bitset_add(&mapp->dam_stable_set, i);
   1303 			spend++;
   1304 			continue;
   1305 		}
   1306 
   1307 		/*
   1308 		 * not stabilized, determine next map timeout
   1309 		 */
   1310 		tpend++;
   1311 		tmo_delta = passp->da_deadline - ts;
   1312 		if (tmo_delta < next_tmov)
   1313 			next_tmov = tmo_delta;
   1314 	}
   1315 
   1316 	/*
   1317 	 * schedule system_taskq activation of stabilized reports
   1318 	 */
   1319 	if (spend) {
   1320 		if (taskq_dispatch(system_taskq, dam_stabilize_map,
   1321 		    mapp, TQ_NOSLEEP)) {
   1322 			mapp->dam_flags  |= DAM_SPEND;
   1323 			DTRACE_PROBE2(damap__map__addr__stable__start, char *,
   1324 			    mapp->dam_name, dam_t *, mapp);
   1325 		} else {
   1326 			tpend++;
   1327 		}
   1328 	}
   1329 
   1330 	/*
   1331 	 * reschedule the stabilization timer if there are reports
   1332 	 * still pending
   1333 	 */
   1334 	if (tpend)
   1335 		dam_sched_tmo(mapp, (clock_t)next_tmov, dam_addr_stable_cb);
   1336 
   1337 	mutex_exit(&mapp->dam_lock);
   1338 }
   1339 
   1340 /*
   1341  * fullset stabilization timeout callback
   1342  */
   1343 static void
   1344 dam_addrset_stable_cb(void *arg)
   1345 {
   1346 	dam_t *mapp = (dam_t *)arg;
   1347 
   1348 	mutex_enter(&mapp->dam_lock);
   1349 	if (mapp->dam_tid == 0) {
   1350 		mutex_exit(&mapp->dam_lock);
   1351 		DTRACE_PROBE2(damap__map__addrset__stable__cancelled,
   1352 		    char *, mapp->dam_name, dam_t *, mapp);
   1353 		return;
   1354 	}
   1355 	mapp->dam_tid = 0;
   1356 
   1357 	/*
   1358 	 * If map still underoing stabilization reschedule timeout,
   1359 	 * else dispatch the task to configure the new stable set of
   1360 	 * addresses.
   1361 	 */
   1362 	if ((mapp->dam_flags & DAM_SPEND) || (taskq_dispatch(system_taskq,
   1363 	    dam_stabilize_map, mapp, TQ_NOSLEEP) == NULL)) {
   1364 		DAM_INCR_STAT(mapp, dam_overrun);
   1365 		mapp->dam_stable_overrun++;
   1366 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb);
   1367 		DTRACE_PROBE2(damap__map__addrset__stable__overrun, char *,
   1368 		    mapp->dam_name, dam_t *, mapp);
   1369 		mutex_exit(&mapp->dam_lock);
   1370 		return;
   1371 	}
   1372 
   1373 	DAM_SET_STAT(mapp, dam_overrun, 0);
   1374 	mapp->dam_stable_overrun = 0;
   1375 	bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
   1376 	bitset_zero(&mapp->dam_report_set);
   1377 	mapp->dam_flags |= DAM_SPEND;
   1378 	mapp->dam_flags &= ~DAM_SETADD;
   1379 	DTRACE_PROBE2(damap__map__addrset__stable__start, char *,
   1380 	    mapp->dam_name, dam_t *, mapp);
   1381 	mutex_exit(&mapp->dam_lock);
   1382 }
   1383 
   1384 /*
   1385  * schedule map timeout 'tmo_ms' ticks
   1386  * if map timer is currently running, cancel if tmo_ms == 0
   1387  */
   1388 static void
   1389 dam_sched_tmo(dam_t *mapp, clock_t tmo_ms, void (*tmo_cb)())
   1390 {
   1391 	timeout_id_t tid;
   1392 
   1393 	DTRACE_PROBE3(damap__sched__tmo, char *, mapp->dam_name, dam_t *, mapp,
   1394 	    clock_t, tmo_ms);
   1395 
   1396 	ASSERT(mutex_owned(&mapp->dam_lock));
   1397 	if ((tid = mapp->dam_tid) != 0) {
   1398 		if (tmo_ms == 0) {
   1399 			mapp->dam_tid = 0;
   1400 			mutex_exit(&mapp->dam_lock);
   1401 			(void) untimeout(tid);
   1402 			mutex_enter(&mapp->dam_lock);
   1403 		}
   1404 	} else {
   1405 		if (tmo_cb && (tmo_ms != 0))
   1406 			mapp->dam_tid = timeout(tmo_cb, mapp, tmo_ms);
   1407 	}
   1408 }
   1409 
   1410 /*
   1411  * report addition or removal of an address
   1412  */
   1413 static void
   1414 dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type)
   1415 {
   1416 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
   1417 
   1418 	DTRACE_PROBE4(damap__addr__report, char *, mapp->dam_name,
   1419 	    char *, addrstr, dam_t *, mapp, int, rpt_type);
   1420 
   1421 	ASSERT(mutex_owned(&mapp->dam_lock));
   1422 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
   1423 	passp->da_last_report = gethrtime();
   1424 	mapp->dam_last_update = gethrtime();
   1425 	passp->da_report_cnt++;
   1426 	passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stabletmo;
   1427 	if (rpt_type == RPT_ADDR_DEL)
   1428 		passp->da_flags |= DA_RELE;
   1429 	else if (rpt_type == RPT_ADDR_ADD)
   1430 		passp->da_flags &= ~DA_RELE;
   1431 	bitset_add(&mapp->dam_report_set, addrid);
   1432 	dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
   1433 }
   1434 
   1435 /*
   1436  * release an address report
   1437  */
   1438 static void
   1439 dam_addr_report_release(dam_t *mapp, id_t addrid)
   1440 {
   1441 	dam_da_t *passp;
   1442 	char *addrstr = damap_id2addr((damap_t *)mapp, addrid);
   1443 
   1444 	DTRACE_PROBE3(damap__addr__report__release, char *, mapp->dam_name,
   1445 	    char *, addrstr, dam_t *, mapp);
   1446 
   1447 	ASSERT(mutex_owned(&mapp->dam_lock));
   1448 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
   1449 	ASSERT(passp);
   1450 	/*
   1451 	 * clear the report bit
   1452 	 * if the address has a registered deactivation handler and
   1453 	 * the address has not stabilized, deactivate the address
   1454 	 */
   1455 	bitset_del(&mapp->dam_report_set, addrid);
   1456 	if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb) {
   1457 		mutex_exit(&mapp->dam_lock);
   1458 		(*mapp->dam_deactivate_cb)(mapp->dam_activate_arg,
   1459 		    ddi_strid_id2str(mapp->dam_addr_hash, addrid),
   1460 		    addrid, passp->da_ppriv_rpt);
   1461 		mutex_enter(&mapp->dam_lock);
   1462 	}
   1463 	passp->da_ppriv_rpt = NULL;
   1464 	if (passp->da_nvl_rpt)
   1465 		nvlist_free(passp->da_nvl_rpt);
   1466 }
   1467 
   1468 /*
   1469  * return the map ID of an address
   1470  */
   1471 static id_t
   1472 dam_get_addrid(dam_t *mapp, char *address)
   1473 {
   1474 	damap_id_t addrid;
   1475 	dam_da_t *passp;
   1476 
   1477 	ASSERT(mutex_owned(&mapp->dam_lock));
   1478 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
   1479 		if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash,
   1480 		    address)) == (damap_id_t)0) {
   1481 			return (0);
   1482 		}
   1483 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
   1484 		    DDI_SUCCESS) {
   1485 			ddi_strid_free(mapp->dam_addr_hash, addrid);
   1486 			return (0);
   1487 		}
   1488 
   1489 		if (addrid >= mapp->dam_high)
   1490 			mapp->dam_high = addrid + 1;
   1491 
   1492 		/*
   1493 		 * expand bitmaps if ID has outgrown old map size
   1494 		 */
   1495 		if (mapp->dam_high > mapp->dam_size) {
   1496 			mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP;
   1497 			bitset_resize(&mapp->dam_active_set, mapp->dam_size);
   1498 			bitset_resize(&mapp->dam_stable_set, mapp->dam_size);
   1499 			bitset_resize(&mapp->dam_report_set, mapp->dam_size);
   1500 		}
   1501 
   1502 		passp = ddi_get_soft_state(mapp->dam_da, addrid);
   1503 		passp->da_ref = 1;
   1504 		passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash,
   1505 		    addrid); /* for mdb */
   1506 	}
   1507 	return (addrid);
   1508 }
   1509 
   1510 /*
   1511  * create and install map statistics
   1512  */
   1513 static int
   1514 dam_kstat_create(dam_t *mapp)
   1515 {
   1516 	kstat_t			*mapsp;
   1517 	struct dam_kstats	*statsp;
   1518 
   1519 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
   1520 	    KSTAT_TYPE_NAMED,
   1521 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
   1522 
   1523 	if (mapsp == NULL)
   1524 		return (DDI_FAILURE);
   1525 
   1526 	statsp = (struct dam_kstats *)mapsp->ks_data;
   1527 	kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32);
   1528 	kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32);
   1529 	kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32);
   1530 	kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32);
   1531 	kstat_install(mapsp);
   1532 	mapp->dam_kstatsp = mapsp;
   1533 	return (DDI_SUCCESS);
   1534 }
   1535