Esempio n. 1
0
/*
 * name_child
 *
 * This function is called from pcmu_init_child to name a node. It is
 * also passed as a callback for node merging functions.
 *
 * return value: DDI_SUCCESS, DDI_FAILURE
 */
static int
name_child(dev_info_t *child, char *name, int namelen)
{
	pci_regspec_t *pcmu_rp;
	int reglen;
	uint_t func;
	char **unit_addr;
	uint_t n;

	/*
	 * Set the address portion of the node name based on
	 * unit-address property, if it exists.
	 * The interpretation of the unit-address is DD[,F]
	 * where DD is the device id and F is the function.
	 */
	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
	    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) ==
	    DDI_PROP_SUCCESS) {
		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
			cmn_err(CE_WARN, "unit-address property in %s.conf"
			    " not well-formed", ddi_driver_name(child));
			ddi_prop_free(unit_addr);
			return (DDI_FAILURE);
		}
		(void) snprintf(name, namelen, "%s", *unit_addr);
		ddi_prop_free(unit_addr);
		return (DDI_SUCCESS);
	}

	/*
	 * The unit-address property is does not exist. Set the address
	 * portion of the node name based on the function and device number.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "reg", (int **)&pcmu_rp, (uint_t *)&reglen) == DDI_SUCCESS) {
		if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) {
			cmn_err(CE_WARN, "reg property not well-formed");
			return (DDI_FAILURE);
		}

		func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi);
		if (func != 0) {
			(void) snprintf(name, namelen, "%x,%x",
				PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func);
		} else {
			(void) snprintf(name, namelen, "%x",
				PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi));
		}
		ddi_prop_free(pcmu_rp);
		return (DDI_SUCCESS);
	}
	cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child));
	return (DDI_FAILURE);
}
Esempio n. 2
0
/*
 * name_child
 *
 * This function is called from init_child to name a node. It is
 * also passed as a callback for node merging functions.
 *
 * return value: DDI_SUCCESS, DDI_FAILURE
 */
static int
ppb_name_child(dev_info_t *child, char *name, int namelen)
{
	pci_regspec_t *pci_rp;
	uint_t slot, func;
	char **unit_addr;
	uint_t n;

	/*
	 * Pseudo nodes indicate a prototype node with per-instance
	 * properties to be merged into the real h/w device node.
	 * The interpretation of the unit-address is DD[,F]
	 * where DD is the device id and F is the function.
	 */
	if (ndi_dev_is_persistent_node(child) == 0) {
		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
		    DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN, "cannot name node from %s.conf",
			    ddi_driver_name(child));
			return (DDI_FAILURE);
		}
		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
			cmn_err(CE_WARN, "unit-address property in %s.conf"
			    " not well-formed", ddi_driver_name(child));
			ddi_prop_free(unit_addr);
			return (DDI_FAILURE);
		}
		(void) snprintf(name, namelen, "%s", *unit_addr);
		ddi_prop_free(unit_addr);
		return (DDI_SUCCESS);
	}

	/*
	 * Get the address portion of the node name based on
	 * the function and device number.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);
	func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi);

	if (func != 0)
		(void) snprintf(name, namelen, "%x,%x", slot, func);
	else
		(void) snprintf(name, namelen, "%x", slot);

	ddi_prop_free(pci_rp);
	return (DDI_SUCCESS);
}
Esempio n. 3
0
static void
isa_create_ranges_prop(dev_info_t *dip)
{
	dev_info_t *used;
	int *ioarray, *memarray, status;
	uint_t nio = 0, nmem = 0, nrng = 0, n;
	pib_ranges_t *ranges;

	used = ddi_find_devinfo(USED_RESOURCES, -1, 0);
	if (used == NULL) {
		cmn_err(CE_WARN, "Failed to find used-resources <%s>\n",
		    ddi_get_name(dip));
		return;
	}
	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
	    DDI_PROP_DONTPASS, "io-space", &ioarray, &nio);
	if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
		cmn_err(CE_WARN, "io-space property failure for %s (%x)\n",
		    ddi_get_name(used), status);
		return;
	}
	status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used,
	    DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem);
	if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) {
		cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n",
		    ddi_get_name(used), status);
		return;
	}
	n = (nio + nmem) / USED_CELL_SIZE;
	ranges =  (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n,
	    KM_SLEEP);

	if (nio != 0) {
		nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges);
		isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio);
		ddi_prop_free(ioarray);
	}
	if (nmem != 0) {
		nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem,
		    ranges + nrng);
		isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem);
		ddi_prop_free(memarray);
	}

	if (!pseudo_isa)
		(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
		    (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int));
	kmem_free(ranges, sizeof (pib_ranges_t) * n);
}
Esempio n. 4
0
static int
ppb_name_child(dev_info_t *child, char *name, int namelen)
{
	pci_regspec_t *pci_rp;
	uint_t slot, func;
	char **unit_addr;
	uint_t n;

	/*
	 * For .conf nodes, use unit-address property as name
	 */
	if (ndi_dev_is_persistent_node(child) == 0) {
		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child,
		    DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) !=
		    DDI_PROP_SUCCESS) {
			cmn_err(CE_WARN,
			    "cannot find unit-address in %s.conf",
			    ddi_driver_name(child));
			return (DDI_FAILURE);
		}
		if (n != 1 || *unit_addr == NULL || **unit_addr == 0) {
			cmn_err(CE_WARN, "unit-address property in %s.conf"
			    " not well-formed", ddi_driver_name(child));
			ddi_prop_free(unit_addr);
			return (DDI_SUCCESS);
		}
		(void) snprintf(name, namelen, "%s", *unit_addr);
		ddi_prop_free(unit_addr);
		return (DDI_SUCCESS);
	}

	/* get child "reg" property */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
	    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	/* copy the device identifications */
	slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
	func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);

	if (func != 0)
		(void) snprintf(name, namelen, "%x,%x", slot, func);
	else
		(void) snprintf(name, namelen, "%x", slot);

	ddi_prop_free(pci_rp);
	return (DDI_SUCCESS);
}
Esempio n. 5
0
int
mp_find_cpu(dev_info_t *dip, void *arg)
{
    extern int get_portid_ddi(dev_info_t *, dev_info_t **);
    struct mp_find_cpu_arg *target = (struct mp_find_cpu_arg *)arg;
    char *type;
    int rv = DDI_WALK_CONTINUE;
    int cpuid;

    if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
                               "device_type", &type))
        return (DDI_WALK_CONTINUE);

    if (strcmp(type, "cpu") != 0)
        goto out;

    cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
                             DDI_PROP_DONTPASS, "cpuid", -1);

    if (cpuid == -1)
        cpuid = get_portid_ddi(dip, NULL);
    if (cpuid != target->cpuid)
        goto out;

    /* Found it */
    rv = DDI_WALK_TERMINATE;
    target->dip = dip;

out:
    ddi_prop_free(type);
    return (rv);
}
Esempio n. 6
0
/*
 * vdds_match_niu_node -- callback function to verify a node is the
 *	NIU Hybrid node.
 */
static int
vdds_match_niu_node(dev_info_t *dip, void *arg)
{
	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
	char		*name;
	vdds_reg_t	*reg_p;
	uint_t		reglen;
	int		rv;
	uint32_t	addr_hi;

	name = ddi_node_name(dip);
	if (strcmp(name, "network")  != 0) {
		return (DDI_WALK_CONTINUE);
	}
	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
	if (rv != DDI_PROP_SUCCESS) {
		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
		return (DDI_WALK_CONTINUE);
	}

	addr_hi = reg_p->addr_hi;
	DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip);
	ddi_prop_free(reg_p);
	if (addr_hi == HVCOOKIE(warg->cookie)) {
		warg->dip = dip;
		if (!e_ddi_branch_held(dip))
			e_ddi_branch_hold(dip);
		DBG1(NULL, "Found dip = 0x%p", dip);
		return (DDI_WALK_TERMINATE);
	}
	return (DDI_WALK_CONTINUE);
}
Esempio n. 7
0
static int
gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func)
{
	pci_regspec_t   *pci_rp;
	uint32_t	length;
	int	rc;

	/* get "reg" property */
	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
		DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
		(uint_t *)&length);
	if ((rc != DDI_SUCCESS) || (length <
			(sizeof (pci_regspec_t) / sizeof (int)))) {
		return (DDI_FAILURE);
	}

	*bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
	*dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
	*func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);

	/*
	 * free the memory allocated by ddi_prop_lookup_int_array().
	 */
	ddi_prop_free(pci_rp);

	return (DDI_SUCCESS);
}
Esempio n. 8
0
int
mp_find_cpu(dev_info_t *dip, void *arg)
{
	struct mp_find_cpu_arg *target = (struct mp_find_cpu_arg *)arg;
	char	*type;
	int	rv = DDI_WALK_CONTINUE;
	int	cpuid;

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "device_type", &type))
		return (DDI_WALK_CONTINUE);

	if (strcmp(type, "cpu") != 0)
		goto out;

	cpuid = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "reg", -1);

	if (cpuid == -1) {
		cmn_err(CE_PANIC, "reg prop not found in cpu node");
	}

	cpuid = PROM_CFGHDL_TO_CPUID(cpuid);

	if (cpuid != target->cpuid)
		goto out;

	/* Found it */
	rv = DDI_WALK_TERMINATE;
	target->dip = dip;

