xref: /illumos-gate/usr/src/uts/common/os/damap.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 static void dam_addrset_activate(dam_t *, bitset_t *);
53 static void dam_addrset_release(dam_t *, bitset_t *);
54 static void dam_activate_taskq(void *);
55 static void dam_addr_stable_cb(void *);
56 static void dam_set_stable_cb(void *);
57 static void dam_sched_tmo(dam_t *, clock_t, void (*tmo_cb)());
58 static void dam_add_report(dam_t *, dam_da_t *, id_t, int);
59 static void dam_release(dam_t *, id_t);
60 static void dam_release_report(dam_t *, id_t);
61 static void dam_deactivate_addr(dam_t *, id_t);
62 static id_t dam_get_addrid(dam_t *, char *);
63 static int dam_kstat_create(dam_t *);
64 static void dam_kstat_destroy(dam_t *);
65 
66 #define	DAM_INCR_STAT(mapp, stat)				\
67 	if ((mapp)->dam_kstatsp) {				\
68 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
69 		stp->stat.value.ui32++;				\
70 	}
71 
72 #define	DAM_SET_STAT(mapp, stat, val)				\
73 	if ((mapp)->dam_kstatsp) {				\
74 		struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data;	\
75 		stp->stat.value.ui32 = (val);			\
76 	}
77 
78 /*
79  * Create new device address map
80  *
81  * ident:		map name (kstat)
82  * size:		max # of map entries
83  * rptmode:		type or mode of reporting
84  * stable_usec:		# of quiescent microseconds before report/map is stable
85  *
86  * activate_arg:	address provider activation-callout private
87  * activate_cb:		address provider activation callback handler
88  * deactivate_cb:	address provider deactivation callback handler
89  *
90  * config_arg:		configuration-callout private
91  * config_cb:		class configuration callout
92  * unconfig_cb:		class unconfiguration callout
93  *
94  * damapp:		pointer to map handle (return)
95  *
96  * Returns:	DAM_SUCCESS
97  *		DAM_EINVAL	Invalid argument(s)
98  *		DAM_FAILURE	General failure
99  */
100 int
101 damap_create(char *ident, size_t size, damap_rptmode_t rptmode,
102     clock_t stable_usec,
103     void *activate_arg, damap_activate_cb_t activate_cb,
104     damap_deactivate_cb_t deactivate_cb,
105     void *config_arg, damap_configure_cb_t configure_cb,
106     damap_unconfig_cb_t unconfig_cb,
107     damap_t **damapp)
108 {
109 	dam_t *mapp;
110 	void *softstate_p;
111 
112 	DTRACE_PROBE1(damap__create__entry, char *, ident);
113 	if ((configure_cb == NULL) || (unconfig_cb == NULL))
114 		return (DAM_EINVAL);
115 
116 	if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t), size) !=
117 	    DDI_SUCCESS)
118 		return (DAM_FAILURE);
119 
120 	mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP);
121 	if (ddi_strid_init(&mapp->dam_addr_hash, size) != DDI_SUCCESS) {
122 		ddi_soft_state_fini(&softstate_p);
123 		kmem_free(mapp, sizeof (*mapp));
124 		return (DAM_FAILURE);
125 	}
126 
127 	mapp->dam_da = softstate_p;
128 	mapp->dam_stabletmo = drv_usectohz(stable_usec);
129 	mapp->dam_size = size;
130 	mapp->dam_high = 1;
131 	mapp->dam_rptmode = rptmode;
132 
133 	mapp->dam_activate_arg = activate_arg;
134 	mapp->dam_activate_cb = (activate_cb_t)activate_cb;
135 	mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb;
136 
137 	mapp->dam_config_arg = config_arg;
138 	mapp->dam_configure_cb = (configure_cb_t)configure_cb;
139 	mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb;
140 
141 	if (ident)
142 		mapp->dam_name = i_ddi_strdup(ident, KM_SLEEP);
143 
144 	bitset_init(&mapp->dam_active_set);
145 	bitset_resize(&mapp->dam_active_set, size);
146 	bitset_init(&mapp->dam_stable_set);
147 	bitset_resize(&mapp->dam_stable_set, size);
148 	bitset_init(&mapp->dam_report_set);
149 	bitset_resize(&mapp->dam_report_set, size);
150 	mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL);
151 	cv_init(&mapp->dam_cv, NULL, CV_DRIVER, NULL);
152 	mapp->dam_taskqp = ddi_taskq_create(NULL, ident, 1, TASKQ_DEFAULTPRI,
153 	    0);
154 	*damapp = (damap_t *)mapp;
155 	if (dam_kstat_create(mapp) != DDI_SUCCESS) {
156 		damap_destroy((damap_t *)mapp);
157 		return (DAM_FAILURE);
158 	}
159 
160 	DTRACE_PROBE1(damap__create__exit, dam_t *, mapp);
161 	return (DAM_SUCCESS);
162 }
163 
164 /*
165  * Destroy device address map
166  *
167  * damapp:	address map
168  *
169  * Returns:	DAM_SUCCESS
170  *		DAM_EINVAL	Invalid argument(s)
171  *		DAM_FAILURE	General failure
172  */
173 void
174 damap_destroy(damap_t *damapp)
175 {
176 	int i;
177 	dam_t *mapp = (dam_t *)damapp;
178 
179 	ASSERT(mapp);
180 
181 	DTRACE_PROBE2(damap__destroy__entry, dam_t *, mapp, char *,
182 	    mapp->dam_name);
183 
184 	DAM_FLAG_SET(mapp, DAM_DESTROYPEND);
185 	(void) damap_sync(damapp);
186 
187 	/*
188 	 * cancel pending timeouts and kill off the taskq
189 	 */
190 	dam_sched_tmo(mapp, 0, NULL);
191 	ddi_taskq_wait(mapp->dam_taskqp);
192 	ddi_taskq_destroy(mapp->dam_taskqp);
193 
194 	for (i = 1; i < mapp->dam_high; i++) {
195 		if (ddi_get_soft_state(mapp->dam_da, i) == NULL)
196 			continue;
197 		if (DAM_IN_REPORT(mapp, i))
198 			dam_release_report(mapp, i);
199 		if (DAM_IS_STABLE(mapp, i))
200 			dam_deactivate_addr(mapp, i);
201 		ddi_strid_free(mapp->dam_addr_hash, i);
202 		ddi_soft_state_free(mapp->dam_da, i);
203 	}
204 	ddi_strid_fini(&mapp->dam_addr_hash);
205 	ddi_soft_state_fini(&mapp->dam_da);
206 	bitset_fini(&mapp->dam_active_set);
207 	bitset_fini(&mapp->dam_stable_set);
208 	bitset_fini(&mapp->dam_report_set);
209 	dam_kstat_destroy(mapp);
210 	mutex_destroy(&mapp->dam_lock);
211 	cv_destroy(&mapp->dam_cv);
212 	if (mapp->dam_name)
213 		kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1);
214 	kmem_free(mapp, sizeof (*mapp));
215 	DTRACE_PROBE(damap__destroy__exit);
216 }
217 
218 /*
219  * Wait for map stability.
220  *
221  * damapp:	address map
222  */
223 int
224 damap_sync(damap_t *damapp)
225 {
226 
227 #define	WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND | MAP_LOCK)
228 
229 	dam_t *mapp = (dam_t *)damapp;
230 	int   none_active;
231 
232 	ASSERT(mapp);
233 
234 	DTRACE_PROBE1(damap__sync__entry, dam_t *, mapp);
235 
236 	mutex_enter(&mapp->dam_lock);
237 	while ((mapp->dam_flags & WAITFOR_FLAGS) ||
238 	    (!bitset_is_null(&mapp->dam_report_set)) || (mapp->dam_tid != 0)) {
239 		cv_wait(&mapp->dam_cv, &mapp->dam_lock);
240 	}
241 
242 	none_active = bitset_is_null(&mapp->dam_active_set);
243 
244 	mutex_exit(&mapp->dam_lock);
245 	DTRACE_PROBE2(damap__sync__exit, dam_t *, mapp, int, none_active);
246 
247 	return (none_active);
248 }
249 
250 /*
251  * Get the name of a device address map
252  *
253  * damapp:	address map
254  *
255  * Returns:	name
256  */
257 char *
258 damap_name(damap_t *damapp)
259 {
260 	dam_t *mapp = (dam_t *)damapp;
261 
262 	return (mapp ? mapp->dam_name : "UNKNOWN_damap");
263 }
264 
265 /*
266  * Report an address to per-address report
267  *
268  * damapp:	address map handle
269  * address:	address in ascii string representation
270  * rindx:	index if address stabilizes
271  * nvl:		optional nvlist of configuration-private data
272  * addr_priv:	optional provider-private (passed to activate/deactivate cb)
273  *
274  * Returns:	DAM_SUCCESS
275  *		DAM_EINVAL	Invalid argument(s)
276  *		DAM_MAPFULL	address map exhausted
277  */
278 int
279 damap_addr_add(damap_t *damapp, char *address, damap_id_t *ridx, nvlist_t *nvl,
280     void *addr_priv)
281 {
282 	dam_t *mapp = (dam_t *)damapp;
283 	id_t addrid;
284 	dam_da_t *passp;
285 
286 	DTRACE_PROBE2(damap__addr__add__entry, dam_t *, mapp,
287 	    char *, address);
288 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR) ||
289 	    (mapp->dam_flags & DAM_DESTROYPEND))
290 		return (DAM_EINVAL);
291 
292 	DAM_LOCK(mapp, ADDR_LOCK);
293 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
294 		DAM_UNLOCK(mapp, ADDR_LOCK);
295 		return (DAM_MAPFULL);
296 	}
297 
298 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
299 	ASSERT(passp != NULL);
300 
301 	/*
302 	 * If re-reporting the same address (add or remove) clear
303 	 * the existing report
304 	 */
305 	if (DAM_IN_REPORT(mapp, addrid)) {
306 		DAM_INCR_STAT(mapp, dam_rereport);
307 		dam_release_report(mapp, addrid);
308 		passp->da_jitter++;
309 	}
310 	passp->da_ppriv_rpt = addr_priv;
311 	if (nvl)
312 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
313 
314 	dam_add_report(mapp, passp, addrid, RPT_ADDR_ADD);
315 	if (ridx != NULL)
316 		*ridx = (damap_id_t)addrid;
317 	DAM_UNLOCK(mapp, ADDR_LOCK);
318 	DTRACE_PROBE3(damap__addr__add__exit, dam_t *, mapp, char *,
319 	    address, int, addrid);
320 	return (DAM_SUCCESS);
321 }
322 
323 /*
324  * Report removal of address from per-address report
325  *
326  * damapp:	address map
327  * address:	address in ascii string representation
328  *
329  * Returns:	DAM_SUCCESS
330  *		DAM_EINVAL	Invalid argument(s)
331  *		DAM_FAILURE	General failure
332  */
333 int
334 damap_addr_del(damap_t *damapp, char *address)
335 {
336 	dam_t *mapp = (dam_t *)damapp;
337 	id_t addrid;
338 	dam_da_t *passp;
339 
340 	DTRACE_PROBE2(damap__addr__del__entry, dam_t *, mapp,
341 	    char *, address);
342 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR) ||
343 	    (mapp->dam_flags & DAM_DESTROYPEND))
344 		return (DAM_EINVAL);
345 
346 	DAM_LOCK(mapp, ADDR_LOCK);
347 	if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) {
348 		DAM_UNLOCK(mapp, ADDR_LOCK);
349 		return (DAM_SUCCESS);
350 	}
351 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
352 	ASSERT(passp);
353 	if (DAM_IN_REPORT(mapp, addrid)) {
354 		DAM_INCR_STAT(mapp, dam_rereport);
355 		dam_release_report(mapp, addrid);
356 		passp->da_jitter++;
357 	}
358 	dam_add_report(mapp, passp, addrid, RPT_ADDR_DEL);
359 	DAM_UNLOCK(mapp, ADDR_LOCK);
360 	DTRACE_PROBE3(damap__addr__del__exit, dam_t *, mapp,
361 	    char *, address, int, addrid);
362 	return (DAM_SUCCESS);
363 }
364 
365 /*
366  * Initiate full-set report
367  *
368  * damapp:	address map
369  *
370  * Returns:	DAM_SUCCESS
371  *		DAM_EINVAL	Invalid argument(s)
372  */
373 int
374 damap_addrset_begin(damap_t *damapp)
375 {
376 	dam_t *mapp = (dam_t *)damapp;
377 	int i;
378 
379 	DTRACE_PROBE1(damap__addrset__begin__entry, dam_t *, mapp);
380 
381 	if ((mapp->dam_rptmode != DAMAP_REPORT_FULLSET) ||
382 	    (mapp->dam_flags & DAM_DESTROYPEND))
383 		return (DAM_EINVAL);
384 
385 	DAM_LOCK(mapp, MAP_LOCK);
386 	/*
387 	 * reset any pending reports
388 	 */
389 	if (mapp->dam_flags & DAM_SETADD) {
390 		/*
391 		 * cancel stabilization timeout
392 		 */
393 		dam_sched_tmo(mapp, 0, NULL);
394 		DAM_INCR_STAT(mapp, dam_rereport);
395 		DAM_UNLOCK(mapp, MAP_LOCK);
396 		DAM_LOCK(mapp, ADDR_LOCK);
397 		for (i = 1; i < mapp->dam_high; i++) {
398 			if (DAM_IN_REPORT(mapp, i))
399 				dam_release_report(mapp, i);
400 		}
401 		DAM_UNLOCK(mapp, ADDR_LOCK);
402 		DAM_LOCK(mapp, MAP_LOCK);
403 	}
404 	DAM_FLAG_SET(mapp, DAM_SETADD);
405 	bitset_zero(&mapp->dam_report_set);
406 	DAM_UNLOCK(mapp, MAP_LOCK);
407 	DTRACE_PROBE(damap__addrset__begin__exit);
408 	return (DAM_SUCCESS);
409 }
410 
411 /*
412  * Report address to full-set report
413  *
414  * damapp:	address map handle
415  * address:	address in ascii string representation
416  * rindx:	index if address stabilizes
417  * nvl:		optional nvlist of configuration-private data
418  * addr_priv:	optional provider-private data (passed to activate/release cb)
419  *
420  * Returns:	DAM_SUCCESS
421  *		DAM_EINVAL	Invalid argument(s)
422  *		DAM_MAPFULL	address map exhausted
423  *		DAM_FAILURE	General failure
424  */
425 int
426 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx,
427     nvlist_t *nvl, void *addr_priv)
428 {
429 	dam_t *mapp = (dam_t *)damapp;
430 	id_t addrid;
431 	dam_da_t *passp;
432 
433 	DTRACE_PROBE2(damap__addrset__add__entry, dam_t *, mapp,
434 	    char *, address);
435 
436 	if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) ||
437 	    (mapp->dam_flags & DAM_DESTROYPEND))
438 		return (DAM_EINVAL);
439 
440 	if (!(mapp->dam_flags & DAM_SETADD))
441 		return (DAM_FAILURE);
442 
443 	DAM_LOCK(mapp, ADDR_LOCK);
444 	if ((addrid = dam_get_addrid(mapp, address)) == 0) {
445 		DAM_UNLOCK(mapp, ADDR_LOCK);
446 		return (DAM_MAPFULL);
447 	}
448 
449 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
450 	ASSERT(passp);
451 	if (DAM_IN_REPORT(mapp, addrid)) {
452 		dam_release_report(mapp, addrid);
453 		passp->da_jitter++;
454 	}
455 	passp->da_ppriv_rpt = addr_priv;
456 	if (nvl)
457 		(void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP);
458 	DAM_LOCK(mapp, MAP_LOCK);
459 	bitset_add(&mapp->dam_report_set, addrid);
460 	DAM_UNLOCK(mapp, MAP_LOCK);
461 	if (ridx)
462 		*ridx = (damap_id_t)addrid;
463 	DAM_UNLOCK(mapp, ADDR_LOCK);
464 	DTRACE_PROBE3(damap__addr__addset__exit, dam_t *, mapp, char *,
465 	    address, int, addrid);
466 	return (DAM_SUCCESS);
467 }
468 
469 /*
470  * Commit full-set report for stabilization
471  *
472  * damapp:	address map handle
473  * flags:	(currently 0)
474  *
475  * Returns:	DAM_SUCCESS
476  *		DAM_EINVAL	Invalid argument(s)
477  *		DAM_FAILURE	General failure
478  */
479 int
480 damap_addrset_end(damap_t *damapp, int flags)
481 {
482 	dam_t *mapp = (dam_t *)damapp;
483 	int i;
484 
485 	DTRACE_PROBE1(damap__addrset__end__entry, dam_t *, mapp);
486 
487 	if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) ||
488 	    (mapp->dam_flags & DAM_DESTROYPEND))
489 		return (DAM_EINVAL);
490 
491 	if (!(mapp->dam_flags & DAM_SETADD))
492 		return (DAM_FAILURE);
493 
494 	if (flags & DAMAP_RESET) {
495 		DAM_LOCK(mapp, MAP_LOCK);
496 		dam_sched_tmo(mapp, 0, NULL);
497 		DAM_UNLOCK(mapp, MAP_LOCK);
498 		DAM_LOCK(mapp, ADDR_LOCK);
499 		for (i = 1; i < mapp->dam_high; i++)
500 			if (DAM_IN_REPORT(mapp, i))
501 				dam_release_report(mapp, i);
502 		DAM_UNLOCK(mapp, ADDR_LOCK);
503 	} else {
504 		mapp->dam_last_update = gethrtime();
505 		DAM_LOCK(mapp, MAP_LOCK);
506 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_set_stable_cb);
507 		DAM_UNLOCK(mapp, MAP_LOCK);
508 	}
509 	DTRACE_PROBE(damap__addrset__end__exit);
510 	return (DAM_SUCCESS);
511 }
512 
513 /*
514  * Return nvlist registered with reported address
515  *
516  * damapp:	address map handle
517  * aid:		address ID
518  *
519  * Returns:	nvlist_t *	provider supplied via damap_addr{set}_add())
520  *		NULL
521  */
522 nvlist_t *
523 damap_id2nvlist(damap_t *damapp, damap_id_t addrid)
524 {
525 	dam_t *mapp = (dam_t *)damapp;
526 	id_t aid = (id_t)addrid;
527 	dam_da_t *pass;
528 
529 	if (ddi_strid_id2str(mapp->dam_addr_hash, aid)) {
530 		if (pass = ddi_get_soft_state(mapp->dam_da, aid))
531 			return (pass->da_nvl);
532 	}
533 	return (NULL);
534 }
535 
536 /*
537  * Return address string
538  *
539  * damapp:	address map handle
540  * aid:		address ID
541  *
542  * Returns:	char *		Address string
543  *		NULL
544  */
545 char *
546 damap_id2addr(damap_t *damapp, damap_id_t aid)
547 {
548 	dam_t *mapp = (dam_t *)damapp;
549 
550 	return (ddi_strid_id2str(mapp->dam_addr_hash, (id_t)aid));
551 }
552 
553 /*
554  * Hold address reference in map
555  *
556  * damapp:	address map handle
557  * aid:		address ID
558  *
559  * Returns:	DAM_SUCCESS
560  *		DAM_FAILURE
561  */
562 int
563 damap_id_hold(damap_t *damapp, damap_id_t aid)
564 {
565 	dam_t *mapp = (dam_t *)damapp;
566 	dam_da_t *passp;
567 
568 
569 	DAM_LOCK(mapp, ADDR_LOCK);
570 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)aid);
571 	if (!passp) {
572 		DAM_UNLOCK(mapp, ADDR_LOCK);
573 		return (DAM_FAILURE);
574 	}
575 	passp->da_ref++;
576 	DAM_UNLOCK(mapp, ADDR_LOCK);
577 	return (DAM_SUCCESS);
578 }
579 
580 /*
581  * Release address reference in map
582  *
583  * damapp:	address map handle
584  * aid:		address ID
585  */
586 void
587 damap_id_rele(damap_t *damapp, damap_id_t addrid)
588 {
589 	dam_t *mapp = (dam_t *)damapp;
590 
591 	DAM_LOCK(mapp, ADDR_LOCK);
592 	dam_release(mapp, (id_t)addrid);
593 	DAM_UNLOCK(mapp, ADDR_LOCK);
594 }
595 
596 /*
597  * Return current reference count on address reference in map
598  *
599  * damapp:	address map handle
600  * aid:		address ID
601  *
602  * Returns:	DAM_SUCCESS
603  *		DAM_FAILURE
604  */
605 int
606 damap_id_ref(damap_t *damapp, damap_id_t aid)
607 {
608 	dam_t *mapp = (dam_t *)damapp;
609 	dam_da_t *passp;
610 	int ref = -1;
611 
612 	DAM_LOCK(mapp, ADDR_LOCK);
613 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)aid);
614 	if (passp)
615 		ref = passp->da_ref;
616 	DAM_UNLOCK(mapp, ADDR_LOCK);
617 	return (ref);
618 }
619 
620 /*
621  * Return next address ID in list
622  *
623  * damapp:	address map handle
624  * damap_list:	address ID list passed to config|unconfig
625  *		returned by look by lookup_all
626  * last:	last ID returned, 0 is start of list
627  *
628  * Returns:	addrid		Next ID from the list
629  *		0		End of the list
630  */
631 damap_id_t
632 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last)
633 {
634 	int i, start;
635 	dam_t *mapp = (dam_t *)damapp;
636 	bitset_t *dam_list = (bitset_t *)damap_list;
637 
638 	if (!mapp || !dam_list)
639 		return ((damap_id_t)0);
640 
641 	start = (int)last + 1;
642 	for (i = start; i < mapp->dam_high; i++)
643 		if (bitset_in_set(dam_list, i))
644 			return ((damap_id_t)i);
645 	return ((damap_id_t)0);
646 }
647 
648 /*
649  * Set config private data
650  *
651  * damapp:	address map handle
652  * aid:		address ID
653  * cfg_priv:	configuration private data
654  *
655  */
656 void
657 damap_id_priv_set(damap_t *damapp, damap_id_t aid, void *cfg_priv)
658 {
659 	dam_t *mapp = (dam_t *)damapp;
660 	dam_da_t *passp;
661 
662 
663 	DAM_LOCK(mapp, ADDR_LOCK);
664 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)aid);
665 	if (!passp) {
666 		DAM_UNLOCK(mapp, ADDR_LOCK);
667 		return;
668 	}
669 	passp->da_cfg_priv = cfg_priv;
670 	DAM_UNLOCK(mapp, ADDR_LOCK);
671 }
672 
673 /*
674  * Get config private data
675  *
676  * damapp:	address map handle
677  * aid:		address ID
678  *
679  * Returns:	configuration private data
680  */
681 void *
682 damap_id_priv_get(damap_t *damapp, damap_id_t aid)
683 {
684 	dam_t *mapp = (dam_t *)damapp;
685 	dam_da_t *passp;
686 	void *rv;
687 
688 
689 	DAM_LOCK(mapp, ADDR_LOCK);
690 	passp = ddi_get_soft_state(mapp->dam_da, (id_t)aid);
691 	if (!passp) {
692 		DAM_UNLOCK(mapp, ADDR_LOCK);
693 		return (NULL);
694 	}
695 	rv = passp->da_cfg_priv;
696 	DAM_UNLOCK(mapp, ADDR_LOCK);
697 	return (rv);
698 }
699 
700 /*
701  * Lookup a single address in the active address map
702  *
703  * damapp:	address map handle
704  * address:	address string
705  *
706  * Returns:	ID of active/stable address
707  *		0	Address not in stable set
708  *
709  * Future: Allow the caller to wait for stabilize before returning not found.
710  */
711 damap_id_t
712 damap_lookup(damap_t *damapp, char *address)
713 {
714 	dam_t *mapp = (dam_t *)damapp;
715 	id_t addrid = 0;
716 	dam_da_t *passp = NULL;
717 
718 	DAM_LOCK(mapp, ADDR_LOCK);
719 	addrid = ddi_strid_str2id(mapp->dam_addr_hash, address);
720 	if (addrid) {
721 		DAM_LOCK(mapp, MAP_LOCK);
722 		if (DAM_IS_STABLE(mapp, addrid)) {
723 			passp = ddi_get_soft_state(mapp->dam_da, addrid);
724 			ASSERT(passp);
725 			if (passp) {
726 				passp->da_ref++;
727 			} else {
728 				addrid = 0;
729 			}
730 		} else {
731 			addrid = 0;
732 		}
733 		DAM_UNLOCK(mapp, MAP_LOCK);
734 	}
735 	DAM_UNLOCK(mapp, ADDR_LOCK);
736 	return ((damap_id_t)addrid);
737 }
738 
739 
740 /*
741  * Return the list of stable addresses in the map
742  *
743  * damapp:	address map handle
744  * id_listp:	pointer to list of address IDs in stable map (returned)
745  *
746  * Returns:	# of entries returned in alist
747  */
748 int
749 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp)
750 {
751 	dam_t *mapp = (dam_t *)damapp;
752 	int mapsz = mapp->dam_size;
753 	int n_ids, i;
754 	bitset_t *bsp;
755 	dam_da_t *passp;
756 
757 	bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP);
758 	bitset_init(bsp);
759 	bitset_resize(bsp, mapsz);
760 	DAM_LOCK(mapp, MAP_LOCK);
761 	bitset_copy(&mapp->dam_active_set, bsp);
762 	DAM_UNLOCK(mapp, MAP_LOCK);
763 	DAM_LOCK(mapp, ADDR_LOCK);
764 	for (n_ids = 0, i = 1; i < mapsz; i++) {
765 		if (bitset_in_set(bsp, i)) {
766 			passp = ddi_get_soft_state(mapp->dam_da, i);
767 			ASSERT(passp);
768 			if (passp) {
769 				passp->da_ref++;
770 				n_ids++;
771 			}
772 		}
773 	}
774 	DAM_UNLOCK(mapp, ADDR_LOCK);
775 	if (n_ids) {
776 		*id_listp = (damap_id_list_t)bsp;
777 		return (n_ids);
778 	} else {
779 		*id_listp = (damap_id_list_t)NULL;
780 		bitset_fini(bsp);
781 		kmem_free(bsp, sizeof (*bsp));
782 		return (0);
783 	}
784 }
785 
786 /*
787  * Release the address list returned by damap_lookup_all()
788  *
789  * mapp:	address map handle
790  * id_list:	list of address IDs returned in damap_lookup_all()
791  */
792 void
793 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list)
794 {
795 	dam_t *mapp = (dam_t *)damapp;
796 	int i;
797 
798 	if (id_list == NULL)
799 		return;
800 
801 	DAM_LOCK(mapp, ADDR_LOCK);
802 	for (i = 1; i < mapp->dam_high; i++) {
803 		if (bitset_in_set((bitset_t *)id_list, i))
804 			(void) dam_release(mapp, i);
805 	}
806 	DAM_UNLOCK(mapp, ADDR_LOCK);
807 	bitset_fini((bitset_t *)id_list);
808 	kmem_free((void *)id_list, sizeof (bitset_t));
809 }
810 
811 /*
812  * Activate a set of stabilized addresses
813  */
814 static void
815 dam_addrset_activate(dam_t *mapp, bitset_t *active_set)
816 {
817 	dam_da_t *passp;
818 	char *addrstr;
819 	int i;
820 	uint32_t n_active = 0;
821 
822 	for (i = 1; i < mapp->dam_high; i++) {
823 		if (bitset_in_set(&mapp->dam_active_set, i))
824 			n_active++;
825 		if (!bitset_in_set(active_set, i))
826 			continue;
827 		n_active++;
828 		passp = ddi_get_soft_state(mapp->dam_da, i);
829 		ASSERT(passp);
830 		if (mapp->dam_activate_cb) {
831 			addrstr = ddi_strid_id2str(mapp->dam_addr_hash, i);
832 			(*mapp->dam_activate_cb)(
833 			    mapp->dam_activate_arg, addrstr, i,
834 			    &passp->da_ppriv_rpt);
835 		}
836 		DTRACE_PROBE2(damap__addrset__activate, dam_t *, mapp, int, i);
837 		DAM_LOCK(mapp, MAP_LOCK);
838 		bitset_add(&mapp->dam_active_set, i);
839 		/*
840 		 * copy the reported nvlist and provider private data
841 		 */
842 		passp->da_nvl = passp->da_nvl_rpt;
843 		passp->da_ppriv = passp->da_ppriv_rpt;
844 		passp->da_ppriv_rpt = NULL;
845 		passp->da_nvl_rpt = NULL;
846 		passp->da_last_stable = gethrtime();
847 		passp->da_stable_cnt++;
848 		DAM_UNLOCK(mapp, MAP_LOCK);
849 		DAM_SET_STAT(mapp, dam_numstable, n_active);
850 	}
851 }
852 
853 /*
854  * Release a set of stabilized addresses
855  */
856 static void
857 dam_addrset_release(dam_t *mapp, bitset_t *release_set)
858 {
859 	int i;
860 
861 	DAM_LOCK(mapp, ADDR_LOCK);
862 	for (i = 1; i < mapp->dam_high; i++) {
863 		if (bitset_in_set(release_set, i)) {
864 			DTRACE_PROBE2(damap__addrset__release, dam_t *, mapp,
865 			    int, i);
866 			DAM_LOCK(mapp, MAP_LOCK);
867 			bitset_del(&mapp->dam_active_set, i);
868 			DAM_UNLOCK(mapp, MAP_LOCK);
869 			(void) dam_release(mapp, i);
870 		}
871 	}
872 	DAM_UNLOCK(mapp, ADDR_LOCK);
873 }
874 
875 /*
876  * release a previously activated address
877  */
878 static void
879 dam_release(dam_t *mapp, id_t addrid)
880 {
881 	dam_da_t *passp;
882 
883 	DAM_ASSERT_LOCKED(mapp, ADDR_LOCK);
884 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
885 	ASSERT(passp);
886 
887 	/*
888 	 * invoke the deactivation callback to notify
889 	 * this address is no longer active
890 	 */
891 	dam_deactivate_addr(mapp, addrid);
892 
893 	/*
894 	 * allow pending reports for this address to stabilize
895 	 */
896 	if (DAM_IN_REPORT(mapp, addrid))
897 		return;
898 
899 	/*
900 	 * defer teardown until outstanding references are released
901 	 */
902 	if (--passp->da_ref) {
903 		passp->da_flags |= DA_RELE;
904 		return;
905 	}
906 	ddi_strid_free(mapp->dam_addr_hash, addrid);
907 	ddi_soft_state_free(mapp->dam_da, addrid);
908 }
909 
910 /*
911  * process stabilized address reports
912  */
913 static void
914 dam_activate_taskq(void *arg)
915 {
916 	dam_t *mapp = (dam_t *)arg;
917 	bitset_t delta;
918 	bitset_t cfg;
919 	bitset_t uncfg;
920 	int has_cfg, has_uncfg;
921 
922 	bitset_init(&delta);
923 	bitset_resize(&delta, mapp->dam_size);
924 	bitset_init(&cfg);
925 	bitset_resize(&cfg, mapp->dam_size);
926 	bitset_init(&uncfg);
927 	bitset_resize(&uncfg, mapp->dam_size);
928 
929 	DTRACE_PROBE1(damap__activate__taskq__entry, dam_t, mapp);
930 	DAM_LOCK(mapp, MAP_LOCK);
931 	if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set,
932 	    &delta)) {
933 		bitset_zero(&mapp->dam_stable_set);
934 		DAM_FLAG_CLR(mapp, DAM_SPEND);
935 		DAM_UNLOCK(mapp, MAP_LOCK);
936 		bitset_fini(&uncfg);
937 		bitset_fini(&cfg);
938 		bitset_fini(&delta);
939 		return;
940 	}
941 	has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg);
942 	has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg);
943 	DAM_UNLOCK(mapp, MAP_LOCK);
944 	if (has_cfg) {
945 		dam_addrset_activate(mapp, &cfg);
946 		(*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp, &cfg);
947 	}
948 	if (has_uncfg) {
949 		(*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, &uncfg);
950 		dam_addrset_release(mapp, &uncfg);
951 	}
952 	DAM_LOCK(mapp, MAP_LOCK);
953 	bitset_zero(&mapp->dam_stable_set);
954 	DAM_FLAG_CLR(mapp, DAM_SPEND);
955 	mapp->dam_last_stable = gethrtime();
956 	mapp->dam_stable_cnt++;
957 	DAM_INCR_STAT(mapp, dam_stable);
958 	DAM_UNLOCK(mapp, MAP_LOCK);
959 	bitset_fini(&uncfg);
960 	bitset_fini(&cfg);
961 	bitset_fini(&delta);
962 	DTRACE_PROBE1(damap__activate__taskq__exit, dam_t, mapp);
963 }
964 
965 /*
966  * per-address stabilization timeout
967  */
968 static void
969 dam_addr_stable_cb(void *arg)
970 {
971 	dam_t *mapp = (dam_t *)arg;
972 	int i;
973 	dam_da_t *passp;
974 	int spend = 0;
975 	int tpend = 0;
976 	int64_t	next_tmov = mapp->dam_stabletmo;
977 	int64_t tmo_delta;
978 	int64_t ts = lbolt64;
979 
980 	DTRACE_PROBE1(damap__addr__stable__cb__entry, dam_t *, mapp);
981 	DAM_LOCK(mapp, MAP_LOCK);
982 	if (mapp->dam_tid == 0) {
983 		DAM_UNLOCK(mapp, MAP_LOCK);
984 		return;
985 	}
986 	mapp->dam_tid = 0;
987 	/*
988 	 * If still under stabilization, reschedule timeout,
989 	 * else dispatch the task to activate & deactivate the stable
990 	 * set.
991 	 */
992 	if (mapp->dam_flags & DAM_SPEND) {
993 		DAM_INCR_STAT(mapp, dam_stable_blocked);
994 		mapp->dam_stable_overrun++;
995 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
996 		DAM_UNLOCK(mapp, MAP_LOCK);
997 		DTRACE_PROBE1(damap__addr__stable__cb__overrun,
998 		    dam_t *, mapp);
999 		return;
1000 	}
1001 
1002 	bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set);
1003 	for (i = 1; i < mapp->dam_high; i++) {
1004 		if (!bitset_in_set(&mapp->dam_report_set, i))
1005 			continue;
1006 		/*
1007 		 * Stabilize each address
1008 		 */
1009 		passp = ddi_get_soft_state(mapp->dam_da, i);
1010 		ASSERT(passp);
1011 		if (!passp) {
1012 			cmn_err(CE_WARN, "Clearing report no softstate %d", i);
1013 			bitset_del(&mapp->dam_report_set, i);
1014 			continue;
1015 		}
1016 
1017 		/* report has stabilized */
1018 		if (passp->da_deadline <= ts) {
1019 			bitset_del(&mapp->dam_report_set, i);
1020 			if (passp->da_flags & DA_RELE) {
1021 				DTRACE_PROBE2(damap__addr__stable__del,
1022 				    dam_t *, mapp, int, i);
1023 				bitset_del(&mapp->dam_stable_set, i);
1024 			} else {
1025 				DTRACE_PROBE2(damap__addr__stable__add,
1026 				    dam_t *, mapp, int, i);
1027 				bitset_add(&mapp->dam_stable_set, i);
1028 			}
1029 			spend++;
1030 			continue;
1031 		}
1032 
1033 		/*
1034 		 * not stabilized, determine next (future) map timeout
1035 		 */
1036 		tpend++;
1037 		tmo_delta = passp->da_deadline - ts;
1038 		if (tmo_delta < next_tmov)
1039 			next_tmov = tmo_delta;
1040 	}
1041 
1042 	/*
1043 	 * schedule taskq activation of stabilized reports
1044 	 */
1045 	if (spend) {
1046 		if (ddi_taskq_dispatch(mapp->dam_taskqp, dam_activate_taskq,
1047 		    mapp, DDI_NOSLEEP) == DDI_SUCCESS) {
1048 			DAM_FLAG_SET(mapp, DAM_SPEND);
1049 		} else
1050 			tpend++;
1051 	}
1052 
1053 	/*
1054 	 * schedule timeout to handle future stabalization of active reports
1055 	 */
1056 	if (tpend)
1057 		dam_sched_tmo(mapp, (clock_t)next_tmov, dam_addr_stable_cb);
1058 	DAM_UNLOCK(mapp, MAP_LOCK);
1059 	DTRACE_PROBE1(damap__addr__stable__cb__exit, dam_t *, mapp);
1060 }
1061 
1062 /*
1063  * fullset stabilization timeout
1064  */
1065 static void
1066 dam_set_stable_cb(void *arg)
1067 {
1068 	dam_t *mapp = (dam_t *)arg;
1069 
1070 	DTRACE_PROBE1(damap__set__stable__cb__enter, dam_t *, mapp);
1071 
1072 	DAM_LOCK(mapp, MAP_LOCK);
1073 	if (mapp->dam_tid == 0) {
1074 		DAM_UNLOCK(mapp, MAP_LOCK);
1075 		return;
1076 	}
1077 	mapp->dam_tid = 0;
1078 
1079 	/*
1080 	 * If still under stabilization, reschedule timeout,
1081 	 * else dispatch the task to activate & deactivate the stable
1082 	 * set.
1083 	 */
1084 	if (mapp->dam_flags & DAM_SPEND) {
1085 		DAM_INCR_STAT(mapp, dam_stable_blocked);
1086 		mapp->dam_stable_overrun++;
1087 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_set_stable_cb);
1088 		DTRACE_PROBE1(damap__set__stable__cb__overrun,
1089 		    dam_t *, mapp);
1090 	} else if (ddi_taskq_dispatch(mapp->dam_taskqp, dam_activate_taskq,
1091 	    mapp, DDI_NOSLEEP) == DDI_FAILURE) {
1092 		dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_set_stable_cb);
1093 	} else {
1094 		bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set);
1095 		bitset_zero(&mapp->dam_report_set);
1096 		DAM_FLAG_CLR(mapp, DAM_SETADD);
1097 		DAM_FLAG_SET(mapp, DAM_SPEND);
1098 	}
1099 	DAM_UNLOCK(mapp, MAP_LOCK);
1100 	DTRACE_PROBE1(damap__set__stable__cb__exit, dam_t *, mapp);
1101 }
1102 
1103 /*
1104  * reschedule map timeout 'tmo_ms' ticks
1105  */
1106 static void
1107 dam_sched_tmo(dam_t *mapp, clock_t tmo_ms, void (*tmo_cb)())
1108 {
1109 	timeout_id_t tid;
1110 
1111 	if ((tid = mapp->dam_tid) != 0) {
1112 		mapp->dam_tid = 0;
1113 		DAM_UNLOCK(mapp, MAP_LOCK);
1114 		(void) untimeout(tid);
1115 		DAM_LOCK(mapp, MAP_LOCK);
1116 	}
1117 
1118 	if (tmo_cb && (tmo_ms != 0))
1119 		mapp->dam_tid = timeout(tmo_cb, mapp, tmo_ms);
1120 }
1121 
1122 /*
1123  * record report addition or removal of an address
1124  */
1125 static void
1126 dam_add_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int report)
1127 {
1128 	ASSERT(!DAM_IN_REPORT(mapp, addrid));
1129 	passp->da_last_report = gethrtime();
1130 	mapp->dam_last_update = gethrtime();
1131 	passp->da_report_cnt++;
1132 	passp->da_deadline = lbolt64 + mapp->dam_stabletmo;
1133 	if (report == RPT_ADDR_DEL)
1134 		passp->da_flags |= DA_RELE;
1135 	else if (report == RPT_ADDR_ADD)
1136 		passp->da_flags &= ~DA_RELE;
1137 	DAM_LOCK(mapp, MAP_LOCK);
1138 	bitset_add(&mapp->dam_report_set, addrid);
1139 	dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb);
1140 	DAM_UNLOCK(mapp, MAP_LOCK);
1141 
1142 }
1143 
1144 /*
1145  * release an address report
1146  */
1147 static void
1148 dam_release_report(dam_t *mapp, id_t addrid)
1149 {
1150 	dam_da_t *passp;
1151 
1152 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
1153 	ASSERT(passp);
1154 	passp->da_ppriv_rpt = NULL;
1155 	if (passp->da_nvl_rpt)
1156 		nvlist_free(passp->da_nvl_rpt);
1157 	passp->da_nvl_rpt = NULL;
1158 	DAM_LOCK(mapp, MAP_LOCK);
1159 	bitset_del(&mapp->dam_report_set, addrid);
1160 	DAM_UNLOCK(mapp, MAP_LOCK);
1161 }
1162 
1163 /*
1164  * deactivate a previously stable address
1165  */
1166 static void
1167 dam_deactivate_addr(dam_t *mapp, id_t addrid)
1168 {
1169 	dam_da_t *passp;
1170 
1171 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
1172 	ASSERT(passp);
1173 	if (passp == NULL)
1174 		return;
1175 	DAM_UNLOCK(mapp, ADDR_LOCK);
1176 	if (mapp->dam_deactivate_cb)
1177 		(*mapp->dam_deactivate_cb)(
1178 		    mapp->dam_activate_arg,
1179 		    ddi_strid_id2str(mapp->dam_addr_hash,
1180 		    addrid), addrid, passp->da_ppriv);
1181 	DAM_LOCK(mapp, ADDR_LOCK);
1182 	passp->da_ppriv = NULL;
1183 	if (passp->da_nvl)
1184 		nvlist_free(passp->da_nvl);
1185 	passp->da_nvl = NULL;
1186 }
1187 
1188 /*
1189  * return the map ID of an address
1190  */
1191 static id_t
1192 dam_get_addrid(dam_t *mapp, char *address)
1193 {
1194 	damap_id_t addrid;
1195 	dam_da_t *passp;
1196 
1197 	if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) {
1198 		if ((addrid = ddi_strid_fixed_alloc(mapp->dam_addr_hash,
1199 		    address)) == (damap_id_t)0) {
1200 			return (0);
1201 		}
1202 		if (ddi_soft_state_zalloc(mapp->dam_da, addrid) !=
1203 		    DDI_SUCCESS) {
1204 			ddi_strid_free(mapp->dam_addr_hash, addrid);
1205 			return (0);
1206 		}
1207 		if (addrid >= mapp->dam_high)
1208 			mapp->dam_high = addrid + 1;
1209 	}
1210 	passp = ddi_get_soft_state(mapp->dam_da, addrid);
1211 	if (passp == NULL)
1212 		return (0);
1213 	passp->da_ref++;
1214 	if (passp->da_addr == NULL)
1215 		passp->da_addr = ddi_strid_id2str(
1216 		    mapp->dam_addr_hash, addrid); /* for mdb */
1217 	return (addrid);
1218 }
1219 
1220 /*
1221  * create and install map statistics
1222  */
1223 static int
1224 dam_kstat_create(dam_t *mapp)
1225 {
1226 	kstat_t			*mapsp;
1227 	struct dam_kstats	*statsp;
1228 
1229 	mapsp = kstat_create("dam", 0, mapp->dam_name, "damap",
1230 	    KSTAT_TYPE_NAMED,
1231 	    sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0);
1232 	if (mapsp == NULL) {
1233 		return (DDI_FAILURE);
1234 	}
1235 
1236 	statsp = (struct dam_kstats *)mapsp->ks_data;
1237 	kstat_named_init(&statsp->dam_stable, "stable cycles",
1238 	    KSTAT_DATA_UINT32);
1239 	kstat_named_init(&statsp->dam_stable_blocked,
1240 	    "stable cycle overrun", KSTAT_DATA_UINT32);
1241 	kstat_named_init(&statsp->dam_rereport,
1242 	    "restarted reports", KSTAT_DATA_UINT32);
1243 	kstat_named_init(&statsp->dam_numstable,
1244 	    "# of stable map entries", KSTAT_DATA_UINT32);
1245 	kstat_install(mapsp);
1246 	mapp->dam_kstatsp = mapsp;
1247 	return (DDI_SUCCESS);
1248 }
1249 
1250 /*
1251  * destroy map stats
1252  */
1253 static void
1254 dam_kstat_destroy(dam_t *mapp)
1255 {
1256 
1257 	kstat_delete(mapp->dam_kstatsp);
1258 }
1259