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 2006 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 * Instance number assignment code 30 */ 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/errno.h> 35 #include <sys/systm.h> 36 #include <sys/kobj.h> 37 #include <sys/t_lock.h> 38 #include <sys/kmem.h> 39 #include <sys/cmn_err.h> 40 #include <sys/ddi.h> 41 #include <sys/sunddi.h> 42 #include <sys/autoconf.h> 43 #include <sys/systeminfo.h> 44 #include <sys/hwconf.h> 45 #include <sys/reboot.h> 46 #include <sys/ddi_impldefs.h> 47 #include <sys/instance.h> 48 #include <sys/debug.h> 49 #include <sys/sysevent.h> 50 #include <sys/modctl.h> 51 #include <sys/console.h> 52 #include <sys/cladm.h> 53 54 static void in_preassign_instance(void); 55 static void i_log_devfs_instance_mod(void); 56 static int in_get_infile(char *); 57 static void in_removenode(struct devnames *dnp, in_node_t *mp, in_node_t *ap); 58 static in_node_t *in_alloc_node(char *name, char *addr); 59 static int in_eqstr(char *a, char *b); 60 static char *in_name_addr(char **cpp, char **addrp); 61 static in_node_t *in_devwalk(dev_info_t *dip, in_node_t **ap, char *addr); 62 static void in_dealloc_node(in_node_t *np); 63 static in_node_t *in_make_path(char *path); 64 static void in_enlist(in_node_t *ap, in_node_t *np); 65 static int in_inuse(int instance, char *name); 66 static void in_hashdrv(in_drv_t *dp); 67 static in_drv_t *in_drvwalk(in_node_t *np, char *binding_name); 68 static in_drv_t *in_alloc_drv(char *bindingname); 69 static void in_endrv(in_node_t *np, in_drv_t *dp); 70 static void in_dq_drv(in_drv_t *np); 71 static void in_removedrv(struct devnames *dnp, in_drv_t *mp); 72 static int in_pathin(char *cp, int instance, char *bname, struct bind **args); 73 static int in_next_instance_block(major_t, int); 74 static int in_next_instance(major_t); 75 76 /* external functions */ 77 extern char *i_binding_to_drv_name(char *bname); 78 79 /* 80 * This plus devnames defines the entire software state of the instance world. 81 */ 82 typedef struct in_softstate { 83 in_node_t *ins_root; /* the root of our instance tree */ 84 in_drv_t *ins_no_major; /* majorless drv entries */ 85 /* 86 * Used to serialize access to data structures 87 */ 88 void *ins_thread; 89 kmutex_t ins_serial; 90 kcondvar_t ins_serial_cv; 91 int ins_busy; 92 char ins_dirty; /* need flush */ 93 } in_softstate_t; 94 95 static in_softstate_t e_ddi_inst_state; 96 97 /* 98 * State transition information: 99 * e_ddi_inst_state contains, among other things, the root of a tree of 100 * device nodes used to track instance number assignments. 101 * Each device node may contain multiple driver bindings, represented 102 * by a linked list of in_drv_t nodes, each with an instance assignment 103 * (except for root node). Each in_drv node can be in one of 3 states, 104 * indicated by ind_state: 105 * 106 * IN_UNKNOWN: Each node created in this state. The instance number of 107 * this node is not known. ind_instance is set to -1. 108 * IN_PROVISIONAL: When a node is assigned an instance number in 109 * e_ddi_assign_instance(), its state is set to IN_PROVISIONAL. 110 * Subsequently, the framework will always call either 111 * e_ddi_keep_instance() which makes the node IN_PERMANENT, 112 * or e_ddi_free_instance(), which deletes the node. 113 * IN_PERMANENT: 114 * If e_ddi_keep_instance() is called on an IN_PROVISIONAL node, 115 * its state is set to IN_PERMANENT. 116 */ 117 118 static char *instance_file = INSTANCE_FILE; 119 static char *instance_file_backup = INSTANCE_FILE INSTANCE_FILE_SUFFIX; 120 121 /* 122 * Return values for in_get_infile(). 123 */ 124 #define PTI_FOUND 0 125 #define PTI_NOT_FOUND 1 126 #define PTI_REBUILD 2 127 128 /* 129 * Path to instance file magic string used for first time boot after 130 * an install. If this is the first string in the file we will 131 * automatically rebuild the file. 132 */ 133 #define PTI_MAGIC_STR "#path_to_inst_bootstrap_1" 134 #define PTI_MAGIC_STR_LEN (sizeof (PTI_MAGIC_STR) - 1) 135 136 void 137 e_ddi_instance_init(void) 138 { 139 char *file; 140 int rebuild = 1; 141 struct in_drv *dp; 142 143 mutex_init(&e_ddi_inst_state.ins_serial, NULL, MUTEX_DEFAULT, NULL); 144 cv_init(&e_ddi_inst_state.ins_serial_cv, NULL, CV_DEFAULT, NULL); 145 146 /* 147 * Only one thread is allowed to change the state of the instance 148 * number assignments on the system at any given time. 149 * Note that this is not really necessary, as we are single-threaded 150 * here, but it won't hurt, and it allows us to keep ASSERTS for 151 * our assumptions in the code. 152 */ 153 e_ddi_enter_instance(); 154 155 /* 156 * Create the root node, instance zallocs to 0. 157 * The name and address of this node never get examined, we always 158 * start searching with its first child. 159 */ 160 ASSERT(e_ddi_inst_state.ins_root == NULL); 161 e_ddi_inst_state.ins_root = in_alloc_node(NULL, NULL); 162 dp = in_alloc_drv("rootnex"); 163 in_endrv(e_ddi_inst_state.ins_root, dp); 164 165 file = instance_file; 166 switch (in_get_infile(file)) { 167 default: 168 case PTI_NOT_FOUND: 169 /* make sure path_to_inst is recreated */ 170 boothowto |= RB_RECONFIG; 171 172 /* 173 * Something is wrong. First try the backup file. 174 * If not found, rebuild path_to_inst. Emit a 175 * message about the problem. 176 */ 177 cmn_err(CE_WARN, "%s empty or not found", file); 178 179 file = instance_file_backup; 180 if (in_get_infile(file) != PTI_FOUND) { 181 cmn_err(CE_NOTE, "rebuilding device instance data"); 182 break; 183 } 184 cmn_err(CE_NOTE, "using backup instance data in %s", file); 185 /*FALLTHROUGH*/ 186 187 case PTI_FOUND: 188 /* 189 * We've got a readable file 190 * parse the file into the instance tree 191 */ 192 (void) read_binding_file(file, NULL, in_pathin); 193 rebuild = 0; 194 break; 195 196 case PTI_REBUILD: 197 cmn_err(CE_CONT, 198 "?Using default device instance data\n"); 199 break; 200 } 201 202 /* 203 * The OBP device tree has been copied to the kernel and 204 * bound to drivers at this point. We walk the per-driver 205 * list to preassign instances. Since the bus addr is 206 * unknown at this point, we cannot place the instance 207 * number in the instance tree. This will be done at 208 * a later time. 209 */ 210 if (rebuild) 211 in_preassign_instance(); 212 213 e_ddi_exit_instance(); 214 } 215 216 static void 217 in_preassign_instance() 218 { 219 major_t m; 220 extern major_t devcnt; 221 222 for (m = 0; m < devcnt; m++) { 223 struct devnames *dnp = &devnamesp[m]; 224 dev_info_t *dip = dnp->dn_head; 225 while (dip) { 226 DEVI(dip)->devi_instance = dnp->dn_instance; 227 dnp->dn_instance++; 228 dip = ddi_get_next(dip); 229 } 230 } 231 } 232 233 /* 234 * Checks to see if the /etc/path_to_inst file exists and whether or not 235 * it has the magic string in it. 236 * 237 * Returns one of the following: 238 * 239 * PTI_FOUND - We have found the /etc/path_to_inst file 240 * PTI_REBUILD - We have found the /etc/path_to_inst file and the 241 * first line was PTI_MAGIC_STR. 242 * PTI_NOT_FOUND - We did not find the /etc/path_to_inst file 243 * 244 */ 245 static int 246 in_get_infile(char *filename) 247 { 248 intptr_t file; 249 int return_val; 250 char buf[PTI_MAGIC_STR_LEN]; 251 252 /* 253 * Try to open the file. 254 */ 255 if ((file = kobj_open(filename)) == -1) { 256 return (PTI_NOT_FOUND); 257 } 258 return_val = PTI_FOUND; 259 260 /* 261 * Read the first PTI_MAGIC_STR_LEN bytes from the file to see if 262 * it contains the magic string. If there aren't that many bytes 263 * in the file, then assume file is correct and no magic string 264 * and move on. 265 */ 266 switch (kobj_read(file, buf, PTI_MAGIC_STR_LEN, 0)) { 267 268 case PTI_MAGIC_STR_LEN: 269 /* 270 * If the first PTI_MAGIC_STR_LEN bytes are the magic string 271 * then return PTI_REBUILD. 272 */ 273 if (strncmp(PTI_MAGIC_STR, buf, PTI_MAGIC_STR_LEN) == 0) 274 return_val = PTI_REBUILD; 275 break; 276 277 case 0: 278 /* 279 * If the file is zero bytes in length, then consider the 280 * file to not be found 281 */ 282 return_val = PTI_NOT_FOUND; 283 284 default: /* Do nothing we have a good file */ 285 break; 286 } 287 288 kobj_close(file); 289 return (return_val); 290 } 291 292 int 293 is_pseudo_device(dev_info_t *dip) 294 { 295 dev_info_t *pdip; 296 297 for (pdip = ddi_get_parent(dip); pdip && pdip != ddi_root_node(); 298 pdip = ddi_get_parent(pdip)) { 299 if (strcmp(ddi_get_name(pdip), DEVI_PSEUDO_NEXNAME) == 0) 300 return (1); 301 } 302 return (0); 303 } 304 305 306 static void 307 in_set_instance(dev_info_t *dip, in_drv_t *dp, major_t major) 308 { 309 /* use preassigned instance if available */ 310 if (DEVI(dip)->devi_instance != -1) 311 dp->ind_instance = DEVI(dip)->devi_instance; 312 else 313 dp->ind_instance = in_next_instance(major); 314 } 315 316 /* 317 * Return 1 if instance block was assigned for the path. 318 * 319 * For multi-port NIC cards, sequential instance assignment across all 320 * ports on a card is highly deseriable since the ppa is typically the 321 * same as the instance number, and the ppa is used in the NIC's public 322 * /dev name. This sequential assignment typically occurs as a result 323 * of in_preassign_instance() after initial install, or by 324 * i_ndi_init_hw_children() for NIC ports that share a common parent. 325 * 326 * Some NIC cards however use multi-function bridge chips, and to 327 * support sequential instance assignment accross all ports, without 328 * disabling multi-threaded attach, we have a (currently) undocumented 329 * hack to allocate instance numbers in contiguous blocks based on 330 * driver.conf properties. 331 * 332 * ^ 333 * /---------- ------------\ 334 * pci@0 pci@0,1 MULTI-FUNCTION BRIDGE CHIP 335 * / \ / \ 336 * FJSV,e4ta@4 FJSV,e4ta@4,1 FJSV,e4ta@6 FJSV,e4ta@6,1 NIC PORTS 337 * n n+2 n+2 n+3 INSTANCE 338 * 339 * For the above example, the following driver.conf properties would be 340 * used to guarantee sequential instance number assignment. 341 * 342 * ddi-instance-blocks ="ib-FJSVe4ca", "ib-FJSVe4ta", "ib-generic"; 343 * ib-FJSVe4ca = "/pci@0/FJSV,e4ca@4", "/pci@0/FJSV,e4ca@4,1", 344 * "/pci@0,1/FJSV,e4ca@6", "/pci@0,1/FJSV,e4ca@6,1"; 345 * ib-FJSVe4ta = "/pci@0/FJSV,e4ta@4", "/pci@0/FJSV,e4ta@4,1", 346 * "/pci@0,1/FJSV,e4ta@6", "/pci@0,1/FJSV,e4ta@6,1"; 347 * ib-generic = "/pci@0/network@4", "/pci@0/network@4,1", 348 * "/pci@0,1/network@6", "/pci@0,1/network@6,1"; 349 * 350 * The value of the 'ddi-instance-blocks' property references a series 351 * of card specific properties, like 'ib-FJSV-e4ta', who's value 352 * defines a single 'instance block'. The 'instance block' describes 353 * all the paths below a multi-function bridge, where each path is 354 * called an 'instance path'. The 'instance block' property value is a 355 * series of 'instance paths'. The number of 'instance paths' in an 356 * 'instance block' defines the size of the instance block, and the 357 * ordering of the 'instance paths' defines the instance number 358 * assignment order for paths going through the 'instance block'. 359 * 360 * In the instance assignment code below, if a (path, driver) that 361 * currently has no instance number has a path that goes through an 362 * 'instance block', then block instance number allocation occurs. The 363 * block allocation code will find a sequential set of unused instance 364 * numbers, and assign instance numbers for all the paths in the 365 * 'instance block'. Each path is assigned a persistent instance 366 * number, even paths that don't exist in the device tree or fail 367 * probe(9E). 368 */ 369 static int 370 in_assign_instance_block(dev_info_t *dip) 371 { 372 char **ibn; /* instance block names */ 373 uint_t nibn; /* number of instance block names */ 374 uint_t ibni; /* ibn index */ 375 char *driver; 376 major_t major; 377 char *path; 378 char *addr; 379 int plen; 380 char **ibp; /* instance block paths */ 381 uint_t nibp; /* number of paths in instance block */ 382 uint_t ibpi; /* ibp index */ 383 int ibplen; /* length of instance block path */ 384 char *ipath; 385 int instance_base; 386 int splice; 387 int i; 388 389 /* check for fresh install case (in miniroot) */ 390 if (DEVI(dip)->devi_instance != -1) 391 return (0); /* already assigned */ 392 393 /* 394 * Check to see if we need to allocate a block of contiguous instance 395 * numbers by looking for the 'ddi-instance-blocks' property. 396 */ 397 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 398 "ddi-instance-blocks", &ibn, &nibn) != DDI_SUCCESS) 399 return (0); /* no instance block needed */ 400 401 /* 402 * Get information out about node we are processing. 403 * 404 * NOTE: Since the node is not yet at DS_INITIALIZED, ddi_pathname() 405 * will not return the unit-address of the final path component even 406 * though the node has an established devi_addr unit-address - so we 407 * need to add the unit-address by hand. 408 */ 409 driver = (char *)ddi_driver_name(dip); 410 major = ddi_driver_major(dip); 411 path = kmem_alloc(MAXPATHLEN, KM_SLEEP); 412 (void) ddi_pathname(dip, path); 413 if ((addr = ddi_get_name_addr(dip)) != NULL) { 414 (void) strcat(path, "@"); 415 (void) strcat(path, addr); 416 } 417 plen = strlen(path); 418 419 /* loop through instance block names */ 420 for (ibni = 0; ibni < nibn; ibni++) { 421 if (ibn[ibni] == NULL) 422 continue; 423 424 /* lookup instance block */ 425 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 426 DDI_PROP_DONTPASS, ibn[ibni], 427 &ibp, &nibp) != DDI_SUCCESS) { 428 cmn_err(CE_WARN, 429 "no devinition for instance block '%s' in %s.conf", 430 ibn[ibni], driver); 431 continue; 432 } 433 434 /* Does 'path' go through this instance block? */ 435 for (ibpi = 0; ibpi < nibp; ibpi++) { 436 if (ibp[ibpi] == NULL) 437 continue; 438 ibplen = strlen(ibp[ibpi]); 439 if ((ibplen <= plen) && 440 (strcmp(ibp[ibpi], path + plen - ibplen) == 0)) 441 break; 442 443 } 444 if (ibpi >= nibp) { 445 ddi_prop_free(ibp); 446 continue; /* no try next instance block */ 447 } 448 449 /* yes, allocate and assign instances for all paths in block */ 450 451 /* 452 * determine where we splice in instance paths and verify 453 * that none of the paths are too long. 454 */ 455 splice = plen - ibplen; 456 for (i = 0; i < nibp; i++) { 457 if ((splice + strlen(ibp[i])+ 1) >= MAXPATHLEN) { 458 cmn_err(CE_WARN, 459 "path %d through instance block '%s' from " 460 "%s.conf too long", i, ibn[ibni], driver); 461 break; 462 } 463 } 464 if (i < nibp) { 465 ddi_prop_free(ibp); 466 continue; /* too long */ 467 } 468 469 /* allocate the instance block - no more failures */ 470 instance_base = in_next_instance_block(major, nibp); 471 472 ipath = kmem_alloc(MAXPATHLEN, KM_SLEEP); 473 for (ibpi = 0; ibpi < nibp; ibpi++) { 474 if (ibp[ibpi] == NULL) 475 continue; 476 (void) strcpy(ipath, path); 477 (void) strcpy(ipath + splice, ibp[ibpi]); 478 (void) in_pathin(ipath, 479 instance_base + ibpi, driver, NULL); 480 } 481 482 /* free allocations */ 483 kmem_free(ipath, MAXPATHLEN); 484 ddi_prop_free(ibp); 485 kmem_free(path, MAXPATHLEN); 486 ddi_prop_free(ibn); 487 488 /* notify devfsadmd to sync of path_to_inst file */ 489 mutex_enter(&e_ddi_inst_state.ins_serial); 490 i_log_devfs_instance_mod(); 491 e_ddi_inst_state.ins_dirty = 1; 492 mutex_exit(&e_ddi_inst_state.ins_serial); 493 return (1); 494 } 495 496 /* our path did not go through any of of the instance blocks */ 497 kmem_free(path, MAXPATHLEN); 498 ddi_prop_free(ibn); 499 return (0); 500 } 501 502 /* 503 * Look up an instance number for a dev_info node, and assign one if it does 504 * not have one (the dev_info node has devi_name and devi_addr already set). 505 */ 506 uint_t 507 e_ddi_assign_instance(dev_info_t *dip) 508 { 509 char *name; 510 in_node_t *ap, *np; 511 in_drv_t *dp; 512 major_t major; 513 uint_t ret; 514 char *bname; 515 516 /* 517 * Allow implementation to override 518 */ 519 if ((ret = impl_assign_instance(dip)) != (uint_t)-1) 520 return (ret); 521 522 /* 523 * If this is a pseudo-device, use the instance number 524 * assigned by the pseudo nexus driver. The mutex is 525 * not needed since the instance tree is not used. 526 */ 527 if (is_pseudo_device(dip)) { 528 return (ddi_get_instance(dip)); 529 } 530 531 /* 532 * Only one thread is allowed to change the state of the instance 533 * number assignments on the system at any given time. 534 */ 535 e_ddi_enter_instance(); 536 537 /* 538 * Look for instance node, allocate one if not found 539 */ 540 np = in_devwalk(dip, &ap, NULL); 541 if (np == NULL) { 542 if (in_assign_instance_block(dip)) { 543 np = in_devwalk(dip, &ap, NULL); 544 } else { 545 name = ddi_node_name(dip); 546 np = in_alloc_node(name, ddi_get_name_addr(dip)); 547 ASSERT(np != NULL); 548 in_enlist(ap, np); /* insert into tree */ 549 } 550 } 551 ASSERT(np == in_devwalk(dip, &ap, NULL)); 552 553 /* 554 * Look for driver entry, allocate one if not found 555 */ 556 bname = (char *)ddi_driver_name(dip); 557 dp = in_drvwalk(np, bname); 558 if (dp == NULL) { 559 dp = in_alloc_drv(bname); 560 ASSERT(dp != NULL); 561 major = ddi_driver_major(dip); 562 ASSERT(major != (major_t)-1); 563 in_endrv(np, dp); 564 in_set_instance(dip, dp, major); 565 dp->ind_state = IN_PROVISIONAL; 566 in_hashdrv(dp); 567 } 568 569 ret = dp->ind_instance; 570 571 e_ddi_exit_instance(); 572 return (ret); 573 } 574 575 static int 576 mkpathname(char *path, in_node_t *np, int len) 577 { 578 int len_needed; 579 580 if (np == e_ddi_inst_state.ins_root) 581 return (DDI_SUCCESS); 582 583 if (mkpathname(path, np->in_parent, len) == DDI_FAILURE) 584 return (DDI_FAILURE); 585 586 len_needed = strlen(path); 587 len_needed += strlen(np->in_node_name) + 1; /* for '/' */ 588 if (np->in_unit_addr) { 589 len_needed += strlen(np->in_unit_addr) + 1; /* for '@' */ 590 } 591 len_needed += 1; /* for '\0' */ 592 593 /* 594 * XX complain 595 */ 596 if (len_needed > len) 597 return (DDI_FAILURE); 598 599 if (np->in_unit_addr[0] == '\0') 600 (void) sprintf(path+strlen(path), "/%s", np->in_node_name); 601 else 602 (void) sprintf(path+strlen(path), "/%s@%s", np->in_node_name, 603 np->in_unit_addr); 604 605 return (DDI_SUCCESS); 606 } 607 608 /* 609 * produce the path to the given instance of a major number. 610 * path must hold MAXPATHLEN string 611 */ 612 int 613 e_ddi_instance_majorinstance_to_path(major_t major, uint_t inst, char *path) 614 { 615 struct devnames *dnp; 616 in_drv_t *dp; 617 int ret; 618 619 e_ddi_enter_instance(); 620 621 /* look for the instance threaded off major */ 622 dnp = &devnamesp[major]; 623 for (dp = dnp->dn_inlist; dp != NULL; dp = dp->ind_next) 624 if (dp->ind_instance == inst) 625 break; 626 627 /* produce path from the node that uses the instance */ 628 if (dp) { 629 *path = 0; 630 ret = mkpathname(path, dp->ind_node, MAXPATHLEN); 631 } else 632 ret = DDI_FAILURE; 633 634 e_ddi_exit_instance(); 635 return (ret); 636 } 637 638 /* 639 * Allocate a sequential block of instance numbers for the specified driver, 640 * and return the base instance number of the block. The implementation 641 * depends on the list being sorted in ascending instance number sequence. 642 * When there are no 'holes' in the allocation sequence, dn_instance is the 643 * next available instance number. When dn_instance is IN_SEARCHME, hole(s) 644 * exists and a slower code path executes which tries to fill holes. 645 */ 646 static int 647 in_next_instance_block(major_t major, int block_size) 648 { 649 unsigned int prev; 650 struct devnames *dnp; 651 in_drv_t *dp; 652 int base; 653 int hole; 654 655 dnp = &devnamesp[major]; 656 ASSERT(major != (major_t)-1); 657 ASSERT(e_ddi_inst_state.ins_busy); 658 ASSERT(block_size); 659 660 /* check to see if we can do a quick allocation */ 661 if (dnp->dn_instance != IN_SEARCHME) { 662 base = dnp->dn_instance; 663 dnp->dn_instance += block_size; 664 return (base); 665 } 666 dp = dnp->dn_inlist; 667 668 /* no existing entries, allocate block at 0 */ 669 if (dp == NULL) { 670 dnp->dn_instance = block_size; 671 return (0); 672 } 673 674 prev = dp->ind_instance; 675 if (prev >= block_size) 676 return (0); /* we fit in hole at beginning */ 677 678 /* search the list for a large enough hole */ 679 for (dp = dp->ind_next, hole = 0; dp; dp = dp->ind_next) { 680 if (dp->ind_instance != (prev + 1)) 681 hole++; /* we have a hole */ 682 if (dp->ind_instance >= (prev + block_size + 1)) 683 break; /* we fit in hole */ 684 prev = dp->ind_instance; 685 } 686 687 /* 688 * If hole is zero then all holes are patched and we can resume 689 * quick allocations. 690 */ 691 if (hole == 0) 692 dnp->dn_instance = prev + 1 + block_size; 693 694 return (prev + 1); 695 } 696 697 /* assign instance block of size 1 */ 698 static int 699 in_next_instance(major_t major) 700 { 701 return (in_next_instance_block(major, 1)); 702 } 703 704 /* 705 * This call causes us to *forget* the instance number we've generated 706 * for a given device if it was not permanent. 707 */ 708 void 709 e_ddi_free_instance(dev_info_t *dip, char *addr) 710 { 711 char *name; 712 in_node_t *np; 713 in_node_t *ap; /* ancestor node */ 714 major_t major; 715 struct devnames *dnp; 716 in_drv_t *dp; /* in_drv entry */ 717 718 /* 719 * Allow implementation override 720 */ 721 if (impl_free_instance(dip) == DDI_SUCCESS) 722 return; 723 724 /* 725 * If this is a pseudo-device, no instance number 726 * was assigned. 727 */ 728 if (is_pseudo_device(dip)) { 729 return; 730 } 731 732 name = (char *)ddi_driver_name(dip); 733 major = ddi_driver_major(dip); 734 ASSERT(major != (major_t)-1); 735 dnp = &devnamesp[major]; 736 /* 737 * Only one thread is allowed to change the state of the instance 738 * number assignments on the system at any given time. 739 */ 740 e_ddi_enter_instance(); 741 np = in_devwalk(dip, &ap, addr); 742 ASSERT(np); 743 dp = in_drvwalk(np, name); 744 ASSERT(dp); 745 if (dp->ind_state == IN_PROVISIONAL) { 746 in_removedrv(dnp, dp); 747 } 748 if (np->in_drivers == NULL) { 749 in_removenode(dnp, np, ap); 750 } 751 e_ddi_exit_instance(); 752 } 753 754 /* 755 * This makes our memory of an instance assignment permanent 756 */ 757 void 758 e_ddi_keep_instance(dev_info_t *dip) 759 { 760 in_node_t *np, *ap; 761 in_drv_t *dp; 762 763 /* 764 * Allow implementation override 765 */ 766 if (impl_keep_instance(dip) == DDI_SUCCESS) 767 return; 768 769 /* 770 * Nothing to do for pseudo devices. 771 */ 772 if (is_pseudo_device(dip)) 773 return; 774 775 /* 776 * Only one thread is allowed to change the state of the instance 777 * number assignments on the system at any given time. 778 */ 779 e_ddi_enter_instance(); 780 np = in_devwalk(dip, &ap, NULL); 781 ASSERT(np); 782 dp = in_drvwalk(np, (char *)ddi_driver_name(dip)); 783 ASSERT(dp); 784 785 mutex_enter(&e_ddi_inst_state.ins_serial); 786 if (dp->ind_state == IN_PROVISIONAL) { 787 dp->ind_state = IN_PERMANENT; 788 i_log_devfs_instance_mod(); 789 e_ddi_inst_state.ins_dirty = 1; 790 } 791 mutex_exit(&e_ddi_inst_state.ins_serial); 792 e_ddi_exit_instance(); 793 } 794 795 /* 796 * A new major has been added to the system. Run through the orphan list 797 * and try to attach each one to a driver's list. 798 */ 799 void 800 e_ddi_unorphan_instance_nos() 801 { 802 in_drv_t *dp, *ndp; 803 804 /* 805 * disconnect the orphan list, and call in_hashdrv for each item 806 * on it 807 */ 808 809 /* 810 * Only one thread is allowed to change the state of the instance 811 * number assignments on the system at any given time. 812 */ 813 e_ddi_enter_instance(); 814 if (e_ddi_inst_state.ins_no_major == NULL) { 815 e_ddi_exit_instance(); 816 return; 817 } 818 /* 819 * Hash instance list to devnames structure of major. 820 * Note that if there is not a valid major number for the 821 * node, in_hashdrv will put it back on the no_major list. 822 */ 823 dp = e_ddi_inst_state.ins_no_major; 824 e_ddi_inst_state.ins_no_major = NULL; 825 while (dp) { 826 ndp = dp->ind_next; 827 ASSERT(dp->ind_state != IN_UNKNOWN); 828 dp->ind_next = NULL; 829 in_hashdrv(dp); 830 dp = ndp; 831 } 832 e_ddi_exit_instance(); 833 } 834 835 static void 836 in_removenode(struct devnames *dnp, in_node_t *mp, in_node_t *ap) 837 { 838 in_node_t *np; 839 840 ASSERT(e_ddi_inst_state.ins_busy); 841 /* 842 * Assertion: parents are always instantiated by the framework 843 * before their children, destroyed after them 844 */ 845 ASSERT(mp->in_child == NULL); 846 /* 847 * Assertion: drv entries are always removed before their owning nodes 848 */ 849 ASSERT(mp->in_drivers == NULL); 850 /* 851 * Take the node out of the tree 852 */ 853 if (ap->in_child == mp) { 854 ap->in_child = mp->in_sibling; 855 in_dealloc_node(mp); 856 return; 857 } else { 858 for (np = ap->in_child; np; np = np->in_sibling) { 859 if (np->in_sibling == mp) { 860 np->in_sibling = mp->in_sibling; 861 in_dealloc_node(mp); 862 return; 863 } 864 } 865 } 866 panic("in_removenode dnp %p mp %p", (void *)dnp, (void *)mp); 867 } 868 869 /* 870 * Recursive ascent 871 * 872 * This now only does half the job. It finds the node, then the caller 873 * has to search the node for the binding name 874 */ 875 static in_node_t * 876 in_devwalk(dev_info_t *dip, in_node_t **ap, char *addr) 877 { 878 in_node_t *np; 879 char *name; 880 881 ASSERT(dip); 882 ASSERT(e_ddi_inst_state.ins_busy); 883 if (dip == ddi_root_node()) { 884 *ap = NULL; 885 return (e_ddi_inst_state.ins_root); 886 } 887 /* 888 * call up to find parent, then look through the list of kids 889 * for a match 890 */ 891 np = in_devwalk(ddi_get_parent(dip), ap, NULL); 892 if (np == NULL) 893 return (np); 894 *ap = np; 895 np = np->in_child; 896 name = ddi_node_name(dip); 897 if (addr == NULL) 898 addr = ddi_get_name_addr(dip); 899 900 while (np) { 901 if (in_eqstr(np->in_node_name, name) && 902 in_eqstr(np->in_unit_addr, addr)) { 903 return (np); 904 } 905 np = np->in_sibling; 906 } 907 return (np); 908 } 909 910 /* 911 * Create a node specified by cp and assign it the given instance no. 912 */ 913 static int 914 in_pathin(char *cp, int instance, char *bname, struct bind **args) 915 { 916 in_node_t *np; 917 in_drv_t *dp; 918 char *name; 919 920 ASSERT(e_ddi_inst_state.ins_busy); 921 ASSERT(args == NULL); 922 923 /* 924 * Give a warning to the console. 925 * return value ignored 926 */ 927 if (cp[0] != '/' || instance == -1 || bname == NULL) { 928 cmn_err(CE_WARN, 929 "invalid instance file entry %s %d", 930 cp, instance); 931 932 return (0); 933 } 934 935 if ((name = i_binding_to_drv_name(bname)) != NULL) 936 bname = name; 937 938 np = in_make_path(cp); 939 ASSERT(np); 940 if (in_inuse(instance, bname)) { 941 cmn_err(CE_WARN, 942 "instance already in use: %s %d", cp, instance); 943 return (0); 944 } 945 dp = in_drvwalk(np, bname); 946 if (dp != NULL) { 947 cmn_err(CE_WARN, 948 "multiple instance number assignments for " 949 "'%s' (driver %s), %d used", 950 cp, bname, dp->ind_instance); 951 return (0); 952 } 953 dp = in_alloc_drv(bname); 954 in_endrv(np, dp); 955 dp->ind_instance = instance; 956 dp->ind_state = IN_PERMANENT; 957 in_hashdrv(dp); 958 959 return (0); 960 } 961 962 /* 963 * Create (or find) the node named by path by recursively descending from the 964 * root's first child (we ignore the root, which is never named) 965 */ 966 static in_node_t * 967 in_make_path(char *path) 968 { 969 in_node_t *ap; /* ancestor pointer */ 970 in_node_t *np; /* working node pointer */ 971 in_node_t *rp; /* return node pointer */ 972 char buf[MAXPATHLEN]; /* copy of string so we can change it */ 973 char *cp, *name, *addr; 974 975 ASSERT(e_ddi_inst_state.ins_busy); 976 if (path == NULL || path[0] != '/') 977 return (NULL); 978 (void) snprintf(buf, sizeof (buf), "%s", path); 979 cp = buf + 1; /* skip over initial '/' in path */ 980 name = in_name_addr(&cp, &addr); 981 982 /* 983 * In S9 and earlier releases, the path_to_inst file 984 * SunCluster was prepended with "/node@#". This was 985 * removed in S10. We skip the prefix if the prefix 986 * still exists in /etc/path_to_inst. It is needed for 987 * various forms of Solaris upgrade to work properly 988 * in the SunCluster environment. 989 */ 990 if ((cluster_bootflags & CLUSTER_CONFIGURED) && 991 (strcmp(name, "node") == 0)) 992 name = in_name_addr(&cp, &addr); 993 994 ap = e_ddi_inst_state.ins_root; 995 rp = np = e_ddi_inst_state.ins_root->in_child; 996 while (name) { 997 while (name && np) { 998 if (in_eqstr(name, np->in_node_name) && 999 in_eqstr(addr, np->in_unit_addr)) { 1000 name = in_name_addr(&cp, &addr); 1001 if (name == NULL) 1002 return (np); 1003 ap = np; 1004 np = np->in_child; 1005 continue; 1006 } else { 1007 np = np->in_sibling; 1008 } 1009 } 1010 np = in_alloc_node(name, addr); 1011 in_enlist(ap, np); /* insert into tree */ 1012 rp = np; /* value to return if we quit */ 1013 ap = np; /* new parent */ 1014 np = NULL; /* can have no children */ 1015 name = in_name_addr(&cp, &addr); 1016 } 1017 return (rp); 1018 } 1019 1020 /* 1021 * Insert node np into the tree as one of ap's children. 1022 */ 1023 static void 1024 in_enlist(in_node_t *ap, in_node_t *np) 1025 { 1026 in_node_t *mp; 1027 ASSERT(e_ddi_inst_state.ins_busy); 1028 /* 1029 * Make this node some other node's child or child's sibling 1030 */ 1031 ASSERT(ap && np); 1032 if (ap->in_child == NULL) { 1033 ap->in_child = np; 1034 } else { 1035 for (mp = ap->in_child; mp; mp = mp->in_sibling) 1036 if (mp->in_sibling == NULL) { 1037 mp->in_sibling = np; 1038 break; 1039 } 1040 } 1041 np->in_parent = ap; 1042 } 1043 1044 /* 1045 * Insert drv entry dp onto a node's driver list 1046 */ 1047 static void 1048 in_endrv(in_node_t *np, in_drv_t *dp) 1049 { 1050 in_drv_t *mp; 1051 ASSERT(e_ddi_inst_state.ins_busy); 1052 ASSERT(np && dp); 1053 mp = np->in_drivers; 1054 np->in_drivers = dp; 1055 dp->ind_next_drv = mp; 1056 dp->ind_node = np; 1057 } 1058 1059 /* 1060 * Parse the next name out of the path, null terminate it and update cp. 1061 * caller has copied string so we can mess with it. 1062 * Upon return *cpp points to the next section to be parsed, *addrp points 1063 * to the current address substring (or NULL if none) and we return the 1064 * current name substring (or NULL if none). name and address substrings 1065 * are null terminated in place. 1066 */ 1067 1068 static char * 1069 in_name_addr(char **cpp, char **addrp) 1070 { 1071 char *namep; /* return value holder */ 1072 char *ap; /* pointer to '@' in string */ 1073 char *sp; /* pointer to '/' in string */ 1074 1075 if (*cpp == NULL || **cpp == '\0') { 1076 *addrp = NULL; 1077 return (NULL); 1078 } 1079 namep = *cpp; 1080 sp = strchr(*cpp, '/'); 1081 if (sp != NULL) { /* more to follow */ 1082 *sp = '\0'; 1083 *cpp = sp + 1; 1084 } else { /* this is last component. */ 1085 *cpp = NULL; 1086 } 1087 ap = strchr(namep, '@'); 1088 if (ap == NULL) { 1089 *addrp = NULL; 1090 } else { 1091 *ap = '\0'; /* terminate the name */ 1092 *addrp = ap + 1; 1093 } 1094 return (namep); 1095 } 1096 1097 /* 1098 * Allocate a node and storage for name and addr strings, and fill them in. 1099 */ 1100 static in_node_t * 1101 in_alloc_node(char *name, char *addr) 1102 { 1103 in_node_t *np; 1104 char *cp; 1105 size_t namelen; 1106 1107 ASSERT(e_ddi_inst_state.ins_busy); 1108 /* 1109 * Has name or will become root 1110 */ 1111 ASSERT(name || e_ddi_inst_state.ins_root == NULL); 1112 if (addr == NULL) 1113 addr = ""; 1114 if (name == NULL) 1115 namelen = 0; 1116 else 1117 namelen = strlen(name) + 1; 1118 cp = kmem_zalloc(sizeof (in_node_t) + namelen + strlen(addr) + 1, 1119 KM_SLEEP); 1120 np = (in_node_t *)cp; 1121 if (name) { 1122 np->in_node_name = cp + sizeof (in_node_t); 1123 (void) strcpy(np->in_node_name, name); 1124 } 1125 np->in_unit_addr = cp + sizeof (in_node_t) + namelen; 1126 (void) strcpy(np->in_unit_addr, addr); 1127 return (np); 1128 } 1129 1130 /* 1131 * Allocate a drv entry and storage for binding name string, and fill it in. 1132 */ 1133 static in_drv_t * 1134 in_alloc_drv(char *bindingname) 1135 { 1136 in_drv_t *dp; 1137 char *cp; 1138 size_t namelen; 1139 1140 ASSERT(e_ddi_inst_state.ins_busy); 1141 /* 1142 * Has name or will become root 1143 */ 1144 ASSERT(bindingname || e_ddi_inst_state.ins_root == NULL); 1145 if (bindingname == NULL) 1146 namelen = 0; 1147 else 1148 namelen = strlen(bindingname) + 1; 1149 cp = kmem_zalloc(sizeof (in_drv_t) + namelen, KM_SLEEP); 1150 dp = (in_drv_t *)cp; 1151 if (bindingname) { 1152 dp->ind_driver_name = cp + sizeof (in_drv_t); 1153 (void) strcpy(dp->ind_driver_name, bindingname); 1154 } 1155 dp->ind_state = IN_UNKNOWN; 1156 dp->ind_instance = -1; 1157 return (dp); 1158 } 1159 1160 static void 1161 in_dealloc_node(in_node_t *np) 1162 { 1163 /* 1164 * The root node can never be de-allocated 1165 */ 1166 ASSERT(np->in_node_name && np->in_unit_addr); 1167 ASSERT(e_ddi_inst_state.ins_busy); 1168 kmem_free(np, sizeof (in_node_t) + strlen(np->in_node_name) 1169 + strlen(np->in_unit_addr) + 2); 1170 } 1171 1172 static void 1173 in_dealloc_drv(in_drv_t *dp) 1174 { 1175 ASSERT(dp->ind_driver_name); 1176 ASSERT(e_ddi_inst_state.ins_busy); 1177 kmem_free(dp, sizeof (in_drv_t) + strlen(dp->ind_driver_name) 1178 + 1); 1179 } 1180 1181 /* 1182 * Handle the various possible versions of "no address" 1183 */ 1184 static int 1185 in_eqstr(char *a, char *b) 1186 { 1187 if (a == b) /* covers case where both are nulls */ 1188 return (1); 1189 if (a == NULL && *b == 0) 1190 return (1); 1191 if (b == NULL && *a == 0) 1192 return (1); 1193 if (a == NULL || b == NULL) 1194 return (0); 1195 return (strcmp(a, b) == 0); 1196 } 1197 1198 /* 1199 * Returns true if instance no. is already in use by named driver 1200 */ 1201 static int 1202 in_inuse(int instance, char *name) 1203 { 1204 major_t major; 1205 in_drv_t *dp; 1206 struct devnames *dnp; 1207 1208 ASSERT(e_ddi_inst_state.ins_busy); 1209 /* 1210 * For now, if we've never heard of this device we assume it is not 1211 * in use, since we can't tell 1212 * XXX could do the weaker search through the nomajor list checking 1213 * XXX for the same name 1214 */ 1215 if ((major = ddi_name_to_major(name)) == (major_t)-1) 1216 return (0); 1217 dnp = &devnamesp[major]; 1218 1219 dp = dnp->dn_inlist; 1220 while (dp) { 1221 if (dp->ind_instance == instance) 1222 return (1); 1223 dp = dp->ind_next; 1224 } 1225 return (0); 1226 } 1227 1228 static void 1229 in_hashdrv(in_drv_t *dp) 1230 { 1231 struct devnames *dnp; 1232 in_drv_t *mp, *pp; 1233 major_t major; 1234 1235 /* hash to no major list */ 1236 if ((major = ddi_name_to_major(dp->ind_driver_name)) == (major_t)-1) { 1237 dp->ind_next = e_ddi_inst_state.ins_no_major; 1238 e_ddi_inst_state.ins_no_major = dp; 1239 return; 1240 } 1241 1242 /* 1243 * dnp->dn_inlist is sorted by instance number. 1244 * Adding a new instance entry may introduce holes, 1245 * set dn_instance to IN_SEARCHME so the next instance 1246 * assignment may fill in holes. 1247 */ 1248 dnp = &devnamesp[major]; 1249 pp = mp = dnp->dn_inlist; 1250 if (mp == NULL || dp->ind_instance < mp->ind_instance) { 1251 /* prepend as the first entry, turn on IN_SEARCHME */ 1252 dnp->dn_instance = IN_SEARCHME; 1253 dp->ind_next = mp; 1254 dnp->dn_inlist = dp; 1255 return; 1256 } 1257 1258 ASSERT(mp->ind_instance != dp->ind_instance); 1259 while (mp->ind_instance < dp->ind_instance && mp->ind_next) { 1260 pp = mp; 1261 mp = mp->ind_next; 1262 ASSERT(mp->ind_instance != dp->ind_instance); 1263 } 1264 1265 if (mp->ind_instance < dp->ind_instance) { /* end of list */ 1266 dp->ind_next = NULL; 1267 mp->ind_next = dp; 1268 } else { 1269 ASSERT(dnp->dn_instance == IN_SEARCHME); 1270 dp->ind_next = pp->ind_next; 1271 pp->ind_next = dp; 1272 } 1273 } 1274 1275 /* 1276 * Remove a driver entry from the list, given a previous pointer 1277 */ 1278 static void 1279 in_removedrv(struct devnames *dnp, in_drv_t *mp) 1280 { 1281 in_drv_t *dp; 1282 in_drv_t *prevp; 1283 1284 if (dnp->dn_inlist == mp) { /* head of list */ 1285 dnp->dn_inlist = mp->ind_next; 1286 dnp->dn_instance = IN_SEARCHME; 1287 in_dq_drv(mp); 1288 in_dealloc_drv(mp); 1289 return; 1290 } 1291 prevp = dnp->dn_inlist; 1292 for (dp = prevp->ind_next; dp; dp = dp->ind_next) { 1293 if (dp == mp) { /* found it */ 1294 break; 1295 } 1296 prevp = dp; 1297 } 1298 1299 ASSERT(dp == mp); 1300 dnp->dn_instance = IN_SEARCHME; 1301 prevp->ind_next = mp->ind_next; 1302 in_dq_drv(mp); 1303 in_dealloc_drv(mp); 1304 } 1305 1306 static void 1307 in_dq_drv(in_drv_t *mp) 1308 { 1309 struct in_node *node = mp->ind_node; 1310 in_drv_t *ptr, *prev; 1311 1312 if (mp == node->in_drivers) { 1313 node->in_drivers = mp->ind_next_drv; 1314 return; 1315 } 1316 prev = node->in_drivers; 1317 for (ptr = prev->ind_next_drv; ptr != (struct in_drv *)NULL; 1318 ptr = ptr->ind_next_drv) { 1319 if (ptr == mp) { 1320 prev->ind_next_drv = ptr->ind_next_drv; 1321 return; 1322 } 1323 } 1324 panic("in_dq_drv: in_drv not found on node driver list"); 1325 } 1326 1327 1328 in_drv_t * 1329 in_drvwalk(in_node_t *np, char *binding_name) 1330 { 1331 char *name; 1332 in_drv_t *dp = np->in_drivers; 1333 while (dp) { 1334 if ((name = i_binding_to_drv_name(dp->ind_driver_name)) 1335 == NULL) { 1336 name = dp->ind_driver_name; 1337 } 1338 if (strcmp(binding_name, name) == 0) { 1339 break; 1340 } 1341 dp = dp->ind_next_drv; 1342 } 1343 return (dp); 1344 } 1345 1346 1347 1348 static void 1349 i_log_devfs_instance_mod(void) 1350 { 1351 sysevent_t *ev; 1352 sysevent_id_t eid; 1353 static int sent_one = 0; 1354 1355 /* 1356 * Prevent unnecessary event generation. Do not generate more than 1357 * one event during boot. 1358 */ 1359 if (sent_one && !i_ddi_io_initialized()) 1360 return; 1361 1362 ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_INSTANCE_MOD, EP_DDI, 1363 SE_NOSLEEP); 1364 if (ev == NULL) { 1365 return; 1366 } 1367 if (log_sysevent(ev, SE_NOSLEEP, &eid) != 0) { 1368 cmn_err(CE_WARN, "i_log_devfs_instance_mod: failed to post " 1369 "event"); 1370 } else { 1371 sent_one = 1; 1372 } 1373 sysevent_free(ev); 1374 } 1375 1376 void 1377 e_ddi_enter_instance() 1378 { 1379 mutex_enter(&e_ddi_inst_state.ins_serial); 1380 if (e_ddi_inst_state.ins_thread == curthread) 1381 e_ddi_inst_state.ins_busy++; 1382 else { 1383 while (e_ddi_inst_state.ins_busy) 1384 cv_wait(&e_ddi_inst_state.ins_serial_cv, 1385 &e_ddi_inst_state.ins_serial); 1386 e_ddi_inst_state.ins_thread = curthread; 1387 e_ddi_inst_state.ins_busy = 1; 1388 } 1389 mutex_exit(&e_ddi_inst_state.ins_serial); 1390 } 1391 1392 void 1393 e_ddi_exit_instance() 1394 { 1395 mutex_enter(&e_ddi_inst_state.ins_serial); 1396 e_ddi_inst_state.ins_busy--; 1397 if (e_ddi_inst_state.ins_busy == 0) { 1398 cv_broadcast(&e_ddi_inst_state.ins_serial_cv); 1399 e_ddi_inst_state.ins_thread = NULL; 1400 } 1401 mutex_exit(&e_ddi_inst_state.ins_serial); 1402 } 1403 1404 int 1405 e_ddi_instance_is_clean() 1406 { 1407 return (e_ddi_inst_state.ins_dirty == 0); 1408 } 1409 1410 void 1411 e_ddi_instance_set_clean() 1412 { 1413 e_ddi_inst_state.ins_dirty = 0; 1414 } 1415 1416 in_node_t * 1417 e_ddi_instance_root() 1418 { 1419 return (e_ddi_inst_state.ins_root); 1420 } 1421 1422 /* 1423 * Visit a node in the instance tree 1424 */ 1425 static int 1426 in_walk_instances(in_node_t *np, char *path, char *this, 1427 int (*f)(const char *, in_node_t *, in_drv_t *, void *), void *arg) 1428 { 1429 in_drv_t *dp; 1430 int rval = INST_WALK_CONTINUE; 1431 char *next; 1432 1433 while (np != NULL) { 1434 1435 if (np->in_unit_addr[0] == 0) 1436 (void) sprintf(this, "/%s", np->in_node_name); 1437 else 1438 (void) sprintf(this, "/%s@%s", np->in_node_name, 1439 np->in_unit_addr); 1440 next = this + strlen(this); 1441 1442 for (dp = np->in_drivers; dp; dp = dp->ind_next_drv) { 1443 if (dp->ind_state == IN_PERMANENT) { 1444 rval = (*f)(path, np, dp, arg); 1445 if (rval == INST_WALK_TERMINATE) 1446 break; 1447 } 1448 } 1449 if (np->in_child) { 1450 rval = in_walk_instances(np->in_child, 1451 path, next, f, arg); 1452 if (rval == INST_WALK_TERMINATE) 1453 break; 1454 } 1455 1456 np = np->in_sibling; 1457 } 1458 1459 return (rval); 1460 } 1461 1462 /* 1463 * A general interface for walking the instance tree, 1464 * calling a user-supplied callback for each node. 1465 */ 1466 int 1467 e_ddi_walk_instances(int (*f)(const char *, 1468 in_node_t *, in_drv_t *, void *), void *arg) 1469 { 1470 in_node_t *root; 1471 int rval; 1472 char *path; 1473 1474 path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 1475 1476 e_ddi_enter_instance(); 1477 root = e_ddi_instance_root(); 1478 rval = in_walk_instances(root->in_child, path, path, f, arg); 1479 e_ddi_exit_instance(); 1480 1481 kmem_free(path, MAXPATHLEN); 1482 return (rval); 1483 } 1484