out:
	ddi_prop_free(type);
	return (rv);
}
Esempio n. 9
0
int
_init(void)
{
	int	err;
	char tty_irq_param[9] = "ttyX-irq";
	char *tty_irq;
	int i;

	if ((err = mod_install(&modlinkage)) != 0)
		return (err);

	/* Check if any tty irqs are overridden by eeprom config */
	for (i = 0; i < num_BIOS_serial; i++) {
		tty_irq_param[3] = 'a' + i;
		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
		    DDI_PROP_DONTPASS, tty_irq_param, &tty_irq)
		    == DDI_PROP_SUCCESS) {
			long data;

			if (ddi_strtol(tty_irq, NULL, 0, &data) == 0) {
				asy_intrs[i] = (int)data;
				asy_intr_override |= 1<<i;
			}

			ddi_prop_free(tty_irq);
		}
	}

	impl_bus_add_probe(isa_enumerate);
	return (0);
}
Esempio n. 10
0
/*
 * function to read the PCI Bus, Device, and function numbers for the
 * device instance.
 *
 * dev - handle to device private data
 */
int
oce_get_bdf(struct oce_dev *dev)
{
	pci_regspec_t *pci_rp;
	uint32_t length;
	int rc;

	/* Get "reg" property */
	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dev->dip,
	    0, "reg", (int **)&pci_rp, (uint_t *)&length);

	if ((rc != DDI_SUCCESS) ||
	    (length < (sizeof (pci_regspec_t) / sizeof (int)))) {
		oce_log(dev, CE_WARN, MOD_CONFIG,
		    "Failed to read \"reg\" property, Status = 0x%x", rc);
		return (rc);
	}

	dev->pci_bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
	dev->pci_device = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
	dev->pci_function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);

	oce_log(dev, CE_NOTE, MOD_CONFIG,
	    "\"reg\" property num=%d, Bus=%d, Device=%d, Function=%d",
	    length, dev->pci_bus, dev->pci_device, dev->pci_function);

	/* Free the memory allocated by ddi_prop_lookup_int_array() */
	ddi_prop_free(pci_rp);
	return (rc);
}
Esempio n. 11
0
/*
 * Get the numeric value of the property "name" in vmxnet3s.conf for
 * the corresponding device instance.
 * If the property isn't found or if it doesn't satisfy the conditions,
 * "def" is returned.
 *
 * Returns:
 *	The value of the property or "def".
 */
int
vmxnet3_getprop(vmxnet3_softc_t *dp, char *name, int min, int max, int def)
{
	int ret = def;
	int *props;
	uint_t nprops;

	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS,
	    name, &props, &nprops) == DDI_PROP_SUCCESS) {
		if (dp->instance < nprops) {
			ret = props[dp->instance];
		} else {
			VMXNET3_WARN(dp, "property %s not available for this "
			    "device\n", name);
		}
		ddi_prop_free(props);
	}

	if (ret < min || ret > max) {
		ASSERT(def >= min && def <= max);
		VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n",
		    name, min, ret, max);
		ret = def;
	}

	VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret);

	return (ret);
}
Esempio n. 12
0
/*ARGSUSED*/
static int
fipe_search_ioat_dev(dev_info_t *dip, void *arg)
{
	char *unit;
	struct fipe_pci_ioat_id *id;
	int i, max, venid, devid, subvenid, subsysid;

	/* Query PCI id properties. */
	venid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "vendor-id", 0xffffffff);
	if (venid == 0xffffffff) {
		return (DDI_WALK_CONTINUE);
	}
	devid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "device-id", 0xffffffff);
	if (devid == 0xffffffff) {
		return (DDI_WALK_CONTINUE);
	}
	subvenid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "subsystem-vendor-id", 0xffffffff);
	if (subvenid == 0xffffffff) {
		return (DDI_WALK_CONTINUE);
	}
	subsysid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "subsystem-id", 0xffffffff);
	if (subvenid == 0xffffffff) {
		return (DDI_WALK_CONTINUE);
	}
	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "unit-address", &unit) != DDI_PROP_SUCCESS) {
		return (DDI_WALK_CONTINUE);
	}

	max = sizeof (fipe_pci_ioat_ids) / sizeof (fipe_pci_ioat_ids[0]);
	for (i = 0; i < max; i++) {
		id = &fipe_pci_ioat_ids[i];
		if ((id->venid == 0xffffu || id->venid == venid) &&
		    (id->devid == 0xffffu || id->devid == devid) &&
		    (id->subvenid == 0xffffu || id->subvenid == subvenid) &&
		    (id->subsysid == 0xffffu || id->subsysid == subsysid) &&
		    (id->unitaddr == NULL || strcmp(id->unitaddr, unit) == 0)) {
			break;
		}
	}
	ddi_prop_free(unit);
	if (i >= max) {
		return (DDI_WALK_CONTINUE);
	}

	/* Found IOAT device, hold one reference count. */
	ndi_hold_devi(dip);
	fipe_ioat_ctrl.ioat_dev_info = dip;

	return (DDI_WALK_TERMINATE);
}
Esempio n. 13
0
int
get_bdf(dev_info_t *dip, int *bus, int *device, int *func)
{
	pci_regspec_t *pci_rp;
	int len;

	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS)
		return (-1);

	if (len < (sizeof (pci_regspec_t) / sizeof (int))) {
		ddi_prop_free(pci_rp);
		return (-1);
	}
	if (bus != NULL)
		*bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi);
	if (device != NULL)
		*device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi);
	if (func != NULL)
		*func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
	ddi_prop_free(pci_rp);
	return (0);
}
Esempio n. 14
0
/*
 * Check's if this child is a PCI device.
 * Child is a PCI device if:
 * parent has a dev_type of "pci"
 * -and-
 * child does not have a dev_type of "pciex"
 *
 * If the parent is not of dev_type "pci", then assume it is "pciex" and all
 * children should support using PCIe style MMCFG access.
 *
 * If parent's dev_type is "pci" and child is "pciex", then also enable using
 * PCIe style MMCFG access.  This covers the case where NPE is "pci" and a PCIe
 * RP is beneath.
 */
boolean_t
npe_child_is_pci(dev_info_t *dip) {
	char *dev_type;
	boolean_t parent_is_pci, child_is_pciex;

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(dip),
	    DDI_PROP_DONTPASS, "device_type", &dev_type) ==
	    DDI_PROP_SUCCESS) {
		parent_is_pci = (strcmp(dev_type, "pci") == 0);
		ddi_prop_free(dev_type);
	} else {
		parent_is_pci = B_FALSE;
	}

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "device_type", &dev_type) == DDI_PROP_SUCCESS) {
		child_is_pciex = (strcmp(dev_type, "pciex") == 0);
		ddi_prop_free(dev_type);
	} else {
		child_is_pciex = B_FALSE;
	}

	return (parent_is_pci && !child_is_pciex);
}
Esempio n. 15
0
/*
 * sets master_ops_debug flag from propertyu passed by the boot
 */
