/*
 * This is a nasty, slow hack.  But we're stuck with it until we do some
 * major surgery on the instance assignment subsystem, to allow pseudonode
 * instance assignment to be tracked there.
 *
 * To auto-assign an instance number, we exhaustively search the instance
 * list for each possible instance number until we find one which is unused.
 */
static int
pseudonex_auto_assign(dev_info_t *child)
{
	dev_info_t	*tdip;
	kmutex_t	*dmp;
	const char 	*childname = ddi_driver_name(child);
	major_t		childmaj = ddi_name_to_major((char *)childname);
	int inst = 0;

	dmp = &devnamesp[childmaj].dn_lock;
	LOCK_DEV_OPS(dmp);
	for (inst = 0; inst <= MAXMIN32; inst++) {
		for (tdip = devnamesp[childmaj].dn_head; tdip != NULL;
		    tdip = ddi_get_next(tdip)) {
			/* is this the current node? */
			if (tdip == child)
				continue;
			if (inst == ddi_get_instance(tdip)) {
				break;
			}
		}
		if (tdip == NULL) {
			UNLOCK_DEV_OPS(dmp);
			return (inst);
		}
	}
	UNLOCK_DEV_OPS(dmp);
	return (-1);
}
static int
pseudonex_check_assignment(dev_info_t *child, int test_inst)
{
	dev_info_t	*tdip;
	kmutex_t	*dmp;
	const char 	*childname = ddi_driver_name(child);
	major_t		childmaj = ddi_name_to_major((char *)childname);

	dmp = &devnamesp[childmaj].dn_lock;
	LOCK_DEV_OPS(dmp);
	for (tdip = devnamesp[childmaj].dn_head;
	    tdip != NULL; tdip = ddi_get_next(tdip)) {
		/* is this the current node? */
		if (tdip == child)
			continue;
		/* is this a duplicate instance? */
		if (test_inst == ddi_get_instance(tdip)) {
			UNLOCK_DEV_OPS(dmp);
			return (DDI_FAILURE);
		}
	}
	UNLOCK_DEV_OPS(dmp);
	return (DDI_SUCCESS);
}
Example #3
0
static int
mod_removedrv(struct modldrv *modl, struct modlinkage *modlp)
{
	struct modctl *mcp;
	struct dev_ops *ops;
	struct devnames *dnp;
	struct dev_ops *dp;
	major_t major;
	char *modname;
	extern kthread_id_t mod_aul_thread;
	struct streamtab *str;
	cdevsw_impl_t *cdp;
	int err = 0;

	/* Don't auto unload modules on if moddebug flag is set */
	if ((moddebug & MODDEBUG_NOAUL_DRV) && (mod_aul_thread == curthread)) {
		err = EBUSY;
		goto done;
	}

	/* Verify modname has a driver major */
	mcp = mod_getctl(modlp);
	ASSERT(mcp != NULL);
	modname = mcp->mod_modname;

	if ((major = ddi_name_to_major(modname)) == -1) {
		cmn_err(CE_WARN, uninstall_err, modname);
		err = EINVAL;
		goto done;
	}

	ops = modl->drv_dev_ops;
	dnp = &(devnamesp[major]);
	LOCK_DEV_OPS(&(dnp->dn_lock));

	dp = devopsp[major];

	if (dp != ops)  {
		cmn_err(CE_NOTE, "mod_removedrv: mismatched driver for %s",
		    modname);
		err = EBUSY;
		goto unlock;
	}

	/*
	 * A driver is not unloadable if its dev_ops are held
	 */
	if (!DRV_UNLOADABLE(dp)) {
		mod_dprintf(DRV_DBG, "Cannot unload device driver <%s>,"
		    " refcnt %d\n", modname, dp->devo_refcnt);
		err = EBUSY;
		goto unlock;
	}

	/*
	 * OK to unload.
	 */
	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
		cdp = &devimpl[major];
		ASSERT(cdp->d_str == str);
		cdp->d_str = NULL;

		/* check for reference to per-dev syncq */
		if (cdp->d_dmp != NULL) {
			rele_dm(cdp->d_dmp);
			cdp->d_dmp = NULL;
		}
	}

	devopsp[major] = &mod_nodev_ops;
	dnp->dn_flags &= ~(DN_DRIVER_HELD|DN_NO_AUTODETACH);

