Ejemplo n.º 1
0
/*
 * 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);
}
Ejemplo n.º 2
0
/*
 * 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();
}
Ejemplo n.º 3
0
/*
 * 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();
}
Ejemplo n.º 4
0
/*
 * 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();
}
Ejemplo n.º 5
0
/*
 * 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);
}
Ejemplo n.º 6
0
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();
}
Ejemplo n.º 7
0
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);
}