static void
set_master_ops_debug_flags()
{
	char *prop;
	long flags;

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
	    DDI_PROP_DONTPASS, "master_ops_debug", &prop) == DDI_PROP_SUCCESS) {
		long data;
		if (ddi_strtol(prop, NULL, 0, &data) == 0) {
			master_ops_debug = (unsigned long)data;
			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
			    "master_ops_debug");
			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
			    "master_ops_debug", data);
		}
		ddi_prop_free(prop);
	}
}
Esempio n. 16
0
static int
name_child(dev_info_t *child, char *name, int namelen)
{
	char *unitaddr;

	ddi_set_parent_data(child, NULL);

	name[0] = '\0';
	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    ACPIDEV_PROP_NAME_UNIT_ADDR, &unitaddr) == DDI_SUCCESS) {
		(void) strlcpy(name, unitaddr, namelen);
		ddi_prop_free(unitaddr);
	} else {
		ACPINEX_DEBUG(CE_NOTE, "!acpinex: failed to lookup child "
		    "unit-address prop for %p.", (void *)child);
	}

	return (DDI_SUCCESS);
}
Esempio n. 17
0
/*
 * Get boot property value for fastreboot_onpanic.
 *
 * NOTE: If fastreboot_onpanic is set to non-zero in /etc/system,
 * new setting passed in via "-B fastreboot_onpanic" is ignored.
 * This order of precedence is to enable developers debugging panics
 * that occur early in boot to utilize Fast Reboot on panic.
 */
static void
fastboot_get_bootprop(void)
{
	int		val = 0xaa, len, ret;
	dev_info_t	*devi;
	char		*propstr = NULL;

	devi = ddi_root_node();

	ret = ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    FASTREBOOT_ONPANIC, &propstr);

	if (ret == DDI_PROP_SUCCESS) {
		if (FASTREBOOT_ONPANIC_NOTSET(propstr))
			val = 0;
		else if (FASTREBOOT_ONPANIC_ISSET(propstr))
			val = UA_FASTREBOOT_ONPANIC;

		/*
		 * Only set fastreboot_onpanic to the value passed in
		 * if it's not already set to non-zero, and the value
		 * has indeed been passed in via command line.
		 */
		if (!fastreboot_onpanic && val != 0xaa)
			fastreboot_onpanic = val;
		ddi_prop_free(propstr);
	} else if (ret != DDI_PROP_NOT_FOUND && ret != DDI_PROP_UNDEFINED) {
		cmn_err(CE_NOTE, "!%s value is invalid, will be ignored",
		    FASTREBOOT_ONPANIC);
	}

	len = sizeof (fastreboot_onpanic_cmdline);
	ret = ddi_getlongprop_buf(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    FASTREBOOT_ONPANIC_CMDLINE, fastreboot_onpanic_cmdline, &len);

	if (ret == DDI_PROP_BUF_TOO_SMALL)
		cmn_err(CE_NOTE, "!%s value is too long, will be ignored",
		    FASTREBOOT_ONPANIC_CMDLINE);
}
Esempio n. 18
0
/*
 * vdds_match_niu_nexus -- callback function to verify a node is the
 *	NIU nexus node.
 */
static int
vdds_match_niu_nexus(dev_info_t *dip, void *arg)
{
	vdds_cb_arg_t	*warg = (vdds_cb_arg_t *)arg;
	vdds_reg_t	*reg_p;
	char		*name;
	uint64_t	hdl;
	uint_t		reglen;
	int		rv;

	if (dip == ddi_root_node()) {
		return (DDI_WALK_CONTINUE);
	}

	name = ddi_node_name(dip);
	if (strcmp(name, "niu")  != 0) {
		return (DDI_WALK_CONTINUE);
	}
	rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "reg", (int **)&reg_p, &reglen);
	if (rv != DDI_PROP_SUCCESS) {
		DWARN(NULL, "Failed to get reg property dip=0x%p", dip);
		return (DDI_WALK_CONTINUE);
	}

	hdl =  reg_p->addr_hi & 0x0FFFFFFF;
	ddi_prop_free(reg_p);

	DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip);
	if (hdl == NIUCFGHDL(warg->cookie)) {
		/* Hold before returning */
		if (!e_ddi_branch_held(dip))
			e_ddi_branch_hold(dip);
		warg->dip = dip;
		DBG2(NULL, "Found dip = 0x%p", dip);
		return (DDI_WALK_TERMINATE);
	}
	return (DDI_WALK_CONTINUE);
}
Esempio n. 19
0
static int
acebus_update_props(ebus_devstate_t *ebus_p)
{
	dev_info_t *dip = ebus_p->dip;
	struct ebus_pci_rangespec er[2], *erp;
	pci_regspec_t *pci_rp, *prp;
	int length, rnums, imask[3], i, found = 0;

	/*
	 * If "ranges" property is found, then the device is initialized
	 * by OBP, hence simply return.
	 * Otherwise we create all the properties here.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "ranges", (int **)&erp, (uint_t *)&length) == DDI_PROP_SUCCESS) {
		ddi_prop_free(erp);
		return (DDI_SUCCESS);
	}

	/*
	 * interrupt-map is the only property that comes from a .conf file.
	 * Since it doesn't have the nodeid field set, it must be done here.
	 * Other properties can come from OBP or created here.
	 */
	if (acebus_set_imap(dip) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	/*
	 * Create the "ranges" property.
	 * Ebus has BAR0 and BAR1 allocated (both in memory space).
	 * Other BARs are 0.
	 * Hence there are 2 memory ranges it operates in. (one for each BAR).
	 * ie. there are 2 entries in its ranges property.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
	    DDI_PROP_DONTPASS, "assigned-addresses",
	    (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not get assigned-addresses",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	/*
	 * Create the 1st mem range in which it operates corresponding
	 * to BAR0
	 */
	er[0].ebus_phys_hi = EBUS_CHILD_PHYS_LOW_RANGE;
	rnums = (length * sizeof (int))/sizeof (pci_regspec_t);
	for (i = 0; i < rnums; i++) {
		prp = pci_rp + i;
		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[0].ebus_phys_hi) {
			found = 1;
			break;
		}
	}
	if (!found) {
		cmn_err(CE_WARN, "No assigned space for memory range 0.");
		ddi_prop_free(pci_rp);
		return (DDI_FAILURE);
	}
	found = 0;
	er[0].ebus_phys_low = 0;
	er[0].pci_phys_hi = prp->pci_phys_hi;
	er[0].pci_phys_mid = prp->pci_phys_mid;
	er[0].pci_phys_low = prp->pci_phys_low;
	er[0].rng_size = prp->pci_size_low;

	/*
	 * Create the 2nd mem range in which it operates corresponding
	 * to BAR1
	 */
	er[1].ebus_phys_hi = EBUS_CHILD_PHYS_HI_RANGE;
	for (i = 0; i < rnums; i++) {
		prp = pci_rp + i;
		if (PCI_REG_REG_G(prp->pci_phys_hi) == er[1].ebus_phys_hi) {
			found = 1;
			break;
		}
	}
	if (!found) {
		cmn_err(CE_WARN, "No assigned space for memory range 1.");
		ddi_prop_free(pci_rp);
		return (DDI_FAILURE);
	}
	er[1].ebus_phys_low = 0;
	er[1].pci_phys_hi = prp->pci_phys_hi;
	er[1].pci_phys_mid = prp->pci_phys_mid;
	er[1].pci_phys_low = prp->pci_phys_low;
	er[1].rng_size = prp->pci_size_low;

	ddi_prop_free(pci_rp);
	length = sizeof (er) / sizeof (int);
	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "ranges", (int *)er, length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not create ranges property",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	/* The following properties are as defined by PCI 1275 bindings. */
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#address-cells", 2) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#size-cells", 1) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);
	if (ddi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#interrupt-cells", 1) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);

	imask[0] = 0x1f;
	imask[1] = 0x00ffffff;
	imask[2] = 0x00000003;
	length = sizeof (imask) / sizeof (int);
	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "interrupt-map-mask", (int *)imask, length) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not update imap mask property",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}

	return (DDI_SUCCESS);
}
Esempio n. 20
0
/*
 * Return 1 if instance block was assigned for the path.
 *
 * For multi-port NIC cards, sequential instance assignment across all
 * ports on a card is highly desirable since the ppa is typically the
 * same as the instance number, and the ppa is used in the NIC's public
 * /dev name. This sequential assignment typically occurs as a result
 * of in_preassign_instance() after initial install, or by
 * i_ndi_init_hw_children() for NIC ports that share a common parent.
 *
 * Some NIC cards however use multi-function bridge chips, and to
 * support sequential instance assignment accross all ports, without
 * disabling multi-threaded attach, we have a (currently) undocumented
 * hack to allocate instance numbers in contiguous blocks based on
 * driver.conf properties.
 *
 *                       ^
 *           /----------   ------------\
 *        pci@0                      pci@0,1	MULTI-FUNCTION BRIDGE CHIP
 *       /     \                    /       \
 * FJSV,e4ta@4  FJSV,e4ta@4,1   FJSV,e4ta@6 FJSV,e4ta@6,1	NIC PORTS
 *      n            n+2             n+2         n+3		INSTANCE
 *
 * For the above example, the following driver.conf properties would be
 * used to guarantee sequential instance number assignment.
 *
 * ddi-instance-blocks ="ib-FJSVe4ca", "ib-FJSVe4ta", "ib-generic";
 * ib-FJSVe4ca =	"/pci@0/FJSV,e4ca@4", "/pci@0/FJSV,e4ca@4,1",
 *			"/pci@0,1/FJSV,e4ca@6", "/pci@0,1/FJSV,e4ca@6,1";
 * ib-FJSVe4ta =	"/pci@0/FJSV,e4ta@4", "/pci@0/FJSV,e4ta@4,1",
 *			"/pci@0,1/FJSV,e4ta@6", "/pci@0,1/FJSV,e4ta@6,1";
 * ib-generic =		"/pci@0/network@4", "/pci@0/network@4,1",
 *			"/pci@0,1/network@6", "/pci@0,1/network@6,1";
 *
 * The value of the 'ddi-instance-blocks' property references a series
 * of card specific properties, like 'ib-FJSV-e4ta', who's value
 * defines a single 'instance block'.  The 'instance block' describes
 * all the paths below a multi-function bridge, where each path is
 * called an 'instance path'.  The 'instance block' property value is a
 * series of 'instance paths'.  The number of 'instance paths' in an
 * 'instance block' defines the size of the instance block, and the
 * ordering of the 'instance paths' defines the instance number
 * assignment order for paths going through the 'instance block'.
 *
 * In the instance assignment code below, if a (path, driver) that
 * currently has no instance number has a path that goes through an
 * 'instance block', then block instance number allocation occurs.  The
 * block allocation code will find a sequential set of unused instance
 * numbers, and assign instance numbers for all the paths in the
 * 'instance block'.  Each path is assigned a persistent instance
 * number, even paths that don't exist in the device tree or fail
 * probe(9E).
 */
