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 /* 239aed1621SDavid Hollister * Copyright 2010 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 521b115575SJohn Danielson extern taskq_t *system_taskq; 531b115575SJohn Danielson 544c06356bSdh142964 static void dam_addrset_activate(dam_t *, bitset_t *); 551b115575SJohn Danielson static void dam_addrset_deactivate(dam_t *, bitset_t *); 561b115575SJohn Danielson static void dam_stabilize_map(void *); 574c06356bSdh142964 static void dam_addr_stable_cb(void *); 581b115575SJohn Danielson static void dam_addrset_stable_cb(void *); 594c06356bSdh142964 static void dam_sched_tmo(dam_t *, clock_t, void (*tmo_cb)()); 601b115575SJohn Danielson static void dam_addr_report(dam_t *, dam_da_t *, id_t, int); 611b115575SJohn Danielson static void dam_addr_release(dam_t *, id_t); 621b115575SJohn Danielson static void dam_addr_report_release(dam_t *, id_t); 631b115575SJohn Danielson static void dam_addr_deactivate(dam_t *, id_t); 64d189c170SReed static void dam_deact_cleanup(dam_t *, id_t, char *, damap_deact_rsn_t); 654c06356bSdh142964 static id_t dam_get_addrid(dam_t *, char *); 664c06356bSdh142964 static int dam_kstat_create(dam_t *); 671b115575SJohn Danielson static int dam_map_alloc(dam_t *); 684c06356bSdh142964 694c06356bSdh142964 #define DAM_INCR_STAT(mapp, stat) \ 704c06356bSdh142964 if ((mapp)->dam_kstatsp) { \ 714c06356bSdh142964 struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data; \ 724c06356bSdh142964 stp->stat.value.ui32++; \ 734c06356bSdh142964 } 744c06356bSdh142964 754c06356bSdh142964 #define DAM_SET_STAT(mapp, stat, val) \ 764c06356bSdh142964 if ((mapp)->dam_kstatsp) { \ 774c06356bSdh142964 struct dam_kstats *stp = (mapp)->dam_kstatsp->ks_data; \ 784c06356bSdh142964 stp->stat.value.ui32 = (val); \ 794c06356bSdh142964 } 804c06356bSdh142964 811b115575SJohn Danielson 821b115575SJohn Danielson /* 831b115575SJohn Danielson * increase damap size by 64 entries at a time 841b115575SJohn Danielson */ 851b115575SJohn Danielson #define DAM_SIZE_BUMP 64 861b115575SJohn Danielson 8764109744SChris Horne int damap_taskq_dispatch_retry_usec = 1000; 8864109744SChris Horne 891b115575SJohn Danielson /* 901b115575SJohn Danielson * config/unconfig taskq data 911b115575SJohn Danielson */ 921b115575SJohn Danielson typedef struct { 931b115575SJohn Danielson dam_t *tqd_mapp; 941b115575SJohn Danielson id_t tqd_id; 951b115575SJohn Danielson } cfg_tqd_t; 961b115575SJohn Danielson 971b115575SJohn Danielson extern pri_t maxclsyspri; 981b115575SJohn Danielson 994c06356bSdh142964 /* 1004c06356bSdh142964 * Create new device address map 1014c06356bSdh142964 * 1021b115575SJohn Danielson * name: map name (kstat unique) 1034c06356bSdh142964 * size: max # of map entries 1041b115575SJohn Danielson * mode: style of address reports: per-address or fullset 1054c06356bSdh142964 * stable_usec: # of quiescent microseconds before report/map is stable 1064c06356bSdh142964 * 1074c06356bSdh142964 * activate_arg: address provider activation-callout private 1084c06356bSdh142964 * activate_cb: address provider activation callback handler 1094c06356bSdh142964 * deactivate_cb: address provider deactivation callback handler 1104c06356bSdh142964 * 1114c06356bSdh142964 * config_arg: configuration-callout private 1124c06356bSdh142964 * config_cb: class configuration callout 1134c06356bSdh142964 * unconfig_cb: class unconfiguration callout 1144c06356bSdh142964 * 1154c06356bSdh142964 * damapp: pointer to map handle (return) 1164c06356bSdh142964 * 1174c06356bSdh142964 * Returns: DAM_SUCCESS 1184c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 1194c06356bSdh142964 * DAM_FAILURE General failure 1204c06356bSdh142964 */ 1214c06356bSdh142964 int 1221b115575SJohn Danielson damap_create(char *name, damap_rptmode_t mode, int map_opts, 1231b115575SJohn Danielson clock_t stable_usec, void *activate_arg, damap_activate_cb_t activate_cb, 1244c06356bSdh142964 damap_deactivate_cb_t deactivate_cb, 1254c06356bSdh142964 void *config_arg, damap_configure_cb_t configure_cb, 1264c06356bSdh142964 damap_unconfig_cb_t unconfig_cb, 1274c06356bSdh142964 damap_t **damapp) 1284c06356bSdh142964 { 1294c06356bSdh142964 dam_t *mapp; 1304c06356bSdh142964 1311b115575SJohn Danielson if (configure_cb == NULL || unconfig_cb == NULL || name == NULL) 1324c06356bSdh142964 return (DAM_EINVAL); 1334c06356bSdh142964 1341b115575SJohn Danielson DTRACE_PROBE3(damap__create, char *, name, 1351b115575SJohn Danielson damap_rptmode_t, mode, clock_t, stable_usec); 1364c06356bSdh142964 1374c06356bSdh142964 mapp = kmem_zalloc(sizeof (*mapp), KM_SLEEP); 1381b115575SJohn Danielson mapp->dam_options = map_opts; 1394c06356bSdh142964 mapp->dam_stabletmo = drv_usectohz(stable_usec); 1401b115575SJohn Danielson mapp->dam_size = 0; 1411b115575SJohn Danielson mapp->dam_rptmode = mode; 1424c06356bSdh142964 mapp->dam_activate_arg = activate_arg; 1434c06356bSdh142964 mapp->dam_activate_cb = (activate_cb_t)activate_cb; 1444c06356bSdh142964 mapp->dam_deactivate_cb = (deactivate_cb_t)deactivate_cb; 1454c06356bSdh142964 mapp->dam_config_arg = config_arg; 1464c06356bSdh142964 mapp->dam_configure_cb = (configure_cb_t)configure_cb; 1474c06356bSdh142964 mapp->dam_unconfig_cb = (unconfig_cb_t)unconfig_cb; 1481b115575SJohn Danielson mapp->dam_name = i_ddi_strdup(name, KM_SLEEP); 1494c06356bSdh142964 mutex_init(&mapp->dam_lock, NULL, MUTEX_DRIVER, NULL); 1504c06356bSdh142964 cv_init(&mapp->dam_cv, NULL, CV_DRIVER, NULL); 1511b115575SJohn Danielson bitset_init(&mapp->dam_active_set); 1521b115575SJohn Danielson bitset_init(&mapp->dam_stable_set); 1531b115575SJohn Danielson bitset_init(&mapp->dam_report_set); 1544c06356bSdh142964 *damapp = (damap_t *)mapp; 1554c06356bSdh142964 return (DAM_SUCCESS); 1564c06356bSdh142964 } 1574c06356bSdh142964 1584c06356bSdh142964 /* 1591b115575SJohn Danielson * Allocate backing resources 1601b115575SJohn Danielson * 1611b115575SJohn Danielson * DAMs are lightly backed on create - major allocations occur 1621b115575SJohn Danielson * at the time a report is made to the map, and are extended on 1631b115575SJohn Danielson * a demand basis. 1641b115575SJohn Danielson */ 1651b115575SJohn Danielson static int 1661b115575SJohn Danielson dam_map_alloc(dam_t *mapp) 1671b115575SJohn Danielson { 1681b115575SJohn Danielson void *softstate_p; 1691b115575SJohn Danielson 1701b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 1711b115575SJohn Danielson if (mapp->dam_flags & DAM_DESTROYPEND) 1721b115575SJohn Danielson return (DAM_FAILURE); 1731b115575SJohn Danielson 1741b115575SJohn Danielson /* 1751b115575SJohn Danielson * dam_high > 0 signals map allocation complete 1761b115575SJohn Danielson */ 1771b115575SJohn Danielson if (mapp->dam_high) 1781b115575SJohn Danielson return (DAM_SUCCESS); 1791b115575SJohn Danielson 1801b115575SJohn Danielson mapp->dam_size = DAM_SIZE_BUMP; 1811b115575SJohn Danielson if (ddi_soft_state_init(&softstate_p, sizeof (dam_da_t), 1821b115575SJohn Danielson mapp->dam_size) != DDI_SUCCESS) 1831b115575SJohn Danielson return (DAM_FAILURE); 1841b115575SJohn Danielson 1851b115575SJohn Danielson if (ddi_strid_init(&mapp->dam_addr_hash, mapp->dam_size) != 1861b115575SJohn Danielson DDI_SUCCESS) { 1871b115575SJohn Danielson ddi_soft_state_fini(softstate_p); 1881b115575SJohn Danielson return (DAM_FAILURE); 1891b115575SJohn Danielson } 1901b115575SJohn Danielson if (dam_kstat_create(mapp) != DDI_SUCCESS) { 1911b115575SJohn Danielson ddi_soft_state_fini(softstate_p); 1921b115575SJohn Danielson ddi_strid_fini(&mapp->dam_addr_hash); 1931b115575SJohn Danielson return (DAM_FAILURE); 1941b115575SJohn Danielson } 1951b115575SJohn Danielson mapp->dam_da = softstate_p; 1961b115575SJohn Danielson mapp->dam_high = 1; 1971b115575SJohn Danielson bitset_resize(&mapp->dam_active_set, mapp->dam_size); 1981b115575SJohn Danielson bitset_resize(&mapp->dam_stable_set, mapp->dam_size); 1991b115575SJohn Danielson bitset_resize(&mapp->dam_report_set, mapp->dam_size); 2001b115575SJohn Danielson return (DAM_SUCCESS); 2011b115575SJohn Danielson } 2021b115575SJohn Danielson 2031b115575SJohn Danielson /* 2041b115575SJohn Danielson * Destroy address map 2054c06356bSdh142964 * 2064c06356bSdh142964 * damapp: address map 2074c06356bSdh142964 * 2084c06356bSdh142964 * Returns: DAM_SUCCESS 2094c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 2104c06356bSdh142964 * DAM_FAILURE General failure 2114c06356bSdh142964 */ 2124c06356bSdh142964 void 2134c06356bSdh142964 damap_destroy(damap_t *damapp) 2144c06356bSdh142964 { 2154c06356bSdh142964 int i; 2164c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 2174c06356bSdh142964 2184c06356bSdh142964 ASSERT(mapp); 2194c06356bSdh142964 2201b115575SJohn Danielson DTRACE_PROBE1(damap__destroy, char *, mapp->dam_name); 2214c06356bSdh142964 2221b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 2234c06356bSdh142964 2244c06356bSdh142964 /* 2251b115575SJohn Danielson * prevent new reports from being added to the map 2264c06356bSdh142964 */ 2271b115575SJohn Danielson mapp->dam_flags |= DAM_DESTROYPEND; 2284c06356bSdh142964 2291b115575SJohn Danielson if (mapp->dam_high) { 2301b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 2311b115575SJohn Danielson /* 2321b115575SJohn Danielson * wait for outstanding reports to stabilize and cancel 2331b115575SJohn Danielson * the timer for this map 2341b115575SJohn Danielson */ 2351b115575SJohn Danielson (void) damap_sync(damapp); 2361b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 2371b115575SJohn Danielson dam_sched_tmo(mapp, 0, NULL); 2381b115575SJohn Danielson 2391b115575SJohn Danielson /* 2401b115575SJohn Danielson * map is at full stop 2411b115575SJohn Danielson * release the contents of the map, invoking the 2421b115575SJohn Danielson * detactivation protocol as addresses are released 2431b115575SJohn Danielson */ 2441b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 2454c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 2464c06356bSdh142964 if (ddi_get_soft_state(mapp->dam_da, i) == NULL) 2474c06356bSdh142964 continue; 2481b115575SJohn Danielson 2491b115575SJohn Danielson ASSERT(DAM_IN_REPORT(mapp, i) == 0); 2501b115575SJohn Danielson 2511b115575SJohn Danielson if (DAM_IS_STABLE(mapp, i)) { 2521b115575SJohn Danielson dam_addr_deactivate(mapp, i); 2531b115575SJohn Danielson } else { 2544c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, i); 2554c06356bSdh142964 ddi_soft_state_free(mapp->dam_da, i); 2564c06356bSdh142964 } 2571b115575SJohn Danielson } 2584c06356bSdh142964 ddi_strid_fini(&mapp->dam_addr_hash); 2594c06356bSdh142964 ddi_soft_state_fini(&mapp->dam_da); 2601b115575SJohn Danielson kstat_delete(mapp->dam_kstatsp); 2611b115575SJohn Danielson } 2624c06356bSdh142964 bitset_fini(&mapp->dam_active_set); 2634c06356bSdh142964 bitset_fini(&mapp->dam_stable_set); 2644c06356bSdh142964 bitset_fini(&mapp->dam_report_set); 2654c06356bSdh142964 mutex_destroy(&mapp->dam_lock); 2664c06356bSdh142964 cv_destroy(&mapp->dam_cv); 2674c06356bSdh142964 if (mapp->dam_name) 2684c06356bSdh142964 kmem_free(mapp->dam_name, strlen(mapp->dam_name) + 1); 2694c06356bSdh142964 kmem_free(mapp, sizeof (*mapp)); 2704c06356bSdh142964 } 2714c06356bSdh142964 2724c06356bSdh142964 /* 2734c06356bSdh142964 * Wait for map stability. 2744c06356bSdh142964 * 2754c06356bSdh142964 * damapp: address map 2764c06356bSdh142964 */ 2774c06356bSdh142964 int 2784c06356bSdh142964 damap_sync(damap_t *damapp) 2794c06356bSdh142964 { 2801b115575SJohn Danielson #define WAITFOR_FLAGS (DAM_SETADD | DAM_SPEND) 2814c06356bSdh142964 2824c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 2834c06356bSdh142964 int none_active; 2844c06356bSdh142964 2854c06356bSdh142964 ASSERT(mapp); 2864c06356bSdh142964 2871b115575SJohn Danielson DTRACE_PROBE2(damap__map__sync__start, char *, mapp->dam_name, 2881b115575SJohn Danielson dam_t *, mapp); 2894c06356bSdh142964 2901b115575SJohn Danielson /* 2911b115575SJohn Danielson * block where waiting for 2921b115575SJohn Danielson * a) stabilization pending or a fullset update pending 2931b115575SJohn Danielson * b) any scheduled timeouts to fire 2941b115575SJohn Danielson * c) the report set to finalize (bitset is null) 2951b115575SJohn Danielson */ 2964c06356bSdh142964 mutex_enter(&mapp->dam_lock); 2974c06356bSdh142964 while ((mapp->dam_flags & WAITFOR_FLAGS) || 2984c06356bSdh142964 (!bitset_is_null(&mapp->dam_report_set)) || (mapp->dam_tid != 0)) { 2991b115575SJohn Danielson DTRACE_PROBE2(damap__map__sync__waiting, char *, mapp->dam_name, 3001b115575SJohn Danielson dam_t *, mapp); 3014c06356bSdh142964 cv_wait(&mapp->dam_cv, &mapp->dam_lock); 3024c06356bSdh142964 } 3034c06356bSdh142964 3044c06356bSdh142964 none_active = bitset_is_null(&mapp->dam_active_set); 3054c06356bSdh142964 3064c06356bSdh142964 mutex_exit(&mapp->dam_lock); 3071b115575SJohn Danielson DTRACE_PROBE3(damap__map__sync__end, char *, mapp->dam_name, int, 3081b115575SJohn Danielson none_active, dam_t *, mapp); 3094c06356bSdh142964 3104c06356bSdh142964 return (none_active); 3114c06356bSdh142964 } 3124c06356bSdh142964 3134c06356bSdh142964 /* 3144c06356bSdh142964 * Get the name of a device address map 3154c06356bSdh142964 * 3164c06356bSdh142964 * damapp: address map 3174c06356bSdh142964 * 3184c06356bSdh142964 * Returns: name 3194c06356bSdh142964 */ 3204c06356bSdh142964 char * 3214c06356bSdh142964 damap_name(damap_t *damapp) 3224c06356bSdh142964 { 3234c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 3244c06356bSdh142964 3254c06356bSdh142964 return (mapp ? mapp->dam_name : "UNKNOWN_damap"); 3264c06356bSdh142964 } 3274c06356bSdh142964 3284c06356bSdh142964 /* 3294c06356bSdh142964 * Report an address to per-address report 3304c06356bSdh142964 * 3314c06356bSdh142964 * damapp: address map handle 3324c06356bSdh142964 * address: address in ascii string representation 3331b115575SJohn Danielson * addridp: address ID 3344c06356bSdh142964 * nvl: optional nvlist of configuration-private data 3354c06356bSdh142964 * addr_priv: optional provider-private (passed to activate/deactivate cb) 3364c06356bSdh142964 * 3374c06356bSdh142964 * Returns: DAM_SUCCESS 3384c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 3394c06356bSdh142964 * DAM_MAPFULL address map exhausted 3404c06356bSdh142964 */ 3414c06356bSdh142964 int 3421b115575SJohn Danielson damap_addr_add(damap_t *damapp, char *address, damap_id_t *addridp, 3431b115575SJohn Danielson nvlist_t *nvl, void *addr_priv) 3444c06356bSdh142964 { 3454c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 3464c06356bSdh142964 id_t addrid; 3474c06356bSdh142964 dam_da_t *passp; 3484c06356bSdh142964 3491b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR)) 3504c06356bSdh142964 return (DAM_EINVAL); 3514c06356bSdh142964 3521b115575SJohn Danielson DTRACE_PROBE3(damap__addr__add, char *, mapp->dam_name, 3531b115575SJohn Danielson char *, address, dam_t *, mapp); 3541b115575SJohn Danielson 3551b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 3561b115575SJohn Danielson if ((dam_map_alloc(mapp) != DAM_SUCCESS) || 3571b115575SJohn Danielson ((addrid = dam_get_addrid(mapp, address)) == 0)) { 3581b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 3594c06356bSdh142964 return (DAM_MAPFULL); 3604c06356bSdh142964 } 3614c06356bSdh142964 3624c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 3634c06356bSdh142964 ASSERT(passp != NULL); 3644c06356bSdh142964 3654c06356bSdh142964 /* 3664c06356bSdh142964 * If re-reporting the same address (add or remove) clear 3674c06356bSdh142964 * the existing report 3684c06356bSdh142964 */ 3694c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 3701b115575SJohn Danielson DTRACE_PROBE3(damap__addr__add__jitter, char *, mapp->dam_name, 3711b115575SJohn Danielson char *, address, dam_t *, mapp); 3721b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_jitter); 3731b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 3744c06356bSdh142964 passp->da_jitter++; 3754c06356bSdh142964 } 3764c06356bSdh142964 passp->da_ppriv_rpt = addr_priv; 3774c06356bSdh142964 if (nvl) 3784c06356bSdh142964 (void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP); 3794c06356bSdh142964 3801b115575SJohn Danielson dam_addr_report(mapp, passp, addrid, RPT_ADDR_ADD); 3811b115575SJohn Danielson if (addridp != NULL) 3821b115575SJohn Danielson *addridp = (damap_id_t)addrid; 3831b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 3844c06356bSdh142964 return (DAM_SUCCESS); 3854c06356bSdh142964 } 3864c06356bSdh142964 3874c06356bSdh142964 /* 3884c06356bSdh142964 * Report removal of address from per-address report 3894c06356bSdh142964 * 3904c06356bSdh142964 * damapp: address map 3914c06356bSdh142964 * address: address in ascii string representation 3924c06356bSdh142964 * 3934c06356bSdh142964 * Returns: DAM_SUCCESS 3944c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 3954c06356bSdh142964 * DAM_FAILURE General failure 3964c06356bSdh142964 */ 3974c06356bSdh142964 int 3984c06356bSdh142964 damap_addr_del(damap_t *damapp, char *address) 3994c06356bSdh142964 { 4004c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 4014c06356bSdh142964 id_t addrid; 4024c06356bSdh142964 dam_da_t *passp; 4034c06356bSdh142964 4041b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_PERADDR)) 4054c06356bSdh142964 return (DAM_EINVAL); 4064c06356bSdh142964 4071b115575SJohn Danielson DTRACE_PROBE3(damap__addr__del, char *, mapp->dam_name, 4081b115575SJohn Danielson char *, address, dam_t *, mapp); 4091b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 4101b115575SJohn Danielson if (dam_map_alloc(mapp) != DAM_SUCCESS) { 4111b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4121b115575SJohn Danielson return (DAM_MAPFULL); 4131b115575SJohn Danielson } 4141b115575SJohn Danielson 4151b115575SJohn Danielson /* 4161b115575SJohn Danielson * if reporting the removal of an address which is not in the map 4171b115575SJohn Danielson * return success 4181b115575SJohn Danielson */ 4194c06356bSdh142964 if (!(addrid = ddi_strid_str2id(mapp->dam_addr_hash, address))) { 4201b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4214c06356bSdh142964 return (DAM_SUCCESS); 4224c06356bSdh142964 } 4234c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 4244c06356bSdh142964 ASSERT(passp); 4254c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 4261b115575SJohn Danielson DTRACE_PROBE3(damap__addr__del__jitter, char *, mapp->dam_name, 4271b115575SJohn Danielson char *, address, dam_t *, mapp); 4281b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_jitter); 4291b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 4304c06356bSdh142964 passp->da_jitter++; 4314c06356bSdh142964 } 4321b115575SJohn Danielson dam_addr_report(mapp, passp, addrid, RPT_ADDR_DEL); 4331b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 4344c06356bSdh142964 return (DAM_SUCCESS); 4354c06356bSdh142964 } 4364c06356bSdh142964 437*0b53804eSReed static int 438*0b53804eSReed damap_addrset_flush_locked(damap_t *damapp) 439*0b53804eSReed { 440*0b53804eSReed dam_t *mapp = (dam_t *)damapp; 441*0b53804eSReed int idx; 442*0b53804eSReed 443*0b53804eSReed ASSERT(mapp); 444*0b53804eSReed ASSERT(mutex_owned(&mapp->dam_lock)); 445*0b53804eSReed if (mapp->dam_rptmode != DAMAP_REPORT_FULLSET) { 446*0b53804eSReed return (DAM_EINVAL); 447*0b53804eSReed } 448*0b53804eSReed 449*0b53804eSReed DTRACE_PROBE2(damap__addrset__flush__locked__enter, char *, 450*0b53804eSReed mapp->dam_name, dam_t *, mapp); 451*0b53804eSReed if (mapp->dam_flags & DAM_SETADD) { 452*0b53804eSReed DTRACE_PROBE2(damap__addrset__flush__locked__reset, char *, 453*0b53804eSReed mapp->dam_name, dam_t *, mapp); 454*0b53804eSReed 455*0b53804eSReed /* 456*0b53804eSReed * cancel stabilization timeout 457*0b53804eSReed */ 458*0b53804eSReed dam_sched_tmo(mapp, 0, NULL); 459*0b53804eSReed DAM_INCR_STAT(mapp, dam_jitter); 460*0b53804eSReed 461*0b53804eSReed /* 462*0b53804eSReed * clear pending reports 463*0b53804eSReed */ 464*0b53804eSReed for (idx = 1; idx < mapp->dam_high; idx++) { 465*0b53804eSReed if (DAM_IN_REPORT(mapp, idx)) { 466*0b53804eSReed dam_addr_report_release(mapp, idx); 467*0b53804eSReed } 468*0b53804eSReed } 469*0b53804eSReed 470*0b53804eSReed bitset_zero(&mapp->dam_report_set); 471*0b53804eSReed mapp->dam_flags &= ~DAM_SETADD; 472*0b53804eSReed } 473*0b53804eSReed 474*0b53804eSReed return (DAM_SUCCESS); 475*0b53804eSReed } 476*0b53804eSReed 4774c06356bSdh142964 /* 4784c06356bSdh142964 * Initiate full-set report 4794c06356bSdh142964 * 4804c06356bSdh142964 * damapp: address map 4814c06356bSdh142964 * 4824c06356bSdh142964 * Returns: DAM_SUCCESS 4834c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 4844c06356bSdh142964 */ 4854c06356bSdh142964 int 4864c06356bSdh142964 damap_addrset_begin(damap_t *damapp) 4874c06356bSdh142964 { 4884c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 489*0b53804eSReed int rv; 4904c06356bSdh142964 491*0b53804eSReed if (mapp == NULL) { 4924c06356bSdh142964 return (DAM_EINVAL); 493*0b53804eSReed } 4944c06356bSdh142964 4951b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__begin, char *, mapp->dam_name, dam_t *, 4961b115575SJohn Danielson mapp); 497*0b53804eSReed 4981b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 4991b115575SJohn Danielson if (dam_map_alloc(mapp) != DAM_SUCCESS) { 5001b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 501*0b53804eSReed 5021b115575SJohn Danielson return (DAM_MAPFULL); 5031b115575SJohn Danielson } 504*0b53804eSReed 505*0b53804eSReed rv = damap_addrset_flush_locked(damapp); 506*0b53804eSReed if (rv == DAM_SUCCESS) { 507*0b53804eSReed mapp->dam_flags |= DAM_SETADD; 508*0b53804eSReed } 509*0b53804eSReed mutex_exit(&mapp->dam_lock); 510*0b53804eSReed 511*0b53804eSReed return (rv); 512*0b53804eSReed } 5131b115575SJohn Danielson 5141b115575SJohn Danielson /* 515*0b53804eSReed * Cancel full-set report 516*0b53804eSReed * 517*0b53804eSReed * damapp: address map 518*0b53804eSReed * 519*0b53804eSReed * Returns: DAM_SUCCESS 520*0b53804eSReed * DAM_EINVAL Invalid argument(s) 5211b115575SJohn Danielson */ 522*0b53804eSReed int 523*0b53804eSReed damap_addrset_flush(damap_t *damapp) 524*0b53804eSReed { 525*0b53804eSReed int rv; 526*0b53804eSReed dam_t *mapp = (dam_t *)damapp; 527*0b53804eSReed 528*0b53804eSReed if (mapp == NULL) { 529*0b53804eSReed return (DAM_EINVAL); 5304c06356bSdh142964 } 531*0b53804eSReed 532*0b53804eSReed DTRACE_PROBE2(damap__addrset__flush, char *, mapp->dam_name, 533*0b53804eSReed dam_t *, mapp); 534*0b53804eSReed 535*0b53804eSReed mutex_enter(&mapp->dam_lock); 536*0b53804eSReed rv = damap_addrset_flush_locked(damapp); 5371b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 538*0b53804eSReed 539*0b53804eSReed return (rv); 5404c06356bSdh142964 } 5414c06356bSdh142964 5424c06356bSdh142964 /* 5434c06356bSdh142964 * Report address to full-set report 5444c06356bSdh142964 * 5454c06356bSdh142964 * damapp: address map handle 5464c06356bSdh142964 * address: address in ascii string representation 5474c06356bSdh142964 * rindx: index if address stabilizes 5484c06356bSdh142964 * nvl: optional nvlist of configuration-private data 5494c06356bSdh142964 * addr_priv: optional provider-private data (passed to activate/release cb) 5504c06356bSdh142964 * 5514c06356bSdh142964 * Returns: DAM_SUCCESS 5524c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 5534c06356bSdh142964 * DAM_MAPFULL address map exhausted 5544c06356bSdh142964 * DAM_FAILURE General failure 5554c06356bSdh142964 */ 5564c06356bSdh142964 int 5574c06356bSdh142964 damap_addrset_add(damap_t *damapp, char *address, damap_id_t *ridx, 5584c06356bSdh142964 nvlist_t *nvl, void *addr_priv) 5594c06356bSdh142964 { 5604c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 5614c06356bSdh142964 id_t addrid; 5624c06356bSdh142964 dam_da_t *passp; 5634c06356bSdh142964 5641b115575SJohn Danielson if (!mapp || !address || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET)) 5654c06356bSdh142964 return (DAM_EINVAL); 5664c06356bSdh142964 5671b115575SJohn Danielson DTRACE_PROBE3(damap__addrset__add, char *, mapp->dam_name, 5681b115575SJohn Danielson char *, address, dam_t *, mapp); 5694c06356bSdh142964 5701b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 5711b115575SJohn Danielson if (!(mapp->dam_flags & DAM_SETADD)) { 5721b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5731b115575SJohn Danielson return (DAM_FAILURE); 5741b115575SJohn Danielson } 5751b115575SJohn Danielson 5764c06356bSdh142964 if ((addrid = dam_get_addrid(mapp, address)) == 0) { 5771b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5784c06356bSdh142964 return (DAM_MAPFULL); 5794c06356bSdh142964 } 5804c06356bSdh142964 5814c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 5824c06356bSdh142964 ASSERT(passp); 5834c06356bSdh142964 if (DAM_IN_REPORT(mapp, addrid)) { 5841b115575SJohn Danielson DTRACE_PROBE3(damap__addrset__add__jitter, char *, 5851b115575SJohn Danielson mapp->dam_name, char *, address, dam_t *, mapp); 5861b115575SJohn Danielson dam_addr_report_release(mapp, addrid); 5874c06356bSdh142964 passp->da_jitter++; 5884c06356bSdh142964 } 5894c06356bSdh142964 passp->da_ppriv_rpt = addr_priv; 5904c06356bSdh142964 if (nvl) 5914c06356bSdh142964 (void) nvlist_dup(nvl, &passp->da_nvl_rpt, KM_SLEEP); 5924c06356bSdh142964 bitset_add(&mapp->dam_report_set, addrid); 5934c06356bSdh142964 if (ridx) 5944c06356bSdh142964 *ridx = (damap_id_t)addrid; 5951b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 5964c06356bSdh142964 return (DAM_SUCCESS); 5974c06356bSdh142964 } 5984c06356bSdh142964 5994c06356bSdh142964 /* 6004c06356bSdh142964 * Commit full-set report for stabilization 6014c06356bSdh142964 * 6024c06356bSdh142964 * damapp: address map handle 6034c06356bSdh142964 * flags: (currently 0) 6044c06356bSdh142964 * 6054c06356bSdh142964 * Returns: DAM_SUCCESS 6064c06356bSdh142964 * DAM_EINVAL Invalid argument(s) 6074c06356bSdh142964 * DAM_FAILURE General failure 6084c06356bSdh142964 */ 6094c06356bSdh142964 int 6104c06356bSdh142964 damap_addrset_end(damap_t *damapp, int flags) 6114c06356bSdh142964 { 6124c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6134c06356bSdh142964 int i; 6144c06356bSdh142964 6151b115575SJohn Danielson if (!mapp || (mapp->dam_rptmode != DAMAP_REPORT_FULLSET)) 6164c06356bSdh142964 return (DAM_EINVAL); 6174c06356bSdh142964 6181b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__end, char *, mapp->dam_name, 6191b115575SJohn Danielson dam_t *, mapp); 6204c06356bSdh142964 6211b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 6221b115575SJohn Danielson if (!(mapp->dam_flags & DAM_SETADD)) { 6231b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 6241b115575SJohn Danielson return (DAM_FAILURE); 6251b115575SJohn Danielson } 6261b115575SJohn Danielson 6271b115575SJohn Danielson if (flags & DAMAP_END_RESET) { 6281b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__end__reset, char *, 6291b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 6304c06356bSdh142964 dam_sched_tmo(mapp, 0, NULL); 6314c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) 6324c06356bSdh142964 if (DAM_IN_REPORT(mapp, i)) 6331b115575SJohn Danielson dam_addr_report_release(mapp, i); 6344c06356bSdh142964 } else { 6354c06356bSdh142964 mapp->dam_last_update = gethrtime(); 6361b115575SJohn Danielson dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addrset_stable_cb); 6374c06356bSdh142964 } 6381b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 6394c06356bSdh142964 return (DAM_SUCCESS); 6404c06356bSdh142964 } 6414c06356bSdh142964 6424c06356bSdh142964 /* 6434c06356bSdh142964 * Return nvlist registered with reported address 6444c06356bSdh142964 * 6454c06356bSdh142964 * damapp: address map handle 6461b115575SJohn Danielson * addrid: address ID 6474c06356bSdh142964 * 6484c06356bSdh142964 * Returns: nvlist_t * provider supplied via damap_addr{set}_add()) 6494c06356bSdh142964 * NULL 6504c06356bSdh142964 */ 6514c06356bSdh142964 nvlist_t * 6524c06356bSdh142964 damap_id2nvlist(damap_t *damapp, damap_id_t addrid) 6534c06356bSdh142964 { 6544c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6554c06356bSdh142964 dam_da_t *pass; 6564c06356bSdh142964 6571b115575SJohn Danielson if (mapp->dam_high && ddi_strid_id2str(mapp->dam_addr_hash, addrid)) { 6581b115575SJohn Danielson if (pass = ddi_get_soft_state(mapp->dam_da, addrid)) 6594c06356bSdh142964 return (pass->da_nvl); 6604c06356bSdh142964 } 6614c06356bSdh142964 return (NULL); 6624c06356bSdh142964 } 6634c06356bSdh142964 6644c06356bSdh142964 /* 6654c06356bSdh142964 * Return address string 6664c06356bSdh142964 * 6674c06356bSdh142964 * damapp: address map handle 6681b115575SJohn Danielson * addrid: address ID 6694c06356bSdh142964 * 6704c06356bSdh142964 * Returns: char * Address string 6714c06356bSdh142964 * NULL 6724c06356bSdh142964 */ 6734c06356bSdh142964 char * 6741b115575SJohn Danielson damap_id2addr(damap_t *damapp, damap_id_t addrid) 6754c06356bSdh142964 { 6764c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6774c06356bSdh142964 6781b115575SJohn Danielson if (mapp->dam_high) 6791b115575SJohn Danielson return (ddi_strid_id2str(mapp->dam_addr_hash, addrid)); 6801b115575SJohn Danielson else 6811b115575SJohn Danielson return (NULL); 6824c06356bSdh142964 } 6834c06356bSdh142964 6844c06356bSdh142964 /* 6854c06356bSdh142964 * Release address reference in map 6864c06356bSdh142964 * 6874c06356bSdh142964 * damapp: address map handle 6881b115575SJohn Danielson * addrid: address ID 6894c06356bSdh142964 */ 6904c06356bSdh142964 void 6914c06356bSdh142964 damap_id_rele(damap_t *damapp, damap_id_t addrid) 6924c06356bSdh142964 { 6934c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 6941b115575SJohn Danielson dam_da_t *passp; 6951b115575SJohn Danielson char *addr; 6964c06356bSdh142964 6971b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 6981b115575SJohn Danielson ASSERT(passp); 6991b115575SJohn Danielson 7001b115575SJohn Danielson addr = damap_id2addr(damapp, addrid); 7011b115575SJohn Danielson DTRACE_PROBE4(damap__id__rele, char *, mapp->dam_name, char *, addr, 7021b115575SJohn Danielson dam_t *, mapp, int, passp->da_ref); 7031b115575SJohn Danielson 7041b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 7051b115575SJohn Danielson 7061b115575SJohn Danielson /* 7071b115575SJohn Danielson * teardown address if last outstanding reference 7081b115575SJohn Danielson */ 7091b115575SJohn Danielson if (--passp->da_ref == 0) 7101b115575SJohn Danielson dam_addr_release(mapp, (id_t)addrid); 7111b115575SJohn Danielson 7121b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7134c06356bSdh142964 } 7144c06356bSdh142964 7154c06356bSdh142964 /* 7164c06356bSdh142964 * Return current reference count on address reference in map 7174c06356bSdh142964 * 7184c06356bSdh142964 * damapp: address map handle 7191b115575SJohn Danielson * addrid: address ID 7204c06356bSdh142964 * 7214c06356bSdh142964 * Returns: DAM_SUCCESS 7224c06356bSdh142964 * DAM_FAILURE 7234c06356bSdh142964 */ 7244c06356bSdh142964 int 7251b115575SJohn Danielson damap_id_ref(damap_t *damapp, damap_id_t addrid) 7264c06356bSdh142964 { 7274c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7284c06356bSdh142964 dam_da_t *passp; 7294c06356bSdh142964 int ref = -1; 7304c06356bSdh142964 7311b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 7324c06356bSdh142964 if (passp) 7334c06356bSdh142964 ref = passp->da_ref; 7341b115575SJohn Danielson 7354c06356bSdh142964 return (ref); 7364c06356bSdh142964 } 7374c06356bSdh142964 7384c06356bSdh142964 /* 7394c06356bSdh142964 * Return next address ID in list 7404c06356bSdh142964 * 7414c06356bSdh142964 * damapp: address map handle 7424c06356bSdh142964 * damap_list: address ID list passed to config|unconfig 7434c06356bSdh142964 * returned by look by lookup_all 7444c06356bSdh142964 * last: last ID returned, 0 is start of list 7454c06356bSdh142964 * 7464c06356bSdh142964 * Returns: addrid Next ID from the list 7474c06356bSdh142964 * 0 End of the list 7484c06356bSdh142964 */ 7494c06356bSdh142964 damap_id_t 7504c06356bSdh142964 damap_id_next(damap_t *damapp, damap_id_list_t damap_list, damap_id_t last) 7514c06356bSdh142964 { 7524c06356bSdh142964 int i, start; 7534c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7544c06356bSdh142964 bitset_t *dam_list = (bitset_t *)damap_list; 7554c06356bSdh142964 7564c06356bSdh142964 if (!mapp || !dam_list) 7574c06356bSdh142964 return ((damap_id_t)0); 7584c06356bSdh142964 7594c06356bSdh142964 start = (int)last + 1; 7601b115575SJohn Danielson for (i = start; i < mapp->dam_high; i++) { 7611b115575SJohn Danielson if (bitset_in_set(dam_list, i)) { 7624c06356bSdh142964 return ((damap_id_t)i); 7631b115575SJohn Danielson } 7641b115575SJohn Danielson } 7654c06356bSdh142964 return ((damap_id_t)0); 7664c06356bSdh142964 } 7674c06356bSdh142964 7684c06356bSdh142964 /* 7694c06356bSdh142964 * Set config private data 7704c06356bSdh142964 * 7714c06356bSdh142964 * damapp: address map handle 7721b115575SJohn Danielson * addrid: address ID 7734c06356bSdh142964 * cfg_priv: configuration private data 7744c06356bSdh142964 * 7754c06356bSdh142964 */ 7764c06356bSdh142964 void 7771b115575SJohn Danielson damap_id_priv_set(damap_t *damapp, damap_id_t addrid, void *cfg_priv) 7784c06356bSdh142964 { 7794c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 7804c06356bSdh142964 dam_da_t *passp; 7814c06356bSdh142964 7821b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 7831b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 7844c06356bSdh142964 if (!passp) { 7851b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7864c06356bSdh142964 return; 7874c06356bSdh142964 } 7884c06356bSdh142964 passp->da_cfg_priv = cfg_priv; 7891b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 7904c06356bSdh142964 } 7914c06356bSdh142964 7924c06356bSdh142964 /* 7934c06356bSdh142964 * Get config private data 7944c06356bSdh142964 * 7954c06356bSdh142964 * damapp: address map handle 7961b115575SJohn Danielson * addrid: address ID 7974c06356bSdh142964 * 7984c06356bSdh142964 * Returns: configuration private data 7994c06356bSdh142964 */ 8004c06356bSdh142964 void * 8011b115575SJohn Danielson damap_id_priv_get(damap_t *damapp, damap_id_t addrid) 8024c06356bSdh142964 { 8034c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 8044c06356bSdh142964 dam_da_t *passp; 8054c06356bSdh142964 void *rv; 8064c06356bSdh142964 8071b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 8081b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, (id_t)addrid); 8094c06356bSdh142964 if (!passp) { 8101b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8114c06356bSdh142964 return (NULL); 8124c06356bSdh142964 } 8134c06356bSdh142964 rv = passp->da_cfg_priv; 8141b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8154c06356bSdh142964 return (rv); 8164c06356bSdh142964 } 8174c06356bSdh142964 8184c06356bSdh142964 /* 8194c06356bSdh142964 * Lookup a single address in the active address map 8204c06356bSdh142964 * 8214c06356bSdh142964 * damapp: address map handle 8224c06356bSdh142964 * address: address string 8234c06356bSdh142964 * 8244c06356bSdh142964 * Returns: ID of active/stable address 8254c06356bSdh142964 * 0 Address not in stable set 8264c06356bSdh142964 * 8274c06356bSdh142964 * Future: Allow the caller to wait for stabilize before returning not found. 8284c06356bSdh142964 */ 8294c06356bSdh142964 damap_id_t 8304c06356bSdh142964 damap_lookup(damap_t *damapp, char *address) 8314c06356bSdh142964 { 8324c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 8334c06356bSdh142964 id_t addrid = 0; 8344c06356bSdh142964 dam_da_t *passp = NULL; 8354c06356bSdh142964 8361b115575SJohn Danielson DTRACE_PROBE3(damap__lookup, char *, mapp->dam_name, 8371b115575SJohn Danielson char *, address, dam_t *, mapp); 8381b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 8391b115575SJohn Danielson if (!mapp->dam_high) 8401b115575SJohn Danielson addrid = 0; 8411b115575SJohn Danielson else 8424c06356bSdh142964 addrid = ddi_strid_str2id(mapp->dam_addr_hash, address); 8434c06356bSdh142964 if (addrid) { 8444c06356bSdh142964 if (DAM_IS_STABLE(mapp, addrid)) { 8454c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 8464c06356bSdh142964 ASSERT(passp); 8474c06356bSdh142964 if (passp) { 8484c06356bSdh142964 passp->da_ref++; 8494c06356bSdh142964 } else { 8504c06356bSdh142964 addrid = 0; 8514c06356bSdh142964 } 8524c06356bSdh142964 } else { 8534c06356bSdh142964 addrid = 0; 8544c06356bSdh142964 } 8554c06356bSdh142964 } 8561b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8571b115575SJohn Danielson DTRACE_PROBE4(damap__lookup__return, char *, mapp->dam_name, 8581b115575SJohn Danielson char *, address, dam_t *, mapp, int, addrid); 8594c06356bSdh142964 return ((damap_id_t)addrid); 8604c06356bSdh142964 } 8614c06356bSdh142964 8624c06356bSdh142964 8634c06356bSdh142964 /* 8644c06356bSdh142964 * Return the list of stable addresses in the map 8654c06356bSdh142964 * 8664c06356bSdh142964 * damapp: address map handle 8674c06356bSdh142964 * id_listp: pointer to list of address IDs in stable map (returned) 8684c06356bSdh142964 * 8694c06356bSdh142964 * Returns: # of entries returned in alist 8704c06356bSdh142964 */ 8714c06356bSdh142964 int 8724c06356bSdh142964 damap_lookup_all(damap_t *damapp, damap_id_list_t *id_listp) 8734c06356bSdh142964 { 8744c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 8754c06356bSdh142964 int mapsz = mapp->dam_size; 8764c06356bSdh142964 int n_ids, i; 8774c06356bSdh142964 bitset_t *bsp; 8781b115575SJohn Danielson char *addrp; 8794c06356bSdh142964 dam_da_t *passp; 8804c06356bSdh142964 8811b115575SJohn Danielson DTRACE_PROBE2(damap__lookup__all, char *, mapp->dam_name, 8821b115575SJohn Danielson dam_t *, mapp); 8831b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 8841b115575SJohn Danielson if (!mapp->dam_high) { 8851b115575SJohn Danielson *id_listp = (damap_id_list_t)NULL; 8861b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 8871b115575SJohn Danielson DTRACE_PROBE3(damap__lookup__all__nomap, char *, 8881b115575SJohn Danielson mapp->dam_name, dam_t *, mapp, int, 0); 8891b115575SJohn Danielson return (0); 8901b115575SJohn Danielson } 8914c06356bSdh142964 bsp = kmem_alloc(sizeof (*bsp), KM_SLEEP); 8924c06356bSdh142964 bitset_init(bsp); 8934c06356bSdh142964 bitset_resize(bsp, mapsz); 8944c06356bSdh142964 bitset_copy(&mapp->dam_active_set, bsp); 8954c06356bSdh142964 for (n_ids = 0, i = 1; i < mapsz; i++) { 8964c06356bSdh142964 if (bitset_in_set(bsp, i)) { 8974c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, i); 8984c06356bSdh142964 ASSERT(passp); 8994c06356bSdh142964 if (passp) { 9001b115575SJohn Danielson addrp = damap_id2addr(damapp, i); 9011b115575SJohn Danielson DTRACE_PROBE3(damap__lookup__all__item, char *, 9021b115575SJohn Danielson mapp->dam_name, char *, addrp, dam_t *, 9031b115575SJohn Danielson mapp); 9044c06356bSdh142964 passp->da_ref++; 9054c06356bSdh142964 n_ids++; 9064c06356bSdh142964 } 9074c06356bSdh142964 } 9084c06356bSdh142964 } 9094c06356bSdh142964 if (n_ids) { 9104c06356bSdh142964 *id_listp = (damap_id_list_t)bsp; 9111b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 9124c06356bSdh142964 return (n_ids); 9134c06356bSdh142964 } else { 9144c06356bSdh142964 *id_listp = (damap_id_list_t)NULL; 9154c06356bSdh142964 bitset_fini(bsp); 9164c06356bSdh142964 kmem_free(bsp, sizeof (*bsp)); 9171b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 9184c06356bSdh142964 return (0); 9194c06356bSdh142964 } 9204c06356bSdh142964 } 9214c06356bSdh142964 9224c06356bSdh142964 /* 9234c06356bSdh142964 * Release the address list returned by damap_lookup_all() 9244c06356bSdh142964 * 9254c06356bSdh142964 * mapp: address map handle 9264c06356bSdh142964 * id_list: list of address IDs returned in damap_lookup_all() 9274c06356bSdh142964 */ 9284c06356bSdh142964 void 9294c06356bSdh142964 damap_id_list_rele(damap_t *damapp, damap_id_list_t id_list) 9304c06356bSdh142964 { 9314c06356bSdh142964 dam_t *mapp = (dam_t *)damapp; 9324c06356bSdh142964 int i; 9334c06356bSdh142964 9344c06356bSdh142964 if (id_list == NULL) 9354c06356bSdh142964 return; 9364c06356bSdh142964 9371b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 9384c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 9394c06356bSdh142964 if (bitset_in_set((bitset_t *)id_list, i)) 9401b115575SJohn Danielson (void) dam_addr_release(mapp, i); 9414c06356bSdh142964 } 9421b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 9434c06356bSdh142964 bitset_fini((bitset_t *)id_list); 9444c06356bSdh142964 kmem_free((void *)id_list, sizeof (bitset_t)); 9454c06356bSdh142964 } 9464c06356bSdh142964 9474c06356bSdh142964 /* 9481b115575SJohn Danielson * activate an address that has passed the stabilization interval 9494c06356bSdh142964 */ 9504c06356bSdh142964 static void 9511b115575SJohn Danielson dam_addr_activate(dam_t *mapp, id_t addrid) 9524c06356bSdh142964 { 9534c06356bSdh142964 dam_da_t *passp; 9541b115575SJohn Danielson int config_rv; 9554c06356bSdh142964 char *addrstr; 9564c06356bSdh142964 9571b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 9581b115575SJohn Danielson bitset_add(&mapp->dam_active_set, addrid); 9591b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, addrid); 9604c06356bSdh142964 ASSERT(passp); 9611b115575SJohn Danielson 9624c06356bSdh142964 /* 9634c06356bSdh142964 * copy the reported nvlist and provider private data 9644c06356bSdh142964 */ 9651b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 9661b115575SJohn Danielson DTRACE_PROBE3(damap__addr__activate__start, char *, mapp->dam_name, 9671b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 9684c06356bSdh142964 passp->da_nvl = passp->da_nvl_rpt; 9694c06356bSdh142964 passp->da_ppriv = passp->da_ppriv_rpt; 9704c06356bSdh142964 passp->da_ppriv_rpt = NULL; 9714c06356bSdh142964 passp->da_nvl_rpt = NULL; 9724c06356bSdh142964 passp->da_last_stable = gethrtime(); 9734c06356bSdh142964 passp->da_stable_cnt++; 9741b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 9751b115575SJohn Danielson if (mapp->dam_activate_cb) { 9761b115575SJohn Danielson (*mapp->dam_activate_cb)(mapp->dam_activate_arg, addrstr, 9771b115575SJohn Danielson addrid, &passp->da_ppriv_rpt); 9784c06356bSdh142964 } 9794c06356bSdh142964 9804c06356bSdh142964 /* 9811b115575SJohn Danielson * call the address-specific configuration action as part of 9821b115575SJohn Danielson * activation. 9834c06356bSdh142964 */ 9841b115575SJohn Danielson config_rv = (*mapp->dam_configure_cb)(mapp->dam_config_arg, mapp, 9851b115575SJohn Danielson addrid); 9861b115575SJohn Danielson if (config_rv != DAM_SUCCESS) { 9871b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 9881b115575SJohn Danielson passp->da_flags |= DA_FAILED_CONFIG; 9891b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 9901b115575SJohn Danielson DTRACE_PROBE3(damap__addr__activate__config__failure, 9911b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp); 992d189c170SReed dam_deact_cleanup(mapp, addrid, addrstr, 993d189c170SReed DAMAP_DEACT_RSN_CFG_FAIL); 994d189c170SReed } else { 995d189c170SReed DTRACE_PROBE3(damap__addr__activate__end, char *, 996d189c170SReed mapp->dam_name, char *, addrstr, dam_t *, mapp); 9974c06356bSdh142964 } 9984c06356bSdh142964 } 9994c06356bSdh142964 10004c06356bSdh142964 /* 10011b115575SJohn Danielson * deactivate a previously stable address 10024c06356bSdh142964 */ 10034c06356bSdh142964 static void 10041b115575SJohn Danielson dam_addr_deactivate(dam_t *mapp, id_t addrid) 10054c06356bSdh142964 { 10061b115575SJohn Danielson char *addrstr; 10074c06356bSdh142964 10081b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 10091b115575SJohn Danielson DTRACE_PROBE3(damap__addr__deactivate__start, char *, mapp->dam_name, 10101b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 10111b115575SJohn Danielson 10121b115575SJohn Danielson /* 10131b115575SJohn Danielson * call the unconfiguration callback 10141b115575SJohn Danielson */ 10151b115575SJohn Danielson (*mapp->dam_unconfig_cb)(mapp->dam_config_arg, mapp, addrid); 1016d189c170SReed dam_deact_cleanup(mapp, addrid, addrstr, DAMAP_DEACT_RSN_GONE); 1017d189c170SReed } 1018d189c170SReed 1019d189c170SReed static void 1020d189c170SReed dam_deact_cleanup(dam_t *mapp, id_t addrid, char *addrstr, 1021d189c170SReed damap_deact_rsn_t deact_rsn) 1022d189c170SReed { 1023d189c170SReed dam_da_t *passp; 1024d189c170SReed 10251b115575SJohn Danielson passp = ddi_get_soft_state(mapp->dam_da, addrid); 10261b115575SJohn Danielson ASSERT(passp); 10271b115575SJohn Danielson if (mapp->dam_deactivate_cb) 10281b115575SJohn Danielson (*mapp->dam_deactivate_cb)(mapp->dam_activate_arg, 10291b115575SJohn Danielson ddi_strid_id2str(mapp->dam_addr_hash, addrid), 1030d189c170SReed addrid, passp->da_ppriv, deact_rsn); 10311b115575SJohn Danielson 10321b115575SJohn Danielson /* 10331b115575SJohn Danielson * clear the active bit and free the backing info for 10341b115575SJohn Danielson * this address 10351b115575SJohn Danielson */ 10361b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 10371b115575SJohn Danielson bitset_del(&mapp->dam_active_set, addrid); 10381b115575SJohn Danielson passp->da_ppriv = NULL; 10391b115575SJohn Danielson if (passp->da_nvl) 10401b115575SJohn Danielson nvlist_free(passp->da_nvl); 10411b115575SJohn Danielson passp->da_nvl = NULL; 10421b115575SJohn Danielson passp->da_ppriv_rpt = NULL; 10431b115575SJohn Danielson if (passp->da_nvl_rpt) 10441b115575SJohn Danielson nvlist_free(passp->da_nvl_rpt); 10451b115575SJohn Danielson passp->da_nvl_rpt = NULL; 10461b115575SJohn Danielson 10471b115575SJohn Danielson DTRACE_PROBE3(damap__addr__deactivate__end, char *, mapp->dam_name, 10481b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 10491b115575SJohn Danielson 10501b115575SJohn Danielson (void) dam_addr_release(mapp, addrid); 10511b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 10521b115575SJohn Danielson } 10531b115575SJohn Danielson 10541b115575SJohn Danielson /* 10551b115575SJohn Danielson * taskq callback for multi-thread activation 10561b115575SJohn Danielson */ 10571b115575SJohn Danielson static void 10581b115575SJohn Danielson dam_tq_config(void *arg) 10591b115575SJohn Danielson { 10601b115575SJohn Danielson cfg_tqd_t *tqd = (cfg_tqd_t *)arg; 10611b115575SJohn Danielson 10621b115575SJohn Danielson dam_addr_activate(tqd->tqd_mapp, tqd->tqd_id); 10631b115575SJohn Danielson kmem_free(tqd, sizeof (*tqd)); 10641b115575SJohn Danielson } 10651b115575SJohn Danielson 10661b115575SJohn Danielson /* 10671b115575SJohn Danielson * taskq callback for multi-thread deactivation 10681b115575SJohn Danielson */ 10691b115575SJohn Danielson static void 10701b115575SJohn Danielson dam_tq_unconfig(void *arg) 10711b115575SJohn Danielson { 10721b115575SJohn Danielson cfg_tqd_t *tqd = (cfg_tqd_t *)arg; 10731b115575SJohn Danielson 10741b115575SJohn Danielson dam_addr_deactivate(tqd->tqd_mapp, tqd->tqd_id); 10751b115575SJohn Danielson kmem_free(tqd, sizeof (*tqd)); 10761b115575SJohn Danielson } 10771b115575SJohn Danielson 10781b115575SJohn Danielson /* 10791b115575SJohn Danielson * Activate a set of stabilized addresses 10801b115575SJohn Danielson */ 10811b115575SJohn Danielson static void 10821b115575SJohn Danielson dam_addrset_activate(dam_t *mapp, bitset_t *activate) 10831b115575SJohn Danielson { 10841b115575SJohn Danielson 10851b115575SJohn Danielson int i, nset; 10861b115575SJohn Danielson taskq_t *tqp = NULL; 10871b115575SJohn Danielson cfg_tqd_t *tqd = NULL; 10881b115575SJohn Danielson char tqn[TASKQ_NAMELEN]; 10891b115575SJohn Danielson extern pri_t maxclsyspri; 10901b115575SJohn Danielson 10911b115575SJohn Danielson if (mapp->dam_options & DAMAP_MTCONFIG) { 10921b115575SJohn Danielson /* 10931b115575SJohn Danielson * calculate the # of taskq threads to create 10941b115575SJohn Danielson */ 10951b115575SJohn Danielson for (i = 1, nset = 0; i < mapp->dam_high; i++) 10961b115575SJohn Danielson if (bitset_in_set(activate, i)) 10971b115575SJohn Danielson nset++; 10981b115575SJohn Danielson ASSERT(nset); 10991b115575SJohn Danielson (void) snprintf(tqn, sizeof (tqn), "actv-%s", mapp->dam_name); 11001b115575SJohn Danielson tqp = taskq_create(tqn, nset, maxclsyspri, 1, 11011b115575SJohn Danielson INT_MAX, TASKQ_PREPOPULATE); 11021b115575SJohn Danielson } 11031b115575SJohn Danielson for (i = 1; i < mapp->dam_high; i++) { 11041b115575SJohn Danielson if (bitset_in_set(activate, i)) { 11051b115575SJohn Danielson if (!tqp) 11061b115575SJohn Danielson dam_addr_activate(mapp, i); 11071b115575SJohn Danielson else { 11081b115575SJohn Danielson /* 11091b115575SJohn Danielson * multi-threaded activation 11101b115575SJohn Danielson */ 11111b115575SJohn Danielson tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP); 11121b115575SJohn Danielson tqd->tqd_mapp = mapp; 11131b115575SJohn Danielson tqd->tqd_id = i; 11141b115575SJohn Danielson (void) taskq_dispatch(tqp, dam_tq_config, 111564109744SChris Horne tqd, TQ_SLEEP); 11161b115575SJohn Danielson } 11171b115575SJohn Danielson } 11181b115575SJohn Danielson } 11191b115575SJohn Danielson if (tqp) { 11201b115575SJohn Danielson taskq_wait(tqp); 11211b115575SJohn Danielson taskq_destroy(tqp); 11221b115575SJohn Danielson } 11231b115575SJohn Danielson } 11241b115575SJohn Danielson 11251b115575SJohn Danielson /* 11261b115575SJohn Danielson * Deactivate a set of stabilized addresses 11271b115575SJohn Danielson */ 11281b115575SJohn Danielson static void 11291b115575SJohn Danielson dam_addrset_deactivate(dam_t *mapp, bitset_t *deactivate) 11301b115575SJohn Danielson { 11311b115575SJohn Danielson int i, nset; 11321b115575SJohn Danielson taskq_t *tqp = NULL; 11331b115575SJohn Danielson cfg_tqd_t *tqd = NULL; 11341b115575SJohn Danielson char tqn[TASKQ_NAMELEN]; 11351b115575SJohn Danielson 11361b115575SJohn Danielson DTRACE_PROBE2(damap__addrset__deactivate, char *, mapp->dam_name, 11371b115575SJohn Danielson dam_t *, mapp); 11381b115575SJohn Danielson 11391b115575SJohn Danielson if (mapp->dam_options & DAMAP_MTCONFIG) { 11401b115575SJohn Danielson /* 11411b115575SJohn Danielson * compute the # of taskq threads to dispatch 11421b115575SJohn Danielson */ 11431b115575SJohn Danielson for (i = 1, nset = 0; i < mapp->dam_high; i++) 11441b115575SJohn Danielson if (bitset_in_set(deactivate, i)) 11451b115575SJohn Danielson nset++; 11461b115575SJohn Danielson (void) snprintf(tqn, sizeof (tqn), "deactv-%s", 11471b115575SJohn Danielson mapp->dam_name); 11481b115575SJohn Danielson tqp = taskq_create(tqn, nset, maxclsyspri, 1, 11491b115575SJohn Danielson INT_MAX, TASKQ_PREPOPULATE); 11501b115575SJohn Danielson } 11511b115575SJohn Danielson for (i = 1; i < mapp->dam_high; i++) { 11521b115575SJohn Danielson if (bitset_in_set(deactivate, i)) { 11531b115575SJohn Danielson if (!tqp) { 11541b115575SJohn Danielson dam_addr_deactivate(mapp, i); 11551b115575SJohn Danielson } else { 11561b115575SJohn Danielson tqd = kmem_alloc(sizeof (*tqd), KM_SLEEP); 11571b115575SJohn Danielson tqd->tqd_mapp = mapp; 11581b115575SJohn Danielson tqd->tqd_id = i; 11591b115575SJohn Danielson (void) taskq_dispatch(tqp, 116064109744SChris Horne dam_tq_unconfig, tqd, TQ_SLEEP); 11611b115575SJohn Danielson } 11621b115575SJohn Danielson } 11631b115575SJohn Danielson } 11641b115575SJohn Danielson 11651b115575SJohn Danielson if (tqp) { 11661b115575SJohn Danielson taskq_wait(tqp); 11671b115575SJohn Danielson taskq_destroy(tqp); 11681b115575SJohn Danielson } 11691b115575SJohn Danielson } 11701b115575SJohn Danielson 11711b115575SJohn Danielson /* 11721b115575SJohn Danielson * Release a previously activated address 11731b115575SJohn Danielson */ 11741b115575SJohn Danielson static void 11751b115575SJohn Danielson dam_addr_release(dam_t *mapp, id_t addrid) 11761b115575SJohn Danielson { 11771b115575SJohn Danielson dam_da_t *passp; 11781b115575SJohn Danielson char *addrstr; 11791b115575SJohn Danielson 11801b115575SJohn Danielson 11811b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 11824c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 11834c06356bSdh142964 ASSERT(passp); 11844c06356bSdh142964 11851b115575SJohn Danielson addrstr = ddi_strid_id2str(mapp->dam_addr_hash, addrid); 11861b115575SJohn Danielson DTRACE_PROBE3(damap__addr__release, char *, mapp->dam_name, 11871b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 11884c06356bSdh142964 11894c06356bSdh142964 /* 11901b115575SJohn Danielson * defer releasing the address until outstanding references 11911b115575SJohn Danielson * are released 11924c06356bSdh142964 */ 11931b115575SJohn Danielson if (passp->da_ref > 1) { 11941b115575SJohn Danielson DTRACE_PROBE4(damap__addr__release__outstanding__refs, 11951b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp, 11961b115575SJohn Danielson int, passp->da_ref); 11974c06356bSdh142964 return; 11984c06356bSdh142964 } 11991b115575SJohn Danielson 12001b115575SJohn Danielson /* 12011b115575SJohn Danielson * allow pending reports to stabilize 12021b115575SJohn Danielson */ 12031b115575SJohn Danielson if (DAM_IN_REPORT(mapp, addrid)) { 12041b115575SJohn Danielson DTRACE_PROBE3(damap__addr__release__report__pending, 12051b115575SJohn Danielson char *, mapp->dam_name, char *, addrstr, dam_t *, mapp); 12061b115575SJohn Danielson return; 12071b115575SJohn Danielson } 12081b115575SJohn Danielson 12094c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, addrid); 12104c06356bSdh142964 ddi_soft_state_free(mapp->dam_da, addrid); 12114c06356bSdh142964 } 12124c06356bSdh142964 12134c06356bSdh142964 /* 12144c06356bSdh142964 * process stabilized address reports 12154c06356bSdh142964 */ 12164c06356bSdh142964 static void 12171b115575SJohn Danielson dam_stabilize_map(void *arg) 12184c06356bSdh142964 { 12194c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 12204c06356bSdh142964 bitset_t delta; 12214c06356bSdh142964 bitset_t cfg; 12224c06356bSdh142964 bitset_t uncfg; 12234c06356bSdh142964 int has_cfg, has_uncfg; 12241b115575SJohn Danielson uint32_t i, n_active; 12251b115575SJohn Danielson 12261b115575SJohn Danielson DTRACE_PROBE2(damap__stabilize__map, char *, mapp->dam_name, 12271b115575SJohn Danielson dam_t *, mapp); 12284c06356bSdh142964 12294c06356bSdh142964 bitset_init(&delta); 12304c06356bSdh142964 bitset_resize(&delta, mapp->dam_size); 12314c06356bSdh142964 bitset_init(&cfg); 12324c06356bSdh142964 bitset_resize(&cfg, mapp->dam_size); 12334c06356bSdh142964 bitset_init(&uncfg); 12344c06356bSdh142964 bitset_resize(&uncfg, mapp->dam_size); 12354c06356bSdh142964 12361b115575SJohn Danielson /* 12371b115575SJohn Danielson * determine which addresses have changed during 12381b115575SJohn Danielson * this stabilization cycle 12391b115575SJohn Danielson */ 12401b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 12411b115575SJohn Danielson ASSERT(mapp->dam_flags & DAM_SPEND); 12424c06356bSdh142964 if (!bitset_xor(&mapp->dam_active_set, &mapp->dam_stable_set, 12434c06356bSdh142964 &delta)) { 12441b115575SJohn Danielson /* 12451b115575SJohn Danielson * no difference 12461b115575SJohn Danielson */ 12474c06356bSdh142964 bitset_zero(&mapp->dam_stable_set); 12481b115575SJohn Danielson mapp->dam_flags &= ~DAM_SPEND; 12491b115575SJohn Danielson cv_signal(&mapp->dam_cv); 12501b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 12514c06356bSdh142964 bitset_fini(&uncfg); 12524c06356bSdh142964 bitset_fini(&cfg); 12534c06356bSdh142964 bitset_fini(&delta); 12541b115575SJohn Danielson DTRACE_PROBE2(damap__stabilize__map__nochange, char *, 12551b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 12564c06356bSdh142964 return; 12574c06356bSdh142964 } 12581b115575SJohn Danielson 12591b115575SJohn Danielson /* 12601b115575SJohn Danielson * compute the sets of addresses to be activated and deactivated 12611b115575SJohn Danielson */ 12624c06356bSdh142964 has_cfg = bitset_and(&delta, &mapp->dam_stable_set, &cfg); 12634c06356bSdh142964 has_uncfg = bitset_and(&delta, &mapp->dam_active_set, &uncfg); 12641b115575SJohn Danielson 12651b115575SJohn Danielson /* 12661b115575SJohn Danielson * drop map lock while invoking callouts 12671b115575SJohn Danielson */ 12681b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 12691b115575SJohn Danielson 12701b115575SJohn Danielson /* 12711b115575SJohn Danielson * activate all newly stable addresss 12721b115575SJohn Danielson */ 12731b115575SJohn Danielson if (has_cfg) 12744c06356bSdh142964 dam_addrset_activate(mapp, &cfg); 12751b115575SJohn Danielson 12761b115575SJohn Danielson /* 12771b115575SJohn Danielson * deactivate addresss which are no longer in the map 12781b115575SJohn Danielson */ 12791b115575SJohn Danielson if (has_uncfg) 12801b115575SJohn Danielson dam_addrset_deactivate(mapp, &uncfg); 12811b115575SJohn Danielson 12821b115575SJohn Danielson 12831b115575SJohn Danielson /* 12841b115575SJohn Danielson * timestamp the last stable time and increment the kstat keeping 12851b115575SJohn Danielson * the # of of stable cycles for the map 12861b115575SJohn Danielson */ 12871b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 12884c06356bSdh142964 bitset_zero(&mapp->dam_stable_set); 12894c06356bSdh142964 mapp->dam_last_stable = gethrtime(); 12904c06356bSdh142964 mapp->dam_stable_cnt++; 12911b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_cycles); 12921b115575SJohn Danielson 12931b115575SJohn Danielson /* 12941b115575SJohn Danielson * determine the number of stable addresses 12951b115575SJohn Danielson * and update the n_active kstat for this map 12961b115575SJohn Danielson */ 12971b115575SJohn Danielson for (i = 1, n_active = 0; i < mapp->dam_high; i++) 12981b115575SJohn Danielson if (bitset_in_set(&mapp->dam_active_set, i)) 12991b115575SJohn Danielson n_active++; 13001b115575SJohn Danielson DAM_SET_STAT(mapp, dam_active, n_active); 13011b115575SJohn Danielson 13021b115575SJohn Danielson DTRACE_PROBE3(damap__map__stable__end, char *, mapp->dam_name, 13031b115575SJohn Danielson dam_t *, mapp, int, n_active); 13041b115575SJohn Danielson 13051b115575SJohn Danielson mapp->dam_flags &= ~DAM_SPEND; 13061b115575SJohn Danielson cv_signal(&mapp->dam_cv); 13071b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 13084c06356bSdh142964 bitset_fini(&uncfg); 13094c06356bSdh142964 bitset_fini(&cfg); 13104c06356bSdh142964 bitset_fini(&delta); 13114c06356bSdh142964 } 13124c06356bSdh142964 13134c06356bSdh142964 /* 13144c06356bSdh142964 * per-address stabilization timeout 13154c06356bSdh142964 */ 13164c06356bSdh142964 static void 13174c06356bSdh142964 dam_addr_stable_cb(void *arg) 13184c06356bSdh142964 { 13194c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 13204c06356bSdh142964 int i; 13214c06356bSdh142964 dam_da_t *passp; 13224c06356bSdh142964 int spend = 0; 13234c06356bSdh142964 int tpend = 0; 13244c06356bSdh142964 int64_t next_tmov = mapp->dam_stabletmo; 13254c06356bSdh142964 int64_t tmo_delta; 1326d3d50737SRafael Vanoni int64_t ts = ddi_get_lbolt64(); 13274c06356bSdh142964 13281b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 13294c06356bSdh142964 if (mapp->dam_tid == 0) { 13301b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__cancelled, char *, 13311b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 13321b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 13334c06356bSdh142964 return; 13344c06356bSdh142964 } 13354c06356bSdh142964 mapp->dam_tid = 0; 13361b115575SJohn Danielson 13374c06356bSdh142964 /* 13384c06356bSdh142964 * If still under stabilization, reschedule timeout, 13391b115575SJohn Danielson * otherwise dispatch the task to activate and deactivate the 13401b115575SJohn Danielson * new stable address 13414c06356bSdh142964 */ 13424c06356bSdh142964 if (mapp->dam_flags & DAM_SPEND) { 13431b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_overrun); 13444c06356bSdh142964 mapp->dam_stable_overrun++; 13454c06356bSdh142964 dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb); 13461b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__overrun, char *, 13471b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 13481b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 13494c06356bSdh142964 return; 13504c06356bSdh142964 } 13514c06356bSdh142964 13521b115575SJohn Danielson DAM_SET_STAT(mapp, dam_overrun, 0); 13531b115575SJohn Danielson mapp->dam_stable_overrun = 0; 13541b115575SJohn Danielson 13551b115575SJohn Danielson /* 13561b115575SJohn Danielson * copy the current active set to the stable map 13571b115575SJohn Danielson * for each address being reported, decrement its 13581b115575SJohn Danielson * stabilize deadline, and if stable, add or remove the 13591b115575SJohn Danielson * address from the stable set 13601b115575SJohn Danielson */ 13614c06356bSdh142964 bitset_copy(&mapp->dam_active_set, &mapp->dam_stable_set); 13624c06356bSdh142964 for (i = 1; i < mapp->dam_high; i++) { 13634c06356bSdh142964 if (!bitset_in_set(&mapp->dam_report_set, i)) 13644c06356bSdh142964 continue; 13654c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, i); 13664c06356bSdh142964 ASSERT(passp); 13674c06356bSdh142964 13684c06356bSdh142964 /* report has stabilized */ 13694c06356bSdh142964 if (passp->da_deadline <= ts) { 13704c06356bSdh142964 bitset_del(&mapp->dam_report_set, i); 13711b115575SJohn Danielson if (passp->da_flags & DA_RELE) 13724c06356bSdh142964 bitset_del(&mapp->dam_stable_set, i); 13731b115575SJohn Danielson else 13744c06356bSdh142964 bitset_add(&mapp->dam_stable_set, i); 13754c06356bSdh142964 spend++; 13764c06356bSdh142964 continue; 13774c06356bSdh142964 } 13784c06356bSdh142964 13794c06356bSdh142964 /* 13801b115575SJohn Danielson * not stabilized, determine next map timeout 13814c06356bSdh142964 */ 13824c06356bSdh142964 tpend++; 13834c06356bSdh142964 tmo_delta = passp->da_deadline - ts; 13844c06356bSdh142964 if (tmo_delta < next_tmov) 13854c06356bSdh142964 next_tmov = tmo_delta; 13864c06356bSdh142964 } 13874c06356bSdh142964 13884c06356bSdh142964 /* 13891b115575SJohn Danielson * schedule system_taskq activation of stabilized reports 13904c06356bSdh142964 */ 13914c06356bSdh142964 if (spend) { 13921b115575SJohn Danielson if (taskq_dispatch(system_taskq, dam_stabilize_map, 139364109744SChris Horne mapp, TQ_NOSLEEP | TQ_NOQUEUE)) { 13941b115575SJohn Danielson mapp->dam_flags |= DAM_SPEND; 13951b115575SJohn Danielson DTRACE_PROBE2(damap__map__addr__stable__start, char *, 13961b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 13971b115575SJohn Danielson } else { 13984c06356bSdh142964 tpend++; 139964109744SChris Horne 140064109744SChris Horne /* 140164109744SChris Horne * Avoid waiting the entire stabalization 140264109744SChris Horne * time again if taskq_diskpatch fails. 140364109744SChris Horne */ 140464109744SChris Horne tmo_delta = drv_usectohz( 140564109744SChris Horne damap_taskq_dispatch_retry_usec); 140664109744SChris Horne if (tmo_delta < next_tmov) 140764109744SChris Horne next_tmov = tmo_delta; 14084c06356bSdh142964 } 14091b115575SJohn Danielson } 14104c06356bSdh142964 14114c06356bSdh142964 /* 14121b115575SJohn Danielson * reschedule the stabilization timer if there are reports 14131b115575SJohn Danielson * still pending 14144c06356bSdh142964 */ 14154c06356bSdh142964 if (tpend) 14164c06356bSdh142964 dam_sched_tmo(mapp, (clock_t)next_tmov, dam_addr_stable_cb); 14171b115575SJohn Danielson 14181b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 14194c06356bSdh142964 } 14204c06356bSdh142964 14214c06356bSdh142964 /* 14221b115575SJohn Danielson * fullset stabilization timeout callback 14234c06356bSdh142964 */ 14244c06356bSdh142964 static void 14251b115575SJohn Danielson dam_addrset_stable_cb(void *arg) 14264c06356bSdh142964 { 14274c06356bSdh142964 dam_t *mapp = (dam_t *)arg; 14284c06356bSdh142964 14291b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 14304c06356bSdh142964 if (mapp->dam_tid == 0) { 14311b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 14321b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__cancelled, 14331b115575SJohn Danielson char *, mapp->dam_name, dam_t *, mapp); 14344c06356bSdh142964 return; 14354c06356bSdh142964 } 14364c06356bSdh142964 mapp->dam_tid = 0; 14374c06356bSdh142964 14384c06356bSdh142964 /* 14391b115575SJohn Danielson * If map still underoing stabilization reschedule timeout, 14401b115575SJohn Danielson * else dispatch the task to configure the new stable set of 14411b115575SJohn Danielson * addresses. 14424c06356bSdh142964 */ 144364109744SChris Horne if ((mapp->dam_flags & DAM_SPEND) || 144464109744SChris Horne (taskq_dispatch(system_taskq, dam_stabilize_map, mapp, 144564109744SChris Horne TQ_NOSLEEP | TQ_NOQUEUE) == NULL)) { 14461b115575SJohn Danielson DAM_INCR_STAT(mapp, dam_overrun); 14474c06356bSdh142964 mapp->dam_stable_overrun++; 144864109744SChris Horne dam_sched_tmo(mapp, 144964109744SChris Horne drv_usectohz(damap_taskq_dispatch_retry_usec), 145064109744SChris Horne dam_addrset_stable_cb); 145164109744SChris Horne 14521b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__overrun, char *, 14531b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 14541b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 14551b115575SJohn Danielson return; 14561b115575SJohn Danielson } 14571b115575SJohn Danielson 14581b115575SJohn Danielson DAM_SET_STAT(mapp, dam_overrun, 0); 14591b115575SJohn Danielson mapp->dam_stable_overrun = 0; 14604c06356bSdh142964 bitset_copy(&mapp->dam_report_set, &mapp->dam_stable_set); 14614c06356bSdh142964 bitset_zero(&mapp->dam_report_set); 14621b115575SJohn Danielson mapp->dam_flags |= DAM_SPEND; 14631b115575SJohn Danielson mapp->dam_flags &= ~DAM_SETADD; 14641b115575SJohn Danielson DTRACE_PROBE2(damap__map__addrset__stable__start, char *, 14651b115575SJohn Danielson mapp->dam_name, dam_t *, mapp); 14661b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 14674c06356bSdh142964 } 14684c06356bSdh142964 14694c06356bSdh142964 /* 14701b115575SJohn Danielson * schedule map timeout 'tmo_ms' ticks 14711b115575SJohn Danielson * if map timer is currently running, cancel if tmo_ms == 0 14724c06356bSdh142964 */ 14734c06356bSdh142964 static void 14744c06356bSdh142964 dam_sched_tmo(dam_t *mapp, clock_t tmo_ms, void (*tmo_cb)()) 14754c06356bSdh142964 { 14764c06356bSdh142964 timeout_id_t tid; 14774c06356bSdh142964 14781b115575SJohn Danielson DTRACE_PROBE3(damap__sched__tmo, char *, mapp->dam_name, dam_t *, mapp, 14791b115575SJohn Danielson clock_t, tmo_ms); 14804c06356bSdh142964 14811b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 14821b115575SJohn Danielson if ((tid = mapp->dam_tid) != 0) { 14831b115575SJohn Danielson if (tmo_ms == 0) { 14841b115575SJohn Danielson mapp->dam_tid = 0; 14851b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 14861b115575SJohn Danielson (void) untimeout(tid); 14871b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 14881b115575SJohn Danielson } 14891b115575SJohn Danielson } else { 14904c06356bSdh142964 if (tmo_cb && (tmo_ms != 0)) 14914c06356bSdh142964 mapp->dam_tid = timeout(tmo_cb, mapp, tmo_ms); 14924c06356bSdh142964 } 14931b115575SJohn Danielson } 14944c06356bSdh142964 14954c06356bSdh142964 /* 14961b115575SJohn Danielson * report addition or removal of an address 14974c06356bSdh142964 */ 14984c06356bSdh142964 static void 14991b115575SJohn Danielson dam_addr_report(dam_t *mapp, dam_da_t *passp, id_t addrid, int rpt_type) 15004c06356bSdh142964 { 15011b115575SJohn Danielson char *addrstr = damap_id2addr((damap_t *)mapp, addrid); 15021b115575SJohn Danielson 15031b115575SJohn Danielson DTRACE_PROBE4(damap__addr__report, char *, mapp->dam_name, 15041b115575SJohn Danielson char *, addrstr, dam_t *, mapp, int, rpt_type); 15051b115575SJohn Danielson 15061b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 15074c06356bSdh142964 ASSERT(!DAM_IN_REPORT(mapp, addrid)); 15084c06356bSdh142964 passp->da_last_report = gethrtime(); 15094c06356bSdh142964 mapp->dam_last_update = gethrtime(); 15104c06356bSdh142964 passp->da_report_cnt++; 1511d3d50737SRafael Vanoni passp->da_deadline = ddi_get_lbolt64() + mapp->dam_stabletmo; 15121b115575SJohn Danielson if (rpt_type == RPT_ADDR_DEL) 15134c06356bSdh142964 passp->da_flags |= DA_RELE; 15141b115575SJohn Danielson else if (rpt_type == RPT_ADDR_ADD) 15154c06356bSdh142964 passp->da_flags &= ~DA_RELE; 15164c06356bSdh142964 bitset_add(&mapp->dam_report_set, addrid); 15174c06356bSdh142964 dam_sched_tmo(mapp, mapp->dam_stabletmo, dam_addr_stable_cb); 15184c06356bSdh142964 } 15194c06356bSdh142964 15204c06356bSdh142964 /* 15214c06356bSdh142964 * release an address report 15224c06356bSdh142964 */ 15234c06356bSdh142964 static void 15241b115575SJohn Danielson dam_addr_report_release(dam_t *mapp, id_t addrid) 15254c06356bSdh142964 { 15264c06356bSdh142964 dam_da_t *passp; 15271b115575SJohn Danielson char *addrstr = damap_id2addr((damap_t *)mapp, addrid); 15284c06356bSdh142964 15291b115575SJohn Danielson DTRACE_PROBE3(damap__addr__report__release, char *, mapp->dam_name, 15301b115575SJohn Danielson char *, addrstr, dam_t *, mapp); 15311b115575SJohn Danielson 15321b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 15334c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 15344c06356bSdh142964 ASSERT(passp); 15351b115575SJohn Danielson /* 15361b115575SJohn Danielson * clear the report bit 15371b115575SJohn Danielson * if the address has a registered deactivation handler and 15389aed1621SDavid Hollister * we are holding a private data pointer and the address has not 15399aed1621SDavid Hollister * stabilized, deactivate the address (private data). 15401b115575SJohn Danielson */ 15411b115575SJohn Danielson bitset_del(&mapp->dam_report_set, addrid); 15429aed1621SDavid Hollister if (!DAM_IS_STABLE(mapp, addrid) && mapp->dam_deactivate_cb && 15439aed1621SDavid Hollister passp->da_ppriv_rpt) { 15441b115575SJohn Danielson mutex_exit(&mapp->dam_lock); 15451b115575SJohn Danielson (*mapp->dam_deactivate_cb)(mapp->dam_activate_arg, 15461b115575SJohn Danielson ddi_strid_id2str(mapp->dam_addr_hash, addrid), 15479aed1621SDavid Hollister addrid, passp->da_ppriv_rpt, DAMAP_DEACT_RSN_UNSTBL); 15481b115575SJohn Danielson mutex_enter(&mapp->dam_lock); 15491b115575SJohn Danielson } 15504c06356bSdh142964 passp->da_ppriv_rpt = NULL; 15514c06356bSdh142964 if (passp->da_nvl_rpt) 15524c06356bSdh142964 nvlist_free(passp->da_nvl_rpt); 15534c06356bSdh142964 } 15544c06356bSdh142964 15554c06356bSdh142964 /* 15564c06356bSdh142964 * return the map ID of an address 15574c06356bSdh142964 */ 15584c06356bSdh142964 static id_t 15594c06356bSdh142964 dam_get_addrid(dam_t *mapp, char *address) 15604c06356bSdh142964 { 15614c06356bSdh142964 damap_id_t addrid; 15624c06356bSdh142964 dam_da_t *passp; 15634c06356bSdh142964 15641b115575SJohn Danielson ASSERT(mutex_owned(&mapp->dam_lock)); 15654c06356bSdh142964 if ((addrid = ddi_strid_str2id(mapp->dam_addr_hash, address)) == 0) { 15661b115575SJohn Danielson if ((addrid = ddi_strid_alloc(mapp->dam_addr_hash, 15674c06356bSdh142964 address)) == (damap_id_t)0) { 15684c06356bSdh142964 return (0); 15694c06356bSdh142964 } 15704c06356bSdh142964 if (ddi_soft_state_zalloc(mapp->dam_da, addrid) != 15714c06356bSdh142964 DDI_SUCCESS) { 15724c06356bSdh142964 ddi_strid_free(mapp->dam_addr_hash, addrid); 15734c06356bSdh142964 return (0); 15744c06356bSdh142964 } 15751b115575SJohn Danielson 15764c06356bSdh142964 if (addrid >= mapp->dam_high) 15774c06356bSdh142964 mapp->dam_high = addrid + 1; 15781b115575SJohn Danielson 15791b115575SJohn Danielson /* 15801b115575SJohn Danielson * expand bitmaps if ID has outgrown old map size 15811b115575SJohn Danielson */ 15821b115575SJohn Danielson if (mapp->dam_high > mapp->dam_size) { 15831b115575SJohn Danielson mapp->dam_size = mapp->dam_size + DAM_SIZE_BUMP; 15841b115575SJohn Danielson bitset_resize(&mapp->dam_active_set, mapp->dam_size); 15851b115575SJohn Danielson bitset_resize(&mapp->dam_stable_set, mapp->dam_size); 15861b115575SJohn Danielson bitset_resize(&mapp->dam_report_set, mapp->dam_size); 15874c06356bSdh142964 } 15881b115575SJohn Danielson 15894c06356bSdh142964 passp = ddi_get_soft_state(mapp->dam_da, addrid); 15901b115575SJohn Danielson passp->da_ref = 1; 15911b115575SJohn Danielson passp->da_addr = ddi_strid_id2str(mapp->dam_addr_hash, 15921b115575SJohn Danielson addrid); /* for mdb */ 15931b115575SJohn Danielson } 15944c06356bSdh142964 return (addrid); 15954c06356bSdh142964 } 15964c06356bSdh142964 15974c06356bSdh142964 /* 15984c06356bSdh142964 * create and install map statistics 15994c06356bSdh142964 */ 16004c06356bSdh142964 static int 16014c06356bSdh142964 dam_kstat_create(dam_t *mapp) 16024c06356bSdh142964 { 16034c06356bSdh142964 kstat_t *mapsp; 16044c06356bSdh142964 struct dam_kstats *statsp; 16054c06356bSdh142964 16064c06356bSdh142964 mapsp = kstat_create("dam", 0, mapp->dam_name, "damap", 16074c06356bSdh142964 KSTAT_TYPE_NAMED, 16084c06356bSdh142964 sizeof (struct dam_kstats) / sizeof (kstat_named_t), 0); 16091b115575SJohn Danielson 16101b115575SJohn Danielson if (mapsp == NULL) 16114c06356bSdh142964 return (DDI_FAILURE); 16124c06356bSdh142964 16134c06356bSdh142964 statsp = (struct dam_kstats *)mapsp->ks_data; 16141b115575SJohn Danielson kstat_named_init(&statsp->dam_cycles, "cycles", KSTAT_DATA_UINT32); 16151b115575SJohn Danielson kstat_named_init(&statsp->dam_overrun, "overrun", KSTAT_DATA_UINT32); 16161b115575SJohn Danielson kstat_named_init(&statsp->dam_jitter, "jitter", KSTAT_DATA_UINT32); 16171b115575SJohn Danielson kstat_named_init(&statsp->dam_active, "active", KSTAT_DATA_UINT32); 16184c06356bSdh142964 kstat_install(mapsp); 16194c06356bSdh142964 mapp->dam_kstatsp = mapsp; 16204c06356bSdh142964 return (DDI_SUCCESS); 16214c06356bSdh142964 } 1622