Ejemplo 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);
}
Ejemplo n.º 2
0
static int
get_reg_dev(di_node_t node)
{
	int *reg = NULL;
	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, OBP_REG, &reg) < 0) {
		if (di_prom_prop_lookup_ints(prom_handle, node, OBP_REG,
			&reg) < 0) {
			return (-1);
		}
		return (PCI_REG_DEV_G(reg[0]));
	}
	return (PCI_REG_DEV_G(reg[0]));
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
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);
}
static int
find_target_node(di_node_t node, void *arg)
{
    int *regbuf = NULL;
    int len = 0;
    uint32_t busno, funcno, devno;
    i_devnode_t *devnode = (i_devnode_t *)arg;

    /*
     * Test the property functions, only for testing
     */
    /*
    void *prop = DI_PROP_NIL;

    (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid);
    while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) {
	int i;
	(void) fprintf(stderr, "name=%s: ", di_prop_name(prop));
	len = 0;
	if (!strcmp(di_prop_name(prop), "reg")) {
	    len = di_prop_ints(prop, &regbuf);
	}
	for (i = 0; i < len; i++) {
	    fprintf(stderr, "0x%0x.", regbuf[i]);
	}
	fprintf(stderr, "\n");
    }
    (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid);
    */

    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &regbuf);

#ifdef __sparc
    if ((len <= 0) && di_phdl)
	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &regbuf);
#endif

    if (len <= 0) {
#ifdef DEBUG
	fprintf(stderr, "error = %x\n", errno);
	fprintf(stderr, "can not find assigned-address\n");
#endif
	return (DI_WALK_CONTINUE);
    }

    busno = PCI_REG_BUS_G(regbuf[0]);
    devno = PCI_REG_DEV_G(regbuf[0]);
    funcno = PCI_REG_FUNC_G(regbuf[0]);

    if ((busno == devnode->bus) &&
	(devno == devnode->dev) &&
	(funcno == devnode->func)) {
	devnode->node = node;

	return (DI_WALK_TERMINATE);
    }

    return (DI_WALK_CONTINUE);
}
Ejemplo n.º 6
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);
}
Ejemplo n.º 7
0
static int
ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
	dev_info_t	*cdip = rdip;
	pci_regspec_t	*pci_rp;
	int		reglen, len;
	uint32_t	d, intr;

	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
	    (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
		goto done;

	/*
	 * If the interrupt-map property is defined at this
	 * node, it will have performed the interrupt
	 * translation as part of the property, so no
	 * rotation needs to be done.
	 */
	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "interrupt-map", &len) == DDI_PROP_SUCCESS)
		goto done;

	cdip = get_my_childs_dip(dip, rdip);

	/*
	 * Use the devices reg property to determine its
	 * PCI bus number and device number.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
		return (DDI_FAILURE);

	intr = hdlp->ih_vector;

	/* Spin the interrupt */
	d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);

	if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
		hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
	else
		cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
		    ddi_driver_name(rdip), ddi_get_instance(rdip),
		    ddi_driver_name(dip), intr);

	kmem_free(pci_rp, reglen);