static int
in_assign_instance_block(dev_info_t *dip)
{
	char		**ibn;		/* instance block names */
	uint_t		nibn;		/* number of instance block names */
	uint_t		ibni;		/* ibn index */
	char		*driver;
	major_t		major;
	char		*path;
	char		*addr;
	int		plen;
	char		**ibp;		/* instance block paths */
	uint_t		nibp;		/* number of paths in instance block */
	uint_t		ibpi;		/* ibp index */
	int		ibplen;		/* length of instance block path */
	char		*ipath;
	int		instance_base;
	int		splice;
	int		i;

	/* check for fresh install case (in miniroot) */
	if (DEVI(dip)->devi_instance != -1)
		return (0);			/* already assigned */

	/*
	 * Check to see if we need to allocate a block of contiguous instance
	 * numbers by looking for the 'ddi-instance-blocks' property.
	 */
	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "ddi-instance-blocks", &ibn, &nibn) != DDI_SUCCESS)
		return (0);			/* no instance block needed */

	/*
	 * Get information out about node we are processing.
	 *
	 * NOTE: Since the node is not yet at DS_INITIALIZED, ddi_pathname()
	 * will not return the unit-address of the final path component even
	 * though the node has an established devi_addr unit-address - so we
	 * need to add the unit-address by hand.
	 */
	driver = (char *)ddi_driver_name(dip);
	major = ddi_driver_major(dip);
	path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
	(void) ddi_pathname(dip, path);
	if ((addr =  ddi_get_name_addr(dip)) != NULL) {
		(void) strcat(path, "@");
		(void) strcat(path, addr);
	}
	plen = strlen(path);

	/* loop through instance block names */
	for (ibni = 0; ibni < nibn; ibni++) {
		if (ibn[ibni] == NULL)
			continue;

		/* lookup instance block */
		if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
		    DDI_PROP_DONTPASS, ibn[ibni],
		    &ibp, &nibp) != DDI_SUCCESS) {
			cmn_err(CE_WARN,
			    "no devinition for instance block '%s' in %s.conf",
			    ibn[ibni], driver);
			continue;
		}

		/* Does 'path' go through this instance block? */
		for (ibpi = 0; ibpi < nibp; ibpi++) {
			if (ibp[ibpi] == NULL)
				continue;
			ibplen = strlen(ibp[ibpi]);
			if ((ibplen <= plen) &&
			    (strcmp(ibp[ibpi], path + plen - ibplen) == 0))
				break;

		}
		if (ibpi >= nibp) {
			ddi_prop_free(ibp);
			continue;		/* no try next instance block */
		}

		/* yes, allocate and assign instances for all paths in block */

		/*
		 * determine where we splice in instance paths and verify
		 * that none of the paths are too long.
		 */
		splice = plen - ibplen;
		for (i = 0; i < nibp; i++) {
			if ((splice + strlen(ibp[i])+ 1) >= MAXPATHLEN) {
				cmn_err(CE_WARN,
				    "path %d through instance block '%s' from "
				    "%s.conf too long", i, ibn[ibni], driver);
				break;
			}
		}
		if (i < nibp) {
			ddi_prop_free(ibp);
			continue;		/* too long */
		}

		/* allocate the instance block - no more failures */
		instance_base = in_next_instance_block(major, nibp);

		ipath = kmem_alloc(MAXPATHLEN, KM_SLEEP);
		for (ibpi = 0; ibpi < nibp; ibpi++) {
			if (ibp[ibpi] == NULL)
				continue;
			(void) strcpy(ipath, path);
			(void) strcpy(ipath + splice, ibp[ibpi]);
			(void) in_pathin(ipath,
			    instance_base + ibpi, driver, NULL);
		}

		/* free allocations */
		kmem_free(ipath, MAXPATHLEN);
		ddi_prop_free(ibp);
		kmem_free(path, MAXPATHLEN);
		ddi_prop_free(ibn);

		/* notify devfsadmd to sync of path_to_inst file */
		mutex_enter(&e_ddi_inst_state.ins_serial);
		i_log_devfs_instance_mod();
		e_ddi_inst_state.ins_dirty = 1;
		mutex_exit(&e_ddi_inst_state.ins_serial);
		return (1);
	}

	/* our path did not go through any of of the instance blocks */
	kmem_free(path, MAXPATHLEN);
	ddi_prop_free(ibn);
	return (0);
}
Esempio n. 21
0
/*ARGSUSED*/
static int
emul64_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
	scsi_hba_tran_t *tran, struct scsi_device *sd)
{
	struct emul64	*emul64;
	emul64_tgt_t	*tgt;
	char		**geo_vidpid = NULL;
	char		*geo, *vidpid;
	uint32_t	*geoip = NULL;
	uint_t		length;
	uint_t		length2;
	lldaddr_t	sector_count;
	char		prop_name[15];
	int		ret = DDI_FAILURE;

	emul64 = TRAN2EMUL64(tran);
	EMUL64_MUTEX_ENTER(emul64);

	/*
	 * We get called for each target driver.conf node, multiple
	 * nodes may map to the same tgt,lun (sd.conf, st.conf, etc).
	 * Check to see if transport to tgt,lun already established.
	 */
	tgt = find_tgt(emul64, sd->sd_address.a_target, sd->sd_address.a_lun);
	if (tgt) {
		ret = DDI_SUCCESS;
		goto out;
	}

	/* see if we have driver.conf specified device for this target,lun */
	(void) snprintf(prop_name, sizeof (prop_name), "targ_%d_%d",
	    sd->sd_address.a_target, sd->sd_address.a_lun);
	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba_dip,
	    DDI_PROP_DONTPASS, prop_name,
	    &geo_vidpid, &length) != DDI_PROP_SUCCESS)
		goto out;
	if (length < 2) {
		cmn_err(CE_WARN, "emul64: %s property does not have 2 "
		    "elements", prop_name);
		goto out;
	}

	/* pick geometry name and vidpid string from string array */
	geo = *geo_vidpid;
	vidpid = *(geo_vidpid + 1);

	/* lookup geometry property integer array */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba_dip, DDI_PROP_DONTPASS,
	    geo, (int **)&geoip, &length2) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "emul64: didn't get prop '%s'", geo);
		goto out;
	}
	if (length2 < 6) {
		cmn_err(CE_WARN, "emul64: property %s does not have 6 "
		    "elements", *geo_vidpid);
		goto out;
	}

	/* allocate and initialize tgt structure for tgt,lun */
	tgt = kmem_zalloc(sizeof (emul64_tgt_t), KM_SLEEP);
	rw_init(&tgt->emul64_tgt_nw_lock, NULL, RW_DRIVER, NULL);
	mutex_init(&tgt->emul64_tgt_blk_lock, NULL, MUTEX_DRIVER, NULL);

	/* create avl for data block storage */
	avl_create(&tgt->emul64_tgt_data, emul64_bsd_blkcompare,
	    sizeof (blklist_t), offsetof(blklist_t, bl_node));

	/* save scsi_address and vidpid */
	bcopy(sd, &tgt->emul64_tgt_saddr, sizeof (struct scsi_address));
	(void) strncpy(tgt->emul64_tgt_inq, vidpid,
	    sizeof (emul64->emul64_tgt->emul64_tgt_inq));

	/*
	 * The high order 4 bytes of the sector count always come first in
	 * emul64.conf.  They are followed by the low order 4 bytes.  Not
	 * all CPU types want them in this order, but laddr_t takes care of
	 * this for us.  We then pick up geometry (ncyl X nheads X nsect).
	 */
	sector_count._p._u	= *(geoip + 0);
	sector_count._p._l	= *(geoip + 1);
	/*
	 * On 32-bit platforms, fix block size if it's greater than the
	 * allowable maximum.
	 */
