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