done:
	/* Pass up the request to our parent. */
	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
}
Ejemplo n.º 8
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);
}
Ejemplo n.º 9
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);
}
Ejemplo n.º 10
0
static int
sunos_add_devices(di_devlink_t link, void *arg)
{
	struct devlink_cbarg	*largs = (struct devlink_cbarg *)arg;
	struct node_args	*nargs;
	di_node_t		myself, pnode;
	uint64_t		session_id = 0;
	uint16_t		bdf = 0;
	struct libusb_device	*dev;
	sunos_dev_priv_t	*devpriv;
	const char		*path, *newpath;
	int			 n, i;
	int			*addr_prop;
	uint8_t			bus_number = 0;

	nargs = (struct node_args *)largs->nargs;
	myself = largs->myself;
	if (nargs->last_ugenpath) {
		/* the same node's links */
		return (DI_WALK_CONTINUE);
	}

	/*
	 * Construct session ID.
	 * session ID = ...parent hub addr|hub addr|dev addr.
	 */
	pnode = myself;
	i = 0;
	while (pnode != DI_NODE_NIL) {
		if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) {
			/* walk to root */
			uint32_t *regbuf = NULL;
			uint32_t reg;

			n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg",
			    (int **)&regbuf);
			reg = regbuf[0];
			bdf = (PCI_REG_BUS_G(reg) << 8) |
			    (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);
			session_id |= (bdf << i * 8);

			/* same as 'unit-address' property */
			bus_number =
			    (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg);

			usbi_dbg("device bus address=%s:%x",
			    di_bus_addr(pnode), bus_number);

			break;
		}

		/* usb_addr */
		n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode,
		    "assigned-address", &addr_prop);
		if ((n != 1) || (addr_prop[0] == 0)) {
			usbi_dbg("cannot get valid usb_addr");

			return (DI_WALK_CONTINUE);
		}

		session_id |= ((addr_prop[0] & 0xff) << i * 8);
		if (++i > 7)
			break;

		pnode = di_parent_node(pnode);
	}

	path = di_devlink_path(link);
	dev = usbi_get_device_by_session_id(nargs->ctx, session_id);
	if (dev == NULL) {
		dev = usbi_alloc_device(nargs->ctx, session_id);
		if (dev == NULL) {
			usbi_dbg("can't alloc device");

			return (DI_WALK_TERMINATE);
		}
		devpriv = (sunos_dev_priv_t *)dev->os_priv;
		if ((newpath = strrchr(path, '/')) == NULL) {
			libusb_unref_device(dev);

			return (DI_WALK_TERMINATE);
		}
		devpriv->ugenpath = strndup(path, strlen(path) -
		    strlen(newpath));
		dev->bus_number = bus_number;

		if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) {
			libusb_unref_device(dev);

			return (DI_WALK_TERMINATE);
		}
		if (usbi_sanitize_device(dev) < 0) {
			libusb_unref_device(dev);
			usbi_dbg("sanatize failed: ");
			return (DI_WALK_TERMINATE);
		}
	} else {
		usbi_dbg("Dev %s exists", path);
	}

	devpriv = (sunos_dev_priv_t *)dev->os_priv;
	if (nargs->last_ugenpath == NULL) {
		/* first device */
		nargs->last_ugenpath = devpriv->ugenpath;

		if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) {
			usbi_dbg("cannot append device");
		}

		/*
		 * we alloc and hence ref this dev. We don't need to ref it
		 * hereafter. Front end or app should take care of their ref.
		 */
		libusb_unref_device(dev);
	}

	usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x",
	    devpriv->ugenpath, path, (uint64_t)session_id,
	    (*nargs->discdevs)->len, bdf);

	return (DI_WALK_CONTINUE);
}
Ejemplo n.º 11
0
static int
probe_device_node(di_node_t node, void *arg)
{
    int *retbuf = NULL;
    int len = 0, i;
    struct pci_device	*pci_base;
    probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo;
    nexus_t *nexus = ((probe_args_t *)arg)->nexus;
    property_info_t property_list[] = {
        { "class-code", 0 },
        { "device-id", 0 },
        { "vendor-id", 0 },
        { "revision-id", 0},
        { "subsystem-vendor-id", 0},
        { "subsystem-id", 0},
    };
#define NUM_PROPERTIES		sizeof(property_list)/sizeof(property_info_t)

    len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf);

#ifdef __sparc
    if ((len <= 0) && di_phdl)
	len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf);
