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