#if !defined(_LP64)
	if (sector_count._f > DK_MAX_BLOCKS)
		sector_count._f = DK_MAX_BLOCKS;
#endif
	tgt->emul64_tgt_sectors = sector_count._f;
	tgt->emul64_tgt_dtype	= *(geoip + 2);
	tgt->emul64_tgt_ncyls	= *(geoip + 3);
	tgt->emul64_tgt_nheads	= *(geoip + 4);
	tgt->emul64_tgt_nsect	= *(geoip + 5);

	/* insert target structure into list */
	tgt->emul64_tgt_next = emul64->emul64_tgt;
	emul64->emul64_tgt = tgt;
	ret = DDI_SUCCESS;

out:	EMUL64_MUTEX_EXIT(emul64);
	if (geoip)
		ddi_prop_free(geoip);
	if (geo_vidpid)
		ddi_prop_free(geo_vidpid);
	return (ret);
}
Esempio n. 22
0
/*
 * cnex_find_chan_dip -- Find the dip of a device that is corresponding
 * 	to the specific channel. Below are the details on how the dip
 *	is derived.
 *
 *	- In the MD, the cfg-handle is expected to be unique for
 *	  virtual-device nodes that have the same 'name' property value.
 *	  This value is expected to be the same as that of "reg" property
 *	  of the corresponding OBP device node.
 *
 *	- The value of the 'name' property of a virtual-device node
 *	  in the MD is expected to be the same for the corresponding
 *	  OBP device node.
 *
 *	- Find the virtual-device node corresponding to a channel-endpoint
 *	  by walking backwards. Then obtain the values for the 'name' and
 *	  'cfg-handle' properties.
 *
 *	- Walk all the children of the cnex, find a matching dip which
 *	  has the same 'name' and 'reg' property values.
 *
 *	- The channels that have no corresponding device driver are
 *	  treated as if they  correspond to the cnex driver,
 *	  that is, return cnex dip for them. This means, the
 *	  cnex acts as an umbrella device driver. Note, this is
 *	  for 'intrstat' statistics purposes only. As a result of this,
 *	  the 'intrstat' shows cnex as the device that is servicing the
 *	  interrupts corresponding to these channels.
 *
 *	  For now, only one such case is known, that is, the channels that
 *	  are used by the "domain-services".
 */
static dev_info_t *
cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id,
    md_t *mdp, mde_cookie_t mde)
{
	int listsz;
	int num_nodes;
	int num_devs;
	uint64_t cfghdl;
	char *md_name;
	mde_cookie_t *listp;
	dev_info_t *cdip = NULL;

	num_nodes = md_node_count(mdp);
	ASSERT(num_nodes > 0);
	listsz = num_nodes * sizeof (mde_cookie_t);
	listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP);

	num_devs = md_scan_dag(mdp, mde, md_find_name(mdp, "virtual-device"),
	    md_find_name(mdp, "back"), listp);
	ASSERT(num_devs <= 1);
	if (num_devs <= 0) {
		DWARN("cnex_find_chan_dip:channel(0x%llx): "
		    "No virtual-device found\n", chan_id);
		goto fdip_exit;
	}
	if (md_get_prop_str(mdp, listp[0], "name", &md_name) != 0) {
		DWARN("cnex_find_chan_dip:channel(0x%llx): "
		    "name property not found\n", chan_id);
		goto fdip_exit;
	}

	D1("cnex_find_chan_dip: channel(0x%llx): virtual-device "
	    "name property value = %s\n", chan_id, md_name);

	if (md_get_prop_val(mdp, listp[0], "cfg-handle", &cfghdl) != 0) {
		DWARN("cnex_find_chan_dip:channel(0x%llx): virtual-device's "
		    "cfg-handle property not found\n", chan_id);
		goto fdip_exit;
	}

	D1("cnex_find_chan_dip:channel(0x%llx): virtual-device cfg-handle "
	    " property value = 0x%x\n", chan_id, cfghdl);

	for (cdip = ddi_get_child(dip); cdip != NULL;
	    cdip = ddi_get_next_sibling(cdip)) {

		int *cnex_regspec;
		uint32_t reglen;
		char	*dev_name;

		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip,
		    DDI_PROP_DONTPASS, "name",
		    &dev_name) != DDI_PROP_SUCCESS) {
			DWARN("cnex_find_chan_dip: name property not"
			    " found for dip(0x%p)\n", cdip);
			continue;
		}
		if (strcmp(md_name, dev_name) != 0) {
			ddi_prop_free(dev_name);
			continue;
		}
		ddi_prop_free(dev_name);
		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
		    DDI_PROP_DONTPASS, "reg",
		    &cnex_regspec, &reglen) != DDI_SUCCESS) {
			DWARN("cnex_find_chan_dip: reg property not"
			    " found for dip(0x%p)\n", cdip);
			continue;
		}
		if (*cnex_regspec == cfghdl) {
			D1("cnex_find_chan_dip:channel(0x%llx): found "
			    "dip(0x%p) drvname=%s\n", chan_id, cdip,
			    ddi_driver_name(cdip));
			ddi_prop_free(cnex_regspec);
			break;
		}
		ddi_prop_free(cnex_regspec);
	}

fdip_exit:
	if (cdip == NULL) {
		/*
		 * If a virtual-device node exists but no dip found,
		 * then for now print a DEBUG error message only.
		 */
		if (num_devs > 0) {
			DERR("cnex_find_chan_dip:channel(0x%llx): "
			    "No device found\n", chan_id);
		}

		/* If no dip was found, return cnex device's dip. */
		cdip = dip;
	}

	kmem_free(listp, listsz);
	D1("cnex_find_chan_dip:channel(0x%llx): returning dip=0x%p\n",
	    chan_id, cdip);
	return (cdip);
}
Esempio n. 23
0
static int
zfs_vfs_mount(struct mount *mp, vnode_t devvp, user_addr_t data, vfs_context_t context)
{
	char	*osname = NULL;
	size_t  osnamelen = 0;
	int		error = 0;
	int		canwrite;
	/*
	 * Get the objset name (the "special" mount argument).
	 * The filesystem that we mount as root is defined in the
	 * "zfs-bootfs" property. 
	 */
	if (data) {
		user_addr_t fspec = USER_ADDR_NULL;
#ifndef __APPLE__
		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
		    DDI_PROP_DONTPASS, "zfs-bootfs", &zfs_bootpath) !=
		    DDI_SUCCESS)
			return (EIO);

		error = parse_bootpath(zfs_bootpath, rootfs.bo_name);
		ddi_prop_free(zfs_bootpath);