#endif

    /* Exclude usb devices */
    if (len < 5) {
	return DI_WALK_CONTINUE;
    }

    pci_base = &pinfo->devices[pinfo->num_devices].base;

    pci_base->domain = nexus->domain;
    pci_base->bus = PCI_REG_BUS_G(retbuf[0]);
    pci_base->dev = PCI_REG_DEV_G(retbuf[0]);
    pci_base->func  = PCI_REG_FUNC_G(retbuf[0]);

    /* Get property values */
    for (i = 0; i < NUM_PROPERTIES; i++) {
	len = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
		property_list[i].name, &retbuf);
#ifdef __sparc
	if ((len <= 0) && di_phdl)
	    len = di_prom_prop_lookup_ints(di_phdl, node,
		property_list[i].name, &retbuf);
#endif

	if (len > 0)
	    property_list[i].value = retbuf[0];
	else {
	    /* a device must have property "class-code", "device-id", "vendor-id" */
	    if (i < 3)
		return DI_WALK_CONTINUE;
#ifdef DEBUG
	    fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n",
		property_list[i].name, nexus->path);
	    fprintf(stderr, "	domain = %x, busno = %x, devno = %x, funcno = %x\n",
		pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
#endif
	}
    }

    if ((property_list[1].value == 0) && (property_list[2].value == 0))
	return DI_WALK_CONTINUE;

    pci_base->device_class = property_list[0].value;
    pci_base->device_id = property_list[1].value;
    pci_base->vendor_id = property_list[2].value;
    pci_base->revision = property_list[3].value;
    pci_base->subvendor_id = property_list[4].value;
    pci_base->subdevice_id = property_list[5].value;