unlock:
	UNLOCK_DEV_OPS(&(dnp->dn_lock));
done:
	return (err);
}
Example #4
0
/*
 * Install a new driver
 */
static int
mod_installdrv(struct modldrv *modl, struct modlinkage *modlp)
{
	struct modctl *mcp;
	struct dev_ops *ops;
	char *modname;
	major_t major;
	struct dev_ops *dp;
	struct devnames *dnp;
	struct streamtab *str;
	cdevsw_impl_t *cdp;
	uint_t sqtype;
	uint_t qflag;
	uint_t flag;
	int err = 0;

	/* sanity check module */
	if ((mcp = mod_getctl(modlp)) == NULL) {
		cmn_err(CE_WARN, "mod_install: bad module linkage data");
		err = ENXIO;
		goto done;
	}
	modname = mcp->mod_modname;

	/* Sanity check modname */
	if ((major = ddi_name_to_major(modname)) == (major_t)-1) {
#ifdef DEBUG
		cmn_err(CE_WARN,
		    "mod_installdrv: no major number for %s", modname);
#endif
		err = ENXIO;
		goto done;
	}

	/* Verify MP safety flag */
	ops = modl->drv_dev_ops;
	if (ops->devo_bus_ops == NULL && ops->devo_cb_ops != NULL &&
	    !(ops->devo_cb_ops->cb_flag & D_MP)) {
		cmn_err(CE_WARN,
		    "mod_installdrv: MT-unsafe driver '%s' rejected", modname);
		err = ENXIO;
		goto done;
	}


	/* Is bus_map_fault signature correct (version 8 and higher)? */
	if (ops->devo_bus_ops != NULL &&
	    ops->devo_bus_ops->bus_map_fault != NULL &&
	    ops->devo_bus_ops->bus_map_fault != i_ddi_map_fault &&
	    ops->devo_bus_ops->busops_rev < BUSO_REV_8) {

		cmn_err(CE_WARN,
		    "mod_installdrv: busops' revision of '%s' is too low"
		    " (must be at least 8)", modname);
		err = ENXIO;
		goto done;
	}


	/* Make sure the driver is uninstalled */
	dnp = &devnamesp[major];
	LOCK_DEV_OPS(&dnp->dn_lock);
	dp = devopsp[major];

	if (dnp->dn_flags & DN_DRIVER_REMOVED) {
#ifdef DEBUG
		cmn_err(CE_NOTE,
		    "mod_installdrv: driver has been removed %s", modname);
#endif
		err = ENXIO;
		goto unlock;
	}

	if (dp != &nodev_ops && dp != &mod_nodev_ops) {
		cmn_err(CE_WARN,
		    "mod_installdrv: driver already installed %s", modname);
		err = EALREADY;
		goto unlock;
	}

	devopsp[major] = ops; /* setup devopsp */

	if ((str = STREAMSTAB(major)) != NULL) {	/* streams driver */
		flag = CBFLAG(major);
		if ((err = devflg_to_qflag(str, flag, &qflag, &sqtype)) != 0)
			goto unlock;
		cdp = &devimpl[major];
		ASSERT(cdp->d_str == NULL);
		cdp->d_str = str;
		cdp->d_qflag = qflag | QISDRV;
		cdp->d_sqtype = sqtype;
	}

	if (ops->devo_bus_ops == NULL)
		dnp->dn_flags |= DN_LEAF_DRIVER;

unlock:
	UNLOCK_DEV_OPS(&dnp->dn_lock);
done:
	return (err);
}