#endif
		osname = kmem_alloc(MAXPATHLEN, KM_SLEEP);

		if (vfs_context_is64bit(context)) {
			if ( (error = copyin(data, (caddr_t)&fspec, sizeof(fspec))) )
				goto out;	
		} else {
#ifdef ZFS_LEOPARD_ONLY
			char *tmp;
#else
			user32_addr_t tmp;
#endif
			if ( (error = copyin(data, (caddr_t)&tmp, sizeof(tmp))) )
				goto out;	
			/* munge into LP64 addr */
			fspec = CAST_USER_ADDR_T(tmp);
		}
		if ( (error = copyinstr(fspec, osname, MAXPATHLEN, &osnamelen)) )
			goto out;
	}

#if 0
	if (mvp->v_type != VDIR)
		return (ENOTDIR);

	mutex_enter(&mvp->v_lock);
	if ((uap->flags & MS_REMOUNT) == 0 &&
	    (uap->flags & MS_OVERLAY) == 0 &&
	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
		mutex_exit(&mvp->v_lock);
		return (EBUSY);
	}
	mutex_exit(&mvp->v_lock);

	/*
	 * ZFS does not support passing unparsed data in via MS_DATA.
	 * Users should use the MS_OPTIONSTR interface; this means
	 * that all option parsing is already done and the options struct
	 * can be interrogated.
	 */
	if ((uap->flags & MS_DATA) && uap->datalen > 0)
		return (EINVAL);

	/*
	 * Get the objset name (the "special" mount argument).
	 */
	if (error = pn_get(uap->spec, fromspace, &spn))
		return (error);

	osname = spn.pn_path;
#endif
	/*
	 * Check for mount privilege?
	 *
	 * If we don't have privilege then see if
	 * we have local permission to allow it
	 */
#ifndef __APPLE__
	error = secpolicy_fs_mount(cr, mvp, vfsp);
	if (error) {
		error = dsl_deleg_access(osname, ZFS_DELEG_PERM_MOUNT, cr);
		if (error == 0) {
			vattr_t		vattr;

			/*
			 * Make sure user is the owner of the mount point
			 * or has sufficient privileges.
			 */

			vattr.va_mask = AT_UID;

			if (error = VOP_GETATTR(mvp, &vattr, 0, cr)) {
				goto out;
			}

			if (error = secpolicy_vnode_owner(cr, vattr.va_uid)) {
				goto out;
			}

			if (error = VOP_ACCESS(mvp, VWRITE, 0, cr)) {
				goto out;
			}

			secpolicy_fs_mount_clearopts(cr, vfsp);
		} else {
			goto out;
		}
	}
#endif

	error = zfs_domount(mp, 0, osname, context);
	if (error)
		printf("zfs_vfs_mount: error %d\n", error);
	if (error == 0) {
		zfsvfs_t *zfsvfs = NULL;

		/* Make the Finder treat sub file systems just like a folder */
		if (strpbrk(osname, "/"))
			vfs_setflags(mp, (u_int64_t)((unsigned int)MNT_DONTBROWSE));

		/* Indicate to VFS that we support ACLs. */
		vfs_setextendedsecurity(mp);

		/* Advisory locking should be handled at the VFS layer */
		vfs_setlocklocal(mp);

		/*
		 * Mac OS X needs a file system modify time
		 *
		 * We use the mtime of the "com.apple.system.mtime" 
		 * extended attribute, which is associated with the
		 * file system root directory.
		 *
		 * Here we need to take a ref on z_mtime_vp to keep it around.
		 * If the attribute isn't there, attempt to create it.
		 */
		zfsvfs = vfs_fsprivate(mp);
		if (zfsvfs->z_mtime_vp == NULL) {
			struct vnode * rvp;
			struct vnode *xdvp = NULLVP;
			struct vnode *xvp = NULLVP;
			znode_t *rootzp;
			timestruc_t modify_time;
			cred_t  *cr;
			timestruc_t  now;
			int flag;
			int result;

			if (zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp) != 0) {
				goto out;
			}
			rvp = ZTOV(rootzp);
			cr = (cred_t *)vfs_context_ucred(context);

			/* Grab the hidden attribute directory vnode. */
			result = zfs_get_xattrdir(rootzp, &xdvp, cr, CREATE_XATTR_DIR);
			vnode_put(rvp);	/* all done with root vnode */
			rvp = NULL;
			if (result) {
				goto out;
			}

			/*
			 * HACK - workaround missing vnode_setnoflush() KPI...
			 *
			 * We tag zfsvfs so that zfs_attach_vnode() can then set
			 * vnfs_marksystem when the vnode gets created.
			 */
			zfsvfs->z_last_unmount_time = 0xBADC0DE;
			zfsvfs->z_last_mtime_synced = VTOZ(xdvp)->z_id;
			flag = vfs_isrdonly(mp) ? 0 : ZEXISTS;
			/* Lookup or create the named attribute. */
			if ( zfs_obtain_xattr(VTOZ(xdvp), ZFS_MTIME_XATTR,
			                          S_IRUSR | S_IWUSR, cr, &xvp,
			                          flag) ) {
					zfsvfs->z_last_unmount_time = 0;
					zfsvfs->z_last_mtime_synced = 0;
					vnode_put(xdvp);
					goto out;
				}
				gethrestime(&now);
			ZFS_TIME_ENCODE(&now, VTOZ(xvp)->z_phys->zp_mtime);
			vnode_put(xdvp);
			vnode_ref(xvp);

			zfsvfs->z_mtime_vp = xvp;
			ZFS_TIME_DECODE(&modify_time, VTOZ(xvp)->z_phys->zp_mtime);
			zfsvfs->z_last_unmount_time = modify_time.tv_sec;
			zfsvfs->z_last_mtime_synced = modify_time.tv_sec;

			/*
			 * Keep this referenced vnode from impeding an unmount.
			 *
			 * XXX vnode_setnoflush() is MIA from KPI (see workaround above).
			 */
#if 0
			vnode_setnoflush(xvp);
#endif
			vnode_put(xvp);
		}
	}
out:
	if (osname) {
		kmem_free(osname, MAXPATHLEN);
	}
	return (error);
}
Esempio n. 24
0
void
spa_free_bootprop(char *value)
{
	ddi_prop_free(value);
}
Esempio n. 25
0
/*
 * This function takes in the ac-interrupt-map property from the .conf file,
 * fills in the 'nodeid' information and then creates the 'interrupt-map'
 * property.
 */
static int
acebus_set_imap(dev_info_t *dip)
{
	int *imapp, *timapp, length, num, i, default_ival = 0;
	dev_info_t *tdip = dip;
	int *port_id, imap_ok = 1;
	int ilength;
	int acebus_default_se_imap[5];

	/*
	 * interrupt-map is specified via .conf file in hotplug mode,
	 * since the child configuration is static.
	 * It could even be hardcoded in the driver.
	 */
	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "ac-interrupt-map", (int **)&imapp, (uint_t *)&ilength) !=
	    DDI_PROP_SUCCESS) {
		/* assume default implementation */
		acebus_default_se_imap[0] = 0x14;
		acebus_default_se_imap[1] = 0x400000;
		acebus_default_se_imap[2] = 1;
		acebus_default_se_imap[3] = 0;
		acebus_default_se_imap[4] = 2;
		imapp = acebus_default_se_imap;
		ilength = 5;
		default_ival = 1;
	}
	num = ilength / 5;	/* there are 5 integer cells in our property */
	timapp = imapp;
	for (i = 0; i < num; i++) {
		if (*(timapp+i*5+3) == 0)
			imap_ok = 0;
	}
	if (imap_ok) {
		if (!default_ival)
			ddi_prop_free(imapp);
		return (DDI_SUCCESS);
	}

	while (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, tdip,
	    DDI_PROP_DONTPASS, "upa-portid", (int **)&port_id,
	    (uint_t *)&length) != DDI_PROP_SUCCESS) {
		tdip = ddi_get_parent(tdip);
		if (tdip == NULL) {
			cmn_err(CE_WARN, "%s%d: Could not get imap parent",
			    ddi_driver_name(dip), ddi_get_instance(dip));
			if (!default_ival)
				ddi_prop_free(imapp);
			return (DDI_FAILURE);
		}
	}
	timapp = imapp;
	for (i = 0; i < num; i++) {
		*(timapp+i*5+3) = ddi_get_nodeid(tdip);
	}

	if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "interrupt-map", imapp, ilength) != DDI_PROP_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: Could not update AC imap property",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		if (!default_ival)
			ddi_prop_free(imapp);
		return (DDI_FAILURE);
	}
	if (!default_ival)
		ddi_prop_free(imapp);
	return (DDI_SUCCESS);
}
Esempio n. 26
0
/*
 * The VGA device could be under a subtractive PCI bridge on some systems.
 * Though the PCI_BCNF_BCNTRL_VGA_ENABLE bit is not set on such subtractive
 * PCI bridge, the subtractive PCI bridge can forward VGA access if no other
 * agent claims the access.
 * The vga_enable element in param acts as a flag, if not set, ignore the
 * checking for the PCI_BCNF_BCNTRL_VGA_ENABLE bit of the PCI bridge during
 * the search.
 */
