/* * Control ops entry point: * * Requests handled completely: * DDI_CTLOPS_INITCHILD * DDI_CTLOPS_UNINITCHILD * All others are passed to the parent. */ static int acpinex_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { int rval = DDI_SUCCESS; switch (op) { case DDI_CTLOPS_INITCHILD: rval = init_child((dev_info_t *)arg); break; case DDI_CTLOPS_UNINITCHILD: impl_ddi_sunbus_removechild((dev_info_t *)arg); break; case DDI_CTLOPS_REPORTDEV: { if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?acpinex: %s@%s, %s%d\n", ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip), ddi_get_instance(rdip)); break; } default: rval = ddi_ctlops(dip, rdip, op, arg, result); break; } return (rval); }
/* * FCA driver's intercepted bus control operations. */ static int fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip, ddi_ctl_enum_t op, void *clientarg, void *result) { int ret; switch (op) { case DDI_CTLOPS_REPORTDEV: case DDI_CTLOPS_IOMIN: ret = DDI_SUCCESS; break; case DDI_CTLOPS_INITCHILD: ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg); break; case DDI_CTLOPS_UNINITCHILD: ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg); break; default: ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result); break; } return (ret); }
unsigned long dvma_pagesize(dev_info_t *dip) { auto unsigned long dvmapgsz; (void) ddi_ctlops(dip, dip, DDI_CTLOPS_DVMAPAGESIZE, NULL, (void *) &dvmapgsz); return (dvmapgsz); }
static void i_attach_ctlop(dev_info_t *devi, ddi_attach_cmd_t cmd, ddi_pre_post_t w, int ret) { int error; struct attachspec as; dev_info_t *pdip = ddi_get_parent(devi); as.cmd = cmd; as.when = w; as.pdip = pdip; as.result = ret; (void) ddi_ctlops(devi, devi, DDI_CTLOPS_ATTACH, &as, &error); }
static void i_detach_ctlop(dev_info_t *devi, ddi_detach_cmd_t cmd, ddi_pre_post_t w, int ret) { int error; struct detachspec ds; dev_info_t *pdip = ddi_get_parent(devi); ds.cmd = cmd; ds.when = w; ds.pdip = pdip; ds.result = ret; (void) ddi_ctlops(devi, devi, DDI_CTLOPS_DETACH, &ds, &error); }
int pcieb_plat_peekpoke(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pcieb_devstate_t *pcieb = ddi_get_soft_state(pcieb_state, ddi_get_instance(dip)); if (!PCIE_IS_RP(PCIE_DIP2BUS(dip))) return (ddi_ctlops(dip, rdip, ctlop, arg, result)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, ddi_ctlops, &pcieb->pcieb_err_mutex, &pcieb->pcieb_peek_poke_mutex, pcieb_peekpoke_cb)); }
static int pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { dev_info_t *child = (dev_info_t *)arg; pmubus_obpregspec_t *pmubus_rp; char name[9]; int reglen; switch (op) { case DDI_CTLOPS_INITCHILD: if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp, ®len) != DDI_SUCCESS) { return (DDI_FAILURE); } if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) { cmn_err(CE_WARN, "pmubus: reg property not well-formed for " "%s size=%d\n", ddi_node_name(child), reglen); kmem_free(pmubus_rp, reglen); return (DDI_FAILURE); } (void) snprintf(name, sizeof (name), "%x,%x", pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo); ddi_set_name_addr(child, name); kmem_free(pmubus_rp, reglen); return (DDI_SUCCESS); case DDI_CTLOPS_UNINITCHILD: ddi_set_name_addr(child, NULL); ddi_remove_minor_node(child, NULL); impl_rem_dev_props(child); return (DDI_SUCCESS); default: break; } return (ddi_ctlops(dip, rdip, op, arg, result)); }
/* * cpunex_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name. */ static int cpunex_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *cdip = (dev_info_t *)arg; int i; char caddr[MAXNAMELEN]; i = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", -1); if (i == -1) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property " "not found", ddi_node_name(cdip), ddi_get_instance(cdip)); return (DDI_NOT_WELL_FORMED); } (void) sprintf(caddr, "%d", i); ddi_set_name_addr(cdip, caddr); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); return (DDI_SUCCESS); } default: { return (ddi_ctlops(dip, rdip, op, arg, result)); } } }
/*ARGSUSED*/ static int eibnx_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { dev_info_t *child = arg; int ret; char name[MAXNAMELEN]; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: ENX_DPRINTF_DEBUG("EoIB device: %s@%s, %s%d", ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip), ddi_get_instance(rdip)); /*FALLTHROUGH*/ case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_POWER: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_IOMIN: ret = DDI_SUCCESS; break; case DDI_CTLOPS_INITCHILD: if ((ret = eibnx_name_child(child, name, sizeof (name))) == DDI_SUCCESS) { ddi_set_name_addr(child, name); } break; case DDI_CTLOPS_UNINITCHILD: ddi_set_name_addr(child, NULL); ret = DDI_SUCCESS; break; default: ret = ddi_ctlops(dip, rdip, ctlop, arg, result); break; } return (ret); }
/* * nx1394_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit * address). */ static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { int status; TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, ""); switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *ocdip, *cdip = (dev_info_t *)arg; dev_info_t *pdip = ddi_get_parent(cdip); int reglen, i; uint32_t *regptr; char addr[MAXNAMELEN]; TNF_PROBE_1(nx1394_bus_ctl_init_child, S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip); i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", (int **)®ptr, (uint_t *)®len); if (i != DDI_PROP_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Reg property not found", tnf_int, reason, i); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_NOT_WELL_FORMED); } ASSERT(reglen != 0); /* * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA] */ if (regptr[2] || regptr[3]) { (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0], regptr[1], regptr[2], regptr[3]); } else { (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]); } ddi_prop_free(regptr); ddi_set_name_addr(cdip, addr); /* * Check for a node with the same name & addr as the current * node. If such a node exists, return failure. */ if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) != NULL && ocdip != cdip) { cmn_err(CE_NOTE, "!%s(%d): Duplicate dev_info node found %s@%s", ddi_node_name(cdip), ddi_get_instance(cdip), ddi_node_name(ocdip), addr); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Duplicate nodes"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } /* * If HAL (parent dip) has "active-dma-flush" property, then * add property to child as well. Workaround for active * context flushing bug in Schizo rev 2.1 and 2.2. */ if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "active-dma-flush") != 0) { status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "active-dma-flush", 1); if (status != NDI_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): Unable to add " "\"active-dma-flush\" property", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Unable to add \"active-dma-flush\" " "property"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } } TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "uninitchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_IOMIN: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "iomin"); return (status); } case DDI_CTLOPS_POWER: { return (DDI_SUCCESS); } /* * These ops correspond to functions that "shouldn't" be called * by a 1394 client driver. */ case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: { cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)", ddi_node_name(dip), ddi_get_instance(dip), op, ddi_node_name(rdip), ddi_get_instance(rdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "invalid op", tnf_int, op, op); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_FAILURE); } /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ default: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (status); } } }
/*ARGSUSED*/ static int tvhci_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?tvhci-device: %s%d\n", ddi_get_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: { dev_info_t *child = (dev_info_t *)arg; return (tvhci_initchild(dip, child)); } case DDI_CTLOPS_UNINITCHILD: { dev_info_t *child = (dev_info_t *)arg; return (tvhci_uninitchild(dip, child)); } case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: /* * These ops correspond to functions that "shouldn't" be called * by a pseudo driver. So we whine when we're called. */ cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", ddi_get_name(dip), ddi_get_instance(dip), ctlop, ddi_get_name(rdip), ddi_get_instance(rdip)); return (DDI_FAILURE); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_BTOP: case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_POWER: case DDI_CTLOPS_PTOB: default: /* * The ops that we pass up (default). We pass up memory * allocation oriented ops that we receive - these may be * associated with pseudo HBA drivers below us with target * drivers below them that use ddi memory allocation * interfaces like scsi_alloc_consistent_buf. */ return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
/*ARGSUSED*/ static int pcmem_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { char name[MAXNAMELEN]; int techreg, cissp; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) { return (DDI_FAILURE); } PCMEM_DEBUG((CE_CONT, "?pcmem_ctlops: %s%d at %s in socket %d\n", ddi_get_name(rdip), ddi_get_instance(rdip), ddi_get_name(dip), ddi_getprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS, "socket", -1))); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: PCMEM_DEBUG((CE_CONT, "pcmem_ctlops - DDI_CTLOPS_INITCHILD persistent=%x\n", ndi_dev_is_persistent_node((dev_info_t *)arg))); if (!ndi_dev_is_persistent_node((dev_info_t *)arg)) return (DDI_FAILURE); /* * XXXX - Read card CIS to determine technology * region(tn) and CIS space(dn). * Refer to Bugid 1179336. */ /* * see cis_handler.h for CISTPL_DEVICE * and CISTPL_DEVICE_A * * CISTPL_DEVICE_DTYPE_NULL 0x00 NULL device * CISTPL_DEVICE_DTYPE_ROM 0x01 ROM * CISTPL_DEVICE_DTYPE_OTPROM 0x02 OTPROM * CISTPL_DEVICE_DTYPE_EPROM 0x03 EPROM * CISTPL_DEVICE_DTYPE_EEPROM 0x04 EEPROM * CISTPL_DEVICE_DTYPE_FLASH 0x05 FLASH * CISTPL_DEVICE_DTYPE_SRAM 0x06 SRAM * CISTPL_DEVICE_DTYPE_DRAM 0x07 DRAM * */ /* * XXXX - For now set to default SRAM device */ techreg = CISTPL_DEVICE_DTYPE_SRAM; cissp = 0; (void) sprintf(name, "%d,%d", techreg, cissp); ddi_set_name_addr((dev_info_t *)arg, name); PCMEM_DEBUG((CE_CONT, "pcmem_ctlops - DDI_CTLOPS_INITCHILD name=%s\n", name)); return (DDI_SUCCESS); case DDI_CTLOPS_UNINITCHILD: ddi_set_name_addr((dev_info_t *)arg, NULL); PCMEM_DEBUG((CE_CONT, "pcmem_ctlops - DDI_CTLOPS_UNINITCHILD child: %s(%d)\n", ddi_node_name(arg), ddi_get_instance(arg))); return (DDI_SUCCESS); default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
static int pseudonex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == NULL) return (DDI_FAILURE); cmn_err(CE_CONT, "?pseudo-device: %s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: { char name[12]; /* enough for a decimal integer */ int instance = -1; dev_info_t *child = (dev_info_t *)arg; const char *childname = ddi_driver_name(child); char **childlist; uint_t nelems; int auto_assign = 0; /* * If this pseudonex node has a valid-children property, * then that acts as an access control list for children * allowed to attach beneath this node. Honor it. */ if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "valid-children", &childlist, &nelems) == DDI_PROP_SUCCESS) { int i, ok = 0; for (i = 0; i < nelems; i++) { if (strcmp(childlist[i], childname) == 0) { ok = 1; break; } } ddi_prop_free(childlist); if (!ok) return (DDI_FAILURE); } /* * Look up the "instance" property. If it does not exist, * check to see if the "auto-assign-instance" property is set. * If not, default to using instance 0; while not ideal, this * is a legacy behavior we must continue to support. */ instance = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "instance", -1); auto_assign = ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "auto-assign-instance"); NDI_CONFIG_DEBUG((CE_NOTE, "pseudonex: DDI_CTLOPS_INITCHILD(instance=%d, " "auto-assign=%d)", instance, auto_assign)); if (instance != -1 && auto_assign != 0) { NDI_CONFIG_DEBUG((CE_NOTE, "both instance and " "auto-assign-instance properties specified. " "Node rejected.")); return (DDI_FAILURE); } if (instance == -1 && auto_assign == 0) { /* default to instance 0 if not specified */ NDI_CONFIG_DEBUG((CE_NOTE, "defaulting to 0")); instance = 0; } /* * If an instance has been specified, determine if this * instance is already in use; if we need to pick an instance, * we do it here. */ if (auto_assign) { if ((instance = pseudonex_auto_assign(child)) == -1) { NDI_CONFIG_DEBUG((CE_NOTE, "failed to " "auto-select instance for %s", childname)); return (DDI_FAILURE); } NDI_CONFIG_DEBUG((CE_NOTE, "auto-selected instance for %s: %d", childname, instance)); } else { if (pseudonex_check_assignment(child, instance) == DDI_FAILURE) { NDI_CONFIG_DEBUG((CE_WARN, "Duplicate instance %d of node \"%s\" " "ignored.", instance, childname)); return (DDI_FAILURE); } NDI_CONFIG_DEBUG((CE_NOTE, "using fixed-assignment instance for %s: %d", childname, instance)); } /* * Attach the instance number to the node. This allows * us to have multiple instances of the same pseudo * device, they will be named 'device@instance'. If this * breaks programs, we may need to special-case instance 0 * into 'device'. Ick. devlinks appears to handle the * new names ok, so if only names in /dev are used * this may not be necessary. */ (void) snprintf(name, sizeof (name), "%d", instance); DEVI(child)->devi_instance = instance; ddi_set_name_addr(child, name); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { dev_info_t *child = (dev_info_t *)arg; NDI_CONFIG_DEBUG((CE_NOTE, "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)", ddi_driver_name(child), DEVI(child)->devi_instance)); ddi_set_name_addr(child, NULL); return (DDI_SUCCESS); } case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: /* * These ops correspond to functions that "shouldn't" be called * by a pseudo driver. So we whine when we're called. */ cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", ddi_driver_name(dip), ddi_get_instance(dip), ctlop, ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_FAILURE); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_BTOP: case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_POWER: case DDI_CTLOPS_PTOB: default: /* * The ops that we pass up (default). We pass up memory * allocation oriented ops that we receive - these may be * associated with pseudo HBA drivers below us with target * drivers below them that use ddi memory allocation * interfaces like scsi_alloc_consistent_buf. */ return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
/*ARGSUSED*/ static int pci_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pci_regspec_t *drv_regp; uint_t reglen; int rn; int totreg; pci_state_t *pcip; struct attachspec *asp; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: return (pci_initchild((dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: return (pci_removechild((dev_info_t *)arg)); case DDI_CTLOPS_SIDDEV: return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); *(int *)result = 0; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, ®len) != DDI_PROP_SUCCESS) { return (DDI_FAILURE); } totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); if (ctlop == DDI_CTLOPS_NREGS) *(int *)result = totreg; else if (ctlop == DDI_CTLOPS_REGSIZE) { rn = *(int *)arg; if (rn >= totreg) { ddi_prop_free(drv_regp); return (DDI_FAILURE); } *(off_t *)result = drv_regp[rn].pci_size_low; } ddi_prop_free(drv_regp); return (DDI_SUCCESS); case DDI_CTLOPS_POWER: { power_req_t *reqp = (power_req_t *)arg; /* * We currently understand reporting of PCI_PM_IDLESPEED * capability. Everything else is passed up. */ if ((reqp->request_type == PMR_REPORT_PMCAP) && (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { return (DDI_SUCCESS); } return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } case DDI_CTLOPS_PEEK: case DDI_CTLOPS_POKE: pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, pci_common_peekpoke, &pcip->pci_err_mutex, &pcip->pci_peek_poke_mutex, pci_peekpoke_cb)); /* for now only X86 systems support PME wakeup from suspended state */ case DDI_CTLOPS_ATTACH: asp = (struct attachspec *)arg; if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) if (pci_pre_resume(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (ddi_ctlops(dip, rdip, ctlop, arg, result)); case DDI_CTLOPS_DETACH: asp = (struct attachspec *)arg; if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST) if (pci_post_suspend(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (ddi_ctlops(dip, rdip, ctlop, arg, result)); default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } /* NOTREACHED */ }
/*ARGSUSED*/ static int ppb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pci_regspec_t *drv_regp; int reglen; int rn; int totreg; ppb_devstate_t *ppb = ddi_get_soft_state(ppb_state, ddi_get_instance(dip)); struct detachspec *dsp; struct attachspec *asp; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: return (ppb_initchild((dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: ppb_removechild((dev_info_t *)arg); return (DDI_SUCCESS); case DDI_CTLOPS_SIDDEV: return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); break; /* X86 systems support PME wakeup from suspend */ case DDI_CTLOPS_ATTACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); asp = (struct attachspec *)arg; if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && (asp->when == DDI_POST) && (asp->result == DDI_SUCCESS)) pf_init(rdip, (void *)ppb->ppb_fm_ibc, asp->cmd); if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) if (pci_pre_resume(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (DDI_SUCCESS); case DDI_CTLOPS_DETACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); dsp = (struct detachspec *)arg; if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && (dsp->when == DDI_PRE)) pf_fini(rdip, dsp->cmd); if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST) if (pci_post_suspend(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (DDI_SUCCESS); case DDI_CTLOPS_PEEK: case DDI_CTLOPS_POKE: if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0) return (ddi_ctlops(dip, rdip, ctlop, arg, result)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, ddi_ctlops, &ppb->ppb_err_mutex, &ppb->ppb_peek_poke_mutex, ppb_peekpoke_cb)); default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } *(int *)result = 0; if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) return (DDI_FAILURE); totreg = reglen / sizeof (pci_regspec_t); if (ctlop == DDI_CTLOPS_NREGS) *(int *)result = totreg; else if (ctlop == DDI_CTLOPS_REGSIZE) { rn = *(int *)arg; if (rn >= totreg) { kmem_free(drv_regp, reglen); return (DDI_FAILURE); } *(off_t *)result = drv_regp[rn].pci_size_low; } kmem_free(drv_regp, reglen); return (DDI_SUCCESS); }
/* * control ops entry point: * * Requests handled completely: * DDI_CTLOPS_INITCHILD * DDI_CTLOPS_UNINITCHILD * DDI_CTLOPS_REPORTDEV * DDI_CTLOPS_REGSIZE * DDI_CTLOPS_NREGS * * All others passed to parent. */ static int acebus_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { #ifdef DEBUG ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip)); #endif ebus_regspec_t *ebus_rp; int32_t reglen; int i, n; char name[10]; switch (op) { case DDI_CTLOPS_INITCHILD: { dev_info_t *child = (dev_info_t *)arg; /* * Set the address portion of the node name based on the * address/offset. */ DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n", ddi_get_name(child), ddi_get_instance(child)); if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", (caddr_t)&ebus_rp, ®len) != DDI_SUCCESS) { DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); return (DDI_FAILURE); } (void) sprintf(name, "%x,%x", ebus_rp->addr_hi, ebus_rp->addr_low); ddi_set_name_addr(child, name); kmem_free((caddr_t)ebus_rp, reglen); ddi_set_parent_data(child, NULL); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n", ddi_get_name((dev_info_t *)arg), ddi_get_instance((dev_info_t *)arg)); ddi_set_name_addr((dev_info_t *)arg, NULL); ddi_remove_minor_node((dev_info_t *)arg, NULL); impl_rem_dev_props((dev_info_t *)arg); return (DDI_SUCCESS); case DDI_CTLOPS_REPORTDEV: DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n", ddi_get_name(rdip), ddi_get_instance(rdip)); cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n", ddi_driver_name(rdip), ddi_get_instance(rdip), ddi_driver_name(dip), ddi_get_instance(dip), ddi_get_name_addr(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n", ddi_get_name(rdip), ddi_get_instance(rdip)); if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); return (DDI_FAILURE); } n = i / sizeof (ebus_regspec_t); if (*(int *)arg < 0 || *(int *)arg >= n) { DBG(D_MAP, ebus_p, "rnumber out of range\n"); kmem_free((caddr_t)ebus_rp, i); return (DDI_FAILURE); } *((off_t *)result) = ebus_rp[*(int *)arg].size; kmem_free((caddr_t)ebus_rp, i); return (DDI_SUCCESS); case DDI_CTLOPS_NREGS: DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n", ddi_get_name(rdip), ddi_get_instance(rdip)); if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) { DBG(D_CTLOPS, ebus_p, "can't get reg property\n"); return (DDI_FAILURE); } *((uint_t *)result) = i / sizeof (ebus_regspec_t); kmem_free((caddr_t)ebus_rp, i); return (DDI_SUCCESS); } /* * Now pass the request up to our parent. */ DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n", ddi_get_name(rdip), ddi_get_instance(rdip)); return (ddi_ctlops(dip, rdip, op, arg, result)); }
/*ARGSUSED*/ static int ppb_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pci_regspec_t *drv_regp; int reglen; int rn; struct attachspec *as; struct detachspec *ds; int totreg; ppb_devstate_t *ppb_p; ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state, ddi_get_instance(dip)); switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n", ddi_node_name(rdip), ddi_get_name_addr(rdip), ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: return (ppb_initchild((dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: ppb_uninitchild((dev_info_t *)arg); return (DDI_SUCCESS); case DDI_CTLOPS_ATTACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); as = (struct attachspec *)arg; if ((ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && (as->when == DDI_POST) && (as->result == DDI_SUCCESS)) pf_init(rdip, ppb_p->fm_ibc, as->cmd); return (DDI_SUCCESS); case DDI_CTLOPS_DETACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); ds = (struct detachspec *)arg; if ((ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) && (ds->when == DDI_PRE)) pf_fini(rdip, ds->cmd); return (DDI_SUCCESS); case DDI_CTLOPS_SIDDEV: return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); break; default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } *(int *)result = 0; if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg", (caddr_t)&drv_regp, ®len) != DDI_SUCCESS) return (DDI_FAILURE); totreg = reglen / sizeof (pci_regspec_t); if (ctlop == DDI_CTLOPS_NREGS) *(int *)result = totreg; else if (ctlop == DDI_CTLOPS_REGSIZE) { rn = *(int *)arg; if (rn >= totreg) { kmem_free(drv_regp, reglen); return (DDI_FAILURE); } *(off_t *)result = drv_regp[rn].pci_size_low | ((uint64_t)drv_regp[rn].pci_size_hi << 32); } kmem_free(drv_regp, reglen); return (DDI_SUCCESS); }
static int cnex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { char name[MAXNAMELEN]; uint32_t reglen; int *cnex_regspec; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == NULL) return (DDI_FAILURE); cmn_err(CE_CONT, "?channel-device: %s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: { dev_info_t *child = (dev_info_t *)arg; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", &cnex_regspec, ®len) != DDI_SUCCESS) { return (DDI_FAILURE); } (void) snprintf(name, sizeof (name), "%x", *cnex_regspec); ddi_set_name_addr(child, name); ddi_set_parent_data(child, NULL); ddi_prop_free(cnex_regspec); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { dev_info_t *child = (dev_info_t *)arg; NDI_CONFIG_DEBUG((CE_NOTE, "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)", ddi_driver_name(child), DEVI(child)->devi_instance)); ddi_set_name_addr(child, NULL); return (DDI_SUCCESS); } case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: /* * These ops correspond to functions that "shouldn't" be called * by a channel-device driver. So we whine when we're called. */ cmn_err(CE_WARN, "%s%d: invalid op (%d) from %s%d\n", ddi_driver_name(dip), ddi_get_instance(dip), ctlop, ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_FAILURE); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_BTOP: case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_POWER: case DDI_CTLOPS_PTOB: default: /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
/* * control ops entry point: * * Requests handled completely: * DDI_CTLOPS_INITCHILD see init_child() for details * DDI_CTLOPS_UNINITCHILD * DDI_CTLOPS_REPORTDEV see report_dev() for details * DDI_CTLOPS_IOMIN cache line size if streaming otherwise 1 * DDI_CTLOPS_REGSIZE * DDI_CTLOPS_NREGS * DDI_CTLOPS_DVMAPAGESIZE * DDI_CTLOPS_POKE * DDI_CTLOPS_PEEK * * All others passed to parent. */ int px_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { px_t *px_p = DIP_TO_STATE(dip); struct detachspec *ds; struct attachspec *as; switch (op) { case DDI_CTLOPS_INITCHILD: return (px_init_child(px_p, (dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: return (px_uninit_child(px_p, (dev_info_t *)arg)); case DDI_CTLOPS_ATTACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); as = (struct attachspec *)arg; switch (as->when) { case DDI_PRE: if (as->cmd == DDI_ATTACH) { DBG(DBG_PWR, dip, "PRE_ATTACH for %s@%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (pcie_pm_hold(dip)); } if (as->cmd == DDI_RESUME) { DBG(DBG_PWR, dip, "PRE_RESUME for %s@%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); pcie_clear_errors(rdip); } return (DDI_SUCCESS); case DDI_POST: DBG(DBG_PWR, dip, "POST_ATTACH for %s@%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); if (as->cmd == DDI_ATTACH && as->result != DDI_SUCCESS) { /* * Attach failed for the child device. The child * driver may have made PM calls before the * attach failed. pcie_pm_remove_child() should * cleanup PM state and holds (if any) * associated with the child device. */ return (pcie_pm_remove_child(dip, rdip)); } if (as->result == DDI_SUCCESS) pf_init(rdip, (void *)px_p->px_fm_ibc, as->cmd); (void) pcie_postattach_child(rdip); return (DDI_SUCCESS); default: break; } break; case DDI_CTLOPS_DETACH: if (!pcie_is_child(dip, rdip)) return (DDI_SUCCESS); ds = (struct detachspec *)arg; switch (ds->when) { case DDI_POST: if (ds->cmd == DDI_DETACH && ds->result == DDI_SUCCESS) { DBG(DBG_PWR, dip, "POST_DETACH for %s@%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (pcie_pm_remove_child(dip, rdip)); } return (DDI_SUCCESS); case DDI_PRE: pf_fini(rdip, ds->cmd); return (DDI_SUCCESS); default: break; } break; case DDI_CTLOPS_REPORTDEV: if (ddi_get_parent(rdip) == dip) return (px_report_dev(rdip)); (void) px_lib_fabric_sync(rdip); return (DDI_SUCCESS); case DDI_CTLOPS_IOMIN: return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: *((off_t *)result) = px_get_reg_set_size(rdip, *((int *)arg)); return (*((off_t *)result) == 0 ? DDI_FAILURE : DDI_SUCCESS); case DDI_CTLOPS_NREGS: *((uint_t *)result) = px_get_nreg_set(rdip); return (DDI_SUCCESS); case DDI_CTLOPS_DVMAPAGESIZE: *((ulong_t *)result) = MMU_PAGE_SIZE; return (DDI_SUCCESS); case DDI_CTLOPS_POKE: /* platform dependent implementation. */ return (px_lib_ctlops_poke(dip, rdip, (peekpoke_ctlops_t *)arg)); case DDI_CTLOPS_PEEK: /* platform dependent implementation. */ return (px_lib_ctlops_peek(dip, rdip, (peekpoke_ctlops_t *)arg, result)); case DDI_CTLOPS_POWER: default: break; } /* * Now pass the request up to our parent. */ DBG(DBG_CTLOPS, dip, "passing request to parent: rdip=%s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (ddi_ctlops(dip, rdip, op, arg, result)); }
/*ARGSUSED*/ static int isa_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { int rn; struct ddi_parent_private_data *pdp; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); cmn_err(CE_CONT, "?ISA-device: %s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: /* * older drivers aren't expecting the "standard" device * node format used by the hardware nodes. these drivers * only expect their own properties set in their driver.conf * files. so they tell us not to call them with hardware * nodes by setting the property "ignore-hardware-nodes". */ if (old_driver((dev_info_t *)arg)) { return (DDI_NOT_WELL_FORMED); } return (isa_initchild((dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: impl_ddi_sunbus_removechild((dev_info_t *)arg); return (DDI_SUCCESS); case DDI_CTLOPS_SIDDEV: if (ndi_dev_is_persistent_node(rdip)) return (DDI_SUCCESS); /* * All ISA devices need to do confirming probes * unless they are PnP ISA. */ if (is_pnpisa(rdip)) return (DDI_SUCCESS); else return (DDI_FAILURE); case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); if ((pdp = ddi_get_parent_data(rdip)) == NULL) return (DDI_FAILURE); if (ctlop == DDI_CTLOPS_NREGS) { *(int *)result = pdp->par_nreg; } else { rn = *(int *)arg; if (rn >= pdp->par_nreg) return (DDI_FAILURE); *(off_t *)result = (off_t)pdp->par_reg[rn].regspec_size; } return (DDI_SUCCESS); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_PEEK: case DDI_CTLOPS_POKE: return (DDI_FAILURE); default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }