1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * DACF: device autoconfiguration support 28 * 29 * DACF provides a fast, lightweight policy engine for the I/O subsystem. 30 * This policy engine provides a mechanism for auto-configuring and 31 * auto-unconfiguring devices. 32 * 33 * After a device is attach(9E)ed, additional configuration may be needed in 34 * order to make the device available for use by the system. For example, 35 * STREAMS modules may need to be pushed atop the driver in order to create 36 * a STREAMS stack. If the device is to be removed from the system, these 37 * configuration operations need to be undone, and the device prepared for 38 * detach(9E). 39 * 40 * It is desirable to move the implementation of such policies outside of the 41 * kernel proper, since such operations are typically infrequent. To this end, 42 * DACF manages kernel modules in (module_path)/dacf directories. These adhere 43 * to the api defined in sys/dacf.h, and register sets of configuration 44 * operations. The kernel loads these modules when the operations they 45 * implement are needed, and can unload them at any time thereafter. 46 * Implementing configuration operations in external modules can also increase 47 * code reuse. 48 * 49 * DACF provides a policy database which associates 50 * 51 * (device descr., kernel action) --> (configuration operation, parameters) 52 * 53 * - Device description is matching rule, for example: 54 * minor-nodetype="ddi_keyboard" 55 * - Kernel action is a reference to a dacf kernel hook. 56 * currently supported are "post-attach" and "pre-detach" 57 * - Configuration action is a reference to a module and a set of operations 58 * within the module, for example: consconfig:kbd_config 59 * - Parameters is a list of name="value" parameters to be passed to the 60 * configuration operation when invoked. 61 * 62 * The contents of the rules database are loaded from /etc/dacf.conf upon boot. 63 * 64 * DACF kernel hooks are comprised of a call into the rule-matching engine, 65 * using parameters from the hook in order find a matching rule. If one is 66 * found, the framework can invoke the configuration operation immediately, or 67 * defer doing so until later, by putting the rule on a 'reservation list.' 68 */ 69 70 #include <sys/param.h> 71 #include <sys/modctl.h> 72 #include <sys/sysmacros.h> 73 #include <sys/kmem.h> 74 #include <sys/cmn_err.h> 75 #include <sys/pathname.h> 76 #include <sys/ddi_impldefs.h> 77 #include <sys/sunddi.h> 78 #include <sys/autoconf.h> 79 #include <sys/modhash.h> 80 #include <sys/dacf.h> 81 #include <sys/dacf_impl.h> 82 #include <sys/systm.h> 83 #include <sys/varargs.h> 84 #include <sys/debug.h> 85 #include <sys/log.h> 86 #include <sys/fs/snode.h> 87 88 /* 89 * Enumeration of the ops exported by the dacf framework. 90 * 91 * To add a new op to the framework, add it to this list, update dacf.h, 92 * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix. 93 * 94 */ 95 typedef struct dacf_opmap { 96 const char *name; 97 dacf_opid_t id; 98 } dacf_opmap_t; 99 100 static dacf_opmap_t dacf_ops[] = { 101 { "post-attach", DACF_OPID_POSTATTACH }, 102 { "pre-detach", DACF_OPID_PREDETACH }, 103 { NULL, 0 }, 104 }; 105 106 /* 107 * Enumeration of the options exported by the dacf framework (currently none). 108 * 109 * To add a new option, add it to this array. 110 */ 111 typedef struct dacf_opt { 112 const char *optname; 113 uint_t optmask; 114 } dacf_opt_t; 115 116 static dacf_opt_t dacf_options[] = { 117 #ifdef DEBUG 118 { "testopt", 1 }, 119 { "testopt2", 2 }, 120 #endif 121 { NULL, 0 }, 122 }; 123 124 static char kmod_name[] = "__kernel"; 125 126 /* 127 * Enumeration of the device specifiers exported by the dacf framework. 128 * 129 * To add a new devspec to the framework, add it to this list, update dacf.h, 130 * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify 131 * dacf_match(). 132 */ 133 typedef struct dacf_ds { 134 const char *name; 135 dacf_devspec_t id; 136 } dacf_ds_t; 137 138 static dacf_ds_t dacf_devspecs[] = { 139 { "minor-nodetype", DACF_DS_MIN_NT }, 140 { "driver-minorname", DACF_DS_DRV_MNAME }, 141 { "device-path", DACF_DS_DEV_PATH }, 142 { NULL, DACF_DS_ERROR }, 143 }; 144 145 mod_hash_t *posta_mntype, *posta_mname, *posta_devname; /* post-attach */ 146 mod_hash_t *pred_mntype, *pred_mname, *pred_devname; /* pre-detach */ 147 148 mod_hash_t *dacf_module_hash; 149 mod_hash_t *dacf_info_hash; 150 151 /* 152 * This is the lookup table for the hash tables that dacf manages. Given an 153 * op id and devspec type, one can obtain the hash for that type of data. 154 */ 155 mod_hash_t **dacf_rule_matrix[DACF_NUM_OPIDS][DACF_NUM_DEVSPECS] = { 156 { &posta_mntype, &posta_mname, &posta_devname }, 157 { &pred_mntype, &pred_mname, &pred_devname }, 158 }; 159 160 kmutex_t dacf_lock; 161 kmutex_t dacf_module_lock; 162 163 int dacfdebug = 0; 164 165 static dacf_rule_t *dacf_rule_ctor(char *, char *, char *, dacf_opid_t, 166 uint_t, dacf_arg_t *); 167 static mod_hash_t *dacf_get_op_hash(dacf_opid_t, dacf_devspec_t); 168 static void dacf_rule_val_dtor(mod_hash_val_t); 169 static void dacf_destroy_opsets(dacf_module_t *module); 170 static void dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src); 171 static void dprintf(const char *, ...) __KPRINTFLIKE(1); 172 173 /*PRINTFLIKE1*/ 174 static void 175 dprintf(const char *format, ...) 176 { 177 va_list alist; 178 char dp_buf[256], *dpbp; 179 if (dacfdebug & DACF_DBG_MSGS) { 180 va_start(alist, format); 181 /* 182 * sprintf up the string that is 'dacf debug: <the message>' 183 */ 184 (void) sprintf(dp_buf, "dacf debug: "); 185 dpbp = &(dp_buf[strlen(dp_buf)]); 186 (void) vsnprintf(dpbp, sizeof (dp_buf) - strlen(dp_buf), 187 format, alist); 188 printf(dp_buf); 189 va_end(alist); 190 } 191 } 192 193 /* 194 * dacf_init() 195 * initialize the dacf framework by creating the various hash tables. 196 */ 197 void 198 dacf_init() 199 { 200 int i, j; 201 char hbuf[40]; 202 203 mutex_enter(&dacf_lock); 204 205 dprintf("dacf_init: creating hashmatrix\n"); 206 207 #ifdef DEBUG 208 /* 209 * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync 210 */ 211 for (i = 0; dacf_devspecs[i].name != NULL; i++) 212 continue; 213 ASSERT(i == DACF_NUM_DEVSPECS); 214 215 /* 216 * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync 217 */ 218 for (i = 0; dacf_ops[i].name != NULL; i++) 219 continue; 220 ASSERT(i == DACF_NUM_OPIDS); 221 #endif 222 223 for (i = 0; i < DACF_NUM_OPIDS; i++) { 224 for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 225 if (dacf_rule_matrix[i][j] == NULL) { 226 continue; 227 } 228 /* 229 * Set up a hash table with no key destructor. The 230 * keys are carried in the rule_t, so the val_dtor 231 * will take care of the key as well. 232 */ 233 (void) snprintf(hbuf, sizeof (hbuf), 234 "dacf hashmatrix [%d][%d]", i, j); 235 *(dacf_rule_matrix[i][j]) = mod_hash_create_extended( 236 hbuf, /* hash name */ 237 DACF_RULE_HASHSIZE, /* # hash elems */ 238 mod_hash_null_keydtor, /* key dtor */ 239 dacf_rule_val_dtor, /* value dtor */ 240 mod_hash_bystr, NULL, /* hash alg & data */ 241 mod_hash_strkey_cmp, /* key comparator */ 242 KM_SLEEP); 243 } 244 } 245 246 dprintf("dacf_init: creating module_hash\n"); 247 /* 248 * dacf_module_hash stores the currently registered dacf modules 249 * by name. 250 */ 251 dacf_module_hash = mod_hash_create_strhash("dacf module hash", 252 DACF_MODULE_HASHSIZE, mod_hash_null_valdtor); 253 254 dprintf("dacf_init: creating info_hash\n"); 255 /* 256 * dacf_info_hash stores pointers to data that modules can associate 257 * on a per minornode basis. The type of data stored is opaque to the 258 * framework-- thus there is no destructor supplied. 259 */ 260 dacf_info_hash = mod_hash_create_ptrhash("dacf info hash", 261 DACF_INFO_HASHSIZE, mod_hash_null_valdtor, 262 sizeof (struct ddi_minor_data)); 263 264 mutex_exit(&dacf_lock); 265 266 /* 267 * Register the '__kernel' module. 268 * 269 * These are operations that are provided by the kernel, not by a 270 * module. We just feed the framework a dacfsw structure; it will get 271 * marked as 'loaded' by dacf_module_register(), and will always be 272 * available. 273 */ 274 (void) dacf_module_register(kmod_name, &kmod_dacfsw); 275 276 (void) read_dacf_binding_file(NULL); 277 278 dprintf("dacf_init: dacf is ready\n"); 279 } 280 281 /* 282 * dacf_clear_rules() 283 * clear the dacf rule database. This is typically done in advance of 284 * rereading the dacf binding file. 285 */ 286 void 287 dacf_clear_rules() 288 { 289 int i, j; 290 ASSERT(MUTEX_HELD(&dacf_lock)); 291 292 for (i = 0; i < DACF_NUM_OPIDS; i++) { 293 for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 294 if ((dacf_rule_matrix[i][j] != NULL) && 295 (*(dacf_rule_matrix[i][j]) != NULL)) { 296 mod_hash_clear(*(dacf_rule_matrix[i][j])); 297 } 298 } 299 } 300 } 301 302 /* 303 * dacf_rule_insert() 304 * Create an entry in the dacf rule database. 305 * If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()). 306 */ 307 int 308 dacf_rule_insert(dacf_devspec_t devspec_type, char *devspec_data, 309 char *module, char *opset, dacf_opid_t opid, uint_t opts, 310 dacf_arg_t *op_args) 311 { 312 dacf_rule_t *rule; 313 mod_hash_t *hash; 314 315 ASSERT(devspec_type != DACF_DS_ERROR); 316 ASSERT(devspec_data); 317 ASSERT(opset); 318 ASSERT(MUTEX_HELD(&dacf_lock)); 319 320 dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n", 321 dacf_devspec_to_str(devspec_type), devspec_data, 322 module ? module : "[kernel]", opset, dacf_opid_to_str(opid)); 323 324 /* 325 * Fetch the hash table associated with this op-name and devspec-type. 326 * Some ops may not support all devspec-types, since they may be 327 * meaningless, so hash may be null. 328 */ 329 hash = dacf_get_op_hash(opid, devspec_type); 330 if (hash == NULL) { 331 cmn_err(CE_WARN, "!dacf dev-spec '%s' does not support op '%s'", 332 dacf_devspec_to_str(devspec_type), dacf_opid_to_str(opid)); 333 return (-1); 334 } 335 336 /* 337 * Allocate a rule and fill it in, take a hold on it. 338 */ 339 rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts, 340 op_args); 341 dacf_rule_hold(rule); 342 343 if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data, 344 (mod_hash_val_t)rule) != 0) { 345 /* 346 * We failed, so release hold. This will cause the rule and 347 * associated data to get nuked. 348 */ 349 dacf_rule_rele(rule); 350 351 cmn_err(CE_WARN, "!dacf rule %s='%s' %s:%s %s duplicates " 352 "another rule, ignored", dacf_devspec_to_str(devspec_type), 353 devspec_data, module, opset, dacf_opid_to_str(opid)); 354 return (-1); 355 } 356 return (0); 357 } 358 359 /* 360 * dacf_rule_ctor() 361 * Allocate and fill out entries in a dacf_rule_t. 362 */ 363 static dacf_rule_t * 364 dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid, 365 uint_t opts, dacf_arg_t *op_args) 366 { 367 dacf_rule_t *rule; 368 dacf_arg_t *p; 369 370 rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP); 371 372 /* 373 * Fill in the entries 374 */ 375 rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP); 376 (void) strcpy(rule->r_devspec_data, device_spec); 377 378 /* 379 * If module is 'null' we set it to __kernel, meaning that this op 380 * is implemented by the kernel. 381 */ 382 if (module == NULL) { 383 module = kmod_name; 384 } 385 386 rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP); 387 (void) strcpy(rule->r_module, module); 388 389 rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP); 390 (void) strcpy(rule->r_opset, opset); 391 392 rule->r_refs = 0; /* no refs yet */ 393 rule->r_opts = opts; 394 rule->r_opid = opid; 395 396 rule->r_args = NULL; 397 p = op_args; 398 while (p != NULL) { 399 ASSERT(p->arg_name); 400 ASSERT(p->arg_val); 401 /* 402 * dacf_arg_insert() should always succeed, since we're copying 403 * another (already duplicate-free) list. 404 */ 405 (void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val); 406 p = p->arg_next; 407 } 408 409 return (rule); 410 } 411 412 /* 413 * dacf_rule_val_dtor() 414 * This is the destructor for dacf_rule_t's in the rule database. It 415 * simply does a dacf_rule_rele() on the rule. This function will take 416 * care of destroying the rule if its ref count has dropped to 0. 417 */ 418 static void 419 dacf_rule_val_dtor(mod_hash_val_t val) 420 { 421 ASSERT((void *)val != NULL); 422 dacf_rule_rele((dacf_rule_t *)val); 423 } 424 425 /* 426 * dacf_rule_destroy() 427 * destroy a dacf_rule_t 428 */ 429 void 430 dacf_rule_destroy(dacf_rule_t *rule) 431 { 432 ASSERT(rule->r_refs == 0); 433 /* 434 * Free arguments. 435 */ 436 dacf_arglist_delete(&(rule->r_args)); 437 kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1); 438 /* 439 * Module may be null for a kernel-managed op-set 440 */ 441 kmem_free(rule->r_module, strlen(rule->r_module) + 1); 442 kmem_free(rule->r_opset, strlen(rule->r_opset) + 1); 443 kmem_free(rule, sizeof (dacf_rule_t)); 444 } 445 446 /* 447 * dacf_rule_hold() 448 * dacf rules are ref-counted. This function increases the reference 449 * count on an rule. 450 */ 451 void 452 dacf_rule_hold(dacf_rule_t *rule) 453 { 454 ASSERT(MUTEX_HELD(&dacf_lock)); 455 456 rule->r_refs++; 457 } 458 459 /* 460 * dacf_rule_rele() 461 * drop the ref count on an rule, and destroy the rule if its 462 * ref count drops to 0. 463 */ 464 void 465 dacf_rule_rele(dacf_rule_t *rule) 466 { 467 ASSERT(MUTEX_HELD(&dacf_lock)); 468 ASSERT(rule->r_refs > 0); 469 470 rule->r_refs--; 471 if (rule->r_refs == 0) { 472 dacf_rule_destroy(rule); 473 } 474 } 475 476 /* 477 * dacf_rsrv_make() 478 * add an rule to a reservation list to be processed later. 479 */ 480 void 481 dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info, 482 dacf_rsrvlist_t **list) 483 { 484 dacf_infohdl_t ihdl = info; 485 ASSERT(MUTEX_HELD(&dacf_lock)); 486 ASSERT(info && rule && list); 487 488 /* 489 * Bump the ref count on rule, so it won't get freed as long as it's on 490 * this reservation list. 491 */ 492 dacf_rule_hold(rule); 493 494 rsrv->rsrv_rule = rule; 495 rsrv->rsrv_ihdl = ihdl; 496 rsrv->rsrv_result = DDI_SUCCESS; 497 rsrv->rsrv_next = *list; 498 *list = rsrv; 499 500 dprintf("dacf: reservation made\n"); 501 } 502 503 /* 504 * dacf_clr_rsrvs() 505 * clear reservation list of operations of type 'op' 506 */ 507 void 508 dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op) 509 { 510 dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE); 511 } 512 513 /* 514 * dacf_process_rsrvs() 515 * iterate across a locked reservation list, processing each element 516 * which matches 'op' according to 'flags'. 517 * 518 * if DACF_PROC_INVOKE is specified, the elements that match 'op' 519 * will have their operations invoked. The return value from that 520 * operation is placed in the rsrv_result field of the dacf_rsrvlist_t 521 */ 522 void 523 dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags) 524 { 525 dacf_rsrvlist_t *p, *dp; 526 dacf_rsrvlist_t **prevptr; 527 528 ASSERT(MUTEX_HELD(&dacf_lock)); 529 ASSERT(list); 530 ASSERT(flags != 0); 531 532 if (*list == NULL) 533 return; 534 535 dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags); 536 537 /* 538 * Walk the list, finding rules whose opid's match op, and performing 539 * the work described by 'flags'. 540 */ 541 prevptr = list; 542 for (p = *list; p != NULL; ) { 543 544 if (p->rsrv_rule->r_opid != op) { 545 prevptr = &(p->rsrv_next); 546 p = p->rsrv_next; 547 continue; 548 } 549 550 if (flags & DACF_PROC_INVOKE) { 551 p->rsrv_result = dacf_op_invoke(p->rsrv_rule, 552 p->rsrv_ihdl, 0); 553 } 554 555 if (flags & DACF_PROC_RELE) { 556 *prevptr = p->rsrv_next; 557 dp = p; 558 p = p->rsrv_next; 559 dacf_rule_rele(dp->rsrv_rule); 560 kmem_free(dp, sizeof (dacf_rsrvlist_t)); 561 } else { 562 prevptr = &(p->rsrv_next); 563 p = p->rsrv_next; 564 } 565 } 566 } 567 568 /* 569 * dacf_get_op_hash() 570 * Given an op name, (i.e. "post-attach" or "pre-detach") and a 571 * devspec-type, return the hash that represents that op indexed 572 * by that devspec. 573 */ 574 static mod_hash_t * 575 dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type) 576 { 577 ASSERT(op <= DACF_NUM_OPIDS && op > 0); 578 ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0); 579 580 /* 581 * dacf_rule_matrix is an array of pointers to pointers to hashes. 582 */ 583 if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) { 584 return (NULL); 585 } 586 return (*(dacf_rule_matrix[op - 1][ds_type - 1])); 587 } 588 589 /* 590 * dacf_arg_insert() 591 * Create and insert an entry in an argument list. 592 * Returns -1 if the argument name is a duplicate of another already 593 * present in the hash. 594 */ 595 int 596 dacf_arg_insert(dacf_arg_t **list, char *name, char *val) 597 { 598 dacf_arg_t *arg; 599 600 /* 601 * Don't allow duplicates. 602 */ 603 for (arg = *list; arg != NULL; arg = arg->arg_next) { 604 if (strcmp(arg->arg_name, name) == 0) { 605 return (-1); 606 } 607 } 608 609 arg = kmem_alloc(sizeof (dacf_arg_t), KM_SLEEP); 610 arg->arg_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 611 (void) strcpy(arg->arg_name, name); 612 arg->arg_val = kmem_alloc(strlen(val) + 1, KM_SLEEP); 613 (void) strcpy(arg->arg_val, val); 614 615 arg->arg_next = *list; 616 *list = arg; 617 618 return (0); 619 } 620 621 /* 622 * dacf_arglist_delete() 623 * free all the elements of a list of dacf_arg_t's. 624 */ 625 void 626 dacf_arglist_delete(dacf_arg_t **list) 627 { 628 dacf_arg_t *arg, *narg; 629 arg = *list; 630 while (arg != NULL) { 631 narg = arg->arg_next; 632 kmem_free(arg->arg_name, strlen(arg->arg_name) + 1); 633 kmem_free(arg->arg_val, strlen(arg->arg_val) + 1); 634 kmem_free(arg, sizeof (dacf_arg_t)); 635 arg = narg; 636 } 637 *list = NULL; 638 } 639 640 /* 641 * dacf_match() 642 * Match a device-spec to a rule. 643 */ 644 dacf_rule_t * 645 dacf_match(dacf_opid_t op, dacf_devspec_t ds, const void *match_info) 646 { 647 dacf_rule_t *rule; 648 649 ASSERT(MUTEX_HELD(&dacf_lock)); 650 651 if (mod_hash_find(dacf_get_op_hash(op, ds), (mod_hash_key_t)match_info, 652 (mod_hash_val_t *)&rule) == 0) { 653 return (rule); 654 } 655 656 return (NULL); /* Not Found */ 657 } 658 659 /* 660 * dacf_module_register() 661 * register a module with the framework. Use when a module gets loaded, 662 * or for the kernel to register a "virtual" module (i.e. a "module" 663 * which the kernel provides). Makes a copy of the interface description 664 * provided by the module. 665 */ 666 int 667 dacf_module_register(char *mod_name, struct dacfsw *sw) 668 { 669 char *str; 670 size_t i, nelems; 671 dacf_module_t *module; 672 dacf_opset_t *opsarray; 673 674 if (sw == NULL) { 675 return (EINVAL); 676 } 677 678 if (sw->dacf_rev != DACF_MODREV_1) { 679 cmn_err(CE_WARN, "dacf: module '%s' exports unsupported " 680 "version %d interface, not registered\n", mod_name, 681 sw->dacf_rev); 682 return (EINVAL); 683 } 684 685 /* 686 * count how many opsets are provided. 687 */ 688 for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++) 689 ; 690 691 dprintf("dacf_module_register: found %lu opsets\n", nelems); 692 693 /* 694 * Temporary: It's ok for the kernel dacf_sw to have no opsets, since 695 * we don't have any opsets to export yet (in NON-DEBUG). 696 */ 697 if ((nelems == 0) && (sw != &kmod_dacfsw)) { 698 cmn_err(CE_WARN, "dacf module %s exports no opsets, " 699 "not registered.\n", mod_name); 700 return (EINVAL); 701 } 702 703 /* 704 * Look to see if the module has been previously registered with the 705 * framework. If so, we can fail with EBUSY. 706 */ 707 if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 708 (mod_hash_val_t)&module) == 0) { 709 /* 710 * See if it is loaded currently 711 */ 712 rw_enter(&module->dm_lock, RW_WRITER); 713 if (module->dm_loaded) { 714 rw_exit(&module->dm_lock); 715 cmn_err(CE_WARN, "dacf module '%s' is " 716 "already registered.", mod_name); 717 return (EBUSY); 718 } 719 } else { 720 /* 721 * This is the first time we've ever seen the module; stick 722 * it into the module hash. If that fails, we've had a 723 * race between two threads, both trying to insert the same 724 * new module. It's safe to stick the module into the 725 * hash only partly filled in, since dm_lock protects the 726 * structure, and we've got that write-locked. 727 */ 728 module = kmem_zalloc(sizeof (dacf_module_t), KM_SLEEP); 729 str = kmem_alloc(strlen(mod_name) + 1, KM_SLEEP); 730 (void) strcpy(str, mod_name); 731 rw_enter(&module->dm_lock, RW_WRITER); 732 733 if (mod_hash_insert(dacf_module_hash, (mod_hash_key_t)str, 734 (mod_hash_val_t)module) != 0) { 735 rw_exit(&module->dm_lock); 736 kmem_free(str, strlen(str) + 1); 737 kmem_free(module, sizeof (dacf_module_t)); 738 cmn_err(CE_WARN, "dacf module '%s' is " 739 "already registered.", mod_name); 740 return (EBUSY); 741 } 742 } 743 /* 744 * In either case (first time we've seen it or not), the module is 745 * not loaded, and we hold it write-locked. 746 */ 747 ASSERT(RW_WRITE_HELD(&module->dm_lock)); 748 749 /* 750 * Alloc array of opsets for this module. Add one for the final 751 * NULL entry 752 */ 753 opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP); 754 755 for (i = 0; i < nelems; i++) { 756 dacf_opset_copy(&(opsarray[i]), &(sw->dacf_opsets[i])); 757 ASSERT(opsarray[i].opset_name != NULL); 758 ASSERT(opsarray[i].opset_ops != NULL); 759 } 760 opsarray[nelems].opset_name = NULL; 761 opsarray[nelems].opset_ops = NULL; 762 763 ASSERT(module->dm_opsets == NULL); /* see dacf_destroy_opsets() */ 764 module->dm_opsets = opsarray; 765 766 if (dacfdebug & DACF_DBG_MSGS) { 767 dprintf("%s registered.\n", mod_name); 768 for (i = 0; i < nelems; i++) { 769 dprintf("registered %s\n", opsarray[i].opset_name); 770 } 771 } 772 773 module->dm_loaded = 1; 774 rw_exit(&module->dm_lock); 775 776 return (0); 777 } 778 779 /* 780 * dacf_module_unregister() 781 * remove a module from the framework, and free framework-allocated 782 * resources. 783 */ 784 int 785 dacf_module_unregister(char *mod_name) 786 { 787 dacf_module_t *module; 788 789 /* 790 * Can't unregister __kernel, since there is no real way to get it 791 * back-- Once it gets marked with dm_loaded == 0, the kernel will 792 * try to modload() if it is ever needed, which will fail utterly, 793 * and send op_invoke into a loop in it's modload logic 794 * 795 * If this is behavior is ever needed in the future, we can just 796 * add a flag indicating that this module is really a fake. 797 */ 798 ASSERT(strcmp(mod_name, kmod_name) != 0); 799 800 dprintf("dacf_module_unregister: called for '%s'!\n", mod_name); 801 802 /* 803 * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and 804 * that fails, return EBUSY, and fail to unregister. 805 */ 806 if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 807 (mod_hash_val_t)&module) == 0) { 808 if ((moddebug & MODDEBUG_NOAUL_DACF) || 809 !rw_tryenter(&module->dm_lock, RW_WRITER)) { 810 return (EBUSY); 811 } 812 } else { 813 return (EINVAL); 814 } 815 816 ASSERT(RW_WRITE_HELD(&module->dm_lock)); 817 dacf_destroy_opsets(module); 818 module->dm_loaded = 0; 819 rw_exit(&module->dm_lock); 820 return (0); 821 } 822 823 /* 824 * dacf_destroy_opsets() 825 * given a module, destroy all of it's associated op-sets. 826 */ 827 static void 828 dacf_destroy_opsets(dacf_module_t *module) 829 { 830 dacf_opset_t *array = module->dm_opsets; 831 dacf_opset_t *p; 832 int i; 833 size_t nelems; 834 835 ASSERT(RW_WRITE_HELD(&module->dm_lock)); 836 ASSERT(module->dm_loaded == 1); 837 838 for (i = 0; array[i].opset_name != NULL; i++) { 839 p = &(array[i]); 840 kmem_free(p->opset_name, strlen(p->opset_name) + 1); 841 /* 842 * count nelems in opset_ops 843 */ 844 for (nelems = 0; ; nelems++) { 845 if (p->opset_ops[nelems].op_id == DACF_OPID_END) { 846 break; 847 } 848 } 849 /* 850 * Free the array of op ptrs. 851 */ 852 kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1)); 853 } 854 855 /* 856 * i has counted how big array is; +1 to account for the last element. 857 */ 858 kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1)); 859 module->dm_opsets = NULL; 860 } 861 862 /* 863 * dacf_opset_copy() 864 * makes a copy of a dacf_opset_t. 865 */ 866 static void 867 dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src) 868 { 869 size_t nelems, i; 870 ASSERT(src && dst); 871 872 dprintf("dacf_opset_copy: called\n"); 873 874 dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP); 875 (void) strcpy(dst->opset_name, src->opset_name); 876 877 dprintf("dacf_opset_copy: counting ops\n"); 878 879 for (nelems = 0; ; nelems++) { 880 if ((src->opset_ops[nelems].op_id == DACF_OPID_END) || 881 (src->opset_ops[nelems].op_func == NULL)) { 882 break; 883 } 884 } 885 886 dprintf("dacf_opset_copy: found %lu ops\n", nelems); 887 888 dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1), 889 KM_SLEEP); 890 891 dprintf("dacf_opset_copy: copying ops\n"); 892 for (i = 0; i < nelems; i++) { 893 dst->opset_ops[i].op_id = src->opset_ops[i].op_id; 894 dst->opset_ops[i].op_func = src->opset_ops[i].op_func; 895 } 896 dst->opset_ops[nelems].op_id = DACF_OPID_END; 897 dst->opset_ops[nelems].op_func = NULL; 898 899 dprintf("dacf_opset_copy: done copying ops\n"); 900 } 901 902 int dacf_modload_laps = 0; /* just a diagnostic aid */ 903 904 /* 905 * dacf_op_invoke() 906 * Invoke a op in a opset in a module given the rule to invoke. 907 * 908 * If the return value of dacf_op_invoke is 0, then rval contains the 909 * return value of the _op_ being invoked. Otherwise, dacf_op_invoke's 910 * return value indicates why the op invocation failed. 911 */ 912 int 913 dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags) 914 { 915 dacf_module_t *module; 916 dacf_opset_t *opsarray; 917 dacf_opset_t *opset; 918 dacf_op_t *op = NULL; 919 dacf_opid_t op_id; 920 dacf_arghdl_t arg_hdl; 921 dev_info_t *dip; 922 int i, rval = -1; 923 924 ASSERT(rule); 925 ASSERT(MUTEX_HELD(&dacf_lock)); 926 927 op_id = rule->r_opid; 928 dprintf("dacf_op_invoke: opid=%d\n", op_id); 929 930 /* 931 * Take laps, trying to load the dacf module. For the case of kernel- 932 * provided operations, __kernel will be found in the hash table, and 933 * no modload will be needed. 934 */ 935 for (;;) { 936 if (mod_hash_find(dacf_module_hash, 937 (mod_hash_key_t)rule->r_module, 938 (mod_hash_val_t *)&module) == 0) { 939 rw_enter(&module->dm_lock, RW_READER); 940 /* 941 * Found the module, and it is loaded. 942 */ 943 if (module->dm_loaded != 0) { 944 break; 945 } 946 rw_exit(&module->dm_lock); 947 } 948 949 /* 950 * If we're here, either: 1) it's not in the hash, or 2) it is, 951 * but dm_loaded is 0, meaning the module needs to be loaded. 952 */ 953 dprintf("dacf_op_invoke: calling modload\n"); 954 if (modload("dacf", rule->r_module) < 0) { 955 return (DACF_ERR_MOD_NOTFOUND); 956 } 957 dacf_modload_laps++; 958 } 959 960 ASSERT(RW_READ_HELD(&module->dm_lock)); 961 962 opsarray = module->dm_opsets; 963 964 /* 965 * Loop through the opsets exported by this module, and find the one 966 * we care about. 967 */ 968 opset = NULL; 969 for (i = 0; opsarray[i].opset_name != NULL; i++) { 970 if (strcmp(opsarray[i].opset_name, rule->r_opset) == 0) { 971 opset = &opsarray[i]; 972 break; 973 } 974 } 975 976 if (opset == NULL) { 977 cmn_err(CE_WARN, "!dacf: couldn't invoke op, opset '%s' not " 978 "found in module '%s'", rule->r_opset, rule->r_module); 979 rw_exit(&module->dm_lock); 980 return (DACF_ERR_OPSET_NOTFOUND); 981 } 982 983 arg_hdl = (dacf_arghdl_t)rule->r_args; 984 985 /* 986 * Call the appropriate routine in the target by looping across the 987 * ops until we find the one whose id matches opid. 988 */ 989 op = NULL; 990 for (i = 0; opset->opset_ops[i].op_id != DACF_OPID_END; i++) { 991 if (opset->opset_ops[i].op_id == op_id) { 992 op = &(opset->opset_ops[i]); 993 break; 994 } 995 } 996 997 if (op == NULL) { 998 cmn_err(CE_WARN, "!dacf: couldn't invoke op, op '%s' not found " 999 "in opset '%s' in module '%s'", dacf_opid_to_str(op_id), 1000 rule->r_opset, rule->r_module); 1001 rw_exit(&module->dm_lock); 1002 return (DACF_ERR_OP_NOTFOUND); 1003 } 1004 1005 dprintf("dacf_op_invoke: found op, invoking...\n"); 1006 1007 /* 1008 * Drop dacf_lock here, so that op_func's that cause drivers to 1009 * get loaded don't wedge the system when they try to acquire dacf_lock 1010 * to do matching. 1011 * 1012 * Mark that an invoke is happening to prevent recursive invokes 1013 */ 1014 dip = ((struct ddi_minor_data *)info_hdl)->dip; 1015 1016 mutex_enter(&(DEVI(dip)->devi_lock)); 1017 DEVI_SET_INVOKING_DACF(dip); 1018 mutex_exit(&(DEVI(dip)->devi_lock)); 1019 1020 mutex_exit(&dacf_lock); 1021 1022 rval = op->op_func(info_hdl, arg_hdl, flags); 1023 1024 mutex_enter(&dacf_lock); 1025 1026 /* 1027 * Completed the invocation against module, so let go of it. 1028 */ 1029 mutex_enter(&(DEVI(dip)->devi_lock)); 1030 DEVI_CLR_INVOKING_DACF(dip); 1031 mutex_exit(&(DEVI(dip)->devi_lock)); 1032 1033 /* 1034 * Drop our r-lock on the module, now that we no longer need the module 1035 * to stay loaded. 1036 */ 1037 rw_exit(&module->dm_lock); 1038 1039 if (rval == DACF_SUCCESS) { 1040 return (DACF_SUCCESS); 1041 } else { 1042 return (DACF_ERR_OP_FAILED); 1043 } 1044 } 1045 1046 /* 1047 * dacf_get_devspec() 1048 * given a devspec-type as a string, return a corresponding dacf_devspec_t 1049 */ 1050 dacf_devspec_t 1051 dacf_get_devspec(char *name) 1052 { 1053 dacf_ds_t *p = &dacf_devspecs[0]; 1054 1055 while (p->name != NULL) { 1056 if (strcmp(p->name, name) == 0) { 1057 return (p->id); 1058 } 1059 p++; 1060 } 1061 return (DACF_DS_ERROR); 1062 } 1063 1064 /* 1065 * dacf_devspec_to_str() 1066 * given a dacf_devspec_t, return a pointer to the human readable string 1067 * representation of that device specifier. 1068 */ 1069 const char * 1070 dacf_devspec_to_str(dacf_devspec_t ds) 1071 { 1072 dacf_ds_t *p = &dacf_devspecs[0]; 1073 1074 while (p->name != NULL) { 1075 if (p->id == ds) { 1076 return (p->name); 1077 } 1078 p++; 1079 } 1080 return (NULL); 1081 } 1082 1083 /* 1084 * dacf_get_op() 1085 * given a op name, returns the corresponding dacf_opid_t. 1086 */ 1087 dacf_opid_t 1088 dacf_get_op(char *name) 1089 { 1090 dacf_opmap_t *p = &dacf_ops[0]; 1091 1092 while (p->name != NULL) { 1093 if (strcmp(p->name, name) == 0) { 1094 return (p->id); 1095 } 1096 p++; 1097 } 1098 return (DACF_OPID_ERROR); 1099 } 1100 1101 /* 1102 * dacf_opid_to_str() 1103 * given a dacf_opid_t, return the human-readable op-name. 1104 */ 1105 const char * 1106 dacf_opid_to_str(dacf_opid_t tid) 1107 { 1108 dacf_opmap_t *p = &dacf_ops[0]; 1109 1110 while (p->name != NULL) { 1111 if (p->id == tid) { 1112 return (p->name); 1113 } 1114 p++; 1115 } 1116 return (NULL); 1117 } 1118 1119 /* 1120 * dacf_getopt() 1121 * given an option specified as a string, add it to the bit-field of 1122 * options given. Returns -1 if the option is unrecognized. 1123 */ 1124 int 1125 dacf_getopt(char *opt_str, uint_t *opts) 1126 { 1127 dacf_opt_t *p = &dacf_options[0]; 1128 1129 /* 1130 * Look through the list for the option given 1131 */ 1132 while (p->optname != NULL) { 1133 if (strcmp(opt_str, p->optname) == 0) { 1134 *opts |= p->optmask; 1135 return (0); 1136 } 1137 p++; 1138 } 1139 return (-1); 1140 } 1141 1142 1143 1144 /* 1145 * This family of functions forms the dacf interface which is exported to 1146 * kernel/dacf modules. Modules _should_not_ use any dacf_* functions 1147 * presented above this point. 1148 * 1149 * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and 1150 * assume that the resulting pointer is not to an alias node. That is true 1151 * because dacf_op_invoke guarantees it by first resolving the alias. 1152 */ 1153 1154 /* 1155 * dacf_minor_name() 1156 * given a dacf_infohdl_t, obtain the minor name of the device instance 1157 * being configured. 1158 */ 1159 const char * 1160 dacf_minor_name(dacf_infohdl_t info_hdl) 1161 { 1162 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1163 1164 return (dmdp->ddm_name); 1165 } 1166 1167 /* 1168 * dacf_minor_number() 1169 * given a dacf_infohdl_t, obtain the device minor number of the instance 1170 * being configured. 1171 */ 1172 minor_t 1173 dacf_minor_number(dacf_infohdl_t info_hdl) 1174 { 1175 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1176 1177 return (getminor(dmdp->ddm_dev)); 1178 } 1179 1180 /* 1181 * dacf_get_dev() 1182 * given a dacf_infohdl_t, obtain the dev_t of the instance being 1183 * configured. 1184 */ 1185 dev_t 1186 dacf_get_dev(dacf_infohdl_t info_hdl) 1187 { 1188 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1189 1190 return (dmdp->ddm_dev); 1191 } 1192 1193 /* 1194 * dacf_driver_name() 1195 * given a dacf_infohdl_t, obtain the device driver name of the device 1196 * instance being configured. 1197 */ 1198 const char * 1199 dacf_driver_name(dacf_infohdl_t info_hdl) 1200 { 1201 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1202 1203 return (ddi_driver_name(dmdp->dip)); 1204 } 1205 1206 /* 1207 * dacf_devinfo_node() 1208 * given a dacf_infohdl_t, obtain the dev_info_t of the device instance 1209 * being configured. 1210 */ 1211 dev_info_t * 1212 dacf_devinfo_node(dacf_infohdl_t info_hdl) 1213 { 1214 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1215 1216 return (dmdp->dip); 1217 } 1218 1219 /* 1220 * dacf_get_arg() 1221 * given the dacf_arghdl_t passed to a op and the name of an argument, 1222 * return the value of that argument. 1223 * 1224 * returns NULL if the argument is not found. 1225 */ 1226 const char * 1227 dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name) 1228 { 1229 dacf_arg_t *arg_list = (dacf_arg_t *)arghdl; 1230 ASSERT(arg_name); 1231 1232 while (arg_list != NULL) { 1233 if (strcmp(arg_list->arg_name, arg_name) == 0) { 1234 return (arg_list->arg_val); 1235 } 1236 arg_list = arg_list->arg_next; 1237 } 1238 1239 return (NULL); 1240 } 1241 1242 /* 1243 * dacf_store_info() 1244 * associate instance-specific data with a device instance. Future 1245 * configuration ops invoked for this instance can retrieve this data using 1246 * dacf_retrieve_info() below. Modules are responsible for cleaning up 1247 * this data as appropriate, and should store NULL as the value of 'data' 1248 * when the data is no longer valid. 1249 */ 1250 void 1251 dacf_store_info(dacf_infohdl_t info_hdl, void *data) 1252 { 1253 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1254 1255 /* 1256 * If the client is 'storing NULL' we can represent that by blowing 1257 * the info entry out of the hash. 1258 */ 1259 if (data == NULL) { 1260 (void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp); 1261 } else { 1262 /* 1263 * mod_hash_replace can only fail on out of memory, but we sleep 1264 * for memory in this hash, so it is safe to ignore the retval. 1265 */ 1266 (void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp, 1267 (mod_hash_val_t)data); 1268 } 1269 } 1270 1271 /* 1272 * dacf_retrieve_info() 1273 * retrieve instance-specific data associated with a device instance. 1274 */ 1275 void * 1276 dacf_retrieve_info(dacf_infohdl_t info_hdl) 1277 { 1278 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1279 void *data; 1280 1281 if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp, 1282 (mod_hash_val_t *)&data) != 0) { 1283 return (NULL); 1284 } 1285 1286 return (data); 1287 } 1288 1289 /* 1290 * dacf_makevp() 1291 * make a vnode for the specified dacf_infohdl_t. 1292 */ 1293 struct vnode * 1294 dacf_makevp(dacf_infohdl_t info_hdl) 1295 { 1296 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1297 struct vnode *vp; 1298 1299 vp = makespecvp(dmdp->ddm_dev, VCHR); 1300 spec_assoc_vp_with_devi(vp, dmdp->dip); 1301 return (vp); 1302 } 1303