#include <sys/param.h>
#include <sys/modctl.h>
#include <sys/sysmacros.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/pathname.h>
#include <sys/ddi_impldefs.h>
#include <sys/sunddi.h>
#include <sys/autoconf.h>
#include <sys/modhash.h>
#include <sys/dacf_impl.h>
#include <sys/systm.h>
#include <sys/debug.h>
void
dacfc_match_create_minor(const char *name, const char *node_type,
dev_info_t *dip, struct ddi_minor_data *dmdp, int flag)
{
dacf_rule_t *r;
char *dev_path, *dev_pathp, *drv_mname = NULL;
dacf_rsrvlist_t *pa_rsrv, *pd_rsrv;
if ((flag & CLONE_DEV) && (strcmp(node_type, DDI_NT_NET) != 0)) {
return;
}
if (!DEVI_IS_ATTACHING(dmdp->dip)) {
return;
}
dev_path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
dev_pathp = ddi_pathname(dip, dev_path);
pa_rsrv = kmem_alloc(sizeof (dacf_rsrvlist_t), KM_SLEEP);
pd_rsrv = kmem_alloc(sizeof (dacf_rsrvlist_t), KM_SLEEP);
if (name) {
const char *drv_name = ddi_driver_name(dip);
if (drv_name == NULL)
drv_name = "???";
drv_mname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
(void) snprintf(drv_mname, MAXPATHLEN, "%s:%s", drv_name, name);
}
mutex_enter(&dacf_lock);
mutex_enter(&(DEVI(dip)->devi_lock));
if (DEVI_IS_INVOKING_DACF(dip)) {
mutex_exit(&(DEVI(dip)->devi_lock));
cmn_err(CE_WARN,
"!dacf detected deadlock, aborting matching procedure\n");
mutex_exit(&dacf_lock);
kmem_free(pa_rsrv, sizeof (dacf_rsrvlist_t));
kmem_free(pd_rsrv, sizeof (dacf_rsrvlist_t));
kmem_free(dev_path, MAXPATHLEN);
if (drv_mname) {
kmem_free(drv_mname, MAXPATHLEN);
}
return;
}
mutex_exit(&(DEVI(dip)->devi_lock));
r = NULL;
if (dev_pathp) {
r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_DEV_PATH,
dev_pathp);
}
if (!r && drv_mname) {
r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_DRV_MNAME,
drv_mname);
}
if (!r && node_type) {
r = dacf_match(DACF_OPID_POSTATTACH, DACF_DS_MIN_NT, node_type);
}
if (r) {
dacf_rsrv_make(pa_rsrv, r, dmdp, &(DEVI(dip)->devi_dacf_tasks));
if (dacfdebug & DACF_DBG_MSGS)
printf("dacf: made 'post-attach' reservation for "
"%s, %s, %s\n", name, node_type, dev_pathp);
} else {
kmem_free(pa_rsrv, sizeof (dacf_rsrvlist_t));
}
r = NULL;
if (dev_pathp) {
r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_DEV_PATH,
dev_pathp);
}
if (!r && drv_mname) {
r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_DRV_MNAME,
drv_mname);
}
if (!r && node_type) {
r = dacf_match(DACF_OPID_PREDETACH, DACF_DS_MIN_NT, node_type);
}
if (r) {
dacf_rsrv_make(pd_rsrv, r, dmdp, &(DEVI(dip)->devi_dacf_tasks));
if (dacfdebug & DACF_DBG_MSGS) {
printf("dacf: made 'pre-detach' reservation for "
"%s, %s, %s\n", name, node_type, dev_pathp);
}
} else {
kmem_free(pd_rsrv, sizeof (dacf_rsrvlist_t));
}
mutex_exit(&dacf_lock);
kmem_free(dev_path, MAXPATHLEN);
if (drv_mname) {
kmem_free(drv_mname, MAXPATHLEN);
}
}
int
dacfc_postattach(dev_info_t *devi)
{
int err = DACF_SUCCESS;
char *path, *pathp;
dacf_rsrvlist_t **opsp, *op;
ASSERT(MUTEX_HELD(&dacf_lock));
opsp = &DEVI(devi)->devi_dacf_tasks;
dacf_process_rsrvs(opsp, DACF_OPID_POSTATTACH, DACF_PROC_INVOKE);
for (op = *opsp; op != NULL; op = op->rsrv_next) {
if (op->rsrv_rule->r_opid != DACF_OPID_POSTATTACH)
continue;
if (op->rsrv_result == DACF_SUCCESS)
continue;
if (dacfdebug & DACF_DBG_DEVI) {
cmn_err(CE_WARN, "op failed, err = %d\n",
op->rsrv_result);
}
err = DACF_FAILURE;
break;
}
if ((err == DACF_FAILURE) && (dacfdebug & DACF_DBG_DEVI)) {
path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
if ((pathp = ddi_pathname(devi, path)) == NULL)
pathp = "<unknown>";
cmn_err(CE_WARN, "%s attached, but failed to auto-configure",
pathp);
kmem_free(path, MAXPATHLEN);
}
return (err);
}
int
dacfc_predetach(dev_info_t *devi)
{
int err = DDI_SUCCESS;
char *path, *pathp;
dacf_rsrvlist_t **opsp, *op;
ASSERT(MUTEX_HELD(&dacf_lock));
opsp = &DEVI(devi)->devi_dacf_tasks;
dacf_process_rsrvs(opsp, DACF_OPID_PREDETACH, DACF_PROC_INVOKE);
for (op = *opsp; op != NULL; op = op->rsrv_next) {
if (op->rsrv_rule->r_opid != DACF_OPID_PREDETACH)
continue;
if (op->rsrv_result == 0)
continue;
err = DDI_FAILURE;
break;
}
if (err == DDI_FAILURE) {
int pa_err;
if (dacfdebug & DACF_DBG_DEVI) {
path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
if ((pathp = ddi_pathname(devi, path)) == NULL)
pathp = "<unknown>";
cmn_err(CE_WARN, "%s failed to auto-unconfigure, "
"attempting to reconfigure...", pathp);
kmem_free(path, MAXPATHLEN);
}
pa_err = dacfc_postattach(devi);
if (dacfdebug & DACF_DBG_DEVI) {
path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
if ((pathp = ddi_pathname(devi, path)) == NULL)
pathp = "<unknown>";
if (pa_err == DDI_FAILURE) {
cmn_err(CE_WARN, "%s failed to "
"auto-unconfigure, and could not be "
"re-autoconfigured.", pathp);
} else {
cmn_err(CE_WARN, "%s failed to "
"auto-unconfigure, but was successfully "
"re-autoconfigured.", pathp);
}
kmem_free(path, MAXPATHLEN);
}
}
return (err);
}
#ifdef DEBUG
static int
kmod_test_postattach(dacf_infohdl_t info_hdl, dacf_arghdl_t arg_hdl, int flags)
{
const char *verbose = dacf_get_arg(arg_hdl, "verbose");
if (verbose && (strcmp(verbose, "true") == 0)) {
cmn_err(CE_WARN, "got kmod_test_postattach\n");
}
return (0);
}
#endif
static dacf_op_t kmod_op_test[] = {
#ifdef DEBUG
{ DACF_OPID_POSTATTACH, kmod_test_postattach },
#endif
{ DACF_OPID_END, NULL },
};
static dacf_opset_t kmod_opsets[] = {
#ifdef DEBUG
{ "kmod_test", kmod_op_test },
#endif
{ NULL, NULL },
};
struct dacfsw kmod_dacfsw = {
DACF_MODREV_1, kmod_opsets
};