static int
find_fb_dev(dev_info_t *dip, void *param)
{
	struct find_fb_dev_param *p = param;
	char *dev_type;
	dev_info_t *pdip;
	char *parent_type;

	if (dip == ddi_root_node())
		return (DDI_WALK_CONTINUE);

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "device_type", &dev_type) != DDI_SUCCESS)
		return (DDI_WALK_PRUNECHILD);

	if ((strcmp(dev_type, "isa") == 0) || (strcmp(dev_type, "eisa") == 0)) {
		ddi_prop_free(dev_type);
		return (DDI_WALK_CONTINUE);
	}

	if ((strcmp(dev_type, "pci") == 0) ||
	    (strcmp(dev_type, "pciex") == 0)) {
		ddi_acc_handle_t pci_conf;
		uint16_t data16;
		char *nodename;

		ddi_prop_free(dev_type);

		if (!p->vga_enable)
			return (DDI_WALK_CONTINUE);

		nodename = ddi_node_name(dip);

		/*
		 * If the node is not a PCI-to-PCI bridge, continue traversing
		 * (it could be the root node), otherwise, check for the
		 * VGAEnable bit to be set in the Bridge Control Register.
		 */
		if (strcmp(nodename, "pci") == 0) {
			if (is_pci_bridge(dip) == B_FALSE)
				return (DDI_WALK_CONTINUE);
		}

		if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS)
			return (DDI_WALK_PRUNECHILD);

		if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS)
			return (DDI_WALK_PRUNECHILD);

		data16 = pci_config_get16(pci_conf, PCI_BCNF_BCNTRL);
		pci_config_teardown(&pci_conf);

		if (data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)
			return (DDI_WALK_CONTINUE);

		return (DDI_WALK_PRUNECHILD);
	}

	if (strcmp(dev_type, "display") != 0) {
		ddi_prop_free(dev_type);
		return (DDI_WALK_CONTINUE);
	}

	ddi_prop_free(dev_type);

	if ((pdip = ddi_get_parent(dip)) == NULL)
		return (DDI_WALK_PRUNECHILD);

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
	    "device_type", &parent_type) != DDI_SUCCESS)
		return (DDI_WALK_PRUNECHILD);

	if ((strcmp(parent_type, "isa") == 0) ||
	    (strcmp(parent_type, "eisa") == 0)) {
		p->found_dip = dip;
		ddi_prop_free(parent_type);
		return (DDI_WALK_TERMINATE);
	}

	if ((strcmp(parent_type, "pci") == 0) ||
	    (strcmp(parent_type, "pciex") == 0)) {
		ddi_acc_handle_t pci_conf;
		uint16_t data16;

		ddi_prop_free(parent_type);

		if (i_ddi_attach_node_hierarchy(dip) != DDI_SUCCESS)
			return (DDI_WALK_PRUNECHILD);

		if (pci_config_setup(dip, &pci_conf) != DDI_SUCCESS)
			return (DDI_WALK_PRUNECHILD);

		data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
		pci_config_teardown(&pci_conf);

		if (!(data16 & PCI_COMM_IO))
			return (DDI_WALK_PRUNECHILD);

		p->found_dip = dip;
		return (DDI_WALK_TERMINATE);
	}

	ddi_prop_free(parent_type);
	return (DDI_WALK_PRUNECHILD);
}
Esempio n. 27
0
/*
 * Process acpi-user-options property  if present
 */
static void
acpica_process_user_options()
{
	static int processed = 0;
	int acpi_user_options;
	char *acpi_prop;

	/*
	 * return if acpi-user-options has already been processed
	 */
	if (processed)
		return;
	else
		processed = 1;

	/* converts acpi-user-options from type string to int, if any */
	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
	    DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) ==
	    DDI_PROP_SUCCESS) {
		long data;
		int ret;
		ret = ddi_strtol(acpi_prop, NULL, 0, &data);
		if (ret == 0) {
			e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(),
			    "acpi-user-options");
			e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(),
			    "acpi-user-options", data);
		}
		ddi_prop_free(acpi_prop);
	}

	/*
	 * fetch the optional options property
	 */
	acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
	    DDI_PROP_DONTPASS, "acpi-user-options", 0);

	/*
	 * Note that 'off' has precedence over 'on'
	 * Also note - all cases of ACPI_OUSER_MASK
	 * provided here, no default: case is present
	 */
	switch (acpi_user_options & ACPI_OUSER_MASK) {
	case ACPI_OUSER_DFLT:
		acpica_enable = acpica_check_bios_date(1999, 1, 1);
		break;
	case ACPI_OUSER_ON:
		acpica_enable = TRUE;
		break;
	case ACPI_OUSER_OFF:
	case ACPI_OUSER_OFF | ACPI_OUSER_ON:
		acpica_enable = FALSE;
		break;
	}

	acpi_init_level = ACPI_FULL_INITIALIZATION;

	/*
	 * special test here; may be generalized in the
	 * future - test for a machines that are known to
	 * work only in legacy mode, and set OUSER_LEGACY if
	 * we're on one
	 */
	if (acpica_metro_old_bios())
		acpi_user_options |= ACPI_OUSER_LEGACY;

	/*
	 * If legacy mode is specified, set initialization
	 * options to avoid entering ACPI mode and hooking SCI
	 * - basically try to act like legacy acpi_intp
	 */
	if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0)
		acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT);

	/*
	 * modify default ACPI CA debug output level for non-DEBUG builds
	 * (to avoid BIOS debug chatter in /var/adm/messages)
	 */
	if (acpica_muzzle_debug_output)
		AcpiDbgLevel = 0;
}
int
gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
	gfxp_vgatext_softc_ptr_t ptr)
{
	struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
	int	unit = ddi_get_instance(devi);
	int	error;
	char	*parent_type = NULL;
	int	reg_rnumber;
	off_t	reg_offset;
	off_t	mem_offset;
	char	*cons;
	int pci_pcie_bus = 0;
	int value;

	switch (cmd) {
	case DDI_ATTACH:
		break;

	case DDI_RESUME:
		vgatext_resume(softc);
		return (DDI_SUCCESS);

	default:
		return (DDI_FAILURE);
	}

	/* DDI_ATTACH */

	softc->devi = devi; /* Copy and init DEVI */

	softc->polledio.arg = (struct vis_polledio_arg *)softc;
	softc->polledio.display = vgatext_polled_display;
	softc->polledio.copy = vgatext_polled_copy;
	softc->polledio.cursor = vgatext_polled_cursor;

	mutex_init(&(softc->lock), NULL, MUTEX_DRIVER, NULL);

	error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
	    DDI_PROP_DONTPASS, "device_type", &parent_type);
	if (error != DDI_SUCCESS) {
		cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
		goto fail;
	}

	/* Not enable AGP and DRM by default */
	if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
		reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
		    &reg_offset);
		if (reg_rnumber < 0) {
			cmn_err(CE_WARN,
			    MYNAME
			    ": can't find reg entry for registers");
			error = DDI_FAILURE;
			goto fail;
		}
		softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
		    VGA_MEM_ADDR, &mem_offset);
		if (softc->fb_regno < 0) {
			cmn_err(CE_WARN,
			    MYNAME
			    ": can't find reg entry for memory");
			error = DDI_FAILURE;
			goto fail;
		}
	} else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
		pci_pcie_bus = 1;
		reg_rnumber = vgatext_get_pci_reg_index(devi,
		    PCI_REG_ADDR_M|PCI_REG_REL_M,
		    PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
		    &reg_offset);
		if (reg_rnumber < 0) {
			cmn_err(CE_WARN,
			    MYNAME
			    ": can't find reg entry for registers");
			error = DDI_FAILURE;
			goto fail;
		}
		softc->fb_regno = vgatext_get_pci_reg_index(devi,
		    PCI_REG_ADDR_M|PCI_REG_REL_M,
		    PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
		    &mem_offset);
		if (softc->fb_regno < 0) {
			cmn_err(CE_WARN,
			    MYNAME
			    ": can't find reg entry for memory");
			error = DDI_FAILURE;
			goto fail;
		}
	} else {
		cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
		    parent_type);
		error = DDI_FAILURE;
		goto fail;
	}
	ddi_prop_free(parent_type);
	parent_type = NULL;

	error = ddi_regs_map_setup(devi, reg_rnumber,
	    (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
	    &dev_attr, &softc->regs.handle);
	if (error != DDI_SUCCESS)
		goto fail;
	softc->regs.mapped = B_TRUE;

	softc->fb_size = VGA_MEM_SIZE;

	error = ddi_regs_map_setup(devi, softc->fb_regno,
	    (caddr_t *)&softc->fb.addr,
	    mem_offset, softc->fb_size,
	    &dev_attr, &softc->fb.handle);
	if (error != DDI_SUCCESS)
		goto fail;
	softc->fb.mapped = B_TRUE;

	if (ddi_get8(softc->regs.handle,
	    softc->regs.addr + VGA_MISC_R) & VGA_MISC_IOA_SEL)
		softc->text_base = (caddr_t)softc->fb.addr + VGA_COLOR_BASE;
	else
		softc->text_base = (caddr_t)softc->fb.addr + VGA_MONO_BASE;

	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
	    DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
		if (strcmp(cons, "graphics") == 0) {
			happyface_boot = 1;
			vgatext_silent = 1;
			softc->current_base = softc->shadow;
		} else {
			softc->current_base = softc->text_base;
		}
		ddi_prop_free(cons);
	} else {
		softc->current_base = softc->text_base;
	}

	error = ddi_prop_create(makedevice(DDI_MAJOR_T_UNKNOWN, unit),
	    devi, DDI_PROP_CANSLEEP, DDI_KERNEL_IOCTL, NULL, 0);
	if (error != DDI_SUCCESS)
		goto fail;

	gfxp_check_for_console(devi, softc, pci_pcie_bus);

	value = GFXP_IS_CONSOLE(softc) ? 1 : 0;
	if (ddi_prop_update_int(DDI_DEV_T_NONE, devi,
	    "primary-controller", value) != DDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "Can not %s primary-controller "
		    "property for driver", value ? "set" : "clear");
	}

	/* only do this if not in graphics mode */
	if ((vgatext_silent == 0) && (GFXP_IS_CONSOLE(softc))) {
		vgatext_init(softc);
		vgatext_save_colormap(softc);
	}

	return (DDI_SUCCESS);

