/* * 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); }
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); }
/* * 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); }