/* * A new major has been added to the system. Run through the orphan list * and try to attach each one to a driver's list. */ void e_ddi_unorphan_instance_nos() { in_drv_t *dp, *ndp; /* * disconnect the orphan list, and call in_hashdrv for each item * on it */ /* * Only one thread is allowed to change the state of the instance * number assignments on the system at any given time. */ e_ddi_enter_instance(); if (e_ddi_inst_state.ins_no_major == NULL) { e_ddi_exit_instance(); return; } /* * Hash instance list to devnames structure of major. * Note that if there is not a valid major number for the * node, in_hashdrv will put it back on the no_major list. */ dp = e_ddi_inst_state.ins_no_major; e_ddi_inst_state.ins_no_major = NULL; while (dp) { ndp = dp->ind_next; ASSERT(dp->ind_state != IN_UNKNOWN); dp->ind_next = NULL; in_hashdrv(dp); dp = ndp; } e_ddi_exit_instance(); }
/* * produce the path to the given instance of a major number. * path must hold MAXPATHLEN string */ int e_ddi_instance_majorinstance_to_path(major_t major, uint_t inst, char *path) { struct devnames *dnp; in_drv_t *dp; int ret; e_ddi_enter_instance(); /* look for the instance threaded off major */ dnp = &devnamesp[major]; for (dp = dnp->dn_inlist; dp != NULL; dp = dp->ind_next) if (dp->ind_instance == inst) break; /* produce path from the node that uses the instance */ if (dp) { *path = 0; ret = mkpathname(path, dp->ind_node, MAXPATHLEN); } else ret = DDI_FAILURE; e_ddi_exit_instance(); return (ret); }
/* * This call causes us to *forget* the instance number we've generated * for a given device if it was not permanent. */ void e_ddi_free_instance(dev_info_t *dip, char *addr) { char *name; in_node_t *np; in_node_t *ap; /* ancestor node */ major_t major; struct devnames *dnp; in_drv_t *dp; /* in_drv entry */ /* * Allow implementation override */ if (impl_free_instance(dip) == DDI_SUCCESS) return; /* * If this is a pseudo-device, no instance number * was assigned. */ if (is_pseudo_device(dip)) { return; } name = (char *)ddi_driver_name(dip); major = ddi_driver_major(dip); ASSERT(major != DDI_MAJOR_T_NONE); dnp = &devnamesp[major]; /* * Only one thread is allowed to change the state of the instance * number assignments on the system at any given time. */ e_ddi_enter_instance(); np = in_devwalk(dip, &ap, addr); ASSERT(np); dp = in_drvwalk(np, name); ASSERT(dp); if (dp->ind_state == IN_PROVISIONAL) { in_removedrv(dnp, dp); } if (np->in_drivers == NULL) { in_removenode(dnp, np, ap); } e_ddi_exit_instance(); }
/* * This makes our memory of an instance assignment permanent */ void e_ddi_keep_instance(dev_info_t *dip) { in_node_t *np, *ap; in_drv_t *dp; /* Don't make nulldriver instance assignments permanent */ if (ddi_driver_major(dip) == nulldriver_major) return; /* * Allow implementation override */ if (impl_keep_instance(dip) == DDI_SUCCESS) return; /* * Nothing to do for pseudo devices. */ if (is_pseudo_device(dip)) return; /* * Only one thread is allowed to change the state of the instance * number assignments on the system at any given time. */ e_ddi_enter_instance(); np = in_devwalk(dip, &ap, NULL); ASSERT(np); dp = in_drvwalk(np, (char *)ddi_driver_name(dip)); ASSERT(dp); mutex_enter(&e_ddi_inst_state.ins_serial); if (dp->ind_state == IN_PROVISIONAL) { dp->ind_state = IN_PERMANENT; i_log_devfs_instance_mod(); e_ddi_inst_state.ins_dirty = 1; } mutex_exit(&e_ddi_inst_state.ins_serial); e_ddi_exit_instance(); }
/* * Look up an instance number for a dev_info node, and assign one if it does * not have one (the dev_info node has devi_name and devi_addr already set). */ uint_t e_ddi_assign_instance(dev_info_t *dip) { char *name; in_node_t *ap, *np; in_drv_t *dp; major_t major; uint_t ret; char *bname; /* * Allow implementation to override */ if ((ret = impl_assign_instance(dip)) != (uint_t)-1) return (ret); /* * If this is a pseudo-device, use the instance number * assigned by the pseudo nexus driver. The mutex is * not needed since the instance tree is not used. */ if (is_pseudo_device(dip)) { return (ddi_get_instance(dip)); } /* * Only one thread is allowed to change the state of the instance * number assignments on the system at any given time. */ e_ddi_enter_instance(); /* * Look for instance node, allocate one if not found */ np = in_devwalk(dip, &ap, NULL); if (np == NULL) { if (in_assign_instance_block(dip)) { np = in_devwalk(dip, &ap, NULL); } else { name = ddi_node_name(dip); np = in_alloc_node(name, ddi_get_name_addr(dip)); ASSERT(np != NULL); in_enlist(ap, np); /* insert into tree */ } } ASSERT(np == in_devwalk(dip, &ap, NULL)); /* * Look for driver entry, allocate one if not found */ bname = (char *)ddi_driver_name(dip); dp = in_drvwalk(np, bname); if (dp == NULL) { dp = in_alloc_drv(bname); ASSERT(dp != NULL); major = ddi_driver_major(dip); ASSERT(major != DDI_MAJOR_T_NONE); in_endrv(np, dp); in_set_instance(dip, dp, major); dp->ind_state = IN_PROVISIONAL; in_hashdrv(dp); } ret = dp->ind_instance; e_ddi_exit_instance(); return (ret); }
void e_ddi_instance_init(void) { char *file; int rebuild = 1; struct in_drv *dp; mutex_init(&e_ddi_inst_state.ins_serial, NULL, MUTEX_DEFAULT, NULL); cv_init(&e_ddi_inst_state.ins_serial_cv, NULL, CV_DEFAULT, NULL); /* * Only one thread is allowed to change the state of the instance * number assignments on the system at any given time. * Note that this is not really necessary, as we are single-threaded * here, but it won't hurt, and it allows us to keep ASSERTS for * our assumptions in the code. */ e_ddi_enter_instance(); /* * Create the root node, instance zallocs to 0. * The name and address of this node never get examined, we always * start searching with its first child. */ ASSERT(e_ddi_inst_state.ins_root == NULL); e_ddi_inst_state.ins_root = in_alloc_node(NULL, NULL); dp = in_alloc_drv("rootnex"); in_endrv(e_ddi_inst_state.ins_root, dp); file = instance_file; switch (in_get_infile(file)) { default: case PTI_NOT_FOUND: /* make sure path_to_inst is recreated */ boothowto |= RB_RECONFIG; /* * Something is wrong. First try the backup file. * If not found, rebuild path_to_inst. Emit a * message about the problem. */ cmn_err(CE_WARN, "%s empty or not found", file); file = instance_file_backup; if (in_get_infile(file) != PTI_FOUND) { cmn_err(CE_NOTE, "rebuilding device instance data"); break; } cmn_err(CE_NOTE, "using backup instance data in %s", file); /*FALLTHROUGH*/ case PTI_FOUND: /* * We've got a readable file * parse the file into the instance tree */ (void) read_binding_file(file, NULL, in_pathin); rebuild = 0; break; case PTI_REBUILD: cmn_err(CE_CONT, "?Using default device instance data\n"); break; } /* * The OBP device tree has been copied to the kernel and * bound to drivers at this point. We walk the per-driver * list to preassign instances. Since the bus addr is * unknown at this point, we cannot place the instance * number in the instance tree. This will be done at * a later time. */ if (rebuild) in_preassign_instance(); e_ddi_exit_instance(); }
static int in_sync_sys(char *pathname, uint_t flags) { struct vnode *vp; int error; /* For debugging/testing */ if (inst_sync_disable) return (0); /* * We must have sufficient privilege to do this, since we lock critical * data structures whilst we're doing it .. */ if ((error = secpolicy_sys_devices(CRED())) != 0) return (set_errno(error)); if (flags != INST_SYNC_ALWAYS && flags != INST_SYNC_IF_REQUIRED) return (set_errno(EINVAL)); /* * Only one process is allowed to get the state of the instance * number assignments on the system at any given time. */ e_ddi_enter_instance(); /* * Recreate the instance file only if the device tree has changed * or if the caller explicitly requests so. */ if (e_ddi_instance_is_clean() && flags != INST_SYNC_ALWAYS) { error = EALREADY; goto end; } /* * Create an instance file for writing, giving it a mode that * will only permit reading. Note that we refuse to overwrite * an existing file. */ if ((error = vn_open(pathname, UIO_USERSPACE, FCREAT, 0444, &vp, CRCREAT, 0)) != 0) { if (error == EISDIR) error = EACCES; /* SVID compliance? */ goto end; } /* * So far so good. We're singly threaded, the vnode is beckoning * so let's get on with it. Any error, and we just give up and * hand the first error we get back to userland. */ error = in_write_instance(vp); /* * If there was any sort of error, we deliberately go and * remove the file we just created so that any attempts to * use it will quickly fail. */ if (error) (void) vn_remove(pathname, UIO_USERSPACE, RMFILE); else e_ddi_instance_set_clean(); end: e_ddi_exit_instance(); return (error ? set_errno(error) : 0); }