17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*d62bc4baSyz147064 * Common Development and Distribution License (the "License"). 6*d62bc4baSyz147064 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*d62bc4baSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * DACF: device autoconfiguration support 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * DACF provides a fast, lightweight policy engine for the I/O subsystem. 327c478bd9Sstevel@tonic-gate * This policy engine provides a mechanism for auto-configuring and 337c478bd9Sstevel@tonic-gate * auto-unconfiguring devices. 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * After a device is attach(9E)ed, additional configuration may be needed in 367c478bd9Sstevel@tonic-gate * order to make the device available for use by the system. For example, 377c478bd9Sstevel@tonic-gate * STREAMS modules may need to be pushed atop the driver in order to create 387c478bd9Sstevel@tonic-gate * a STREAMS stack. If the device is to be removed from the system, these 397c478bd9Sstevel@tonic-gate * configuration operations need to be undone, and the device prepared for 407c478bd9Sstevel@tonic-gate * detach(9E). 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * It is desirable to move the implementation of such policies outside of the 437c478bd9Sstevel@tonic-gate * kernel proper, since such operations are typically infrequent. To this end, 447c478bd9Sstevel@tonic-gate * DACF manages kernel modules in (module_path)/dacf directories. These adhere 457c478bd9Sstevel@tonic-gate * to the api defined in sys/dacf.h, and register sets of configuration 467c478bd9Sstevel@tonic-gate * operations. The kernel loads these modules when the operations they 477c478bd9Sstevel@tonic-gate * implement are needed, and can unload them at any time thereafter. 487c478bd9Sstevel@tonic-gate * Implementing configuration operations in external modules can also increase 497c478bd9Sstevel@tonic-gate * code reuse. 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * DACF provides a policy database which associates 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * (device descr., kernel action) --> (configuration operation, parameters) 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * - Device description is matching rule, for example: 567c478bd9Sstevel@tonic-gate * minor-nodetype="ddi_keyboard" 577c478bd9Sstevel@tonic-gate * - Kernel action is a reference to a dacf kernel hook. 587c478bd9Sstevel@tonic-gate * currently supported are "post-attach" and "pre-detach" 597c478bd9Sstevel@tonic-gate * - Configuration action is a reference to a module and a set of operations 607c478bd9Sstevel@tonic-gate * within the module, for example: consconfig:kbd_config 617c478bd9Sstevel@tonic-gate * - Parameters is a list of name="value" parameters to be passed to the 627c478bd9Sstevel@tonic-gate * configuration operation when invoked. 637c478bd9Sstevel@tonic-gate * 647c478bd9Sstevel@tonic-gate * The contents of the rules database are loaded from /etc/dacf.conf upon boot. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * DACF kernel hooks are comprised of a call into the rule-matching engine, 677c478bd9Sstevel@tonic-gate * using parameters from the hook in order find a matching rule. If one is 687c478bd9Sstevel@tonic-gate * found, the framework can invoke the configuration operation immediately, or 697c478bd9Sstevel@tonic-gate * defer doing so until later, by putting the rule on a 'reservation list.' 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #include <sys/param.h> 737c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 747c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 757c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 767c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 777c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 787c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 797c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 807c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 817c478bd9Sstevel@tonic-gate #include <sys/modhash.h> 827c478bd9Sstevel@tonic-gate #include <sys/dacf.h> 837c478bd9Sstevel@tonic-gate #include <sys/dacf_impl.h> 847c478bd9Sstevel@tonic-gate #include <sys/systm.h> 857c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 867c478bd9Sstevel@tonic-gate #include <sys/debug.h> 877c478bd9Sstevel@tonic-gate #include <sys/log.h> 887c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h> 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Enumeration of the ops exported by the dacf framework. 927c478bd9Sstevel@tonic-gate * 937c478bd9Sstevel@tonic-gate * To add a new op to the framework, add it to this list, update dacf.h, 947c478bd9Sstevel@tonic-gate * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix. 957c478bd9Sstevel@tonic-gate * 967c478bd9Sstevel@tonic-gate */ 977c478bd9Sstevel@tonic-gate typedef struct dacf_opmap { 987c478bd9Sstevel@tonic-gate const char *name; 997c478bd9Sstevel@tonic-gate dacf_opid_t id; 1007c478bd9Sstevel@tonic-gate } dacf_opmap_t; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static dacf_opmap_t dacf_ops[] = { 1037c478bd9Sstevel@tonic-gate { "post-attach", DACF_OPID_POSTATTACH }, 1047c478bd9Sstevel@tonic-gate { "pre-detach", DACF_OPID_PREDETACH }, 1057c478bd9Sstevel@tonic-gate { NULL, 0 }, 1067c478bd9Sstevel@tonic-gate }; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * Enumeration of the options exported by the dacf framework (currently none). 1107c478bd9Sstevel@tonic-gate * 1117c478bd9Sstevel@tonic-gate * To add a new option, add it to this array. 1127c478bd9Sstevel@tonic-gate */ 1137c478bd9Sstevel@tonic-gate typedef struct dacf_opt { 1147c478bd9Sstevel@tonic-gate const char *optname; 1157c478bd9Sstevel@tonic-gate uint_t optmask; 1167c478bd9Sstevel@tonic-gate } dacf_opt_t; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static dacf_opt_t dacf_options[] = { 1197c478bd9Sstevel@tonic-gate #ifdef DEBUG 1207c478bd9Sstevel@tonic-gate { "testopt", 1 }, 1217c478bd9Sstevel@tonic-gate { "testopt2", 2 }, 1227c478bd9Sstevel@tonic-gate #endif 1237c478bd9Sstevel@tonic-gate { NULL, 0 }, 1247c478bd9Sstevel@tonic-gate }; 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate static char kmod_name[] = "__kernel"; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * Enumeration of the device specifiers exported by the dacf framework. 1307c478bd9Sstevel@tonic-gate * 1317c478bd9Sstevel@tonic-gate * To add a new devspec to the framework, add it to this list, update dacf.h, 1327c478bd9Sstevel@tonic-gate * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify 1337c478bd9Sstevel@tonic-gate * dacf_match(). 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate typedef struct dacf_ds { 1367c478bd9Sstevel@tonic-gate const char *name; 1377c478bd9Sstevel@tonic-gate dacf_devspec_t id; 1387c478bd9Sstevel@tonic-gate } dacf_ds_t; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate static dacf_ds_t dacf_devspecs[] = { 1417c478bd9Sstevel@tonic-gate { "minor-nodetype", DACF_DS_MIN_NT }, 1427c478bd9Sstevel@tonic-gate { "driver-minorname", DACF_DS_DRV_MNAME }, 1437c478bd9Sstevel@tonic-gate { "device-path", DACF_DS_DEV_PATH }, 1447c478bd9Sstevel@tonic-gate { NULL, NULL }, 1457c478bd9Sstevel@tonic-gate }; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate mod_hash_t *posta_mntype, *posta_mname, *posta_devname; /* post-attach */ 1487c478bd9Sstevel@tonic-gate mod_hash_t *pred_mntype, *pred_mname, *pred_devname; /* pre-detach */ 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate mod_hash_t *dacf_module_hash; 1517c478bd9Sstevel@tonic-gate mod_hash_t *dacf_info_hash; 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * This is the lookup table for the hash tables that dacf manages. Given an 1557c478bd9Sstevel@tonic-gate * op id and devspec type, one can obtain the hash for that type of data. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate mod_hash_t **dacf_rule_matrix[DACF_NUM_OPIDS][DACF_NUM_DEVSPECS] = { 1587c478bd9Sstevel@tonic-gate { &posta_mntype, &posta_mname, &posta_devname }, 1597c478bd9Sstevel@tonic-gate { &pred_mntype, &pred_mname, &pred_devname }, 1607c478bd9Sstevel@tonic-gate }; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate kmutex_t dacf_lock; 1637c478bd9Sstevel@tonic-gate kmutex_t dacf_module_lock; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate int dacfdebug = 0; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate static dacf_rule_t *dacf_rule_ctor(char *, char *, char *, dacf_opid_t, 1687c478bd9Sstevel@tonic-gate uint_t, dacf_arg_t *); 1697c478bd9Sstevel@tonic-gate static mod_hash_t *dacf_get_op_hash(dacf_opid_t, dacf_devspec_t); 1707c478bd9Sstevel@tonic-gate static void dacf_rule_val_dtor(mod_hash_val_t); 1717c478bd9Sstevel@tonic-gate static void dacf_destroy_opsets(dacf_module_t *module); 1727c478bd9Sstevel@tonic-gate static void dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src); 1737c478bd9Sstevel@tonic-gate static void dprintf(const char *, ...) __KPRINTFLIKE(1); 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 1767c478bd9Sstevel@tonic-gate static void 1777c478bd9Sstevel@tonic-gate dprintf(const char *format, ...) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate va_list alist; 1807c478bd9Sstevel@tonic-gate char dp_buf[256], *dpbp; 1817c478bd9Sstevel@tonic-gate if (dacfdebug & DACF_DBG_MSGS) { 1827c478bd9Sstevel@tonic-gate va_start(alist, format); 1837c478bd9Sstevel@tonic-gate /* 1847c478bd9Sstevel@tonic-gate * sprintf up the string that is 'dacf debug: <the message>' 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate (void) sprintf(dp_buf, "dacf debug: "); 1877c478bd9Sstevel@tonic-gate dpbp = &(dp_buf[strlen(dp_buf)]); 1887c478bd9Sstevel@tonic-gate (void) vsnprintf(dpbp, sizeof (dp_buf) - strlen(dp_buf), 1897c478bd9Sstevel@tonic-gate format, alist); 1907c478bd9Sstevel@tonic-gate printf(dp_buf); 1917c478bd9Sstevel@tonic-gate va_end(alist); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * dacf_init() 1977c478bd9Sstevel@tonic-gate * initialize the dacf framework by creating the various hash tables. 1987c478bd9Sstevel@tonic-gate */ 1997c478bd9Sstevel@tonic-gate void 2007c478bd9Sstevel@tonic-gate dacf_init() 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate int i, j; 2037c478bd9Sstevel@tonic-gate char hbuf[40]; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate mutex_enter(&dacf_lock); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate dprintf("dacf_init: creating hashmatrix\n"); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate #ifdef DEBUG 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync 2127c478bd9Sstevel@tonic-gate */ 2137c478bd9Sstevel@tonic-gate for (i = 0; dacf_devspecs[i].name != NULL; i++) 2147c478bd9Sstevel@tonic-gate continue; 2157c478bd9Sstevel@tonic-gate ASSERT(i == DACF_NUM_DEVSPECS); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate /* 2187c478bd9Sstevel@tonic-gate * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate for (i = 0; dacf_ops[i].name != NULL; i++) 2217c478bd9Sstevel@tonic-gate continue; 2227c478bd9Sstevel@tonic-gate ASSERT(i == DACF_NUM_OPIDS); 2237c478bd9Sstevel@tonic-gate #endif 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate for (i = 0; i < DACF_NUM_OPIDS; i++) { 2267c478bd9Sstevel@tonic-gate for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 2277c478bd9Sstevel@tonic-gate if (dacf_rule_matrix[i][j] == NULL) { 2287c478bd9Sstevel@tonic-gate continue; 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Set up a hash table with no key destructor. The 2327c478bd9Sstevel@tonic-gate * keys are carried in the rule_t, so the val_dtor 2337c478bd9Sstevel@tonic-gate * will take care of the key as well. 2347c478bd9Sstevel@tonic-gate */ 2357c478bd9Sstevel@tonic-gate (void) snprintf(hbuf, sizeof (hbuf), 2367c478bd9Sstevel@tonic-gate "dacf hashmatrix [%d][%d]", i, j); 2377c478bd9Sstevel@tonic-gate *(dacf_rule_matrix[i][j]) = mod_hash_create_extended( 2387c478bd9Sstevel@tonic-gate hbuf, /* hash name */ 2397c478bd9Sstevel@tonic-gate DACF_RULE_HASHSIZE, /* # hash elems */ 2407c478bd9Sstevel@tonic-gate mod_hash_null_keydtor, /* key dtor */ 2417c478bd9Sstevel@tonic-gate dacf_rule_val_dtor, /* value dtor */ 2427c478bd9Sstevel@tonic-gate mod_hash_bystr, NULL, /* hash alg & data */ 2437c478bd9Sstevel@tonic-gate mod_hash_strkey_cmp, /* key comparator */ 2447c478bd9Sstevel@tonic-gate KM_SLEEP); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate dprintf("dacf_init: creating module_hash\n"); 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * dacf_module_hash stores the currently registered dacf modules 2517c478bd9Sstevel@tonic-gate * by name. 2527c478bd9Sstevel@tonic-gate */ 2537c478bd9Sstevel@tonic-gate dacf_module_hash = mod_hash_create_strhash("dacf module hash", 2547c478bd9Sstevel@tonic-gate DACF_MODULE_HASHSIZE, mod_hash_null_valdtor); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate dprintf("dacf_init: creating info_hash\n"); 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * dacf_info_hash stores pointers to data that modules can associate 2597c478bd9Sstevel@tonic-gate * on a per minornode basis. The type of data stored is opaque to the 2607c478bd9Sstevel@tonic-gate * framework-- thus there is no destructor supplied. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate dacf_info_hash = mod_hash_create_ptrhash("dacf info hash", 2637c478bd9Sstevel@tonic-gate DACF_INFO_HASHSIZE, mod_hash_null_valdtor, 2647c478bd9Sstevel@tonic-gate sizeof (struct ddi_minor_data)); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate mutex_exit(&dacf_lock); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate /* 2697c478bd9Sstevel@tonic-gate * Register the '__kernel' module. 2707c478bd9Sstevel@tonic-gate * 2717c478bd9Sstevel@tonic-gate * These are operations that are provided by the kernel, not by a 2727c478bd9Sstevel@tonic-gate * module. We just feed the framework a dacfsw structure; it will get 2737c478bd9Sstevel@tonic-gate * marked as 'loaded' by dacf_module_register(), and will always be 2747c478bd9Sstevel@tonic-gate * available. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate (void) dacf_module_register(kmod_name, &kmod_dacfsw); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate (void) read_dacf_binding_file(NULL); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate dprintf("dacf_init: dacf is ready\n"); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate /* 2847c478bd9Sstevel@tonic-gate * dacf_clear_rules() 2857c478bd9Sstevel@tonic-gate * clear the dacf rule database. This is typically done in advance of 2867c478bd9Sstevel@tonic-gate * rereading the dacf binding file. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate void 2897c478bd9Sstevel@tonic-gate dacf_clear_rules() 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate int i, j; 2927c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate for (i = 0; i < DACF_NUM_OPIDS; i++) { 2957c478bd9Sstevel@tonic-gate for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 2967c478bd9Sstevel@tonic-gate if ((dacf_rule_matrix[i][j] != NULL) && 2977c478bd9Sstevel@tonic-gate (*(dacf_rule_matrix[i][j]) != NULL)) { 2987c478bd9Sstevel@tonic-gate mod_hash_clear(*(dacf_rule_matrix[i][j])); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * dacf_rule_insert() 3067c478bd9Sstevel@tonic-gate * Create an entry in the dacf rule database. 3077c478bd9Sstevel@tonic-gate * If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()). 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate int 3107c478bd9Sstevel@tonic-gate dacf_rule_insert(dacf_devspec_t devspec_type, char *devspec_data, 3117c478bd9Sstevel@tonic-gate char *module, char *opset, dacf_opid_t opid, uint_t opts, 3127c478bd9Sstevel@tonic-gate dacf_arg_t *op_args) 3137c478bd9Sstevel@tonic-gate { 3147c478bd9Sstevel@tonic-gate dacf_rule_t *rule; 3157c478bd9Sstevel@tonic-gate mod_hash_t *hash; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate ASSERT(devspec_type != DACF_DS_ERROR); 3187c478bd9Sstevel@tonic-gate ASSERT(devspec_data); 3197c478bd9Sstevel@tonic-gate ASSERT(opset); 3207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n", 3237c478bd9Sstevel@tonic-gate dacf_devspec_to_str(devspec_type), devspec_data, 3247c478bd9Sstevel@tonic-gate module ? module : "[kernel]", opset, dacf_opid_to_str(opid)); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * Fetch the hash table associated with this op-name and devspec-type. 3287c478bd9Sstevel@tonic-gate * Some ops may not support all devspec-types, since they may be 3297c478bd9Sstevel@tonic-gate * meaningless, so hash may be null. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate hash = dacf_get_op_hash(opid, devspec_type); 3327c478bd9Sstevel@tonic-gate if (hash == NULL) { 3337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf dev-spec '%s' does not support op '%s'", 3347c478bd9Sstevel@tonic-gate dacf_devspec_to_str(devspec_type), dacf_opid_to_str(opid)); 3357c478bd9Sstevel@tonic-gate return (-1); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate /* 3397c478bd9Sstevel@tonic-gate * Allocate a rule and fill it in, take a hold on it. 3407c478bd9Sstevel@tonic-gate */ 3417c478bd9Sstevel@tonic-gate rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts, 3427c478bd9Sstevel@tonic-gate op_args); 3437c478bd9Sstevel@tonic-gate dacf_rule_hold(rule); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data, 3467c478bd9Sstevel@tonic-gate (mod_hash_val_t)rule) != 0) { 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * We failed, so release hold. This will cause the rule and 3497c478bd9Sstevel@tonic-gate * associated data to get nuked. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate dacf_rule_rele(rule); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf rule %s='%s' %s:%s %s duplicates " 3547c478bd9Sstevel@tonic-gate "another rule, ignored", dacf_devspec_to_str(devspec_type), 3557c478bd9Sstevel@tonic-gate devspec_data, module, opset, dacf_opid_to_str(opid)); 3567c478bd9Sstevel@tonic-gate return (-1); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate return (0); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * dacf_rule_ctor() 3637c478bd9Sstevel@tonic-gate * Allocate and fill out entries in a dacf_rule_t. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate static dacf_rule_t * 3667c478bd9Sstevel@tonic-gate dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid, 3677c478bd9Sstevel@tonic-gate uint_t opts, dacf_arg_t *op_args) 3687c478bd9Sstevel@tonic-gate { 3697c478bd9Sstevel@tonic-gate dacf_rule_t *rule; 3707c478bd9Sstevel@tonic-gate dacf_arg_t *p; 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * Fill in the entries 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP); 3787c478bd9Sstevel@tonic-gate (void) strcpy(rule->r_devspec_data, device_spec); 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * If module is 'null' we set it to __kernel, meaning that this op 3827c478bd9Sstevel@tonic-gate * is implemented by the kernel. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate if (module == NULL) { 3857c478bd9Sstevel@tonic-gate module = kmod_name; 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP); 3897c478bd9Sstevel@tonic-gate (void) strcpy(rule->r_module, module); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP); 3927c478bd9Sstevel@tonic-gate (void) strcpy(rule->r_opset, opset); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate rule->r_refs = 0; /* no refs yet */ 3957c478bd9Sstevel@tonic-gate rule->r_opts = opts; 3967c478bd9Sstevel@tonic-gate rule->r_opid = opid; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate rule->r_args = NULL; 3997c478bd9Sstevel@tonic-gate p = op_args; 4007c478bd9Sstevel@tonic-gate while (p != NULL) { 4017c478bd9Sstevel@tonic-gate ASSERT(p->arg_name); 4027c478bd9Sstevel@tonic-gate ASSERT(p->arg_val); 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * dacf_arg_insert() should always succeed, since we're copying 4057c478bd9Sstevel@tonic-gate * another (already duplicate-free) list. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate (void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val); 4087c478bd9Sstevel@tonic-gate p = p->arg_next; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate return (rule); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate /* 4157c478bd9Sstevel@tonic-gate * dacf_rule_val_dtor() 4167c478bd9Sstevel@tonic-gate * This is the destructor for dacf_rule_t's in the rule database. It 4177c478bd9Sstevel@tonic-gate * simply does a dacf_rule_rele() on the rule. This function will take 4187c478bd9Sstevel@tonic-gate * care of destroying the rule if its ref count has dropped to 0. 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate static void 4217c478bd9Sstevel@tonic-gate dacf_rule_val_dtor(mod_hash_val_t val) 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate ASSERT((void *)val != NULL); 4247c478bd9Sstevel@tonic-gate dacf_rule_rele((dacf_rule_t *)val); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * dacf_rule_destroy() 4297c478bd9Sstevel@tonic-gate * destroy a dacf_rule_t 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate void 4327c478bd9Sstevel@tonic-gate dacf_rule_destroy(dacf_rule_t *rule) 4337c478bd9Sstevel@tonic-gate { 4347c478bd9Sstevel@tonic-gate ASSERT(rule->r_refs == 0); 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * Free arguments. 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate dacf_arglist_delete(&(rule->r_args)); 4397c478bd9Sstevel@tonic-gate kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1); 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * Module may be null for a kernel-managed op-set 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate kmem_free(rule->r_module, strlen(rule->r_module) + 1); 4447c478bd9Sstevel@tonic-gate kmem_free(rule->r_opset, strlen(rule->r_opset) + 1); 4457c478bd9Sstevel@tonic-gate kmem_free(rule, sizeof (dacf_rule_t)); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * dacf_rule_hold() 4507c478bd9Sstevel@tonic-gate * dacf rules are ref-counted. This function increases the reference 4517c478bd9Sstevel@tonic-gate * count on an rule. 4527c478bd9Sstevel@tonic-gate */ 4537c478bd9Sstevel@tonic-gate void 4547c478bd9Sstevel@tonic-gate dacf_rule_hold(dacf_rule_t *rule) 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate rule->r_refs++; 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * dacf_rule_rele() 4637c478bd9Sstevel@tonic-gate * drop the ref count on an rule, and destroy the rule if its 4647c478bd9Sstevel@tonic-gate * ref count drops to 0. 4657c478bd9Sstevel@tonic-gate */ 4667c478bd9Sstevel@tonic-gate void 4677c478bd9Sstevel@tonic-gate dacf_rule_rele(dacf_rule_t *rule) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 4707c478bd9Sstevel@tonic-gate ASSERT(rule->r_refs > 0); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate rule->r_refs--; 4737c478bd9Sstevel@tonic-gate if (rule->r_refs == 0) { 4747c478bd9Sstevel@tonic-gate dacf_rule_destroy(rule); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * dacf_rsrv_make() 4807c478bd9Sstevel@tonic-gate * add an rule to a reservation list to be processed later. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate void 4837c478bd9Sstevel@tonic-gate dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info, 4847c478bd9Sstevel@tonic-gate dacf_rsrvlist_t **list) 4857c478bd9Sstevel@tonic-gate { 4867c478bd9Sstevel@tonic-gate dacf_infohdl_t ihdl = info; 4877c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 4887c478bd9Sstevel@tonic-gate ASSERT(info && rule && list); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * Bump the ref count on rule, so it won't get freed as long as it's on 4927c478bd9Sstevel@tonic-gate * this reservation list. 4937c478bd9Sstevel@tonic-gate */ 4947c478bd9Sstevel@tonic-gate dacf_rule_hold(rule); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate rsrv->rsrv_rule = rule; 4977c478bd9Sstevel@tonic-gate rsrv->rsrv_ihdl = ihdl; 4987c478bd9Sstevel@tonic-gate rsrv->rsrv_result = DDI_SUCCESS; 4997c478bd9Sstevel@tonic-gate rsrv->rsrv_next = *list; 5007c478bd9Sstevel@tonic-gate *list = rsrv; 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate dprintf("dacf: reservation made\n"); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * dacf_clr_rsrvs() 5077c478bd9Sstevel@tonic-gate * clear reservation list of operations of type 'op' 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate void 5107c478bd9Sstevel@tonic-gate dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op) 5117c478bd9Sstevel@tonic-gate { 5127c478bd9Sstevel@tonic-gate dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * dacf_process_rsrvs() 5177c478bd9Sstevel@tonic-gate * iterate across a locked reservation list, processing each element 5187c478bd9Sstevel@tonic-gate * which matches 'op' according to 'flags'. 5197c478bd9Sstevel@tonic-gate * 5207c478bd9Sstevel@tonic-gate * if DACF_PROC_INVOKE is specified, the elements that match 'op' 5217c478bd9Sstevel@tonic-gate * will have their operations invoked. The return value from that 5227c478bd9Sstevel@tonic-gate * operation is placed in the rsrv_result field of the dacf_rsrvlist_t 5237c478bd9Sstevel@tonic-gate */ 5247c478bd9Sstevel@tonic-gate void 5257c478bd9Sstevel@tonic-gate dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags) 5267c478bd9Sstevel@tonic-gate { 5277c478bd9Sstevel@tonic-gate dacf_rsrvlist_t *p, *dp; 5287c478bd9Sstevel@tonic-gate dacf_rsrvlist_t **prevptr; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 5317c478bd9Sstevel@tonic-gate ASSERT(list); 5327c478bd9Sstevel@tonic-gate ASSERT(flags != 0); 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (*list == NULL) 5357c478bd9Sstevel@tonic-gate return; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags); 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate /* 5407c478bd9Sstevel@tonic-gate * Walk the list, finding rules whose opid's match op, and performing 5417c478bd9Sstevel@tonic-gate * the work described by 'flags'. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate prevptr = list; 5447c478bd9Sstevel@tonic-gate for (p = *list; p != NULL; ) { 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate if (p->rsrv_rule->r_opid != op) { 5477c478bd9Sstevel@tonic-gate prevptr = &(p->rsrv_next); 5487c478bd9Sstevel@tonic-gate p = p->rsrv_next; 5497c478bd9Sstevel@tonic-gate continue; 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (flags & DACF_PROC_INVOKE) { 5537c478bd9Sstevel@tonic-gate p->rsrv_result = dacf_op_invoke(p->rsrv_rule, 5547c478bd9Sstevel@tonic-gate p->rsrv_ihdl, 0); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate if (flags & DACF_PROC_RELE) { 5587c478bd9Sstevel@tonic-gate *prevptr = p->rsrv_next; 5597c478bd9Sstevel@tonic-gate dp = p; 5607c478bd9Sstevel@tonic-gate p = p->rsrv_next; 5617c478bd9Sstevel@tonic-gate dacf_rule_rele(dp->rsrv_rule); 5627c478bd9Sstevel@tonic-gate kmem_free(dp, sizeof (dacf_rsrvlist_t)); 5637c478bd9Sstevel@tonic-gate } else { 5647c478bd9Sstevel@tonic-gate prevptr = &(p->rsrv_next); 5657c478bd9Sstevel@tonic-gate p = p->rsrv_next; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * dacf_get_op_hash() 5727c478bd9Sstevel@tonic-gate * Given an op name, (i.e. "post-attach" or "pre-detach") and a 5737c478bd9Sstevel@tonic-gate * devspec-type, return the hash that represents that op indexed 5747c478bd9Sstevel@tonic-gate * by that devspec. 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate static mod_hash_t * 5777c478bd9Sstevel@tonic-gate dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type) 5787c478bd9Sstevel@tonic-gate { 5797c478bd9Sstevel@tonic-gate ASSERT(op <= DACF_NUM_OPIDS && op > 0); 5807c478bd9Sstevel@tonic-gate ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * dacf_rule_matrix is an array of pointers to pointers to hashes. 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) { 5867c478bd9Sstevel@tonic-gate return (NULL); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate return (*(dacf_rule_matrix[op - 1][ds_type - 1])); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * dacf_arg_insert() 5937c478bd9Sstevel@tonic-gate * Create and insert an entry in an argument list. 5947c478bd9Sstevel@tonic-gate * Returns -1 if the argument name is a duplicate of another already 5957c478bd9Sstevel@tonic-gate * present in the hash. 5967c478bd9Sstevel@tonic-gate */ 5977c478bd9Sstevel@tonic-gate int 5987c478bd9Sstevel@tonic-gate dacf_arg_insert(dacf_arg_t **list, char *name, char *val) 5997c478bd9Sstevel@tonic-gate { 6007c478bd9Sstevel@tonic-gate dacf_arg_t *arg; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * Don't allow duplicates. 6047c478bd9Sstevel@tonic-gate */ 6057c478bd9Sstevel@tonic-gate for (arg = *list; arg != NULL; arg = arg->arg_next) { 6067c478bd9Sstevel@tonic-gate if (strcmp(arg->arg_name, name) == 0) { 6077c478bd9Sstevel@tonic-gate return (-1); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate arg = kmem_alloc(sizeof (dacf_arg_t), KM_SLEEP); 6127c478bd9Sstevel@tonic-gate arg->arg_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 6137c478bd9Sstevel@tonic-gate (void) strcpy(arg->arg_name, name); 6147c478bd9Sstevel@tonic-gate arg->arg_val = kmem_alloc(strlen(val) + 1, KM_SLEEP); 6157c478bd9Sstevel@tonic-gate (void) strcpy(arg->arg_val, val); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate arg->arg_next = *list; 6187c478bd9Sstevel@tonic-gate *list = arg; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate return (0); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate /* 6247c478bd9Sstevel@tonic-gate * dacf_arglist_delete() 6257c478bd9Sstevel@tonic-gate * free all the elements of a list of dacf_arg_t's. 6267c478bd9Sstevel@tonic-gate */ 6277c478bd9Sstevel@tonic-gate void 6287c478bd9Sstevel@tonic-gate dacf_arglist_delete(dacf_arg_t **list) 6297c478bd9Sstevel@tonic-gate { 6307c478bd9Sstevel@tonic-gate dacf_arg_t *arg, *narg; 6317c478bd9Sstevel@tonic-gate arg = *list; 6327c478bd9Sstevel@tonic-gate while (arg != NULL) { 6337c478bd9Sstevel@tonic-gate narg = arg->arg_next; 6347c478bd9Sstevel@tonic-gate kmem_free(arg->arg_name, strlen(arg->arg_name) + 1); 6357c478bd9Sstevel@tonic-gate kmem_free(arg->arg_val, strlen(arg->arg_val) + 1); 6367c478bd9Sstevel@tonic-gate kmem_free(arg, sizeof (dacf_arg_t)); 6377c478bd9Sstevel@tonic-gate arg = narg; 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate *list = NULL; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * dacf_match() 6447c478bd9Sstevel@tonic-gate * Match a device-spec to a rule. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate dacf_rule_t * 6477c478bd9Sstevel@tonic-gate dacf_match(dacf_opid_t op, dacf_devspec_t ds, void *match_info) 6487c478bd9Sstevel@tonic-gate { 6497c478bd9Sstevel@tonic-gate dacf_rule_t *rule; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if (mod_hash_find(dacf_get_op_hash(op, ds), (mod_hash_key_t)match_info, 6547c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&rule) == 0) { 6557c478bd9Sstevel@tonic-gate return (rule); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate return (NULL); /* Not Found */ 6597c478bd9Sstevel@tonic-gate } 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * dacf_module_register() 6637c478bd9Sstevel@tonic-gate * register a module with the framework. Use when a module gets loaded, 6647c478bd9Sstevel@tonic-gate * or for the kernel to register a "virtual" module (i.e. a "module" 6657c478bd9Sstevel@tonic-gate * which the kernel provides). Makes a copy of the interface description 6667c478bd9Sstevel@tonic-gate * provided by the module. 6677c478bd9Sstevel@tonic-gate */ 6687c478bd9Sstevel@tonic-gate int 6697c478bd9Sstevel@tonic-gate dacf_module_register(char *mod_name, struct dacfsw *sw) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate char *str; 6727c478bd9Sstevel@tonic-gate size_t i, nelems; 6737c478bd9Sstevel@tonic-gate dacf_module_t *module; 6747c478bd9Sstevel@tonic-gate dacf_opset_t *opsarray; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (sw == NULL) { 6777c478bd9Sstevel@tonic-gate return (EINVAL); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if (sw->dacf_rev != DACF_MODREV_1) { 6817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "dacf: module '%s' exports unsupported " 6827c478bd9Sstevel@tonic-gate "version %d interface, not registered\n", mod_name, 6837c478bd9Sstevel@tonic-gate sw->dacf_rev); 6847c478bd9Sstevel@tonic-gate return (EINVAL); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * count how many opsets are provided. 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++) 6917c478bd9Sstevel@tonic-gate ; 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate dprintf("dacf_module_register: found %lu opsets\n", nelems); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * Temporary: It's ok for the kernel dacf_sw to have no opsets, since 6977c478bd9Sstevel@tonic-gate * we don't have any opsets to export yet (in NON-DEBUG). 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate if ((nelems == 0) && (sw != &kmod_dacfsw)) { 7007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module %s exports no opsets, " 7017c478bd9Sstevel@tonic-gate "not registered.\n", mod_name); 7027c478bd9Sstevel@tonic-gate return (EINVAL); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * Look to see if the module has been previously registered with the 7077c478bd9Sstevel@tonic-gate * framework. If so, we can fail with EBUSY. 7087c478bd9Sstevel@tonic-gate */ 7097c478bd9Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 7107c478bd9Sstevel@tonic-gate (mod_hash_val_t)&module) == 0) { 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * See if it is loaded currently 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_WRITER); 7157c478bd9Sstevel@tonic-gate if (module->dm_loaded) { 7167c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 7177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module '%s' is " 7187c478bd9Sstevel@tonic-gate "already registered.", mod_name); 7197c478bd9Sstevel@tonic-gate return (EBUSY); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } else { 7227c478bd9Sstevel@tonic-gate /* 7237c478bd9Sstevel@tonic-gate * This is the first time we've ever seen the module; stick 7247c478bd9Sstevel@tonic-gate * it into the module hash. If that fails, we've had a 7257c478bd9Sstevel@tonic-gate * race between two threads, both trying to insert the same 7267c478bd9Sstevel@tonic-gate * new module. It's safe to stick the module into the 7277c478bd9Sstevel@tonic-gate * hash only partly filled in, since dm_lock protects the 7287c478bd9Sstevel@tonic-gate * structure, and we've got that write-locked. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate module = kmem_zalloc(sizeof (dacf_module_t), KM_SLEEP); 7317c478bd9Sstevel@tonic-gate str = kmem_alloc(strlen(mod_name) + 1, KM_SLEEP); 7327c478bd9Sstevel@tonic-gate (void) strcpy(str, mod_name); 7337c478bd9Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_WRITER); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (mod_hash_insert(dacf_module_hash, (mod_hash_key_t)str, 7367c478bd9Sstevel@tonic-gate (mod_hash_val_t)module) != 0) { 7377c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 7387c478bd9Sstevel@tonic-gate kmem_free(str, strlen(str) + 1); 7397c478bd9Sstevel@tonic-gate kmem_free(module, sizeof (dacf_module_t)); 7407c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module '%s' is " 7417c478bd9Sstevel@tonic-gate "already registered.", mod_name); 7427c478bd9Sstevel@tonic-gate return (EBUSY); 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * In either case (first time we've seen it or not), the module is 7477c478bd9Sstevel@tonic-gate * not loaded, and we hold it write-locked. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* 7527c478bd9Sstevel@tonic-gate * Alloc array of opsets for this module. Add one for the final 7537c478bd9Sstevel@tonic-gate * NULL entry 7547c478bd9Sstevel@tonic-gate */ 7557c478bd9Sstevel@tonic-gate opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP); 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 7587c478bd9Sstevel@tonic-gate dacf_opset_copy(&(opsarray[i]), &(sw->dacf_opsets[i])); 7597c478bd9Sstevel@tonic-gate ASSERT(opsarray[i].opset_name != NULL); 7607c478bd9Sstevel@tonic-gate ASSERT(opsarray[i].opset_ops != NULL); 7617c478bd9Sstevel@tonic-gate } 7627c478bd9Sstevel@tonic-gate opsarray[nelems].opset_name = NULL; 7637c478bd9Sstevel@tonic-gate opsarray[nelems].opset_ops = NULL; 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate ASSERT(module->dm_opsets == NULL); /* see dacf_destroy_opsets() */ 7667c478bd9Sstevel@tonic-gate module->dm_opsets = opsarray; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate if (dacfdebug & DACF_DBG_MSGS) { 7697c478bd9Sstevel@tonic-gate dprintf("%s registered.\n", mod_name); 7707c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 7717c478bd9Sstevel@tonic-gate dprintf("registered %s\n", opsarray[i].opset_name); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate module->dm_loaded = 1; 7767c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate return (0); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate /* 7827c478bd9Sstevel@tonic-gate * dacf_module_unregister() 7837c478bd9Sstevel@tonic-gate * remove a module from the framework, and free framework-allocated 7847c478bd9Sstevel@tonic-gate * resources. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate int 7877c478bd9Sstevel@tonic-gate dacf_module_unregister(char *mod_name) 7887c478bd9Sstevel@tonic-gate { 7897c478bd9Sstevel@tonic-gate dacf_module_t *module; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * Can't unregister __kernel, since there is no real way to get it 7937c478bd9Sstevel@tonic-gate * back-- Once it gets marked with dm_loaded == 0, the kernel will 7947c478bd9Sstevel@tonic-gate * try to modload() if it is ever needed, which will fail utterly, 7957c478bd9Sstevel@tonic-gate * and send op_invoke into a loop in it's modload logic 7967c478bd9Sstevel@tonic-gate * 7977c478bd9Sstevel@tonic-gate * If this is behavior is ever needed in the future, we can just 7987c478bd9Sstevel@tonic-gate * add a flag indicating that this module is really a fake. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate ASSERT(strcmp(mod_name, kmod_name) != 0); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate dprintf("dacf_module_unregister: called for '%s'!\n", mod_name); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate /* 8057c478bd9Sstevel@tonic-gate * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and 8067c478bd9Sstevel@tonic-gate * that fails, return EBUSY, and fail to unregister. 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 8097c478bd9Sstevel@tonic-gate (mod_hash_val_t)&module) == 0) { 8107c478bd9Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_DACF) || 8117c478bd9Sstevel@tonic-gate !rw_tryenter(&module->dm_lock, RW_WRITER)) { 8127c478bd9Sstevel@tonic-gate return (EBUSY); 8137c478bd9Sstevel@tonic-gate } 8147c478bd9Sstevel@tonic-gate } else { 8157c478bd9Sstevel@tonic-gate return (EINVAL); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 8197c478bd9Sstevel@tonic-gate dacf_destroy_opsets(module); 8207c478bd9Sstevel@tonic-gate module->dm_loaded = 0; 8217c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 8227c478bd9Sstevel@tonic-gate return (0); 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * dacf_destroy_opsets() 8277c478bd9Sstevel@tonic-gate * given a module, destroy all of it's associated op-sets. 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate static void 8307c478bd9Sstevel@tonic-gate dacf_destroy_opsets(dacf_module_t *module) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate dacf_opset_t *array = module->dm_opsets; 8337c478bd9Sstevel@tonic-gate dacf_opset_t *p; 8347c478bd9Sstevel@tonic-gate int i; 8357c478bd9Sstevel@tonic-gate size_t nelems; 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 8387c478bd9Sstevel@tonic-gate ASSERT(module->dm_loaded == 1); 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate for (i = 0; array[i].opset_name != NULL; i++) { 8417c478bd9Sstevel@tonic-gate p = &(array[i]); 8427c478bd9Sstevel@tonic-gate kmem_free(p->opset_name, strlen(p->opset_name) + 1); 8437c478bd9Sstevel@tonic-gate /* 8447c478bd9Sstevel@tonic-gate * count nelems in opset_ops 8457c478bd9Sstevel@tonic-gate */ 8467c478bd9Sstevel@tonic-gate for (nelems = 0; ; nelems++) { 8477c478bd9Sstevel@tonic-gate if (p->opset_ops[nelems].op_id == DACF_OPID_END) { 8487c478bd9Sstevel@tonic-gate break; 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Free the array of op ptrs. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1)); 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate /* 8587c478bd9Sstevel@tonic-gate * i has counted how big array is; +1 to account for the last element. 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1)); 8617c478bd9Sstevel@tonic-gate module->dm_opsets = NULL; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * dacf_opset_copy() 8667c478bd9Sstevel@tonic-gate * makes a copy of a dacf_opset_t. 8677c478bd9Sstevel@tonic-gate */ 8687c478bd9Sstevel@tonic-gate static void 8697c478bd9Sstevel@tonic-gate dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src) 8707c478bd9Sstevel@tonic-gate { 8717c478bd9Sstevel@tonic-gate size_t nelems, i; 8727c478bd9Sstevel@tonic-gate ASSERT(src && dst); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate dprintf("dacf_opset_copy: called\n"); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP); 8777c478bd9Sstevel@tonic-gate (void) strcpy(dst->opset_name, src->opset_name); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate dprintf("dacf_opset_copy: counting ops\n"); 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate for (nelems = 0; ; nelems++) { 8827c478bd9Sstevel@tonic-gate if ((src->opset_ops[nelems].op_id == DACF_OPID_END) || 8837c478bd9Sstevel@tonic-gate (src->opset_ops[nelems].op_func == NULL)) { 8847c478bd9Sstevel@tonic-gate break; 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate dprintf("dacf_opset_copy: found %lu ops\n", nelems); 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1), 8917c478bd9Sstevel@tonic-gate KM_SLEEP); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate dprintf("dacf_opset_copy: copying ops\n"); 8947c478bd9Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 8957c478bd9Sstevel@tonic-gate dst->opset_ops[i].op_id = src->opset_ops[i].op_id; 8967c478bd9Sstevel@tonic-gate dst->opset_ops[i].op_func = src->opset_ops[i].op_func; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate dst->opset_ops[nelems].op_id = DACF_OPID_END; 8997c478bd9Sstevel@tonic-gate dst->opset_ops[nelems].op_func = NULL; 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate dprintf("dacf_opset_copy: done copying ops\n"); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate int dacf_modload_laps = 0; /* just a diagnostic aid */ 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * dacf_op_invoke() 9087c478bd9Sstevel@tonic-gate * Invoke a op in a opset in a module given the rule to invoke. 9097c478bd9Sstevel@tonic-gate * 9107c478bd9Sstevel@tonic-gate * If the return value of dacf_op_invoke is 0, then rval contains the 9117c478bd9Sstevel@tonic-gate * return value of the _op_ being invoked. Otherwise, dacf_op_invoke's 9127c478bd9Sstevel@tonic-gate * return value indicates why the op invocation failed. 9137c478bd9Sstevel@tonic-gate */ 9147c478bd9Sstevel@tonic-gate int 9157c478bd9Sstevel@tonic-gate dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags) 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate dacf_module_t *module; 9187c478bd9Sstevel@tonic-gate dacf_opset_t *opsarray; 9197c478bd9Sstevel@tonic-gate dacf_opset_t *opset; 9207c478bd9Sstevel@tonic-gate dacf_op_t *op = NULL; 9217c478bd9Sstevel@tonic-gate dacf_opid_t op_id; 9227c478bd9Sstevel@tonic-gate dacf_arghdl_t arg_hdl; 9237c478bd9Sstevel@tonic-gate dev_info_t *dip; 9247c478bd9Sstevel@tonic-gate int i, rval = -1; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate ASSERT(rule); 9277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate op_id = rule->r_opid; 9307c478bd9Sstevel@tonic-gate dprintf("dacf_op_invoke: opid=%d\n", op_id); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate /* 9337c478bd9Sstevel@tonic-gate * Take laps, trying to load the dacf module. For the case of kernel- 9347c478bd9Sstevel@tonic-gate * provided operations, __kernel will be found in the hash table, and 9357c478bd9Sstevel@tonic-gate * no modload will be needed. 9367c478bd9Sstevel@tonic-gate */ 9377c478bd9Sstevel@tonic-gate for (;;) { 9387c478bd9Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, 9397c478bd9Sstevel@tonic-gate (mod_hash_key_t)rule->r_module, 9407c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&module) == 0) { 9417c478bd9Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_READER); 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * Found the module, and it is loaded. 9447c478bd9Sstevel@tonic-gate */ 9457c478bd9Sstevel@tonic-gate if (module->dm_loaded != 0) { 9467c478bd9Sstevel@tonic-gate break; 9477c478bd9Sstevel@tonic-gate } 9487c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * If we're here, either: 1) it's not in the hash, or 2) it is, 9537c478bd9Sstevel@tonic-gate * but dm_loaded is 0, meaning the module needs to be loaded. 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate dprintf("dacf_op_invoke: calling modload\n"); 9567c478bd9Sstevel@tonic-gate if (modload("dacf", rule->r_module) < 0) { 9577c478bd9Sstevel@tonic-gate return (DACF_ERR_MOD_NOTFOUND); 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate dacf_modload_laps++; 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 9627c478bd9Sstevel@tonic-gate ASSERT(RW_READ_HELD(&module->dm_lock)); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate opsarray = module->dm_opsets; 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate /* 9677c478bd9Sstevel@tonic-gate * Loop through the opsets exported by this module, and find the one 9687c478bd9Sstevel@tonic-gate * we care about. 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate opset = NULL; 9717c478bd9Sstevel@tonic-gate for (i = 0; opsarray[i].opset_name != NULL; i++) { 9727c478bd9Sstevel@tonic-gate if (strcmp(opsarray[i].opset_name, rule->r_opset) == 0) { 9737c478bd9Sstevel@tonic-gate opset = &opsarray[i]; 9747c478bd9Sstevel@tonic-gate break; 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate if (opset == NULL) { 9797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf: couldn't invoke op, opset '%s' not " 9807c478bd9Sstevel@tonic-gate "found in module '%s'", rule->r_opset, rule->r_module); 9817c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 9827c478bd9Sstevel@tonic-gate return (DACF_ERR_OPSET_NOTFOUND); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate arg_hdl = (dacf_arghdl_t)rule->r_args; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * Call the appropriate routine in the target by looping across the 9897c478bd9Sstevel@tonic-gate * ops until we find the one whose id matches opid. 9907c478bd9Sstevel@tonic-gate */ 9917c478bd9Sstevel@tonic-gate op = NULL; 9927c478bd9Sstevel@tonic-gate for (i = 0; opset->opset_ops[i].op_id != DACF_OPID_END; i++) { 9937c478bd9Sstevel@tonic-gate if (opset->opset_ops[i].op_id == op_id) { 9947c478bd9Sstevel@tonic-gate op = &(opset->opset_ops[i]); 9957c478bd9Sstevel@tonic-gate break; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate if (op == NULL) { 10007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf: couldn't invoke op, op '%s' not found " 10017c478bd9Sstevel@tonic-gate "in opset '%s' in module '%s'", dacf_opid_to_str(op_id), 10027c478bd9Sstevel@tonic-gate rule->r_opset, rule->r_module); 10037c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 10047c478bd9Sstevel@tonic-gate return (DACF_ERR_OP_NOTFOUND); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate dprintf("dacf_op_invoke: found op, invoking...\n"); 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * Drop dacf_lock here, so that op_func's that cause drivers to 10117c478bd9Sstevel@tonic-gate * get loaded don't wedge the system when they try to acquire dacf_lock 10127c478bd9Sstevel@tonic-gate * to do matching. 10137c478bd9Sstevel@tonic-gate * 10147c478bd9Sstevel@tonic-gate * Mark that an invoke is happening to prevent recursive invokes 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate dip = ((struct ddi_minor_data *)info_hdl)->dip; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 10197c478bd9Sstevel@tonic-gate DEVI_SET_INVOKING_DACF(dip); 10207c478bd9Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate mutex_exit(&dacf_lock); 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate rval = op->op_func(info_hdl, arg_hdl, flags); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate mutex_enter(&dacf_lock); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate /* 10297c478bd9Sstevel@tonic-gate * Completed the invocation against module, so let go of it. 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 10327c478bd9Sstevel@tonic-gate DEVI_CLR_INVOKING_DACF(dip); 10337c478bd9Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate /* 10367c478bd9Sstevel@tonic-gate * Drop our r-lock on the module, now that we no longer need the module 10377c478bd9Sstevel@tonic-gate * to stay loaded. 10387c478bd9Sstevel@tonic-gate */ 10397c478bd9Sstevel@tonic-gate rw_exit(&module->dm_lock); 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate if (rval == DACF_SUCCESS) { 10427c478bd9Sstevel@tonic-gate return (DACF_SUCCESS); 10437c478bd9Sstevel@tonic-gate } else { 10447c478bd9Sstevel@tonic-gate return (DACF_ERR_OP_FAILED); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate } 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate /* 10497c478bd9Sstevel@tonic-gate * dacf_get_devspec() 10507c478bd9Sstevel@tonic-gate * given a devspec-type as a string, return a corresponding dacf_devspec_t 10517c478bd9Sstevel@tonic-gate */ 10527c478bd9Sstevel@tonic-gate dacf_devspec_t 10537c478bd9Sstevel@tonic-gate dacf_get_devspec(char *name) 10547c478bd9Sstevel@tonic-gate { 10557c478bd9Sstevel@tonic-gate dacf_ds_t *p = &dacf_devspecs[0]; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate while (p->name != NULL) { 10587c478bd9Sstevel@tonic-gate if (strcmp(p->name, name) == 0) { 10597c478bd9Sstevel@tonic-gate return (p->id); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate p++; 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate return (DACF_DS_ERROR); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate /* 10677c478bd9Sstevel@tonic-gate * dacf_devspec_to_str() 10687c478bd9Sstevel@tonic-gate * given a dacf_devspec_t, return a pointer to the human readable string 10697c478bd9Sstevel@tonic-gate * representation of that device specifier. 10707c478bd9Sstevel@tonic-gate */ 10717c478bd9Sstevel@tonic-gate const char * 10727c478bd9Sstevel@tonic-gate dacf_devspec_to_str(dacf_devspec_t ds) 10737c478bd9Sstevel@tonic-gate { 10747c478bd9Sstevel@tonic-gate dacf_ds_t *p = &dacf_devspecs[0]; 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate while (p->name != NULL) { 10777c478bd9Sstevel@tonic-gate if (p->id == ds) { 10787c478bd9Sstevel@tonic-gate return (p->name); 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate p++; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate return (NULL); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate /* 10867c478bd9Sstevel@tonic-gate * dacf_get_op() 10877c478bd9Sstevel@tonic-gate * given a op name, returns the corresponding dacf_opid_t. 10887c478bd9Sstevel@tonic-gate */ 10897c478bd9Sstevel@tonic-gate dacf_opid_t 10907c478bd9Sstevel@tonic-gate dacf_get_op(char *name) 10917c478bd9Sstevel@tonic-gate { 10927c478bd9Sstevel@tonic-gate dacf_opmap_t *p = &dacf_ops[0]; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate while (p->name != NULL) { 10957c478bd9Sstevel@tonic-gate if (strcmp(p->name, name) == 0) { 10967c478bd9Sstevel@tonic-gate return (p->id); 10977c478bd9Sstevel@tonic-gate } 10987c478bd9Sstevel@tonic-gate p++; 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate return (DACF_OPID_ERROR); 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* 11047c478bd9Sstevel@tonic-gate * dacf_opid_to_str() 11057c478bd9Sstevel@tonic-gate * given a dacf_opid_t, return the human-readable op-name. 11067c478bd9Sstevel@tonic-gate */ 11077c478bd9Sstevel@tonic-gate const char * 11087c478bd9Sstevel@tonic-gate dacf_opid_to_str(dacf_opid_t tid) 11097c478bd9Sstevel@tonic-gate { 11107c478bd9Sstevel@tonic-gate dacf_opmap_t *p = &dacf_ops[0]; 11117c478bd9Sstevel@tonic-gate 11127c478bd9Sstevel@tonic-gate while (p->name != NULL) { 11137c478bd9Sstevel@tonic-gate if (p->id == tid) { 11147c478bd9Sstevel@tonic-gate return (p->name); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate p++; 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate return (NULL); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * dacf_getopt() 11237c478bd9Sstevel@tonic-gate * given an option specified as a string, add it to the bit-field of 11247c478bd9Sstevel@tonic-gate * options given. Returns -1 if the option is unrecognized. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate int 11277c478bd9Sstevel@tonic-gate dacf_getopt(char *opt_str, uint_t *opts) 11287c478bd9Sstevel@tonic-gate { 11297c478bd9Sstevel@tonic-gate dacf_opt_t *p = &dacf_options[0]; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * Look through the list for the option given 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate while (p->optname != NULL) { 11357c478bd9Sstevel@tonic-gate if (strcmp(opt_str, p->optname) == 0) { 11367c478bd9Sstevel@tonic-gate *opts |= p->optmask; 11377c478bd9Sstevel@tonic-gate return (0); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate p++; 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate return (-1); 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* 11477c478bd9Sstevel@tonic-gate * This family of functions forms the dacf interface which is exported to 11487c478bd9Sstevel@tonic-gate * kernel/dacf modules. Modules _should_not_ use any dacf_* functions 11497c478bd9Sstevel@tonic-gate * presented above this point. 11507c478bd9Sstevel@tonic-gate * 11517c478bd9Sstevel@tonic-gate * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and 11527c478bd9Sstevel@tonic-gate * assume that the resulting pointer is not to an alias node. That is true 11537c478bd9Sstevel@tonic-gate * because dacf_op_invoke guarantees it by first resolving the alias. 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * dacf_minor_name() 11587c478bd9Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the minor name of the device instance 11597c478bd9Sstevel@tonic-gate * being configured. 11607c478bd9Sstevel@tonic-gate */ 11617c478bd9Sstevel@tonic-gate const char * 11627c478bd9Sstevel@tonic-gate dacf_minor_name(dacf_infohdl_t info_hdl) 11637c478bd9Sstevel@tonic-gate { 11647c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate return (dmdp->ddm_name); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate /* 11707c478bd9Sstevel@tonic-gate * dacf_minor_number() 11717c478bd9Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the device minor number of the instance 11727c478bd9Sstevel@tonic-gate * being configured. 11737c478bd9Sstevel@tonic-gate */ 11747c478bd9Sstevel@tonic-gate minor_t 11757c478bd9Sstevel@tonic-gate dacf_minor_number(dacf_infohdl_t info_hdl) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate return (getminor(dmdp->ddm_dev)); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate /* 1183*d62bc4baSyz147064 * dacf_get_dev() 1184*d62bc4baSyz147064 * given a dacf_infohdl_t, obtain the dev_t of the instance being 1185*d62bc4baSyz147064 * configured. 1186*d62bc4baSyz147064 */ 1187*d62bc4baSyz147064 dev_t 1188*d62bc4baSyz147064 dacf_get_dev(dacf_infohdl_t info_hdl) 1189*d62bc4baSyz147064 { 1190*d62bc4baSyz147064 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1191*d62bc4baSyz147064 1192*d62bc4baSyz147064 return (dmdp->ddm_dev); 1193*d62bc4baSyz147064 } 1194*d62bc4baSyz147064 1195*d62bc4baSyz147064 /* 11967c478bd9Sstevel@tonic-gate * dacf_driver_name() 11977c478bd9Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the device driver name of the device 11987c478bd9Sstevel@tonic-gate * instance being configured. 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate const char * 12017c478bd9Sstevel@tonic-gate dacf_driver_name(dacf_infohdl_t info_hdl) 12027c478bd9Sstevel@tonic-gate { 12037c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate return (ddi_driver_name(dmdp->dip)); 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * dacf_devinfo_node() 12107c478bd9Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the dev_info_t of the device instance 12117c478bd9Sstevel@tonic-gate * being configured. 12127c478bd9Sstevel@tonic-gate */ 12137c478bd9Sstevel@tonic-gate dev_info_t * 12147c478bd9Sstevel@tonic-gate dacf_devinfo_node(dacf_infohdl_t info_hdl) 12157c478bd9Sstevel@tonic-gate { 12167c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate return (dmdp->dip); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * dacf_get_arg() 12237c478bd9Sstevel@tonic-gate * given the dacf_arghdl_t passed to a op and the name of an argument, 12247c478bd9Sstevel@tonic-gate * return the value of that argument. 12257c478bd9Sstevel@tonic-gate * 12267c478bd9Sstevel@tonic-gate * returns NULL if the argument is not found. 12277c478bd9Sstevel@tonic-gate */ 12287c478bd9Sstevel@tonic-gate const char * 12297c478bd9Sstevel@tonic-gate dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name) 12307c478bd9Sstevel@tonic-gate { 12317c478bd9Sstevel@tonic-gate dacf_arg_t *arg_list = (dacf_arg_t *)arghdl; 12327c478bd9Sstevel@tonic-gate ASSERT(arg_name); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate while (arg_list != NULL) { 12357c478bd9Sstevel@tonic-gate if (strcmp(arg_list->arg_name, arg_name) == 0) { 12367c478bd9Sstevel@tonic-gate return (arg_list->arg_val); 12377c478bd9Sstevel@tonic-gate } 12387c478bd9Sstevel@tonic-gate arg_list = arg_list->arg_next; 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate return (NULL); 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate 12447c478bd9Sstevel@tonic-gate /* 12457c478bd9Sstevel@tonic-gate * dacf_store_info() 12467c478bd9Sstevel@tonic-gate * associate instance-specific data with a device instance. Future 12477c478bd9Sstevel@tonic-gate * configuration ops invoked for this instance can retrieve this data using 12487c478bd9Sstevel@tonic-gate * dacf_retrieve_info() below. Modules are responsible for cleaning up 12497c478bd9Sstevel@tonic-gate * this data as appropriate, and should store NULL as the value of 'data' 12507c478bd9Sstevel@tonic-gate * when the data is no longer valid. 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate void 12537c478bd9Sstevel@tonic-gate dacf_store_info(dacf_infohdl_t info_hdl, void *data) 12547c478bd9Sstevel@tonic-gate { 12557c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * If the client is 'storing NULL' we can represent that by blowing 12597c478bd9Sstevel@tonic-gate * the info entry out of the hash. 12607c478bd9Sstevel@tonic-gate */ 12617c478bd9Sstevel@tonic-gate if (data == NULL) { 12627c478bd9Sstevel@tonic-gate (void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp); 12637c478bd9Sstevel@tonic-gate } else { 12647c478bd9Sstevel@tonic-gate /* 12657c478bd9Sstevel@tonic-gate * mod_hash_replace can only fail on out of memory, but we sleep 12667c478bd9Sstevel@tonic-gate * for memory in this hash, so it is safe to ignore the retval. 12677c478bd9Sstevel@tonic-gate */ 12687c478bd9Sstevel@tonic-gate (void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp, 12697c478bd9Sstevel@tonic-gate (mod_hash_val_t)data); 12707c478bd9Sstevel@tonic-gate } 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate 12737c478bd9Sstevel@tonic-gate /* 12747c478bd9Sstevel@tonic-gate * dacf_retrieve_info() 12757c478bd9Sstevel@tonic-gate * retrieve instance-specific data associated with a device instance. 12767c478bd9Sstevel@tonic-gate */ 12777c478bd9Sstevel@tonic-gate void * 12787c478bd9Sstevel@tonic-gate dacf_retrieve_info(dacf_infohdl_t info_hdl) 12797c478bd9Sstevel@tonic-gate { 12807c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 12817c478bd9Sstevel@tonic-gate void *data; 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp, 12847c478bd9Sstevel@tonic-gate (mod_hash_val_t *)&data) != 0) { 12857c478bd9Sstevel@tonic-gate return (NULL); 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate return (data); 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate /* 12927c478bd9Sstevel@tonic-gate * dacf_makevp() 12937c478bd9Sstevel@tonic-gate * make a vnode for the specified dacf_infohdl_t. 12947c478bd9Sstevel@tonic-gate */ 12957c478bd9Sstevel@tonic-gate struct vnode * 12967c478bd9Sstevel@tonic-gate dacf_makevp(dacf_infohdl_t info_hdl) 12977c478bd9Sstevel@tonic-gate { 12987c478bd9Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 12997c478bd9Sstevel@tonic-gate struct vnode *vp; 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate vp = makespecvp(dmdp->ddm_dev, VCHR); 13027c478bd9Sstevel@tonic-gate spec_assoc_vp_with_devi(vp, dmdp->dip); 13037c478bd9Sstevel@tonic-gate return (vp); 13047c478bd9Sstevel@tonic-gate } 1305