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