#ifdef DEBUG
    fprintf(stderr,
	    "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n",
	    nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
#endif

    pinfo->num_devices++;
    if (pinfo->num_devices == pinfo->num_allocated_elems) {
	struct pci_device_private *new_devs;
	size_t new_num_elems = pinfo->num_allocated_elems * 2;

	new_devs = realloc(pinfo->devices,
	new_num_elems * sizeof (struct pci_device_private));
	if (new_devs == NULL) {
	    (void) fprintf(stderr,
	           "Error allocating memory for PCI devices:"
		   " %s\n discarding additional devices\n",
		   strerror(errno));
	    ((probe_args_t *)arg)->ret = 1;
	    return (DI_WALK_TERMINATE);
	}
	(void) memset(&new_devs[pinfo->num_devices], 0,
		pinfo->num_allocated_elems *
		sizeof (struct pci_device_private));
	pinfo->num_allocated_elems = new_num_elems;
	pinfo->devices = new_devs;
    }

    return (DI_WALK_CONTINUE);
}
Ejemplo n.º 12
0
static int
pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
	off_t offset, off_t len, caddr_t *vaddrp)
{
	struct regspec reg;
	ddi_map_req_t mr;
	ddi_acc_hdl_t *hp;
	pci_regspec_t pci_reg;
	pci_regspec_t *pci_rp;
	int 	rnumber;
	int	length;
	pci_acc_cfblk_t *cfp;
	int	space;


	mr = *mp; /* Get private copy of request */
	mp = &mr;

	/*
	 * check for register number
	 */
	switch (mp->map_type) {
	case DDI_MT_REGSPEC:
		pci_reg = *(pci_regspec_t *)(mp->map_obj.rp);
		pci_rp = &pci_reg;
		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
			return (DDI_FAILURE);
		break;
	case DDI_MT_RNUMBER:
		rnumber = mp->map_obj.rnumber;
		/*
		 * get ALL "reg" properties for dip, select the one of
		 * of interest. In x86, "assigned-addresses" property
		 * is identical to the "reg" property, so there is no
		 * need to cross check the two to determine the physical
		 * address of the registers.
		 * This routine still performs some validity checks to
		 * make sure that everything is okay.
		 */
		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
		    DDI_PROP_DONTPASS, "reg", (int **)&pci_rp,
		    (uint_t *)&length) != DDI_PROP_SUCCESS)
			return (DDI_FAILURE);

		/*
		 * validate the register number.
		 */
		length /= (sizeof (pci_regspec_t) / sizeof (int));
		if (rnumber >= length) {
			ddi_prop_free(pci_rp);
			return (DDI_FAILURE);
		}

		/*
		 * copy the required entry.
		 */
		pci_reg = pci_rp[rnumber];

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

		pci_rp = &pci_reg;
		if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS)
			return (DDI_FAILURE);
		mp->map_type = DDI_MT_REGSPEC;
		break;
	default:
		return (DDI_ME_INVAL);
	}

	space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M;

	/*
	 * check for unmap and unlock of address space
	 */
	if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) {
		/*
		 * Adjust offset and length
		 * A non-zero length means override the one in the regspec.
		 */
		pci_rp->pci_phys_low += (uint_t)offset;
		if (len != 0)
			pci_rp->pci_size_low = len;

		switch (space) {
		case PCI_ADDR_CONFIG:
			/* No work required on unmap of Config space */
			return (DDI_SUCCESS);

		case PCI_ADDR_IO:
			reg.regspec_bustype = 1;
			break;

		case PCI_ADDR_MEM64:
			/*
			 * MEM64 requires special treatment on map, to check
			 * that the device is below 4G.  On unmap, however,
			 * we can assume that everything is OK... the map
			 * must have succeeded.
			 */
			/* FALLTHROUGH */
		case PCI_ADDR_MEM32:
			reg.regspec_bustype = 0;
			break;

		default:
			return (DDI_FAILURE);
		}
		reg.regspec_addr = pci_rp->pci_phys_low;
		reg.regspec_size = pci_rp->pci_size_low;

		mp->map_obj.rp = &reg;
		return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));

	}

	/* check for user mapping request - not legal for Config */
	if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) {
		return (DDI_FAILURE);
	}

	/*
	 * check for config space
	 * On x86, CONFIG is not mapped via MMU and there is
	 * no endian-ness issues. Set the attr field in the handle to
	 * indicate that the common routines to call the nexus driver.
	 */
	if (space == PCI_ADDR_CONFIG) {
		/* Can't map config space without a handle */
		hp = (ddi_acc_hdl_t *)mp->map_handlep;
		if (hp == NULL)
			return (DDI_FAILURE);

		/* record the device address for future reference */
		cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private;
		cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi);
		cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi);
		cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi);

		*vaddrp = (caddr_t)offset;
		return (pci_fm_acc_setup(hp, offset, len));
	}

	/*
	 * range check
	 */
	if ((offset >= pci_rp->pci_size_low) ||
	    (len > pci_rp->pci_size_low) ||
	    (offset + len > pci_rp->pci_size_low)) {
		return (DDI_FAILURE);
	}

	/*
	 * Adjust offset and length
	 * A non-zero length means override the one in the regspec.
	 */
	pci_rp->pci_phys_low += (uint_t)offset;
	if (len != 0)
		pci_rp->pci_size_low = len;

	/*
	 * convert the pci regsec into the generic regspec used by the
	 * parent root nexus driver.
	 */
	switch (space) {
	case PCI_ADDR_IO:
		reg.regspec_bustype = 1;
		break;
	case PCI_ADDR_MEM64:
		/*
		 * We can't handle 64-bit devices that are mapped above
		 * 4G or that are larger than 4G.
		 */
		if (pci_rp->pci_phys_mid != 0 ||
		    pci_rp->pci_size_hi != 0)
			return (DDI_FAILURE);
		/*
		 * Other than that, we can treat them as 32-bit mappings
		 */
		/* FALLTHROUGH */
	case PCI_ADDR_MEM32:
		reg.regspec_bustype = 0;
		break;
	default:
		return (DDI_FAILURE);
	}
	reg.regspec_addr = pci_rp->pci_phys_low;
	reg.regspec_size = pci_rp->pci_size_low;

	mp->map_obj.rp = &reg;
	return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp));
}