14c06356bSdh142964 /* 24c06356bSdh142964 * CDDL HEADER START 34c06356bSdh142964 * 44c06356bSdh142964 * The contents of this file are subject to the terms of the 54c06356bSdh142964 * Common Development and Distribution License (the "License"). 64c06356bSdh142964 * You may not use this file except in compliance with the License. 74c06356bSdh142964 * 84c06356bSdh142964 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94c06356bSdh142964 * or http://www.opensolaris.org/os/licensing. 104c06356bSdh142964 * See the License for the specific language governing permissions 114c06356bSdh142964 * and limitations under the License. 124c06356bSdh142964 * 134c06356bSdh142964 * When distributing Covered Code, include this CDDL HEADER in each 144c06356bSdh142964 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154c06356bSdh142964 * If applicable, add the following below this CDDL HEADER, with the 164c06356bSdh142964 * fields enclosed by brackets "[]" replaced with your own identifying 174c06356bSdh142964 * information: Portions Copyright [yyyy] [name of copyright owner] 184c06356bSdh142964 * 194c06356bSdh142964 * CDDL HEADER END 204c06356bSdh142964 */ 214c06356bSdh142964 224c06356bSdh142964 /* 234c06356bSdh142964 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244c06356bSdh142964 * Use is subject to license terms. 254c06356bSdh142964 */ 264c06356bSdh142964 274c06356bSdh142964 #include <sys/note.h> 284c06356bSdh142964 #include <sys/types.h> 294c06356bSdh142964 #include <sys/param.h> 304c06356bSdh142964 #include <sys/systm.h> 314c06356bSdh142964 #include <sys/buf.h> 324c06356bSdh142964 #include <sys/kmem.h> 334c06356bSdh142964 #include <sys/cmn_err.h> 344c06356bSdh142964 #include <sys/debug.h> 354c06356bSdh142964 #include <sys/sunndi.h> 364c06356bSdh142964 #include <sys/kstat.h> 374c06356bSdh142964 #include <sys/conf.h> 384c06356bSdh142964 #include <sys/ddi_timer.h> 394c06356bSdh142964 #include <sys/devctl.h> 404c06356bSdh142964 #include <sys/callb.h> 414c06356bSdh142964 #include <sys/sysevent.h> 424c06356bSdh142964 #include <sys/taskq.h> 434c06356bSdh142964 #include <sys/ddi.h> 444c06356bSdh142964 #include <sys/bitset.h> 454c06356bSdh142964 #include <sys/damap.h> 464c06356bSdh142964 #include <sys/damap_impl.h> 474c06356bSdh142964 484c06356bSdh142964 #ifdef DEBUG 494c06356bSdh142964 static int damap_debug = 0; 504c06356bSdh142964 #endif /* DEBUG */ 514c06356bSdh142964 52*1b115575SJohn Danielson extern taskq_t *system_taskq; 53*1b115575SJohn Danielson 544c06356bSdh142964 static void dam_addrset_activate(dam_t *, bitset_t *); 55*1b115575SJohn Danielson static void dam_addrset_deactivate(dam_t *, bitset_t *); 56*1b115575SJohn Danielson static void dam_stabilize_map(void *); 574c06356bSdh142964 static void dam_addr_stable_cb(void *); 58*1b115575SJohn Danielson static void dam_addrset_stable_cb(void *); 594c06356bSdh142964 static void dam_sched_tmo(dam_t *, clock_t, void (*tmo_cb)()); 60*1b115575SJohn Danielson static void dam_addr_report(dam_t *, dam_da_t *, id_t, int); 61*1b115575SJohn Danielson static void dam_addr_release(dam_t *, id_t); 62*1b115575SJohn Danielson static void dam_addr_report_release(dam_t *, id_t); 63*1b115575SJohn Danielson static void dam_addr_deactivate(dam_t *, id_t); 644c06356bSdh142964 static id_t dam_get_addrid(dam_t *, char *); 654c06356bSdh142964 static int dam_kstat_create(dam_t *); 66*1b115575SJohn Danielson static int dam_map_alloc(dam_t *); 674c06356bSdh142964 684c06356bSdh142964 #define DAM_INCR_STAT(mapp, stat) \ 694c06356bSdh142964 if ((mapp)->dam_kstatsp) { \ 704c06356bSdh142964 struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data; \ 714c06356bSdh142964 stp->stat.value.ui32++; \ 724c06356bSdh142964 } 734c06356bSdh142964 744c06356bSdh142964 #define DAM_SET_STAT(mapp, stat, val) \ 754c06356bSdh142964 if ((mapp)->dam_kstatsp) { \ 764c06356bSdh142964 struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data; \ 774c06356bSdh142964 stp->stat.value.ui32 = (val); \ 784c06356bSdh142964 } 794c06356bSdh142964 80*1b115575SJohn Danielson 81*1b115575SJohn Danielson /* 82*1b115575SJohn Danielson * increase damap size by 64 entries at a time 83*1b115575SJohn Danielson */ 84*1b115575SJohn Danielson #define DAM_SIZE_BUMP 64 85*1b115575SJohn Danielson 86*1b115575SJohn Danielson /* 87*1b115575SJohn Danielson * config/unconfig taskq data 88*1b115575SJohn Danielson */ 89*1b115575SJohn Danielson typedef struct { 90*1b115575SJohn Danielson dam_t *tqd_mapp; 91*1b115575SJohn Danielson id_t tqd_id; 92*1b115575SJohn Danielson } cfg_tqd_t; 93*1b115575SJohn Danielson 94*1b115575SJohn Danielson extern pri_t maxclsyspri; 95*1b115575SJohn Danielson 964c06356bSdh142964 /* 974c06356bSdh142964 * Create new device address map 984c06356bSdh142964 * 99*1b115575SJohn Danielson * name: map name (kstat unique) 1004c06356bSdh142964 * size: max # of map entries 101*1b115575SJohn Danielson * mode: style of address reports: per-address or fullset 1024c06356bSdh142964 * stable_usec: # of quiescent microseconds before report/map is stable 1034c06356bSdh142964 * 1044c06356bSdh142964 * activate_arg: address provider activation-callout private 1054c06356bSdh142964 * activate_cb: address provider activation callback handler 1064c06356bSdh142964 * deactivate_cb: address provider deactivation callback handler 1074c06356bSdh142964 * 1084c06356bSdh142964 * config_arg: configuration-callout private 1094c06356bSdh142964 * config_cb: class configuration callout 1104c06356bSdh142964 * unconfig_cb: class unconfiguration callout 1114c06356bSdh142964 * 1124c06356bSdh142964 * damapp: pointer to map handle (return) 1134c06356bSdh142964 * 1144c06356bSdh142964 * Returns: DAM_SUCCESS 1154c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 1164c06356bSdh142964 * DAM_FAILURE General failure 1174c06356bSdh142964 */ 1184c06356bSdh142964 int 119*1b115575SJohn Danielson damap_create(char *name, damap_rptmode_t mode, int map_opts, 120*1b115575SJohn Danielson clock_t stable_usec, void *activate_arg, damap_activate_cb_t activate_cb, 1214c06356bSdh142964 damap_deactivate_cb_t deactivate_cb, 1224c06356bSdh142964 void *config_arg, damap_configure_cb_t configure_cb, 1234c06356bSdh142964 damap_unconfig_cb_t unconfig_cb, 1244c06356bSdh142964 damap_t **damapp) 1254c06356bSdh142964 { 1264c06356bSdh142964 dam_t *mapp; 1274c06356bSdh142964 128*1b115575SJohn Danielson if (configure_cb == NULL || unconfig_cb == NULL || name == NULL) 1294c06356bSdh142964 return (DAM_EINVAL); 1304c06356bSdh142964 131*1b115575SJohn Danielson DTRACE_PROBE3(damap__create, char *, name, 132*1b115575SJohn Danielson damap_rptmode_t, mode, clock_t, stable_usec); 1334c06356bSdh142964 1344c06356bSdh142964 mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP); 135*1b115575SJohn Danielson mapp->dam_options = map_opts; 1364c06356bSdh142964 mapp->dam_stabletmo = drv_usectohz(stable_usec); 137*1b115575SJohn Danielson mapp->dam_size = 0; 138*1b115575SJohn Danielson mapp->dam_rptmode = mode; 1394c06356bSdh142964 mapp->dam_activate_arg = activate_arg; 1404c06356bSdh142964 mapp->dam_activate_cb = (activate_cb_t)activate_cb; 1414c06356bSdh142964 mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb; 1424c06356bSdh142964 mapp->dam_config_arg = config_arg; 1434c06356bSdh142964 mapp->dam_configure_cb = (configure_cb_t)configure_cb; 1444c06356bSdh142964 mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb; 145*1b115575SJohn Danielson mapp->dam_name = i_ddi_strdup(name, KM_SLEEP); 1464c06356bSdh142964 mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL); 1474c06356bSdh142964 cv_init(&mapp->dam_cv, NULL, CV_DRIVER, NULL); 148*1b115575SJohn Danielson bitset_init(&mapp->dam_active_set); 149*1b115575SJohn Danielson bitset_init(&mapp->dam_stable_set); 150*1b115575SJohn Danielson bitset_init(&mapp->dam_report_set); 1514c06356bSdh142964 *damapp = (damap_t *)mapp; 1524c06356bSdh142964 return (DAM_SUCCESS); 1534c06356bSdh142964 } 1544c06356bSdh142964 1554c06356bSdh142964 /* 156*1b115575SJohn Danielson * Allocate backing resources 157*1b115575SJohn Danielson * 158*1b115575SJohn Danielson * DAMs are lightly backed on create - major allocations occur 159*1b115575SJohn Danielson * at the time a report is made to the map, and are extended on 160*1b115575SJohn Danielson * a demand basis. 161*1b115575SJohn Danielson */ 162*1b115575SJohn Danielson static int 163*1b115575SJohn Danielson dam_map_alloc(dam_t *mapp) 164*1b115575SJohn Danielson { 165*1b115575SJohn Danielson void *softstate_p; 166*1b115575SJohn Danielson 167*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 168*1b115575SJohn Danielson if (mapp->dam_flags & DAM_DESTROYPEND) 169*1b115575SJohn Danielson return (DAM_FAILURE); 170*1b115575SJohn Danielson 171*1b115575SJohn Danielson /* 172*1b115575SJohn Danielson * dam_high > 0 signals map allocation complete 173*1b115575SJohn Danielson */ 174*1b115575SJohn Danielson if (mapp->dam_high) 175*1b115575SJohn Danielson return (DAM_SUCCESS); 176*1b115575SJohn Danielson 177*1b115575SJohn Danielson mapp->dam_size = DAM_SIZE_BUMP; 178*1b115575SJohn Danielson if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t), 179*1b115575SJohn Danielson mapp->dam_size) != DDI_SUCCESS) 180*1b115575SJohn Danielson return (DAM_FAILURE); 181*1b115575SJohn Danielson 182*1b115575SJohn Danielson if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) != 183*1b115575SJohn Danielson DDI_SUCCESS) { 184*1b115575SJohn Danielson ddi_soft_state_fini(softstate_p); 185*1b115575SJohn Danielson return (DAM_FAILURE); 186*1b115575SJohn Danielson } 187*1b115575SJohn Danielson if (dam_kstat_create(mapp) != DDI_SUCCESS) { 188*1b115575SJohn Danielson ddi_soft_state_fini(softstate_p); 189*1b115575SJohn Danielson ddi_strid_fini(&mapp->dam_addr_hash); 190*1b115575SJohn Danielson return (DAM_FAILURE); 191*1b115575SJohn Danielson } 192*1b115575SJohn Danielson mapp->dam_da = softstate_p; 193*1b115575SJohn Danielson mapp->dam_high = 1; 194*1b115575SJohn Danielson bitset_resize(&mapp->dam_active_set, mapp->dam_size); 195*1b115575SJohn Danielson bitset_resize(&mapp->dam_stable_set, mapp->dam_size); 196*1b115575SJohn Danielson bitset_resize(&mapp->dam_report_set, mapp->dam_size); 197*1b115575SJohn Danielson return (DAM_SUCCESS); 198*1b115575SJohn Danielson } 199*1b115575SJohn Danielson 200*1b115575SJohn Danielson /* 201*1b115575SJohn Danielson * Destroy address map 2024c06356bSdh142964 * 2034c06356bSdh142964 * damapp: address map 2044c06356bSdh142964 * 2054c06356bSdh142964 * Returns: DAM_SUCCESS 2064c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 2074c06356bSdh142964 * DAM_FAILURE General failure 2084c06356bSdh142964 */ 2094c06356bSdh142964 void 2104c06356bSdh142964 damap_destroy(damap_t *damapp) 2114c06356bSdh142964 { 2124c06356bSdh142964 int i; 2134c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 2144c06356bSdh142964 2154c06356bSdh142964 ASSERT(mapp); 2164c06356bSdh142964 217*1b115575SJohn Danielson DTRACE_PROBE1(damap__destroy, char *, mapp->dam_name); 2184c06356bSdh142964 219*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 2204c06356bSdh142964 2214c06356bSdh142964 /* 222*1b115575SJohn Danielson * prevent new reports from being added to the map 2234c06356bSdh142964 */ 224*1b115575SJohn Danielson mapp->dam_flags |= DAM_DESTROYPEND; 2254c06356bSdh142964 226*1b115575SJohn Danielson if (mapp->dam_high) { 227*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 228*1b115575SJohn Danielson /* 229*1b115575SJohn Danielson * wait for outstanding reports to stabilize and cancel 230*1b115575SJohn Danielson * the timer for this map 231*1b115575SJohn Danielson */ 232*1b115575SJohn Danielson (void) damap_sync(damapp); 233*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 234*1b115575SJohn Danielson dam_sched_tmo(mapp, 0, NULL); 235*1b115575SJohn Danielson 236*1b115575SJohn Danielson /* 237*1b115575SJohn Danielson * map is at full stop 238*1b115575SJohn Danielson * release the contents of the map, invoking the 239*1b115575SJohn Danielson * detactivation protocol as addresses are released 240*1b115575SJohn Danielson */ 241*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 2424c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 2434c06356bSdh142964 if (ddi_get_soft_state(mapp->dam_da, i) == NULL) 2444c06356bSdh142964 continue; 245*1b115575SJohn Danielson 246*1b115575SJohn Danielson ASSERT(DAM_IN_REPORT(mapp, i) == 0); 247*1b115575SJohn Danielson 248*1b115575SJohn Danielson if (DAM_IS_STABLE(mapp, i)) { 249*1b115575SJohn Danielson dam_addr_deactivate(mapp, i); 250*1b115575SJohn Danielson } else { 2514c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, i); 2524c06356bSdh142964 ddi_soft_state_free(mapp->dam_da, i); 2534c06356bSdh142964 } 254*1b115575SJohn Danielson } 2554c06356bSdh142964 ddi_strid_fini(&mapp->dam_addr_hash); 2564c06356bSdh142964 ddi_soft_state_fini(&mapp->dam_da); 257*1b115575SJohn Danielson kstat_delete(mapp->dam_kstatsp); 258*1b115575SJohn Danielson } 2594c06356bSdh142964 bitset_fini(&mapp->dam_active_set); 2604c06356bSdh142964 bitset_fini(&mapp->dam_stable_set); 2614c06356bSdh142964 bitset_fini(&mapp->dam_report_set); 2624c06356bSdh142964 mutex_destroy(&mapp->dam_lock); 2634c06356bSdh142964 cv_destroy(&mapp->dam_cv); 2644c06356bSdh142964 if (mapp->dam_name) 2654c06356bSdh142964 kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1); 2664c06356bSdh142964 kmem_free(mapp, sizeof (*mapp)); 2674c06356bSdh142964 } 2684c06356bSdh142964 2694c06356bSdh142964 /* 2704c06356bSdh142964 * Wait for map stability. 2714c06356bSdh142964 * 2724c06356bSdh142964 * damapp: address map 2734c06356bSdh142964 */ 2744c06356bSdh142964 int 2754c06356bSdh142964 damap_sync(damap_t *damapp) 2764c06356bSdh142964 { 277*1b115575SJohn Danielson #define WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND) 2784c06356bSdh142964 2794c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 2804c06356bSdh142964 int none_active; 2814c06356bSdh142964 2824c06356bSdh142964 ASSERT(mapp); 2834c06356bSdh142964 284*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__sync__start, char *, mapp->dam_name, 285*1b115575SJohn Danielson dam_t *, mapp); 2864c06356bSdh142964 287*1b115575SJohn Danielson /* 288*1b115575SJohn Danielson * block where waiting for 289*1b115575SJohn Danielson * a) stabilization pending or a fullset update pending 290*1b115575SJohn Danielson * b) any scheduled timeouts to fire 291*1b115575SJohn Danielson * c) the report set to finalize (bitset is null) 292*1b115575SJohn Danielson */ 2934c06356bSdh142964 mutex_enter(&mapp->dam_lock); 2944c06356bSdh142964 while ((mapp->dam_flags & WAITFOR_FLAGS) || 2954c06356bSdh142964 (!bitset_is_null(&mapp->dam_report_set)) || (mapp->dam_tid != 0)) { 296*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__sync__waiting, char *, mapp->dam_name, 297*1b115575SJohn Danielson dam_t *, mapp); 2984c06356bSdh142964 cv_wait(&mapp->dam_cv, &mapp->dam_lock); 2994c06356bSdh142964 } 3004c06356bSdh142964 3014c06356bSdh142964 none_active = bitset_is_null(&mapp->dam_active_set); 3024c06356bSdh142964 3034c06356bSdh142964 mutex_exit(&mapp->dam_lock); 304*1b115575SJohn Danielson DTRACE_PROBE3(damap__map__sync__end, char *, mapp->dam_name, int, 305*1b115575SJohn Danielson none_active, dam_t *, mapp); 3064c06356bSdh142964 3074c06356bSdh142964 return (none_active); 3084c06356bSdh142964 } 3094c06356bSdh142964 3104c06356bSdh142964 /* 3114c06356bSdh142964 * Get the name of a device address map 3124c06356bSdh142964 * 3134c06356bSdh142964 * damapp: address map 3144c06356bSdh142964 * 3154c06356bSdh142964 * Returns: name 3164c06356bSdh142964 */ 3174c06356bSdh142964 char * 3184c06356bSdh142964 damap_name(damap_t *damapp) 3194c06356bSdh142964 { 3204c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 3214c06356bSdh142964 3224c06356bSdh142964 return (mapp ? mapp->dam_name : "UNKNOWN_damap"); 3234c06356bSdh142964 } 3244c06356bSdh142964 3254c06356bSdh142964 /* 3264c06356bSdh142964 * Report an address to per-address report 3274c06356bSdh142964 * 3284c06356bSdh142964 * damapp: address map handle 3294c06356bSdh142964 * address: address in ascii string representation 330*1b115575SJohn Danielson * addridp: address ID 3314c06356bSdh142964 * nvl: optional nvlist of configuration-private data 3324c06356bSdh142964 * addr_priv: optional provider-private (passed to activate/deactivate cb) 3334c06356bSdh142964 * 3344c06356bSdh142964 * Returns: DAM_SUCCESS 3354c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 3364c06356bSdh142964 * DAM_MAPFULL address map exhausted 3374c06356bSdh142964 */ 3384c06356bSdh142964 int 339*1b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp, 340*1b115575SJohn Danielson nvlist_t *nvl, void *addr_priv) 3414c06356bSdh142964 { 3424c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 3434c06356bSdh142964 id_t addrid; 3444c06356bSdh142964 dam_da_t *passp; 3454c06356bSdh142964 346*1b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR)) 3474c06356bSdh142964 return (DAM_EINVAL); 3484c06356bSdh142964 349*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__add, char *, mapp->dam_name, 350*1b115575SJohn Danielson char *, address, dam_t *, mapp); 351*1b115575SJohn Danielson 352*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 353*1b115575SJohn Danielson if ((dam_map_alloc(mapp) != DAM_SUCCESS) || 354*1b115575SJohn Danielson ((addrid = dam_get_addrid(mapp, address)) == 0)) { 355*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 3564c06356bSdh142964 return (DAM_MAPFULL); 3574c06356bSdh142964 } 3584c06356bSdh142964 3594c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 3604c06356bSdh142964 ASSERT(passp != NULL); 3614c06356bSdh142964 3624c06356bSdh142964 /* 3634c06356bSdh142964 * If re-reporting the same address (add or remove) clear 3644c06356bSdh142964 * the existing report 3654c06356bSdh142964 */ 3664c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 367*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__add__jitter, char *, mapp->dam_name, 368*1b115575SJohn Danielson char *, address, dam_t *, mapp); 369*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_jitter); 370*1b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 3714c06356bSdh142964 passp->da_jitter++; 3724c06356bSdh142964 } 3734c06356bSdh142964 passp->da_ppriv_rpt = addr_priv; 3744c06356bSdh142964 if (nvl) 3754c06356bSdh142964 (void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP); 3764c06356bSdh142964 377*1b115575SJohn Danielson dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD); 378*1b115575SJohn Danielson if (addridp != NULL) 379*1b115575SJohn Danielson *addridp = (damap_id_t)addrid; 380*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 3814c06356bSdh142964 return (DAM_SUCCESS); 3824c06356bSdh142964 } 3834c06356bSdh142964 3844c06356bSdh142964 /* 3854c06356bSdh142964 * Report removal of address from per-address report 3864c06356bSdh142964 * 3874c06356bSdh142964 * damapp: address map 3884c06356bSdh142964 * address: address in ascii string representation 3894c06356bSdh142964 * 3904c06356bSdh142964 * Returns: DAM_SUCCESS 3914c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 3924c06356bSdh142964 * DAM_FAILURE General failure 3934c06356bSdh142964 */ 3944c06356bSdh142964 int 3954c06356bSdh142964 damap_addr_del(damap_t *damapp, char *address) 3964c06356bSdh142964 { 3974c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 3984c06356bSdh142964 id_t addrid; 3994c06356bSdh142964 dam_da_t *passp; 4004c06356bSdh142964 401*1b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR)) 4024c06356bSdh142964 return (DAM_EINVAL); 4034c06356bSdh142964 404*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__del, char *, mapp->dam_name, 405*1b115575SJohn Danielson char *, address, dam_t *, mapp); 406*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 407*1b115575SJohn Danielson if (dam_map_alloc(mapp) != DAM_SUCCESS) { 408*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 409*1b115575SJohn Danielson return (DAM_MAPFULL); 410*1b115575SJohn Danielson } 411*1b115575SJohn Danielson 412*1b115575SJohn Danielson /* 413*1b115575SJohn Danielson * if reporting the removal of an address which is not in the map 414*1b115575SJohn Danielson * return success 415*1b115575SJohn Danielson */ 4164c06356bSdh142964 if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) { 417*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4184c06356bSdh142964 return (DAM_SUCCESS); 4194c06356bSdh142964 } 4204c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 4214c06356bSdh142964 ASSERT(passp); 4224c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 423*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__del__jitter, char *, mapp->dam_name, 424*1b115575SJohn Danielson char *, address, dam_t *, mapp); 425*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_jitter); 426*1b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 4274c06356bSdh142964 passp->da_jitter++; 4284c06356bSdh142964 } 429*1b115575SJohn Danielson dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL); 430*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4314c06356bSdh142964 return (DAM_SUCCESS); 4324c06356bSdh142964 } 4334c06356bSdh142964 4344c06356bSdh142964 /* 4354c06356bSdh142964 * Initiate full-set report 4364c06356bSdh142964 * 4374c06356bSdh142964 * damapp: address map 4384c06356bSdh142964 * 4394c06356bSdh142964 * Returns: DAM_SUCCESS 4404c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 4414c06356bSdh142964 */ 4424c06356bSdh142964 int 4434c06356bSdh142964 damap_addrset_begin(damap_t *damapp) 4444c06356bSdh142964 { 4454c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 4464c06356bSdh142964 int i; 4474c06356bSdh142964 448*1b115575SJohn Danielson if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET)) 4494c06356bSdh142964 return (DAM_EINVAL); 4504c06356bSdh142964 451*1b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__begin, char *, mapp->dam_name, dam_t *, 452*1b115575SJohn Danielson mapp); 453*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 454*1b115575SJohn Danielson if (dam_map_alloc(mapp) != DAM_SUCCESS) { 455*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 456*1b115575SJohn Danielson return (DAM_MAPFULL); 457*1b115575SJohn Danielson } 4584c06356bSdh142964 if (mapp->dam_flags & DAM_SETADD) { 459*1b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__begin__reset, char *, 460*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 4614c06356bSdh142964 /* 4624c06356bSdh142964 * cancel stabilization timeout 4634c06356bSdh142964 */ 4644c06356bSdh142964 dam_sched_tmo(mapp, 0, NULL); 465*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_jitter); 466*1b115575SJohn Danielson 467*1b115575SJohn Danielson /* 468*1b115575SJohn Danielson * clear pending reports 469*1b115575SJohn Danielson */ 4704c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 4714c06356bSdh142964 if (DAM_IN_REPORT(mapp, i)) 472*1b115575SJohn Danielson dam_addr_report_release(mapp, i); 4734c06356bSdh142964 } 4744c06356bSdh142964 } 4754c06356bSdh142964 bitset_zero(&mapp->dam_report_set); 476*1b115575SJohn Danielson mapp->dam_flags |= DAM_SETADD; 477*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4784c06356bSdh142964 return (DAM_SUCCESS); 4794c06356bSdh142964 } 4804c06356bSdh142964 4814c06356bSdh142964 /* 4824c06356bSdh142964 * Report address to full-set report 4834c06356bSdh142964 * 4844c06356bSdh142964 * damapp: address map handle 4854c06356bSdh142964 * address: address in ascii string representation 4864c06356bSdh142964 * rindx: index if address stabilizes 4874c06356bSdh142964 * nvl: optional nvlist of configuration-private data 4884c06356bSdh142964 * addr_priv: optional provider-private data (passed to activate/release cb) 4894c06356bSdh142964 * 4904c06356bSdh142964 * Returns: DAM_SUCCESS 4914c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 4924c06356bSdh142964 * DAM_MAPFULL address map exhausted 4934c06356bSdh142964 * DAM_FAILURE General failure 4944c06356bSdh142964 */ 4954c06356bSdh142964 int 4964c06356bSdh142964 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx, 4974c06356bSdh142964 nvlist_t *nvl, void *addr_priv) 4984c06356bSdh142964 { 4994c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 5004c06356bSdh142964 id_t addrid; 5014c06356bSdh142964 dam_da_t *passp; 5024c06356bSdh142964 503*1b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET)) 5044c06356bSdh142964 return (DAM_EINVAL); 5054c06356bSdh142964 506*1b115575SJohn Danielson DTRACE_PROBE3(damap__addrset__add, char *, mapp->dam_name, 507*1b115575SJohn Danielson char *, address, dam_t *, mapp); 5084c06356bSdh142964 509*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 510*1b115575SJohn Danielson if (!(mapp->dam_flags & DAM_SETADD)) { 511*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 512*1b115575SJohn Danielson return (DAM_FAILURE); 513*1b115575SJohn Danielson } 514*1b115575SJohn Danielson 5154c06356bSdh142964 if ((addrid = dam_get_addrid(mapp, address)) == 0) { 516*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5174c06356bSdh142964 return (DAM_MAPFULL); 5184c06356bSdh142964 } 5194c06356bSdh142964 5204c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 5214c06356bSdh142964 ASSERT(passp); 5224c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 523*1b115575SJohn Danielson DTRACE_PROBE3(damap__addrset__add__jitter, char *, 524*1b115575SJohn Danielson mapp->dam_name, char *, address, dam_t *, mapp); 525*1b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 5264c06356bSdh142964 passp->da_jitter++; 5274c06356bSdh142964 } 5284c06356bSdh142964 passp->da_ppriv_rpt = addr_priv; 5294c06356bSdh142964 if (nvl) 5304c06356bSdh142964 (void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP); 5314c06356bSdh142964 bitset_add(&mapp->dam_report_set, addrid); 5324c06356bSdh142964 if (ridx) 5334c06356bSdh142964 *ridx = (damap_id_t)addrid; 534*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5354c06356bSdh142964 return (DAM_SUCCESS); 5364c06356bSdh142964 } 5374c06356bSdh142964 5384c06356bSdh142964 /* 5394c06356bSdh142964 * Commit full-set report for stabilization 5404c06356bSdh142964 * 5414c06356bSdh142964 * damapp: address map handle 5424c06356bSdh142964 * flags: (currently 0) 5434c06356bSdh142964 * 5444c06356bSdh142964 * Returns: DAM_SUCCESS 5454c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 5464c06356bSdh142964 * DAM_FAILURE General failure 5474c06356bSdh142964 */ 5484c06356bSdh142964 int 5494c06356bSdh142964 damap_addrset_end(damap_t *damapp, int flags) 5504c06356bSdh142964 { 5514c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 5524c06356bSdh142964 int i; 5534c06356bSdh142964 554*1b115575SJohn Danielson if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET)) 5554c06356bSdh142964 return (DAM_EINVAL); 5564c06356bSdh142964 557*1b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__end, char *, mapp->dam_name, 558*1b115575SJohn Danielson dam_t *, mapp); 5594c06356bSdh142964 560*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 561*1b115575SJohn Danielson if (!(mapp->dam_flags & DAM_SETADD)) { 562*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 563*1b115575SJohn Danielson return (DAM_FAILURE); 564*1b115575SJohn Danielson } 565*1b115575SJohn Danielson 566*1b115575SJohn Danielson if (flags & DAMAP_END_RESET) { 567*1b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__end__reset, char *, 568*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 5694c06356bSdh142964 dam_sched_tmo(mapp, 0, NULL); 5704c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) 5714c06356bSdh142964 if (DAM_IN_REPORT(mapp, i)) 572*1b115575SJohn Danielson dam_addr_report_release(mapp, i); 5734c06356bSdh142964 } else { 5744c06356bSdh142964 mapp->dam_last_update = gethrtime(); 575*1b115575SJohn Danielson dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb); 5764c06356bSdh142964 } 577*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5784c06356bSdh142964 return (DAM_SUCCESS); 5794c06356bSdh142964 } 5804c06356bSdh142964 5814c06356bSdh142964 /* 5824c06356bSdh142964 * Return nvlist registered with reported address 5834c06356bSdh142964 * 5844c06356bSdh142964 * damapp: address map handle 585*1b115575SJohn Danielson * addrid: address ID 5864c06356bSdh142964 * 5874c06356bSdh142964 * Returns: nvlist_t * provider supplied via damap_addr{set}_add()) 5884c06356bSdh142964 * NULL 5894c06356bSdh142964 */ 5904c06356bSdh142964 nvlist_t * 5914c06356bSdh142964 damap_id2nvlist(damap_t *damapp, damap_id_t addrid) 5924c06356bSdh142964 { 5934c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 5944c06356bSdh142964 dam_da_t *pass; 5954c06356bSdh142964 596*1b115575SJohn Danielson if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) { 597*1b115575SJohn Danielson if (pass = ddi_get_soft_state(mapp->dam_da, addrid)) 5984c06356bSdh142964 return (pass->da_nvl); 5994c06356bSdh142964 } 6004c06356bSdh142964 return (NULL); 6014c06356bSdh142964 } 6024c06356bSdh142964 6034c06356bSdh142964 /* 6044c06356bSdh142964 * Return address string 6054c06356bSdh142964 * 6064c06356bSdh142964 * damapp: address map handle 607*1b115575SJohn Danielson * addrid: address ID 6084c06356bSdh142964 * 6094c06356bSdh142964 * Returns: char * Address string 6104c06356bSdh142964 * NULL 6114c06356bSdh142964 */ 6124c06356bSdh142964 char * 613*1b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid) 6144c06356bSdh142964 { 6154c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6164c06356bSdh142964 617*1b115575SJohn Danielson if (mapp->dam_high) 618*1b115575SJohn Danielson return (ddi_strid_id2str(mapp->dam_addr_hash, addrid)); 619*1b115575SJohn Danielson else 620*1b115575SJohn Danielson return (NULL); 6214c06356bSdh142964 } 6224c06356bSdh142964 6234c06356bSdh142964 /* 6244c06356bSdh142964 * Release address reference in map 6254c06356bSdh142964 * 6264c06356bSdh142964 * damapp: address map handle 627*1b115575SJohn Danielson * addrid: address ID 6284c06356bSdh142964 */ 6294c06356bSdh142964 void 6304c06356bSdh142964 damap_id_rele(damap_t *damapp, damap_id_t addrid) 6314c06356bSdh142964 { 6324c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 633*1b115575SJohn Danielson dam_da_t *passp; 634*1b115575SJohn Danielson char *addr; 6354c06356bSdh142964 636*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 637*1b115575SJohn Danielson ASSERT(passp); 638*1b115575SJohn Danielson 639*1b115575SJohn Danielson addr = damap_id2addr(damapp, addrid); 640*1b115575SJohn Danielson DTRACE_PROBE4(damap__id__rele, char *, mapp->dam_name, char *, addr, 641*1b115575SJohn Danielson dam_t *, mapp, int, passp->da_ref); 642*1b115575SJohn Danielson 643*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 644*1b115575SJohn Danielson 645*1b115575SJohn Danielson /* 646*1b115575SJohn Danielson * teardown address if last outstanding reference 647*1b115575SJohn Danielson */ 648*1b115575SJohn Danielson if (--passp->da_ref == 0) 649*1b115575SJohn Danielson dam_addr_release(mapp, (id_t)addrid); 650*1b115575SJohn Danielson 651*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 6524c06356bSdh142964 } 6534c06356bSdh142964 6544c06356bSdh142964 /* 6554c06356bSdh142964 * Return current reference count on address reference in map 6564c06356bSdh142964 * 6574c06356bSdh142964 * damapp: address map handle 658*1b115575SJohn Danielson * addrid: address ID 6594c06356bSdh142964 * 6604c06356bSdh142964 * Returns: DAM_SUCCESS 6614c06356bSdh142964 * DAM_FAILURE 6624c06356bSdh142964 */ 6634c06356bSdh142964 int 664*1b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid) 6654c06356bSdh142964 { 6664c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6674c06356bSdh142964 dam_da_t *passp; 6684c06356bSdh142964 int ref = -1; 6694c06356bSdh142964 670*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 6714c06356bSdh142964 if (passp) 6724c06356bSdh142964 ref = passp->da_ref; 673*1b115575SJohn Danielson 6744c06356bSdh142964 return (ref); 6754c06356bSdh142964 } 6764c06356bSdh142964 6774c06356bSdh142964 /* 6784c06356bSdh142964 * Return next address ID in list 6794c06356bSdh142964 * 6804c06356bSdh142964 * damapp: address map handle 6814c06356bSdh142964 * damap_list: address ID list passed to config|unconfig 6824c06356bSdh142964 * returned by look by lookup_all 6834c06356bSdh142964 * last: last ID returned, 0 is start of list 6844c06356bSdh142964 * 6854c06356bSdh142964 * Returns: addrid Next ID from the list 6864c06356bSdh142964 * 0 End of the list 6874c06356bSdh142964 */ 6884c06356bSdh142964 damap_id_t 6894c06356bSdh142964 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last) 6904c06356bSdh142964 { 6914c06356bSdh142964 int i, start; 6924c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6934c06356bSdh142964 bitset_t *dam_list = (bitset_t *)damap_list; 6944c06356bSdh142964 6954c06356bSdh142964 if (!mapp || !dam_list) 6964c06356bSdh142964 return ((damap_id_t)0); 6974c06356bSdh142964 6984c06356bSdh142964 start = (int)last + 1; 699*1b115575SJohn Danielson for (i = start; i < mapp->dam_high; i++) { 700*1b115575SJohn Danielson if (bitset_in_set(dam_list, i)) { 7014c06356bSdh142964 return ((damap_id_t)i); 702*1b115575SJohn Danielson } 703*1b115575SJohn Danielson } 7044c06356bSdh142964 return ((damap_id_t)0); 7054c06356bSdh142964 } 7064c06356bSdh142964 7074c06356bSdh142964 /* 7084c06356bSdh142964 * Set config private data 7094c06356bSdh142964 * 7104c06356bSdh142964 * damapp: address map handle 711*1b115575SJohn Danielson * addrid: address ID 7124c06356bSdh142964 * cfg_priv: configuration private data 7134c06356bSdh142964 * 7144c06356bSdh142964 */ 7154c06356bSdh142964 void 716*1b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv) 7174c06356bSdh142964 { 7184c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7194c06356bSdh142964 dam_da_t *passp; 7204c06356bSdh142964 721*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 722*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 7234c06356bSdh142964 if (!passp) { 724*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7254c06356bSdh142964 return; 7264c06356bSdh142964 } 7274c06356bSdh142964 passp->da_cfg_priv = cfg_priv; 728*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7294c06356bSdh142964 } 7304c06356bSdh142964 7314c06356bSdh142964 /* 7324c06356bSdh142964 * Get config private data 7334c06356bSdh142964 * 7344c06356bSdh142964 * damapp: address map handle 735*1b115575SJohn Danielson * addrid: address ID 7364c06356bSdh142964 * 7374c06356bSdh142964 * Returns: configuration private data 7384c06356bSdh142964 */ 7394c06356bSdh142964 void * 740*1b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid) 7414c06356bSdh142964 { 7424c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7434c06356bSdh142964 dam_da_t *passp; 7444c06356bSdh142964 void *rv; 7454c06356bSdh142964 746*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 747*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 7484c06356bSdh142964 if (!passp) { 749*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7504c06356bSdh142964 return (NULL); 7514c06356bSdh142964 } 7524c06356bSdh142964 rv = passp->da_cfg_priv; 753*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7544c06356bSdh142964 return (rv); 7554c06356bSdh142964 } 7564c06356bSdh142964 7574c06356bSdh142964 /* 7584c06356bSdh142964 * Lookup a single address in the active address map 7594c06356bSdh142964 * 7604c06356bSdh142964 * damapp: address map handle 7614c06356bSdh142964 * address: address string 7624c06356bSdh142964 * 7634c06356bSdh142964 * Returns: ID of active/stable address 7644c06356bSdh142964 * 0 Address not in stable set 7654c06356bSdh142964 * 7664c06356bSdh142964 * Future: Allow the caller to wait for stabilize before returning not found. 7674c06356bSdh142964 */ 7684c06356bSdh142964 damap_id_t 7694c06356bSdh142964 damap_lookup(damap_t *damapp, char *address) 7704c06356bSdh142964 { 7714c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7724c06356bSdh142964 id_t addrid = 0; 7734c06356bSdh142964 dam_da_t *passp = NULL; 7744c06356bSdh142964 775*1b115575SJohn Danielson DTRACE_PROBE3(damap__lookup, char *, mapp->dam_name, 776*1b115575SJohn Danielson char *, address, dam_t *, mapp); 777*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 778*1b115575SJohn Danielson if (!mapp->dam_high) 779*1b115575SJohn Danielson addrid = 0; 780*1b115575SJohn Danielson else 7814c06356bSdh142964 addrid = ddi_strid_str2id(mapp->dam_addr_hash, address); 7824c06356bSdh142964 if (addrid) { 7834c06356bSdh142964 if (DAM_IS_STABLE(mapp, addrid)) { 7844c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 7854c06356bSdh142964 ASSERT(passp); 7864c06356bSdh142964 if (passp) { 7874c06356bSdh142964 passp->da_ref++; 7884c06356bSdh142964 } else { 7894c06356bSdh142964 addrid = 0; 7904c06356bSdh142964 } 7914c06356bSdh142964 } else { 7924c06356bSdh142964 addrid = 0; 7934c06356bSdh142964 } 7944c06356bSdh142964 } 795*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 796*1b115575SJohn Danielson DTRACE_PROBE4(damap__lookup__return, char *, mapp->dam_name, 797*1b115575SJohn Danielson char *, address, dam_t *, mapp, int, addrid); 7984c06356bSdh142964 return ((damap_id_t)addrid); 7994c06356bSdh142964 } 8004c06356bSdh142964 8014c06356bSdh142964 8024c06356bSdh142964 /* 8034c06356bSdh142964 * Return the list of stable addresses in the map 8044c06356bSdh142964 * 8054c06356bSdh142964 * damapp: address map handle 8064c06356bSdh142964 * id_listp: pointer to list of address IDs in stable map (returned) 8074c06356bSdh142964 * 8084c06356bSdh142964 * Returns: # of entries returned in alist 8094c06356bSdh142964 */ 8104c06356bSdh142964 int 8114c06356bSdh142964 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp) 8124c06356bSdh142964 { 8134c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 8144c06356bSdh142964 int mapsz = mapp->dam_size; 8154c06356bSdh142964 int n_ids, i; 8164c06356bSdh142964 bitset_t *bsp; 817*1b115575SJohn Danielson char *addrp; 8184c06356bSdh142964 dam_da_t *passp; 8194c06356bSdh142964 820*1b115575SJohn Danielson DTRACE_PROBE2(damap__lookup__all, char *, mapp->dam_name, 821*1b115575SJohn Danielson dam_t *, mapp); 822*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 823*1b115575SJohn Danielson if (!mapp->dam_high) { 824*1b115575SJohn Danielson *id_listp = (damap_id_list_t)NULL; 825*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 826*1b115575SJohn Danielson DTRACE_PROBE3(damap__lookup__all__nomap, char *, 827*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp, int, 0); 828*1b115575SJohn Danielson return (0); 829*1b115575SJohn Danielson } 8304c06356bSdh142964 bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP); 8314c06356bSdh142964 bitset_init(bsp); 8324c06356bSdh142964 bitset_resize(bsp, mapsz); 8334c06356bSdh142964 bitset_copy(&mapp->dam_active_set, bsp); 8344c06356bSdh142964 for (n_ids = 0, i = 1; i < mapsz; i++) { 8354c06356bSdh142964 if (bitset_in_set(bsp, i)) { 8364c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, i); 8374c06356bSdh142964 ASSERT(passp); 8384c06356bSdh142964 if (passp) { 839*1b115575SJohn Danielson addrp = damap_id2addr(damapp, i); 840*1b115575SJohn Danielson DTRACE_PROBE3(damap__lookup__all__item, char *, 841*1b115575SJohn Danielson mapp->dam_name, char *, addrp, dam_t *, 842*1b115575SJohn Danielson mapp); 8434c06356bSdh142964 passp->da_ref++; 8444c06356bSdh142964 n_ids++; 8454c06356bSdh142964 } 8464c06356bSdh142964 } 8474c06356bSdh142964 } 8484c06356bSdh142964 if (n_ids) { 8494c06356bSdh142964 *id_listp = (damap_id_list_t)bsp; 850*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8514c06356bSdh142964 return (n_ids); 8524c06356bSdh142964 } else { 8534c06356bSdh142964 *id_listp = (damap_id_list_t)NULL; 8544c06356bSdh142964 bitset_fini(bsp); 8554c06356bSdh142964 kmem_free(bsp, sizeof (*bsp)); 856*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8574c06356bSdh142964 return (0); 8584c06356bSdh142964 } 8594c06356bSdh142964 } 8604c06356bSdh142964 8614c06356bSdh142964 /* 8624c06356bSdh142964 * Release the address list returned by damap_lookup_all() 8634c06356bSdh142964 * 8644c06356bSdh142964 * mapp: address map handle 8654c06356bSdh142964 * id_list: list of address IDs returned in damap_lookup_all() 8664c06356bSdh142964 */ 8674c06356bSdh142964 void 8684c06356bSdh142964 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list) 8694c06356bSdh142964 { 8704c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 8714c06356bSdh142964 int i; 8724c06356bSdh142964 8734c06356bSdh142964 if (id_list == NULL) 8744c06356bSdh142964 return; 8754c06356bSdh142964 876*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 8774c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 8784c06356bSdh142964 if (bitset_in_set((bitset_t *)id_list, i)) 879*1b115575SJohn Danielson (void) dam_addr_release(mapp, i); 8804c06356bSdh142964 } 881*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8824c06356bSdh142964 bitset_fini((bitset_t *)id_list); 8834c06356bSdh142964 kmem_free((void *)id_list, sizeof (bitset_t)); 8844c06356bSdh142964 } 8854c06356bSdh142964 8864c06356bSdh142964 /* 887*1b115575SJohn Danielson * activate an address that has passed the stabilization interval 8884c06356bSdh142964 */ 8894c06356bSdh142964 static void 890*1b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid) 8914c06356bSdh142964 { 8924c06356bSdh142964 dam_da_t *passp; 893*1b115575SJohn Danielson int config_rv; 8944c06356bSdh142964 char *addrstr; 8954c06356bSdh142964 896*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 897*1b115575SJohn Danielson bitset_add(&mapp->dam_active_set, addrid); 898*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, addrid); 8994c06356bSdh142964 ASSERT(passp); 900*1b115575SJohn Danielson 9014c06356bSdh142964 /* 9024c06356bSdh142964 * copy the reported nvlist and provider private data 9034c06356bSdh142964 */ 904*1b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 905*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__activate__start, char *, mapp->dam_name, 906*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 9074c06356bSdh142964 passp->da_nvl = passp->da_nvl_rpt; 9084c06356bSdh142964 passp->da_ppriv = passp->da_ppriv_rpt; 9094c06356bSdh142964 passp->da_ppriv_rpt = NULL; 9104c06356bSdh142964 passp->da_nvl_rpt = NULL; 9114c06356bSdh142964 passp->da_last_stable = gethrtime(); 9124c06356bSdh142964 passp->da_stable_cnt++; 913*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 914*1b115575SJohn Danielson if (mapp->dam_activate_cb) { 915*1b115575SJohn Danielson (*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr, 916*1b115575SJohn Danielson addrid, &passp->da_ppriv_rpt); 9174c06356bSdh142964 } 9184c06356bSdh142964 9194c06356bSdh142964 /* 920*1b115575SJohn Danielson * call the address-specific configuration action as part of 921*1b115575SJohn Danielson * activation. 9224c06356bSdh142964 */ 923*1b115575SJohn Danielson config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp, 924*1b115575SJohn Danielson addrid); 925*1b115575SJohn Danielson if (config_rv != DAM_SUCCESS) { 926*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 927*1b115575SJohn Danielson passp->da_flags |= DA_FAILED_CONFIG; 928*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 929*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__activate__config__failure, 930*1b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp); 9314c06356bSdh142964 } 932*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__activate__end, char *, mapp->dam_name, 933*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 9344c06356bSdh142964 } 9354c06356bSdh142964 9364c06356bSdh142964 /* 937*1b115575SJohn Danielson * deactivate a previously stable address 9384c06356bSdh142964 */ 9394c06356bSdh142964 static void 940*1b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid) 9414c06356bSdh142964 { 9424c06356bSdh142964 dam_da_t *passp; 943*1b115575SJohn Danielson char *addrstr; 9444c06356bSdh142964 945*1b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 946*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__deactivate__start, char *, mapp->dam_name, 947*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 948*1b115575SJohn Danielson 949*1b115575SJohn Danielson /* 950*1b115575SJohn Danielson * call the unconfiguration callback 951*1b115575SJohn Danielson */ 952*1b115575SJohn Danielson (*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid); 953*1b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, addrid); 954*1b115575SJohn Danielson ASSERT(passp); 955*1b115575SJohn Danielson if (mapp->dam_deactivate_cb) 956*1b115575SJohn Danielson (*mapp->dam_deactivate_cb)(mapp->dam_activate_arg, 957*1b115575SJohn Danielson ddi_strid_id2str(mapp->dam_addr_hash, addrid), 958*1b115575SJohn Danielson addrid, passp->da_ppriv); 959*1b115575SJohn Danielson 960*1b115575SJohn Danielson /* 961*1b115575SJohn Danielson * clear the active bit and free the backing info for 962*1b115575SJohn Danielson * this address 963*1b115575SJohn Danielson */ 964*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 965*1b115575SJohn Danielson bitset_del(&mapp->dam_active_set, addrid); 966*1b115575SJohn Danielson passp->da_ppriv = NULL; 967*1b115575SJohn Danielson if (passp->da_nvl) 968*1b115575SJohn Danielson nvlist_free(passp->da_nvl); 969*1b115575SJohn Danielson passp->da_nvl = NULL; 970*1b115575SJohn Danielson passp->da_ppriv_rpt = NULL; 971*1b115575SJohn Danielson if (passp->da_nvl_rpt) 972*1b115575SJohn Danielson nvlist_free(passp->da_nvl_rpt); 973*1b115575SJohn Danielson passp->da_nvl_rpt = NULL; 974*1b115575SJohn Danielson 975*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__deactivate__end, char *, mapp->dam_name, 976*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 977*1b115575SJohn Danielson 978*1b115575SJohn Danielson (void) dam_addr_release(mapp, addrid); 979*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 980*1b115575SJohn Danielson } 981*1b115575SJohn Danielson 982*1b115575SJohn Danielson /* 983*1b115575SJohn Danielson * taskq callback for multi-thread activation 984*1b115575SJohn Danielson */ 985*1b115575SJohn Danielson static void 986*1b115575SJohn Danielson dam_tq_config(void *arg) 987*1b115575SJohn Danielson { 988*1b115575SJohn Danielson cfg_tqd_t *tqd = (cfg_tqd_t *)arg; 989*1b115575SJohn Danielson 990*1b115575SJohn Danielson dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id); 991*1b115575SJohn Danielson kmem_free(tqd, sizeof (*tqd)); 992*1b115575SJohn Danielson } 993*1b115575SJohn Danielson 994*1b115575SJohn Danielson /* 995*1b115575SJohn Danielson * taskq callback for multi-thread deactivation 996*1b115575SJohn Danielson */ 997*1b115575SJohn Danielson static void 998*1b115575SJohn Danielson dam_tq_unconfig(void *arg) 999*1b115575SJohn Danielson { 1000*1b115575SJohn Danielson cfg_tqd_t *tqd = (cfg_tqd_t *)arg; 1001*1b115575SJohn Danielson 1002*1b115575SJohn Danielson dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id); 1003*1b115575SJohn Danielson kmem_free(tqd, sizeof (*tqd)); 1004*1b115575SJohn Danielson } 1005*1b115575SJohn Danielson 1006*1b115575SJohn Danielson /* 1007*1b115575SJohn Danielson * Activate a set of stabilized addresses 1008*1b115575SJohn Danielson */ 1009*1b115575SJohn Danielson static void 1010*1b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate) 1011*1b115575SJohn Danielson { 1012*1b115575SJohn Danielson 1013*1b115575SJohn Danielson int i, nset; 1014*1b115575SJohn Danielson taskq_t *tqp = NULL; 1015*1b115575SJohn Danielson cfg_tqd_t *tqd = NULL; 1016*1b115575SJohn Danielson char tqn[TASKQ_NAMELEN]; 1017*1b115575SJohn Danielson extern pri_t maxclsyspri; 1018*1b115575SJohn Danielson 1019*1b115575SJohn Danielson if (mapp->dam_options & DAMAP_MTCONFIG) { 1020*1b115575SJohn Danielson /* 1021*1b115575SJohn Danielson * calculate the # of taskq threads to create 1022*1b115575SJohn Danielson */ 1023*1b115575SJohn Danielson for (i = 1, nset = 0; i < mapp->dam_high; i++) 1024*1b115575SJohn Danielson if (bitset_in_set(activate, i)) 1025*1b115575SJohn Danielson nset++; 1026*1b115575SJohn Danielson ASSERT(nset); 1027*1b115575SJohn Danielson (void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name); 1028*1b115575SJohn Danielson tqp = taskq_create(tqn, nset, maxclsyspri, 1, 1029*1b115575SJohn Danielson INT_MAX, TASKQ_PREPOPULATE); 1030*1b115575SJohn Danielson } 1031*1b115575SJohn Danielson for (i = 1; i < mapp->dam_high; i++) { 1032*1b115575SJohn Danielson if (bitset_in_set(activate, i)) { 1033*1b115575SJohn Danielson if (!tqp) 1034*1b115575SJohn Danielson dam_addr_activate(mapp, i); 1035*1b115575SJohn Danielson else { 1036*1b115575SJohn Danielson /* 1037*1b115575SJohn Danielson * multi-threaded activation 1038*1b115575SJohn Danielson */ 1039*1b115575SJohn Danielson tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP); 1040*1b115575SJohn Danielson tqd->tqd_mapp = mapp; 1041*1b115575SJohn Danielson tqd->tqd_id = i; 1042*1b115575SJohn Danielson (void) taskq_dispatch(tqp, dam_tq_config, 1043*1b115575SJohn Danielson tqd, KM_SLEEP); 1044*1b115575SJohn Danielson } 1045*1b115575SJohn Danielson } 1046*1b115575SJohn Danielson } 1047*1b115575SJohn Danielson if (tqp) { 1048*1b115575SJohn Danielson taskq_wait(tqp); 1049*1b115575SJohn Danielson taskq_destroy(tqp); 1050*1b115575SJohn Danielson } 1051*1b115575SJohn Danielson } 1052*1b115575SJohn Danielson 1053*1b115575SJohn Danielson /* 1054*1b115575SJohn Danielson * Deactivate a set of stabilized addresses 1055*1b115575SJohn Danielson */ 1056*1b115575SJohn Danielson static void 1057*1b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate) 1058*1b115575SJohn Danielson { 1059*1b115575SJohn Danielson int i, nset; 1060*1b115575SJohn Danielson taskq_t *tqp = NULL; 1061*1b115575SJohn Danielson cfg_tqd_t *tqd = NULL; 1062*1b115575SJohn Danielson char tqn[TASKQ_NAMELEN]; 1063*1b115575SJohn Danielson 1064*1b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__deactivate, char *, mapp->dam_name, 1065*1b115575SJohn Danielson dam_t *, mapp); 1066*1b115575SJohn Danielson 1067*1b115575SJohn Danielson if (mapp->dam_options & DAMAP_MTCONFIG) { 1068*1b115575SJohn Danielson /* 1069*1b115575SJohn Danielson * compute the # of taskq threads to dispatch 1070*1b115575SJohn Danielson */ 1071*1b115575SJohn Danielson for (i = 1, nset = 0; i < mapp->dam_high; i++) 1072*1b115575SJohn Danielson if (bitset_in_set(deactivate, i)) 1073*1b115575SJohn Danielson nset++; 1074*1b115575SJohn Danielson (void) snprintf(tqn, sizeof (tqn), "deactv-%s", 1075*1b115575SJohn Danielson mapp->dam_name); 1076*1b115575SJohn Danielson tqp = taskq_create(tqn, nset, maxclsyspri, 1, 1077*1b115575SJohn Danielson INT_MAX, TASKQ_PREPOPULATE); 1078*1b115575SJohn Danielson } 1079*1b115575SJohn Danielson for (i = 1; i < mapp->dam_high; i++) { 1080*1b115575SJohn Danielson if (bitset_in_set(deactivate, i)) { 1081*1b115575SJohn Danielson if (!tqp) { 1082*1b115575SJohn Danielson dam_addr_deactivate(mapp, i); 1083*1b115575SJohn Danielson } else { 1084*1b115575SJohn Danielson tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP); 1085*1b115575SJohn Danielson tqd->tqd_mapp = mapp; 1086*1b115575SJohn Danielson tqd->tqd_id = i; 1087*1b115575SJohn Danielson (void) taskq_dispatch(tqp, 1088*1b115575SJohn Danielson dam_tq_unconfig, tqd, KM_SLEEP); 1089*1b115575SJohn Danielson } 1090*1b115575SJohn Danielson } 1091*1b115575SJohn Danielson } 1092*1b115575SJohn Danielson 1093*1b115575SJohn Danielson if (tqp) { 1094*1b115575SJohn Danielson taskq_wait(tqp); 1095*1b115575SJohn Danielson taskq_destroy(tqp); 1096*1b115575SJohn Danielson } 1097*1b115575SJohn Danielson } 1098*1b115575SJohn Danielson 1099*1b115575SJohn Danielson /* 1100*1b115575SJohn Danielson * Release a previously activated address 1101*1b115575SJohn Danielson */ 1102*1b115575SJohn Danielson static void 1103*1b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid) 1104*1b115575SJohn Danielson { 1105*1b115575SJohn Danielson dam_da_t *passp; 1106*1b115575SJohn Danielson char *addrstr; 1107*1b115575SJohn Danielson 1108*1b115575SJohn Danielson 1109*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 11104c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 11114c06356bSdh142964 ASSERT(passp); 11124c06356bSdh142964 1113*1b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 1114*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__release, char *, mapp->dam_name, 1115*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 11164c06356bSdh142964 11174c06356bSdh142964 /* 1118*1b115575SJohn Danielson * defer releasing the address until outstanding references 1119*1b115575SJohn Danielson * are released 11204c06356bSdh142964 */ 1121*1b115575SJohn Danielson if (passp->da_ref > 1) { 1122*1b115575SJohn Danielson DTRACE_PROBE4(damap__addr__release__outstanding__refs, 1123*1b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp, 1124*1b115575SJohn Danielson int, passp->da_ref); 11254c06356bSdh142964 return; 11264c06356bSdh142964 } 1127*1b115575SJohn Danielson 1128*1b115575SJohn Danielson /* 1129*1b115575SJohn Danielson * allow pending reports to stabilize 1130*1b115575SJohn Danielson */ 1131*1b115575SJohn Danielson if (DAM_IN_REPORT(mapp, addrid)) { 1132*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__release__report__pending, 1133*1b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp); 1134*1b115575SJohn Danielson return; 1135*1b115575SJohn Danielson } 1136*1b115575SJohn Danielson 11374c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, addrid); 11384c06356bSdh142964 ddi_soft_state_free(mapp->dam_da, addrid); 11394c06356bSdh142964 } 11404c06356bSdh142964 11414c06356bSdh142964 /* 11424c06356bSdh142964 * process stabilized address reports 11434c06356bSdh142964 */ 11444c06356bSdh142964 static void 1145*1b115575SJohn Danielson dam_stabilize_map(void *arg) 11464c06356bSdh142964 { 11474c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 11484c06356bSdh142964 bitset_t delta; 11494c06356bSdh142964 bitset_t cfg; 11504c06356bSdh142964 bitset_t uncfg; 11514c06356bSdh142964 int has_cfg, has_uncfg; 1152*1b115575SJohn Danielson uint32_t i, n_active; 1153*1b115575SJohn Danielson 1154*1b115575SJohn Danielson DTRACE_PROBE2(damap__stabilize__map, char *, mapp->dam_name, 1155*1b115575SJohn Danielson dam_t *, mapp); 11564c06356bSdh142964 11574c06356bSdh142964 bitset_init(&delta); 11584c06356bSdh142964 bitset_resize(&delta, mapp->dam_size); 11594c06356bSdh142964 bitset_init(&cfg); 11604c06356bSdh142964 bitset_resize(&cfg, mapp->dam_size); 11614c06356bSdh142964 bitset_init(&uncfg); 11624c06356bSdh142964 bitset_resize(&uncfg, mapp->dam_size); 11634c06356bSdh142964 1164*1b115575SJohn Danielson /* 1165*1b115575SJohn Danielson * determine which addresses have changed during 1166*1b115575SJohn Danielson * this stabilization cycle 1167*1b115575SJohn Danielson */ 1168*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 1169*1b115575SJohn Danielson ASSERT(mapp->dam_flags & DAM_SPEND); 11704c06356bSdh142964 if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set, 11714c06356bSdh142964 &delta)) { 1172*1b115575SJohn Danielson /* 1173*1b115575SJohn Danielson * no difference 1174*1b115575SJohn Danielson */ 11754c06356bSdh142964 bitset_zero(&mapp->dam_stable_set); 1176*1b115575SJohn Danielson mapp->dam_flags &= ~DAM_SPEND; 1177*1b115575SJohn Danielson cv_signal(&mapp->dam_cv); 1178*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 11794c06356bSdh142964 bitset_fini(&uncfg); 11804c06356bSdh142964 bitset_fini(&cfg); 11814c06356bSdh142964 bitset_fini(&delta); 1182*1b115575SJohn Danielson DTRACE_PROBE2(damap__stabilize__map__nochange, char *, 1183*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 11844c06356bSdh142964 return; 11854c06356bSdh142964 } 1186*1b115575SJohn Danielson 1187*1b115575SJohn Danielson /* 1188*1b115575SJohn Danielson * compute the sets of addresses to be activated and deactivated 1189*1b115575SJohn Danielson */ 11904c06356bSdh142964 has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg); 11914c06356bSdh142964 has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg); 1192*1b115575SJohn Danielson 1193*1b115575SJohn Danielson /* 1194*1b115575SJohn Danielson * drop map lock while invoking callouts 1195*1b115575SJohn Danielson */ 1196*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 1197*1b115575SJohn Danielson 1198*1b115575SJohn Danielson /* 1199*1b115575SJohn Danielson * activate all newly stable addresss 1200*1b115575SJohn Danielson */ 1201*1b115575SJohn Danielson if (has_cfg) 12024c06356bSdh142964 dam_addrset_activate(mapp, &cfg); 1203*1b115575SJohn Danielson 1204*1b115575SJohn Danielson /* 1205*1b115575SJohn Danielson * deactivate addresss which are no longer in the map 1206*1b115575SJohn Danielson */ 1207*1b115575SJohn Danielson if (has_uncfg) 1208*1b115575SJohn Danielson dam_addrset_deactivate(mapp, &uncfg); 1209*1b115575SJohn Danielson 1210*1b115575SJohn Danielson 1211*1b115575SJohn Danielson /* 1212*1b115575SJohn Danielson * timestamp the last stable time and increment the kstat keeping 1213*1b115575SJohn Danielson * the # of of stable cycles for the map 1214*1b115575SJohn Danielson */ 1215*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 12164c06356bSdh142964 bitset_zero(&mapp->dam_stable_set); 12174c06356bSdh142964 mapp->dam_last_stable = gethrtime(); 12184c06356bSdh142964 mapp->dam_stable_cnt++; 1219*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_cycles); 1220*1b115575SJohn Danielson 1221*1b115575SJohn Danielson /* 1222*1b115575SJohn Danielson * determine the number of stable addresses 1223*1b115575SJohn Danielson * and update the n_active kstat for this map 1224*1b115575SJohn Danielson */ 1225*1b115575SJohn Danielson for (i = 1, n_active = 0; i < mapp->dam_high; i++) 1226*1b115575SJohn Danielson if (bitset_in_set(&mapp->dam_active_set, i)) 1227*1b115575SJohn Danielson n_active++; 1228*1b115575SJohn Danielson DAM_SET_STAT(mapp, dam_active, n_active); 1229*1b115575SJohn Danielson 1230*1b115575SJohn Danielson DTRACE_PROBE3(damap__map__stable__end, char *, mapp->dam_name, 1231*1b115575SJohn Danielson dam_t *, mapp, int, n_active); 1232*1b115575SJohn Danielson 1233*1b115575SJohn Danielson mapp->dam_flags &= ~DAM_SPEND; 1234*1b115575SJohn Danielson cv_signal(&mapp->dam_cv); 1235*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 12364c06356bSdh142964 bitset_fini(&uncfg); 12374c06356bSdh142964 bitset_fini(&cfg); 12384c06356bSdh142964 bitset_fini(&delta); 12394c06356bSdh142964 } 12404c06356bSdh142964 12414c06356bSdh142964 /* 12424c06356bSdh142964 * per-address stabilization timeout 12434c06356bSdh142964 */ 12444c06356bSdh142964 static void 12454c06356bSdh142964 dam_addr_stable_cb(void *arg) 12464c06356bSdh142964 { 12474c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 12484c06356bSdh142964 int i; 12494c06356bSdh142964 dam_da_t *passp; 12504c06356bSdh142964 int spend = 0; 12514c06356bSdh142964 int tpend = 0; 12524c06356bSdh142964 int64_t next_tmov = mapp->dam_stabletmo; 12534c06356bSdh142964 int64_t tmo_delta; 1254d3d50737SRafael Vanoni int64_t ts = ddi_get_lbolt64(); 12554c06356bSdh142964 1256*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 12574c06356bSdh142964 if (mapp->dam_tid == 0) { 1258*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__cancelled, char *, 1259*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 1260*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 12614c06356bSdh142964 return; 12624c06356bSdh142964 } 12634c06356bSdh142964 mapp->dam_tid = 0; 1264*1b115575SJohn Danielson 12654c06356bSdh142964 /* 12664c06356bSdh142964 * If still under stabilization, reschedule timeout, 1267*1b115575SJohn Danielson * otherwise dispatch the task to activate and deactivate the 1268*1b115575SJohn Danielson * new stable address 12694c06356bSdh142964 */ 12704c06356bSdh142964 if (mapp->dam_flags & DAM_SPEND) { 1271*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_overrun); 12724c06356bSdh142964 mapp->dam_stable_overrun++; 12734c06356bSdh142964 dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb); 1274*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__overrun, char *, 1275*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 1276*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 12774c06356bSdh142964 return; 12784c06356bSdh142964 } 12794c06356bSdh142964 1280*1b115575SJohn Danielson DAM_SET_STAT(mapp, dam_overrun, 0); 1281*1b115575SJohn Danielson mapp->dam_stable_overrun = 0; 1282*1b115575SJohn Danielson 1283*1b115575SJohn Danielson /* 1284*1b115575SJohn Danielson * copy the current active set to the stable map 1285*1b115575SJohn Danielson * for each address being reported, decrement its 1286*1b115575SJohn Danielson * stabilize deadline, and if stable, add or remove the 1287*1b115575SJohn Danielson * address from the stable set 1288*1b115575SJohn Danielson */ 12894c06356bSdh142964 bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set); 12904c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 12914c06356bSdh142964 if (!bitset_in_set(&mapp->dam_report_set, i)) 12924c06356bSdh142964 continue; 12934c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, i); 12944c06356bSdh142964 ASSERT(passp); 12954c06356bSdh142964 12964c06356bSdh142964 /* report has stabilized */ 12974c06356bSdh142964 if (passp->da_deadline <= ts) { 12984c06356bSdh142964 bitset_del(&mapp->dam_report_set, i); 1299*1b115575SJohn Danielson if (passp->da_flags & DA_RELE) 13004c06356bSdh142964 bitset_del(&mapp->dam_stable_set, i); 1301*1b115575SJohn Danielson else 13024c06356bSdh142964 bitset_add(&mapp->dam_stable_set, i); 13034c06356bSdh142964 spend++; 13044c06356bSdh142964 continue; 13054c06356bSdh142964 } 13064c06356bSdh142964 13074c06356bSdh142964 /* 1308*1b115575SJohn Danielson * not stabilized, determine next map timeout 13094c06356bSdh142964 */ 13104c06356bSdh142964 tpend++; 13114c06356bSdh142964 tmo_delta = passp->da_deadline - ts; 13124c06356bSdh142964 if (tmo_delta < next_tmov) 13134c06356bSdh142964 next_tmov = tmo_delta; 13144c06356bSdh142964 } 13154c06356bSdh142964 13164c06356bSdh142964 /* 1317*1b115575SJohn Danielson * schedule system_taskq activation of stabilized reports 13184c06356bSdh142964 */ 13194c06356bSdh142964 if (spend) { 1320*1b115575SJohn Danielson if (taskq_dispatch(system_taskq, dam_stabilize_map, 1321*1b115575SJohn Danielson mapp, TQ_NOSLEEP)) { 1322*1b115575SJohn Danielson mapp->dam_flags |= DAM_SPEND; 1323*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__start, char *, 1324*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 1325*1b115575SJohn Danielson } else { 13264c06356bSdh142964 tpend++; 13274c06356bSdh142964 } 1328*1b115575SJohn Danielson } 13294c06356bSdh142964 13304c06356bSdh142964 /* 1331*1b115575SJohn Danielson * reschedule the stabilization timer if there are reports 1332*1b115575SJohn Danielson * still pending 13334c06356bSdh142964 */ 13344c06356bSdh142964 if (tpend) 13354c06356bSdh142964 dam_sched_tmo(mapp, (clock_t)next_tmov, dam_addr_stable_cb); 1336*1b115575SJohn Danielson 1337*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 13384c06356bSdh142964 } 13394c06356bSdh142964 13404c06356bSdh142964 /* 1341*1b115575SJohn Danielson * fullset stabilization timeout callback 13424c06356bSdh142964 */ 13434c06356bSdh142964 static void 1344*1b115575SJohn Danielson dam_addrset_stable_cb(void *arg) 13454c06356bSdh142964 { 13464c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 13474c06356bSdh142964 1348*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 13494c06356bSdh142964 if (mapp->dam_tid == 0) { 1350*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 1351*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__cancelled, 1352*1b115575SJohn Danielson char *, mapp->dam_name, dam_t *, mapp); 13534c06356bSdh142964 return; 13544c06356bSdh142964 } 13554c06356bSdh142964 mapp->dam_tid = 0; 13564c06356bSdh142964 13574c06356bSdh142964 /* 1358*1b115575SJohn Danielson * If map still underoing stabilization reschedule timeout, 1359*1b115575SJohn Danielson * else dispatch the task to configure the new stable set of 1360*1b115575SJohn Danielson * addresses. 13614c06356bSdh142964 */ 1362*1b115575SJohn Danielson if ((mapp->dam_flags & DAM_SPEND) || (taskq_dispatch(system_taskq, 1363*1b115575SJohn Danielson dam_stabilize_map, mapp, TQ_NOSLEEP) == NULL)) { 1364*1b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_overrun); 13654c06356bSdh142964 mapp->dam_stable_overrun++; 1366*1b115575SJohn Danielson dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb); 1367*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__overrun, char *, 1368*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 1369*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 1370*1b115575SJohn Danielson return; 1371*1b115575SJohn Danielson } 1372*1b115575SJohn Danielson 1373*1b115575SJohn Danielson DAM_SET_STAT(mapp, dam_overrun, 0); 1374*1b115575SJohn Danielson mapp->dam_stable_overrun = 0; 13754c06356bSdh142964 bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set); 13764c06356bSdh142964 bitset_zero(&mapp->dam_report_set); 1377*1b115575SJohn Danielson mapp->dam_flags |= DAM_SPEND; 1378*1b115575SJohn Danielson mapp->dam_flags &= ~DAM_SETADD; 1379*1b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__start, char *, 1380*1b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 1381*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 13824c06356bSdh142964 } 13834c06356bSdh142964 13844c06356bSdh142964 /* 1385*1b115575SJohn Danielson * schedule map timeout 'tmo_ms' ticks 1386*1b115575SJohn Danielson * if map timer is currently running, cancel if tmo_ms == 0 13874c06356bSdh142964 */ 13884c06356bSdh142964 static void 13894c06356bSdh142964 dam_sched_tmo(dam_t *mapp, clock_t tmo_ms, void (*tmo_cb)()) 13904c06356bSdh142964 { 13914c06356bSdh142964 timeout_id_t tid; 13924c06356bSdh142964 1393*1b115575SJohn Danielson DTRACE_PROBE3(damap__sched__tmo, char *, mapp->dam_name, dam_t *, mapp, 1394*1b115575SJohn Danielson clock_t, tmo_ms); 13954c06356bSdh142964 1396*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 1397*1b115575SJohn Danielson if ((tid = mapp->dam_tid) != 0) { 1398*1b115575SJohn Danielson if (tmo_ms == 0) { 1399*1b115575SJohn Danielson mapp->dam_tid = 0; 1400*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 1401*1b115575SJohn Danielson (void) untimeout(tid); 1402*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 1403*1b115575SJohn Danielson } 1404*1b115575SJohn Danielson } else { 14054c06356bSdh142964 if (tmo_cb && (tmo_ms != 0)) 14064c06356bSdh142964 mapp->dam_tid = timeout(tmo_cb, mapp, tmo_ms); 14074c06356bSdh142964 } 1408*1b115575SJohn Danielson } 14094c06356bSdh142964 14104c06356bSdh142964 /* 1411*1b115575SJohn Danielson * report addition or removal of an address 14124c06356bSdh142964 */ 14134c06356bSdh142964 static void 1414*1b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type) 14154c06356bSdh142964 { 1416*1b115575SJohn Danielson char *addrstr = damap_id2addr((damap_t *)mapp, addrid); 1417*1b115575SJohn Danielson 1418*1b115575SJohn Danielson DTRACE_PROBE4(damap__addr__report, char *, mapp->dam_name, 1419*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp, int, rpt_type); 1420*1b115575SJohn Danielson 1421*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 14224c06356bSdh142964 ASSERT(!DAM_IN_REPORT(mapp, addrid)); 14234c06356bSdh142964 passp->da_last_report = gethrtime(); 14244c06356bSdh142964 mapp->dam_last_update = gethrtime(); 14254c06356bSdh142964 passp->da_report_cnt++; 1426d3d50737SRafael Vanoni passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stabletmo; 1427*1b115575SJohn Danielson if (rpt_type == RPT_ADDR_DEL) 14284c06356bSdh142964 passp->da_flags |= DA_RELE; 1429*1b115575SJohn Danielson else if (rpt_type == RPT_ADDR_ADD) 14304c06356bSdh142964 passp->da_flags &= ~DA_RELE; 14314c06356bSdh142964 bitset_add(&mapp->dam_report_set, addrid); 14324c06356bSdh142964 dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb); 14334c06356bSdh142964 } 14344c06356bSdh142964 14354c06356bSdh142964 /* 14364c06356bSdh142964 * release an address report 14374c06356bSdh142964 */ 14384c06356bSdh142964 static void 1439*1b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid) 14404c06356bSdh142964 { 14414c06356bSdh142964 dam_da_t *passp; 1442*1b115575SJohn Danielson char *addrstr = damap_id2addr((damap_t *)mapp, addrid); 14434c06356bSdh142964 1444*1b115575SJohn Danielson DTRACE_PROBE3(damap__addr__report__release, char *, mapp->dam_name, 1445*1b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 1446*1b115575SJohn Danielson 1447*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 14484c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 14494c06356bSdh142964 ASSERT(passp); 1450*1b115575SJohn Danielson /* 1451*1b115575SJohn Danielson * clear the report bit 1452*1b115575SJohn Danielson * if the address has a registered deactivation handler and 1453*1b115575SJohn Danielson * the address has not stabilized, deactivate the address 1454*1b115575SJohn Danielson */ 1455*1b115575SJohn Danielson bitset_del(&mapp->dam_report_set, addrid); 1456*1b115575SJohn Danielson if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb) { 1457*1b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 1458*1b115575SJohn Danielson (*mapp->dam_deactivate_cb)(mapp->dam_activate_arg, 1459*1b115575SJohn Danielson ddi_strid_id2str(mapp->dam_addr_hash, addrid), 1460*1b115575SJohn Danielson addrid, passp->da_ppriv_rpt); 1461*1b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 1462*1b115575SJohn Danielson } 14634c06356bSdh142964 passp->da_ppriv_rpt = NULL; 14644c06356bSdh142964 if (passp->da_nvl_rpt) 14654c06356bSdh142964 nvlist_free(passp->da_nvl_rpt); 14664c06356bSdh142964 } 14674c06356bSdh142964 14684c06356bSdh142964 /* 14694c06356bSdh142964 * return the map ID of an address 14704c06356bSdh142964 */ 14714c06356bSdh142964 static id_t 14724c06356bSdh142964 dam_get_addrid(dam_t *mapp, char *address) 14734c06356bSdh142964 { 14744c06356bSdh142964 damap_id_t addrid; 14754c06356bSdh142964 dam_da_t *passp; 14764c06356bSdh142964 1477*1b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 14784c06356bSdh142964 if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) { 1479*1b115575SJohn Danielson if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash, 14804c06356bSdh142964 address)) == (damap_id_t)0) { 14814c06356bSdh142964 return (0); 14824c06356bSdh142964 } 14834c06356bSdh142964 if (ddi_soft_state_zalloc(mapp->dam_da, addrid) != 14844c06356bSdh142964 DDI_SUCCESS) { 14854c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, addrid); 14864c06356bSdh142964 return (0); 14874c06356bSdh142964 } 1488*1b115575SJohn Danielson 14894c06356bSdh142964 if (addrid >= mapp->dam_high) 14904c06356bSdh142964 mapp->dam_high = addrid + 1; 1491*1b115575SJohn Danielson 1492*1b115575SJohn Danielson /* 1493*1b115575SJohn Danielson * expand bitmaps if ID has outgrown old map size 1494*1b115575SJohn Danielson */ 1495*1b115575SJohn Danielson if (mapp->dam_high > mapp->dam_size) { 1496*1b115575SJohn Danielson mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP; 1497*1b115575SJohn Danielson bitset_resize(&mapp->dam_active_set, mapp->dam_size); 1498*1b115575SJohn Danielson bitset_resize(&mapp->dam_stable_set, mapp->dam_size); 1499*1b115575SJohn Danielson bitset_resize(&mapp->dam_report_set, mapp->dam_size); 15004c06356bSdh142964 } 1501*1b115575SJohn Danielson 15024c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 1503*1b115575SJohn Danielson passp->da_ref = 1; 1504*1b115575SJohn Danielson passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash, 1505*1b115575SJohn Danielson addrid); /* for mdb */ 1506*1b115575SJohn Danielson } 15074c06356bSdh142964 return (addrid); 15084c06356bSdh142964 } 15094c06356bSdh142964 15104c06356bSdh142964 /* 15114c06356bSdh142964 * create and install map statistics 15124c06356bSdh142964 */ 15134c06356bSdh142964 static int 15144c06356bSdh142964 dam_kstat_create(dam_t *mapp) 15154c06356bSdh142964 { 15164c06356bSdh142964 kstat_t *mapsp; 15174c06356bSdh142964 struct dam_kstats *statsp; 15184c06356bSdh142964 15194c06356bSdh142964 mapsp = kstat_create("dam", 0, mapp->dam_name, "damap", 15204c06356bSdh142964 KSTAT_TYPE_NAMED, 15214c06356bSdh142964 sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0); 1522*1b115575SJohn Danielson 1523*1b115575SJohn Danielson if (mapsp == NULL) 15244c06356bSdh142964 return (DDI_FAILURE); 15254c06356bSdh142964 15264c06356bSdh142964 statsp = (struct dam_kstats *)mapsp->ks_data; 1527*1b115575SJohn Danielson kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32); 1528*1b115575SJohn Danielson kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32); 1529*1b115575SJohn Danielson kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32); 1530*1b115575SJohn Danielson kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32); 15314c06356bSdh142964 kstat_install(mapsp); 15324c06356bSdh142964 mapp->dam_kstatsp = mapsp; 15334c06356bSdh142964 return (DDI_SUCCESS); 15344c06356bSdh142964 } 1535