fail:
	if (parent_type != NULL)
		ddi_prop_free(parent_type);
	(void) gfxp_vgatext_detach(devi, DDI_DETACH, (void *)softc);
	return (error);
}
Esempio n. 29
0
static int
console_type()
{
	static int boot_console = CONS_INVALID;

	char *cons;
	dev_info_t *root;

	if (boot_console != CONS_INVALID)
		return (boot_console);

#if defined(__xpv)
	if (!DOMAIN_IS_INITDOMAIN(xen_info) || bcons_hypervisor_redirect()) {
		boot_console = CONS_HYPERVISOR;
		return (boot_console);
	}
#endif /* __xpv */

	/*
	 * console is defined by "console" property, with
	 * fallback on the old "input-device" property.
	 * If "input-device" is not defined either, also check "output-device".
	 */
	boot_console = CONS_SCREEN;	/* default is screen/kb */
	root = ddi_root_node();
	if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, root,
	    DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) ||
	    (ddi_prop_lookup_string(DDI_DEV_T_ANY, root,
	    DDI_PROP_DONTPASS, "input-device", &cons) == DDI_SUCCESS) ||
	    (ddi_prop_lookup_string(DDI_DEV_T_ANY, root,
	    DDI_PROP_DONTPASS, "output-device", &cons) == DDI_SUCCESS)) {
		if (strcmp(cons, "ttya") == 0) {
			boot_console = CONS_TTYA;
		} else if (strcmp(cons, "ttyb") == 0) {
			boot_console = CONS_TTYB;
		} else if (strcmp(cons, "usb-serial") == 0) {
			(void) i_ddi_attach_hw_nodes("ehci");
			(void) i_ddi_attach_hw_nodes("uhci");
			(void) i_ddi_attach_hw_nodes("ohci");
			/*
			 * USB device enumerate asynchronously.
			 * Wait 2 seconds for USB serial devices to attach.
			 */
			delay(drv_usectohz(2000000));
			boot_console = CONS_USBSER;
#if defined(__xpv)
		} else if (strcmp(cons, "hypervisor") == 0) {
			boot_console = CONS_HYPERVISOR;
#endif /* __xpv */
		}
		ddi_prop_free(cons);
	}

	/*
	 * If the console is configured to use a framebuffer but none
	 * could be found, fallback to "ttya" since it's likely to exist
	 * and it matches longstanding behavior on SPARC.
	 */
	if (boot_console == CONS_SCREEN && plat_fbpath() == NULL)
		boot_console = CONS_TTYA;

	return (boot_console);
}
static void
gfxp_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
	int pci_pcie_bus)
{
	ddi_acc_handle_t pci_conf;
	dev_info_t *pdevi;
	uint16_t data16;

	/*
	 * Based on Section 11.3, "PCI Display Subsystem Initialization",
	 * of the 1.1 PCI-to-PCI Bridge Architecture Specification
	 * determine if this is the boot console device.  First, see
	 * if the SBIOS has turned on PCI I/O for this device.  Then if
	 * this is PCI/PCI-E, verify the parent bridge has VGAEnable set.
	 */

	if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
		cmn_err(CE_WARN,
		    MYNAME
		    ": can't get PCI conf handle");
		return;
	}

	data16 = pci_config_get16(pci_conf, PCI_CONF_COMM);
	if (data16 & PCI_COMM_IO)
		softc->flags |= GFXP_FLAG_CONSOLE;

	pci_config_teardown(&pci_conf);

	/* If IO not enabled or ISA/EISA, just return */
	if (!(softc->flags & GFXP_FLAG_CONSOLE) || !pci_pcie_bus)
		return;

	/*
	 * Check for VGA Enable in the Bridge Control register for all
	 * PCI/PCIEX parents.  If not set all the way up the chain,
	 * this cannot be the boot console.
	 */

	pdevi = ddi_get_parent(devi);
	while (pdevi) {
		int	error;
		ddi_acc_handle_t ppci_conf;
		char	*parent_type = NULL;

		error = ddi_prop_lookup_string(DDI_DEV_T_ANY, pdevi,
		    DDI_PROP_DONTPASS, "device_type", &parent_type);
		if (error != DDI_SUCCESS) {
			return;
		}

		/* Verify still on the PCI/PCIEX parent tree */
		if (!STREQ(parent_type, "pci") &&
		    !STREQ(parent_type, "pciex")) {
			ddi_prop_free(parent_type);
			return;
		}

		ddi_prop_free(parent_type);
		parent_type = NULL;

		if (pci_config_setup(pdevi, &ppci_conf) != DDI_SUCCESS) {
			/* No registers on root node, done with check */
			return;
		}

		data16 = pci_config_get16(ppci_conf, PCI_BCNF_BCNTRL);
		pci_config_teardown(&ppci_conf);

		if (!(data16 & PCI_BCNF_BCNTRL_VGA_ENABLE)) {
			softc->flags &= ~GFXP_FLAG_CONSOLE;
			return;
		}

		pdevi = ddi_get_parent(pdevi);
	}
}