10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*506Scth  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * fcpci.c: Framework PCI fcode ops
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/kmem.h>
340Sstevel@tonic-gate #include <sys/systm.h>
350Sstevel@tonic-gate #include <sys/pci.h>
360Sstevel@tonic-gate #include <sys/ddi.h>
370Sstevel@tonic-gate #include <sys/sunddi.h>
380Sstevel@tonic-gate #include <sys/sunndi.h>
390Sstevel@tonic-gate #include <sys/ddidmareq.h>
400Sstevel@tonic-gate #include <sys/pci.h>
410Sstevel@tonic-gate #include <sys/modctl.h>
420Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
430Sstevel@tonic-gate #include <sys/fcode.h>
440Sstevel@tonic-gate #include <sys/promif.h>
450Sstevel@tonic-gate #include <sys/promimpl.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate #define	PCI_NPT_bits	(PCI_RELOCAT_B | PCI_PREFETCH_B | PCI_ALIAS_B)
480Sstevel@tonic-gate #define	PCICFG_CONF_INDIRECT_MAP	1
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static int pfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
510Sstevel@tonic-gate static int pfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
520Sstevel@tonic-gate static int pfc_dma_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
530Sstevel@tonic-gate static int pfc_dma_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
540Sstevel@tonic-gate static int pfc_dma_sync(dev_info_t *, fco_handle_t, fc_ci_t *);
550Sstevel@tonic-gate static int pfc_dma_cleanup(dev_info_t *, fco_handle_t, fc_ci_t *);
560Sstevel@tonic-gate 
570Sstevel@tonic-gate static int pfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
580Sstevel@tonic-gate static int pfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
590Sstevel@tonic-gate static int pfc_config_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
600Sstevel@tonic-gate static int pfc_config_store(dev_info_t *, fco_handle_t, fc_ci_t *);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static int pfc_probe_address(dev_info_t *, fco_handle_t, fc_ci_t *);
630Sstevel@tonic-gate static int pfc_probe_space(dev_info_t *, fco_handle_t, fc_ci_t *);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static int pfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
660Sstevel@tonic-gate static int pfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
670Sstevel@tonic-gate static int pfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
680Sstevel@tonic-gate int prom_get_fcode_size(char *);
690Sstevel@tonic-gate int prom_get_fcode(char *, char *);
700Sstevel@tonic-gate int pfc_update_assigned_prop(dev_info_t *, pci_regspec_t *);
710Sstevel@tonic-gate int pfc_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
720Sstevel@tonic-gate int pci_alloc_resource(dev_info_t *, pci_regspec_t);
730Sstevel@tonic-gate int pci_free_resource(dev_info_t *, pci_regspec_t);
740Sstevel@tonic-gate int pci_alloc_mem_chunk(dev_info_t *,  uint64_t, uint64_t *,  uint64_t *);
750Sstevel@tonic-gate int pci_alloc_io_chunk(dev_info_t *,  uint64_t,  uint64_t *, uint64_t *);
760Sstevel@tonic-gate static int fcpci_indirect_map(dev_info_t *);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate int fcpci_unloadable;
790Sstevel@tonic-gate int no_advisory_dma;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #ifndef	lint
820Sstevel@tonic-gate static char _depends_on[] = "misc/fcodem misc/busra";
830Sstevel@tonic-gate #endif
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #define	HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
860Sstevel@tonic-gate #define	LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
870Sstevel@tonic-gate #define	LADDR(lo, hi)    (((uint64_t)(hi) << 32) | (uint32_t)(lo))
880Sstevel@tonic-gate #define	PCI_4GIG_LIMIT 0xFFFFFFFFUL
890Sstevel@tonic-gate #define	PCI_MEMGRAN 0x100000
900Sstevel@tonic-gate #define	PCI_IOGRAN 0x1000
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * Module linkage information for the kernel.
950Sstevel@tonic-gate  */
960Sstevel@tonic-gate static struct modlmisc modlmisc = {
970Sstevel@tonic-gate 	&mod_miscops, "FCode pci bus functions %I%"
980Sstevel@tonic-gate };
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate static struct modlinkage modlinkage = {
1010Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate int
1050Sstevel@tonic-gate _init(void)
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate int
1110Sstevel@tonic-gate _fini(void)
1120Sstevel@tonic-gate {
1130Sstevel@tonic-gate 	if (fcpci_unloadable)
1140Sstevel@tonic-gate 		return (mod_remove(&modlinkage));
1150Sstevel@tonic-gate 	return (EBUSY);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate int
1190Sstevel@tonic-gate _info(struct modinfo *modinfop)
1200Sstevel@tonic-gate {
1210Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate struct pfc_ops_v {
1260Sstevel@tonic-gate 	char *svc_name;
1270Sstevel@tonic-gate 	fc_ops_t *f;
1280Sstevel@tonic-gate };
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static struct pfc_ops_v pov[] = {
1310Sstevel@tonic-gate 	{	"map-in",		pfc_map_in},
1320Sstevel@tonic-gate 	{	"map-out",		pfc_map_out},
1330Sstevel@tonic-gate 	{	"dma-map-in",		pfc_dma_map_in},
1340Sstevel@tonic-gate 	{	"dma-map-out",		pfc_dma_map_out},
1350Sstevel@tonic-gate 	{	"dma-sync",		pfc_dma_sync},
1360Sstevel@tonic-gate 	{	"rx@",			pfc_register_fetch},
1370Sstevel@tonic-gate 	{	"rl@",			pfc_register_fetch},
1380Sstevel@tonic-gate 	{	"rw@",			pfc_register_fetch},
1390Sstevel@tonic-gate 	{	"rb@",			pfc_register_fetch},
1400Sstevel@tonic-gate 	{	"rx!",			pfc_register_store},
1410Sstevel@tonic-gate 	{	"rl!",			pfc_register_store},
1420Sstevel@tonic-gate 	{	"rw!",			pfc_register_store},
1430Sstevel@tonic-gate 	{	"rb!",			pfc_register_store},
1440Sstevel@tonic-gate 	{	"config-l@",		pfc_config_fetch},
1450Sstevel@tonic-gate 	{	"config-w@",		pfc_config_fetch},
1460Sstevel@tonic-gate 	{	"config-b@",		pfc_config_fetch},
1470Sstevel@tonic-gate 	{	"config-l!",		pfc_config_store},
1480Sstevel@tonic-gate 	{	"config-w!",		pfc_config_store},
1490Sstevel@tonic-gate 	{	"config-b!",		pfc_config_store},
1500Sstevel@tonic-gate 	{	FC_PROBE_ADDRESS,	pfc_probe_address},
1510Sstevel@tonic-gate 	{	FC_PROBE_SPACE,		pfc_probe_space},
1520Sstevel@tonic-gate 	{	FC_SVC_EXIT,		pfc_dma_cleanup},
1530Sstevel@tonic-gate 	{	FC_CONFIG_CHILD,	pfc_config_child},
1540Sstevel@tonic-gate 	{	FC_GET_FCODE_SIZE,	pfc_get_fcode_size},
1550Sstevel@tonic-gate 	{	FC_GET_FCODE,		pfc_get_fcode},
1560Sstevel@tonic-gate 	{	NULL,			NULL}
1570Sstevel@tonic-gate };
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate static struct pfc_ops_v shared_pov[] = {
1600Sstevel@tonic-gate 	{	FC_SVC_EXIT,		pfc_dma_cleanup},
1610Sstevel@tonic-gate 	{	NULL,			NULL}
1620Sstevel@tonic-gate };
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate int pci_map_phys(dev_info_t *, pci_regspec_t *,
1650Sstevel@tonic-gate     caddr_t *, ddi_device_acc_attr_t *, ddi_acc_handle_t *);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate void pci_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate fco_handle_t
1700Sstevel@tonic-gate pci_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
1710Sstevel@tonic-gate     void *fcode, size_t fcode_size, char *unit_address,
1720Sstevel@tonic-gate     struct pci_ops_bus_args *up)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	fco_handle_t rp;
1750Sstevel@tonic-gate 	struct pci_ops_bus_args *bp = NULL;
1760Sstevel@tonic-gate 	phandle_t h;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
1790Sstevel@tonic-gate 	rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size,
1800Sstevel@tonic-gate 	    unit_address, NULL);
1810Sstevel@tonic-gate 	rp->ap = ap;
1820Sstevel@tonic-gate 	rp->child = child;
1830Sstevel@tonic-gate 	rp->fcode = fcode;
1840Sstevel@tonic-gate 	rp->fcode_size = fcode_size;
1850Sstevel@tonic-gate 	if (unit_address) {
1860Sstevel@tonic-gate 		char *buf;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 		buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
1890Sstevel@tonic-gate 		(void) strcpy(buf, unit_address);
1900Sstevel@tonic-gate 		rp->unit_address = buf;
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	bp = kmem_zalloc(sizeof (struct pci_ops_bus_args), KM_SLEEP);
1940Sstevel@tonic-gate 	*bp = *up;
1950Sstevel@tonic-gate 	rp->bus_args = bp;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	/*
1980Sstevel@tonic-gate 	 * Add the child's nodeid to our table...
1990Sstevel@tonic-gate 	 */
2000Sstevel@tonic-gate 	h = ddi_get_nodeid(rp->child);
2010Sstevel@tonic-gate 	fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	return (rp);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate void
2070Sstevel@tonic-gate pci_fc_ops_free_handle(fco_handle_t rp)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	struct pci_ops_bus_args *bp;
2100Sstevel@tonic-gate 	struct fc_resource *ip, *np;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	ASSERT(rp);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (rp->next_handle)
2150Sstevel@tonic-gate 		fc_ops_free_handle(rp->next_handle);
2160Sstevel@tonic-gate 	if (rp->unit_address)
2170Sstevel@tonic-gate 		kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
2180Sstevel@tonic-gate 	if ((bp = rp->bus_args) != NULL)
2190Sstevel@tonic-gate 		kmem_free(bp, sizeof (struct pci_ops_bus_args));
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	/*
2220Sstevel@tonic-gate 	 * Release all the resources from the resource list
2230Sstevel@tonic-gate 	 * XXX: We don't handle 'unknown' types, but we don't create them.
2240Sstevel@tonic-gate 	 */
2250Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = np) {
2260Sstevel@tonic-gate 		np = ip->next;
2270Sstevel@tonic-gate 		switch (ip->type) {
2280Sstevel@tonic-gate 		case RT_MAP:
2290Sstevel@tonic-gate 			FC_DEBUG1(1, CE_CONT, "pci_fc_ops_free: "
2300Sstevel@tonic-gate 			    "pci_unmap_phys(%p)\n", ip->fc_map_handle);
2310Sstevel@tonic-gate 			pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec);
2320Sstevel@tonic-gate 			kmem_free(ip->fc_regspec, sizeof (pci_regspec_t));
2330Sstevel@tonic-gate 			break;
2340Sstevel@tonic-gate 		case RT_DMA:
2350Sstevel@tonic-gate 			/* DMA has to be freed up at exit time */
2360Sstevel@tonic-gate 			cmn_err(CE_CONT, "pfc_fc_ops_free: DMA seen!\n");
2370Sstevel@tonic-gate 			break;
2380Sstevel@tonic-gate 		default:
2390Sstevel@tonic-gate 			cmn_err(CE_CONT, "pci_fc_ops_free: "
2400Sstevel@tonic-gate 			    "unknown resource type %d\n", ip->type);
2410Sstevel@tonic-gate 			break;
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 		fc_rem_resource(rp, ip);
2440Sstevel@tonic-gate 		kmem_free(ip, sizeof (struct fc_resource));
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate 	kmem_free(rp, sizeof (struct fc_resource_list));
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate int
2500Sstevel@tonic-gate pci_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	struct pfc_ops_v *pv;
2530Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	ASSERT(rp);
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * First try the generic fc_ops. If the ops is a shared op,
2590Sstevel@tonic-gate 	 * also call our local function.
2600Sstevel@tonic-gate 	 */
2610Sstevel@tonic-gate 	if (fc_ops(ap, rp->next_handle, cp) == 0) {
2620Sstevel@tonic-gate 		for (pv = shared_pov; pv->svc_name != NULL; ++pv)
2630Sstevel@tonic-gate 			if (strcmp(pv->svc_name, name) == 0)
2640Sstevel@tonic-gate 				return (pv->f(ap, rp, cp));
2650Sstevel@tonic-gate 		return (0);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	for (pv = pov; pv->svc_name != NULL; ++pv)
2690Sstevel@tonic-gate 		if (strcmp(pv->svc_name, name) == 0)
2700Sstevel@tonic-gate 			return (pv->f(ap, rp, cp));
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pci_fc_ops: <%s> not serviced\n", name);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	return (-1);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate  * Create a dma mapping for a given user address.
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate static int
2810Sstevel@tonic-gate pfc_dma_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate 	ddi_dma_handle_t h;
2840Sstevel@tonic-gate 	int error;
2850Sstevel@tonic-gate 	caddr_t virt;
2860Sstevel@tonic-gate 	size_t len;
2870Sstevel@tonic-gate 	uint_t flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
2880Sstevel@tonic-gate 	struct fc_resource *ip;
2890Sstevel@tonic-gate 	ddi_dma_cookie_t c;
2900Sstevel@tonic-gate 	struct buf *bp;
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
2930Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
2960Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	/*
2990Sstevel@tonic-gate 	 * XXX: It's not clear what we should do with a non-cacheable request
3000Sstevel@tonic-gate 	 */
3010Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
3020Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 1));
3030Sstevel@tonic-gate #ifdef	notdef
3040Sstevel@tonic-gate 	cacheable = fc_cell2int(fc_arg(cp, 0));	/* XXX: do what? */
3050Sstevel@tonic-gate #endif
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	FC_DEBUG2(6, CE_CONT, "pcf_dma_map_in: virt %p, len %d\n", virt, len);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * Set up the address space for physio from userland
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	error = fc_physio_setup(&bp, virt, len);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	if (error)  {
3150Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: fc_physio_setup failed "
3160Sstevel@tonic-gate 		    "error: %d  virt: %p  len %d\n", error, virt, len);
3170Sstevel@tonic-gate 		return (fc_priv_error(cp, "fc_physio_setup failed"));
3180Sstevel@tonic-gate 	}
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if (no_advisory_dma == 0) {
3210Sstevel@tonic-gate 		/*
3220Sstevel@tonic-gate 		 * First try the advisory call to see if it's legal ..
3230Sstevel@tonic-gate 		 * for advisory dma, don't pass in a ptr to a dma handle.
3240Sstevel@tonic-gate 		 */
3250Sstevel@tonic-gate 		FC_DEBUG0(9, CE_CONT, "pfc_dma_map_in: advisory dma_map_in\n");
3260Sstevel@tonic-gate 		error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP,
3270Sstevel@tonic-gate 		    NULL, NULL, NULL);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		if (error)  {
3300Sstevel@tonic-gate 			FC_DEBUG3(9, CE_CONT, "pfc_dma_map_in: advisory "
3310Sstevel@tonic-gate 			    "dma-map-in failed error: %d  virt: %p  len %d\n",
3320Sstevel@tonic-gate 			    error, virt, len);
3330Sstevel@tonic-gate 			return (fc_priv_error(cp, "advisory dma-map-in "
3340Sstevel@tonic-gate 			    "failed"));
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: dma_map_in; bp = %p\n", bp);
3390Sstevel@tonic-gate 	error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP,
3400Sstevel@tonic-gate 	    NULL, NULL, &h);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	if (error)  {
3430Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: real dma-map-in failed "
3440Sstevel@tonic-gate 		    "error: %d  virt: %p  len %d\n", error, virt, len);
3450Sstevel@tonic-gate 		return (fc_priv_error(cp, "real dma-map-in failed"));
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/*
3490Sstevel@tonic-gate 	 * Now that the resource is mapped in, we need the dma cookie
3500Sstevel@tonic-gate 	 * so we can return it to the driver.
3510Sstevel@tonic-gate 	 */
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	error = fc_ddi_dma_htoc(ap, h, 0, &c);
3540Sstevel@tonic-gate 	if (error)  {
3550Sstevel@tonic-gate 		(void) fc_ddi_dma_free(ap, h);
3560Sstevel@tonic-gate 		return (fc_priv_error(cp, "ddi_dma_htoc failed"));
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	if (c.dmac_size < len)  {
3600Sstevel@tonic-gate 		(void) fc_ddi_dma_free(ap, h);
3610Sstevel@tonic-gate 		return (fc_priv_error(cp, "ddi_dma_htoc size < len"));
3620Sstevel@tonic-gate 	}
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: returning devaddr %x\n",
3650Sstevel@tonic-gate 		c.dmac_address);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
3680Sstevel@tonic-gate 	fc_result(cp, 0) = fc_uint32_t2cell(c.dmac_address);	/* XXX size */
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/*
3710Sstevel@tonic-gate 	 * Now we have to log this resource saving the handle and buf header
3720Sstevel@tonic-gate 	 */
3730Sstevel@tonic-gate 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
3740Sstevel@tonic-gate 	ip->type = RT_DMA;
3750Sstevel@tonic-gate 	ip->fc_dma_virt = virt;
3760Sstevel@tonic-gate 	ip->fc_dma_len = len;
3770Sstevel@tonic-gate 	ip->fc_dma_handle = h;
3780Sstevel@tonic-gate 	ip->fc_dma_devaddr = c.dmac_address;
3790Sstevel@tonic-gate 	ip->fc_dma_bp = bp;
3800Sstevel@tonic-gate 	fc_add_resource(rp, ip);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate static int
3860Sstevel@tonic-gate pfc_dma_sync(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3870Sstevel@tonic-gate {
3880Sstevel@tonic-gate 	void *virt;
3890Sstevel@tonic-gate 	size_t len;
3900Sstevel@tonic-gate 	uint32_t devaddr;
3910Sstevel@tonic-gate 	int error;
3920Sstevel@tonic-gate 	struct fc_resource *ip;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
3950Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
3980Sstevel@tonic-gate 	devaddr = fc_cell2uint32_t(fc_arg(cp, 1));
3990Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/*
4020Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 	fc_lock_resource_list(rp);
4050Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
4060Sstevel@tonic-gate 		if (ip->type != RT_DMA)
4070Sstevel@tonic-gate 			continue;
4080Sstevel@tonic-gate 		if (ip->fc_dma_devaddr != devaddr)
4090Sstevel@tonic-gate 			continue;
4100Sstevel@tonic-gate 		if (((char *)virt >= (char *)ip->fc_dma_virt) &&
4110Sstevel@tonic-gate 		    (((char *)virt + len) <=
4120Sstevel@tonic-gate 		    ((char *)ip->fc_dma_virt + ip->fc_dma_len)))
4130Sstevel@tonic-gate 			break;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	if (ip == NULL)
4180Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
4190Sstevel@tonic-gate 		    "known dma mapping"));
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * We know about this request, so we trust it enough to sync it.
4230Sstevel@tonic-gate 	 * Unfortunately, we don't know which direction, so we'll do
4240Sstevel@tonic-gate 	 * both directions.
4250Sstevel@tonic-gate 	 */
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	error = fc_ddi_dma_sync(ip->fc_dma_handle,
4280Sstevel@tonic-gate 	    (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORCPU);
4290Sstevel@tonic-gate 	error |= fc_ddi_dma_sync(ip->fc_dma_handle,
4300Sstevel@tonic-gate 	    (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORDEV);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (error)
4330Sstevel@tonic-gate 		return (fc_priv_error(cp, "Call to ddi_dma_sync failed"));
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
4360Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate static int
4400Sstevel@tonic-gate pfc_dma_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	void *virt;
4430Sstevel@tonic-gate 	size_t len;
4440Sstevel@tonic-gate 	uint32_t devaddr;
4450Sstevel@tonic-gate 	struct fc_resource *ip;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
4480Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
4510Sstevel@tonic-gate 	devaddr = fc_cell2uint32_t(fc_arg(cp, 1));
4520Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/*
4550Sstevel@tonic-gate 	 * Find if this virt matches a request we know about
4560Sstevel@tonic-gate 	 */
4570Sstevel@tonic-gate 	fc_lock_resource_list(rp);
4580Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
4590Sstevel@tonic-gate 		if (ip->type != RT_DMA)
4600Sstevel@tonic-gate 			continue;
4610Sstevel@tonic-gate 		if (ip->fc_dma_devaddr != devaddr)
4620Sstevel@tonic-gate 			continue;
4630Sstevel@tonic-gate 		if (ip->fc_dma_virt != virt)
4640Sstevel@tonic-gate 			continue;
4650Sstevel@tonic-gate 		if (len == ip->fc_dma_len)
4660Sstevel@tonic-gate 			break;
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	if (ip == NULL)
4710Sstevel@tonic-gate 		return (fc_priv_error(cp, "request doesn't match a "
4720Sstevel@tonic-gate 		    "known dma mapping"));
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * ddi_dma_free does an implied sync ...
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	if (fc_ddi_dma_free(ap, ip->fc_dma_handle))
4780Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_dma_map_out: ddi_dma_free failed!\n");
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/*
4810Sstevel@tonic-gate 	 * Tear down the physio mappings
4820Sstevel@tonic-gate 	 */
4830Sstevel@tonic-gate 	fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	/*
4860Sstevel@tonic-gate 	 * remove the resource from the list and release it.
4870Sstevel@tonic-gate 	 */
4880Sstevel@tonic-gate 	fc_rem_resource(rp, ip);
4890Sstevel@tonic-gate 	kmem_free(ip, sizeof (struct fc_resource));
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
4920Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate static struct fc_resource *
4960Sstevel@tonic-gate next_dma_resource(fco_handle_t rp)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 	struct fc_resource *ip;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	fc_lock_resource_list(rp);
5010Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next)
5020Sstevel@tonic-gate 		if (ip->type == RT_DMA)
5030Sstevel@tonic-gate 			break;
5040Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	return (ip);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate static int
5100Sstevel@tonic-gate pfc_dma_cleanup(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	struct fc_resource *ip;
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	while ((ip = next_dma_resource(rp)) != NULL) {
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		FC_DEBUG2(9, CE_CONT, "pfc_dma_cleanup: virt %x len %x\n",
5170Sstevel@tonic-gate 			ip->fc_dma_virt, ip->fc_dma_len);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		/*
5200Sstevel@tonic-gate 		 * Free the dma handle
5210Sstevel@tonic-gate 		 */
5220Sstevel@tonic-gate 		if (fc_ddi_dma_free(ap, ip->fc_dma_handle))
5230Sstevel@tonic-gate 			cmn_err(CE_CONT, "pfc_dma_cleanup: "
5240Sstevel@tonic-gate 			    "ddi_dma_free failed!\n");
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		/*
5270Sstevel@tonic-gate 		 * Tear down the userland mapping and free the buf header
5280Sstevel@tonic-gate 		 */
5290Sstevel@tonic-gate 		fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		fc_rem_resource(rp, ip);
5320Sstevel@tonic-gate 		kmem_free(ip, sizeof (struct fc_resource));
5330Sstevel@tonic-gate 	}
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
5360Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate static int
5400Sstevel@tonic-gate pfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	size_t len;
5430Sstevel@tonic-gate 	int error;
5440Sstevel@tonic-gate 	caddr_t virt;
5450Sstevel@tonic-gate 	pci_regspec_t p, *ph;
5460Sstevel@tonic-gate 	struct fc_resource *ip;
5470Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
5480Sstevel@tonic-gate 	ddi_acc_handle_t h;
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 4)
5510Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 4"));
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
5540Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	p.pci_size_hi = 0;
5570Sstevel@tonic-gate 	p.pci_size_low = len = fc_cell2size(fc_arg(cp, 0));
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 1));
5600Sstevel@tonic-gate 	p.pci_phys_mid = fc_cell2uint(fc_arg(cp, 2));
5610Sstevel@tonic-gate 	p.pci_phys_low = fc_cell2uint(fc_arg(cp, 3));
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	/*
5660Sstevel@tonic-gate 	 * Fcode is expecting the bytes are not swapped.
5670Sstevel@tonic-gate 	 */
5680Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5690Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	/*
5720Sstevel@tonic-gate 	 * First We need to allocate the PCI Resource.
5730Sstevel@tonic-gate 	 */
5740Sstevel@tonic-gate 	error = pci_alloc_resource(rp->child, p);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (error)  {
5770Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci map-in failed"));
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	if (error)  {
5830Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci map-in failed"));
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
5870Sstevel@tonic-gate 	fc_result(cp, 0) = fc_ptr2cell(virt);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/*
5900Sstevel@tonic-gate 	 * Log this resource ...
5910Sstevel@tonic-gate 	 */
5920Sstevel@tonic-gate 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
5930Sstevel@tonic-gate 	ip->type = RT_MAP;
5940Sstevel@tonic-gate 	ip->fc_map_virt = virt;
5950Sstevel@tonic-gate 	ip->fc_map_len = len;
5960Sstevel@tonic-gate 	ip->fc_map_handle = h;
5970Sstevel@tonic-gate 	ph = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP);
5980Sstevel@tonic-gate 	*ph = p;
5990Sstevel@tonic-gate 	ip->fc_regspec = ph;	/* cache a copy of the reg spec */
6000Sstevel@tonic-gate 	fc_add_resource(rp, ip);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate static int
6060Sstevel@tonic-gate pfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	caddr_t virt;
6090Sstevel@tonic-gate 	size_t len;
6100Sstevel@tonic-gate 	struct fc_resource *ip;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
6130Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 1));
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * Find if this request matches a mapping resource we set up.
6210Sstevel@tonic-gate 	 */
6220Sstevel@tonic-gate 	fc_lock_resource_list(rp);
6230Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
6240Sstevel@tonic-gate 		if (ip->type != RT_MAP)
6250Sstevel@tonic-gate 			continue;
6260Sstevel@tonic-gate 		if (ip->fc_map_virt != virt)
6270Sstevel@tonic-gate 			continue;
6280Sstevel@tonic-gate 		if (ip->fc_map_len == len)
6290Sstevel@tonic-gate 			break;
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	if (ip == NULL)
6340Sstevel@tonic-gate 		return (fc_priv_error(cp, "request doesn't match a "
6350Sstevel@tonic-gate 		    "known mapping"));
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	kmem_free(ip->fc_regspec, sizeof (pci_regspec_t));
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/*
6420Sstevel@tonic-gate 	 * remove the resource from the list and release it.
6430Sstevel@tonic-gate 	 */
6440Sstevel@tonic-gate 	fc_rem_resource(rp, ip);
6450Sstevel@tonic-gate 	kmem_free(ip, sizeof (struct fc_resource));
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
6480Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate static int
6520Sstevel@tonic-gate pfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate 	size_t len;
6550Sstevel@tonic-gate 	caddr_t virt;
6560Sstevel@tonic-gate 	int error;
6570Sstevel@tonic-gate 	uint64_t x;
6580Sstevel@tonic-gate 	uint32_t l;
6590Sstevel@tonic-gate 	uint16_t w;
6600Sstevel@tonic-gate 	uint8_t b;
6610Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
6620Sstevel@tonic-gate 	struct fc_resource *ip;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
6650Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
6680Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	/*
6730Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 2nd
6740Sstevel@tonic-gate 	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	switch (*(name + 1)) {
6770Sstevel@tonic-gate 	case 'x':	len = sizeof (x); break;
6780Sstevel@tonic-gate 	case 'l':	len = sizeof (l); break;
6790Sstevel@tonic-gate 	case 'w':	len = sizeof (w); break;
6800Sstevel@tonic-gate 	case 'b':	len = sizeof (b); break;
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/*
6840Sstevel@tonic-gate 	 * Check the alignment ...
6850Sstevel@tonic-gate 	 */
6860Sstevel@tonic-gate 	if (((intptr_t)virt & (len - 1)) != 0)
6870Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	/*
6900Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	fc_lock_resource_list(rp);
6930Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
6940Sstevel@tonic-gate 		if (ip->type != RT_MAP)
6950Sstevel@tonic-gate 			continue;
6960Sstevel@tonic-gate 		if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
6970Sstevel@tonic-gate 		    ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
6980Sstevel@tonic-gate 			break;
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	if (ip == NULL)
7030Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
7040Sstevel@tonic-gate 		    "known mapping"));
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
7080Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
7090Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
7100Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
7110Sstevel@tonic-gate 	 */
7120Sstevel@tonic-gate 	switch (len) {
7130Sstevel@tonic-gate 	case sizeof (x):
7140Sstevel@tonic-gate 		error = ddi_peek64(rp->child, (int64_t *)virt, (int64_t *)&x);
7150Sstevel@tonic-gate 		break;
7160Sstevel@tonic-gate 	case sizeof (l):
7170Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&l);
7180Sstevel@tonic-gate 		break;
7190Sstevel@tonic-gate 	case sizeof (w):
7200Sstevel@tonic-gate 		error = ddi_peek16(rp->child, (int16_t *)virt, (int16_t *)&w);
7210Sstevel@tonic-gate 		break;
7220Sstevel@tonic-gate 	case sizeof (b):
7230Sstevel@tonic-gate 		error = ddi_peek8(rp->child, (int8_t *)virt, (int8_t *)&b);
7240Sstevel@tonic-gate 		break;
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (error) {
7280Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
7290Sstevel@tonic-gate 	}
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
7320Sstevel@tonic-gate 	switch (len) {
7330Sstevel@tonic-gate 	case sizeof (x): fc_result(cp, 0) = x; break;
7340Sstevel@tonic-gate 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
7350Sstevel@tonic-gate 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
7360Sstevel@tonic-gate 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate static int
7420Sstevel@tonic-gate pfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	size_t len;
7450Sstevel@tonic-gate 	caddr_t virt;
7460Sstevel@tonic-gate 	int error;
7470Sstevel@tonic-gate 	uint64_t x;
7480Sstevel@tonic-gate 	uint32_t l;
7490Sstevel@tonic-gate 	uint16_t w;
7500Sstevel@tonic-gate 	uint8_t b;
7510Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
7520Sstevel@tonic-gate 	struct fc_resource *ip;
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
7550Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	/*
7600Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 2nd
7610Sstevel@tonic-gate 	 * character of the name which is "rl!", "rb!" or "rw!"
7620Sstevel@tonic-gate 	 */
7630Sstevel@tonic-gate 	switch (*(name + 1)) {
7640Sstevel@tonic-gate 	case 'x': len = sizeof (x); x = fc_arg(cp, 1); break;
7650Sstevel@tonic-gate 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
7660Sstevel@tonic-gate 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
7670Sstevel@tonic-gate 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/*
7710Sstevel@tonic-gate 	 * Check the alignment ...
7720Sstevel@tonic-gate 	 */
7730Sstevel@tonic-gate 	if (((intptr_t)virt & (len - 1)) != 0)
7740Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	fc_lock_resource_list(rp);
7800Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
7810Sstevel@tonic-gate 		if (ip->type != RT_MAP)
7820Sstevel@tonic-gate 			continue;
7830Sstevel@tonic-gate 		if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
7840Sstevel@tonic-gate 		    ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
7850Sstevel@tonic-gate 			break;
7860Sstevel@tonic-gate 	}
7870Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	if (ip == NULL)
7900Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
7910Sstevel@tonic-gate 		    "known mapping"));
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	/*
7940Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
7950Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
7960Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
7970Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
7980Sstevel@tonic-gate 	 */
7990Sstevel@tonic-gate 	switch (len) {
8000Sstevel@tonic-gate 	case sizeof (x):
8010Sstevel@tonic-gate 		error = ddi_poke64(rp->child, (int64_t *)virt, x);
8020Sstevel@tonic-gate 		break;
8030Sstevel@tonic-gate 	case sizeof (l):
8040Sstevel@tonic-gate 		error = ddi_poke32(rp->child, (int32_t *)virt, l);
8050Sstevel@tonic-gate 		break;
8060Sstevel@tonic-gate 	case sizeof (w):
8070Sstevel@tonic-gate 		error = ddi_poke16(rp->child, (int16_t *)virt, w);
8080Sstevel@tonic-gate 		break;
8090Sstevel@tonic-gate 	case sizeof (b):
8100Sstevel@tonic-gate 		error = ddi_poke8(rp->child, (int8_t *)virt, b);
8110Sstevel@tonic-gate 		break;
8120Sstevel@tonic-gate 	}
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (error) {
8150Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
8190Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate static int
8230Sstevel@tonic-gate pfc_config_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8240Sstevel@tonic-gate {
8250Sstevel@tonic-gate 	caddr_t virt, v;
8260Sstevel@tonic-gate 	int error, reg, flags = 0;
8270Sstevel@tonic-gate 	size_t len;
8280Sstevel@tonic-gate 	uint32_t l, tmp;
8290Sstevel@tonic-gate 	uint16_t w;
8300Sstevel@tonic-gate 	uint8_t b;
8310Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
8320Sstevel@tonic-gate 	pci_regspec_t p;
8330Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
8340Sstevel@tonic-gate 	ddi_acc_handle_t h;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
8370Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
8400Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	/*
8430Sstevel@tonic-gate 	 * Construct a config address pci reg property from the args.
8440Sstevel@tonic-gate 	 * arg[0] is the configuration address.
8450Sstevel@tonic-gate 	 */
8460Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0));
8470Sstevel@tonic-gate 	p.pci_phys_mid = p.pci_phys_low = 0;
8480Sstevel@tonic-gate 	p.pci_size_hi = p.pci_size_low = 0;
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	/*
8510Sstevel@tonic-gate 	 * Verify that the address is a configuration space address
8520Sstevel@tonic-gate 	 * ss must be zero, n,p,t must be zero.
8530Sstevel@tonic-gate 	 */
8540Sstevel@tonic-gate 	if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) ||
8550Sstevel@tonic-gate 	    ((p.pci_phys_hi & PCI_NPT_bits) != 0)) {
8560Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_fetch: "
8570Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
8580Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
8590Sstevel@tonic-gate 	}
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	/*
8620Sstevel@tonic-gate 	 * Extract the register number from the config address and
8630Sstevel@tonic-gate 	 * remove the register number from the physical address.
8640Sstevel@tonic-gate 	 */
8650Sstevel@tonic-gate 	reg = p.pci_phys_hi & PCI_REG_REG_M;
8660Sstevel@tonic-gate 	p.pci_phys_hi &= ~PCI_REG_REG_M;
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	/*
8690Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 9th
8700Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
8710Sstevel@tonic-gate 	 */
8720Sstevel@tonic-gate 	switch (*(name + 7)) {
8730Sstevel@tonic-gate 	case 'l':	len = sizeof (l); break;
8740Sstevel@tonic-gate 	case 'w':	len = sizeof (w); break;
8750Sstevel@tonic-gate 	case 'b':	len = sizeof (b); break;
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/*
8790Sstevel@tonic-gate 	 * Verify that the access is properly aligned
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
8820Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/*
8850Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
8860Sstevel@tonic-gate 	 */
8870Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8880Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8890Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	if (error)  {
8940Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
8980Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
9010Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
9020Sstevel@tonic-gate 		error = DDI_SUCCESS;
9030Sstevel@tonic-gate 	} else
9040Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
9070Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
9080Sstevel@tonic-gate 			error = DDI_FAILURE;
9090Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpcii: conf probe failed.l=%x", tmp);
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
9130Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config fetch failed"));
9140Sstevel@tonic-gate 	}
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	/*
9180Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
9190Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
9200Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
9210Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
9220Sstevel@tonic-gate 	 */
9230Sstevel@tonic-gate 	v = virt + reg;
9240Sstevel@tonic-gate 	switch (len) {
9250Sstevel@tonic-gate 	case sizeof (l):
9260Sstevel@tonic-gate 		l = (int32_t)ddi_get32(h, (uint32_t *)v);
9270Sstevel@tonic-gate 		break;
9280Sstevel@tonic-gate 	case sizeof (w):
9290Sstevel@tonic-gate 		w = (int16_t)ddi_get16(h, (uint16_t *)v);
9300Sstevel@tonic-gate 		break;
9310Sstevel@tonic-gate 	case sizeof (b):
9320Sstevel@tonic-gate 		b = (int8_t)ddi_get8(h, (uint8_t *)v);
9330Sstevel@tonic-gate 		break;
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Remove the temporary config space mapping
9380Sstevel@tonic-gate 	 */
9390Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	if (error) {
9420Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
9460Sstevel@tonic-gate 	switch (len) {
9470Sstevel@tonic-gate 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
9480Sstevel@tonic-gate 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
9490Sstevel@tonic-gate 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
9500Sstevel@tonic-gate 	}
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
9530Sstevel@tonic-gate }
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate static int
9560Sstevel@tonic-gate pfc_config_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
9570Sstevel@tonic-gate {
9580Sstevel@tonic-gate 	caddr_t virt, v;
9590Sstevel@tonic-gate 	int error, reg, flags = 0;
9600Sstevel@tonic-gate 	size_t len;
9610Sstevel@tonic-gate 	uint32_t l, tmp;
9620Sstevel@tonic-gate 	uint16_t w;
9630Sstevel@tonic-gate 	uint8_t b;
9640Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
9650Sstevel@tonic-gate 	pci_regspec_t p;
9660Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
9670Sstevel@tonic-gate 	ddi_acc_handle_t h;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
9700Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/*
9730Sstevel@tonic-gate 	 * Construct a config address pci reg property from the args.
9740Sstevel@tonic-gate 	 * arg[0] is the configuration address. arg[1] is the data.
9750Sstevel@tonic-gate 	 */
9760Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0));
9770Sstevel@tonic-gate 	p.pci_phys_mid = p.pci_phys_low = 0;
9780Sstevel@tonic-gate 	p.pci_size_hi = p.pci_size_low = 0;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	/*
9810Sstevel@tonic-gate 	 * Verify that the address is a configuration space address
9820Sstevel@tonic-gate 	 * ss must be zero, n,p,t must be zero.
9830Sstevel@tonic-gate 	 */
9840Sstevel@tonic-gate 	if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) ||
9850Sstevel@tonic-gate 	    ((p.pci_phys_hi & PCI_NPT_bits) != 0)) {
9860Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_store: "
9870Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
9880Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	/*
9920Sstevel@tonic-gate 	 * Extract the register number from the config address and
9930Sstevel@tonic-gate 	 * remove the register number from the physical address.
9940Sstevel@tonic-gate 	 */
9950Sstevel@tonic-gate 	reg = p.pci_phys_hi & PCI_REG_REG_M;
9960Sstevel@tonic-gate 	p.pci_phys_hi &= ~PCI_REG_REG_M;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	/*
9990Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 8th
10000Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
10010Sstevel@tonic-gate 	 */
10020Sstevel@tonic-gate 	switch (*(name + 7)) {
10030Sstevel@tonic-gate 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
10040Sstevel@tonic-gate 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
10050Sstevel@tonic-gate 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	/*
10090Sstevel@tonic-gate 	 * Verify that the access is properly aligned
10100Sstevel@tonic-gate 	 */
10110Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
10120Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	/*
10150Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
10160Sstevel@tonic-gate 	 */
10170Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
10180Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
10190Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	if (error)  {
10240Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
10280Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
10310Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
10320Sstevel@tonic-gate 		error = DDI_SUCCESS;
10330Sstevel@tonic-gate 	} else
10340Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
10370Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
10380Sstevel@tonic-gate 			error = DDI_FAILURE;
10390Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpci: conf probe failed.l=%x", tmp);
10400Sstevel@tonic-gate 		}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
10430Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config store failed"));
10440Sstevel@tonic-gate 	}
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	/*
10480Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
10490Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
10500Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
10510Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
10520Sstevel@tonic-gate 	 */
10530Sstevel@tonic-gate 	v = virt + reg;
10540Sstevel@tonic-gate 	switch (len) {
10550Sstevel@tonic-gate 	case sizeof (l):
10560Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, (uint32_t)l);
10570Sstevel@tonic-gate 		break;
10580Sstevel@tonic-gate 	case sizeof (w):
10590Sstevel@tonic-gate 		ddi_put16(h, (uint16_t *)v, (uint16_t)w);
10600Sstevel@tonic-gate 		break;
10610Sstevel@tonic-gate 	case sizeof (b):
10620Sstevel@tonic-gate 		ddi_put8(h, (uint8_t *)v, (uint8_t)b);
10630Sstevel@tonic-gate 		break;
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	/*
10670Sstevel@tonic-gate 	 * Remove the temporary config space mapping
10680Sstevel@tonic-gate 	 */
10690Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	if (error) {
10720Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
10760Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate static int
10810Sstevel@tonic-gate pfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	caddr_t name_virt, fcode_virt;
10840Sstevel@tonic-gate 	char *name, *fcode;
10850Sstevel@tonic-gate 	int fcode_len, status;
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
10880Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
10910Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	name_virt = fc_cell2ptr(fc_arg(cp, 0));
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	fcode_len = fc_cell2int(fc_arg(cp, 2));
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(name_virt), name,
11020Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
11030Sstevel@tonic-gate 		status = 0;
11040Sstevel@tonic-gate 	} else {
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		if ((status = prom_get_fcode(name, fcode)) != 0) {
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 			if (copyout((void *)fcode, (void *)fcode_virt,
11110Sstevel@tonic-gate 			    fcode_len)) {
11120Sstevel@tonic-gate 				cmn_err(CE_WARN, " pfc_get_fcode: Unable "
11130Sstevel@tonic-gate 				    "to copy out fcode image\n");
11140Sstevel@tonic-gate 				status = 0;
11150Sstevel@tonic-gate 			}
11160Sstevel@tonic-gate 		}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 		kmem_free(fcode, fcode_len);
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
11240Sstevel@tonic-gate 	fc_result(cp, 0) = status;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate static int
11300Sstevel@tonic-gate pfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11310Sstevel@tonic-gate {
11320Sstevel@tonic-gate 	caddr_t virt;
11330Sstevel@tonic-gate 	char *name;
11340Sstevel@tonic-gate 	int len;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
11370Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
11400Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(virt), name,
11470Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
11480Sstevel@tonic-gate 		len = 0;
11490Sstevel@tonic-gate 	} else {
11500Sstevel@tonic-gate 		len = prom_get_fcode_size(name);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
11560Sstevel@tonic-gate 	fc_result(cp, 0) = len;
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate /*
11620Sstevel@tonic-gate  * Return the physical probe address: lo=0, mid=0, hi-config-addr
11630Sstevel@tonic-gate  */
11640Sstevel@tonic-gate static int
11650Sstevel@tonic-gate pfc_probe_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
11680Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 2)
11710Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 3"));
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	cp->nresults = fc_int2cell(2);
11740Sstevel@tonic-gate 	fc_result(cp, 1) = fc_int2cell(0);	/* phys.lo */
11750Sstevel@tonic-gate 	fc_result(cp, 0) = fc_int2cell(0);	/* phys.mid */
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate /*
11810Sstevel@tonic-gate  * Return the phys.hi component of the probe address.
11820Sstevel@tonic-gate  */
11830Sstevel@tonic-gate static int
11840Sstevel@tonic-gate pfc_probe_space(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate 	struct pci_ops_bus_args *ba = rp->bus_args;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	ASSERT(ba);
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
11910Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
11940Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
11970Sstevel@tonic-gate 	fc_result(cp, 0) = fc_uint32_t2cell(ba->config_address); /* phys.hi */
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate static int
12030Sstevel@tonic-gate pfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
12040Sstevel@tonic-gate {
12050Sstevel@tonic-gate 	fc_phandle_t h;
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
12080Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
12110Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
12160Sstevel@tonic-gate 	fc_result(cp, 0) = fc_phandle2cell(h);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate int
12220Sstevel@tonic-gate pci_alloc_mem_chunk(dev_info_t *dip, uint64_t mem_align, uint64_t *mem_size,
12230Sstevel@tonic-gate     uint64_t *mem_answer)
12240Sstevel@tonic-gate {
12250Sstevel@tonic-gate 	ndi_ra_request_t req;
12260Sstevel@tonic-gate 	int rval;
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
12290Sstevel@tonic-gate 	req.ra_flags = NDI_RA_ALLOC_BOUNDED;
12300Sstevel@tonic-gate 	req.ra_boundbase = 0;
12310Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
12320Sstevel@tonic-gate 	req.ra_len = *mem_size;
12330Sstevel@tonic-gate 	req.ra_align_mask = mem_align - 1;
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, mem_answer, mem_size,
12360Sstevel@tonic-gate 	    NDI_RA_TYPE_MEM, NDI_RA_PASS);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	return (rval);
12390Sstevel@tonic-gate }
12400Sstevel@tonic-gate int
12410Sstevel@tonic-gate pci_alloc_io_chunk(dev_info_t *dip, uint64_t io_align, uint64_t *io_size,
12420Sstevel@tonic-gate     uint64_t *io_answer)
12430Sstevel@tonic-gate {
12440Sstevel@tonic-gate 	ndi_ra_request_t req;
12450Sstevel@tonic-gate 	int rval;
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
12480Sstevel@tonic-gate 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
12490Sstevel@tonic-gate 	req.ra_boundbase = 0;
12500Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
12510Sstevel@tonic-gate 	req.ra_len = *io_size;
12520Sstevel@tonic-gate 	req.ra_align_mask = io_align - 1;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, io_answer, io_size,
12550Sstevel@tonic-gate 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	return (rval);
12580Sstevel@tonic-gate }
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate int
12610Sstevel@tonic-gate pci_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate 	uint64_t answer;
12640Sstevel@tonic-gate 	uint64_t alen;
12650Sstevel@tonic-gate 	int offset, tmp;
12660Sstevel@tonic-gate 	pci_regspec_t config;
12670Sstevel@tonic-gate 	caddr_t virt, v;
12680Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
12690Sstevel@tonic-gate 	ddi_acc_handle_t h;
12700Sstevel@tonic-gate 	ndi_ra_request_t request;
12710Sstevel@tonic-gate 	pci_regspec_t *assigned;
12720Sstevel@tonic-gate 	int assigned_len, entries, i, l, flags = 0, error;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
12770Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
12780Sstevel@tonic-gate 	    &assigned_len) == DDI_PROP_SUCCESS) {
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 		entries = assigned_len / (sizeof (pci_regspec_t));
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 		/*
12830Sstevel@tonic-gate 		 * Walk through the assigned-addresses entries. If there is
12840Sstevel@tonic-gate 		 * a match, there is no need to allocate the resource.
12850Sstevel@tonic-gate 		 */
12860Sstevel@tonic-gate 		for (i = 0; i < entries; i++) {
12870Sstevel@tonic-gate 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
12880Sstevel@tonic-gate 				if (assigned[i].pci_size_low >=
12890Sstevel@tonic-gate 				    phys_spec.pci_size_low) {
12900Sstevel@tonic-gate 					kmem_free(assigned, assigned_len);
12910Sstevel@tonic-gate 					return (0);
12920Sstevel@tonic-gate 				}
12930Sstevel@tonic-gate 				/*
12940Sstevel@tonic-gate 				 * Fcode wants to assign more than what
12950Sstevel@tonic-gate 				 * probe found.
12960Sstevel@tonic-gate 				 */
12970Sstevel@tonic-gate 				(void) pci_free_resource(dip, assigned[i]);
12980Sstevel@tonic-gate 				/*
12990Sstevel@tonic-gate 				 * Go on to allocate resources.
13000Sstevel@tonic-gate 				 */
13010Sstevel@tonic-gate 				break;
13020Sstevel@tonic-gate 			}
13030Sstevel@tonic-gate 			/*
13040Sstevel@tonic-gate 			 * Check if Fcode wants to map using different
13050Sstevel@tonic-gate 			 * NPT bits.
13060Sstevel@tonic-gate 			 */
13070Sstevel@tonic-gate 			if (PCI_REG_BDFR_G(assigned[i].pci_phys_hi) ==
13080Sstevel@tonic-gate 			    PCI_REG_BDFR_G(phys_spec.pci_phys_hi)) {
13090Sstevel@tonic-gate 				/*
13100Sstevel@tonic-gate 				 * It is an error to change SS bits
13110Sstevel@tonic-gate 				 */
13120Sstevel@tonic-gate 				if (PCI_REG_ADDR_G(assigned[i].pci_phys_hi) !=
13130Sstevel@tonic-gate 				    PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 					cmn_err(CE_WARN, "Fcode changing ss "
13160Sstevel@tonic-gate 					    "bits in reg %x -- %x",
13170Sstevel@tonic-gate 					    assigned[i].pci_phys_hi,
13180Sstevel@tonic-gate 					    phys_spec.pci_phys_hi);
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 					kmem_free(assigned, assigned_len);
13210Sstevel@tonic-gate 					return (1);
13220Sstevel@tonic-gate 				}
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 				/*
13250Sstevel@tonic-gate 				 * Allocate enough
13260Sstevel@tonic-gate 				 */
13270Sstevel@tonic-gate 				l = MAX(assigned[i].pci_size_low,
13280Sstevel@tonic-gate 				    phys_spec.pci_size_low);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 				(void) pci_free_resource(dip, assigned[i]);
13310Sstevel@tonic-gate 				/*
13320Sstevel@tonic-gate 				 * Go on to allocate resources.
13330Sstevel@tonic-gate 				 */
13340Sstevel@tonic-gate 				break;
13350Sstevel@tonic-gate 			}
13360Sstevel@tonic-gate 		}
13370Sstevel@tonic-gate 		kmem_free(assigned, assigned_len);
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
13430Sstevel@tonic-gate 	config.pci_phys_hi &= ~PCI_REG_REG_M;
13440Sstevel@tonic-gate 	config.pci_phys_mid = config.pci_phys_low = 0;
13450Sstevel@tonic-gate 	config.pci_size_hi = config.pci_size_low = 0;
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	/*
13480Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
13490Sstevel@tonic-gate 	 */
13500Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
13510Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
13520Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
13530Sstevel@tonic-gate 
13540Sstevel@tonic-gate 	if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) {
13550Sstevel@tonic-gate 		return (1);
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	if (fcpci_indirect_map(dip) == DDI_SUCCESS)
13590Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
13620Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
13630Sstevel@tonic-gate 		error = DDI_SUCCESS;
13640Sstevel@tonic-gate 	} else
13650Sstevel@tonic-gate 		error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp);
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
13680Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
13690Sstevel@tonic-gate 			error = DDI_FAILURE;
13700Sstevel@tonic-gate 		}
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
13730Sstevel@tonic-gate 		return (1);
13740Sstevel@tonic-gate 	}
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
13770Sstevel@tonic-gate 	request.ra_boundbase = 0;
13780Sstevel@tonic-gate 	request.ra_boundlen = PCI_4GIG_LIMIT;
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	v = virt + offset;
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
13850Sstevel@tonic-gate 		request.ra_len = l;
13860Sstevel@tonic-gate 		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		/* allocate memory space from the allocator */
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		if (ndi_ra_alloc(ddi_get_parent(dip),
13910Sstevel@tonic-gate 			&request, &answer, &alen,
13920Sstevel@tonic-gate 			NDI_RA_TYPE_MEM, NDI_RA_PASS)
13930Sstevel@tonic-gate 					!= NDI_SUCCESS) {
13940Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
13950Sstevel@tonic-gate 			return (1);
13960Sstevel@tonic-gate 		}
13970Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "ROM addr = [0x%x.%x] len [0x%x]\n",
13980Sstevel@tonic-gate 			HIADDR(answer),
13990Sstevel@tonic-gate 			LOADDR(answer),
14000Sstevel@tonic-gate 			alen);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 		/* program the low word */
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, LOADDR(answer));
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 		phys_spec.pci_phys_low = LOADDR(answer);
14070Sstevel@tonic-gate 		phys_spec.pci_phys_mid = HIADDR(answer);
14080Sstevel@tonic-gate 	} else {
14090Sstevel@tonic-gate 		request.ra_len = l;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
14120Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
14130Sstevel@tonic-gate 			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
14160Sstevel@tonic-gate 				/*
14170Sstevel@tonic-gate 				 * If it is a non relocatable address,
14180Sstevel@tonic-gate 				 * then specify the address we want.
14190Sstevel@tonic-gate 				 */
14200Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
14210Sstevel@tonic-gate 				request.ra_addr = (uint64_t)LADDR(
14220Sstevel@tonic-gate 				    phys_spec.pci_phys_low,
14230Sstevel@tonic-gate 				    phys_spec.pci_phys_mid);
14240Sstevel@tonic-gate 			}
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 			/* allocate memory space from the allocator */
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
14290Sstevel@tonic-gate 				&request, &answer, &alen,
14300Sstevel@tonic-gate 				NDI_RA_TYPE_MEM, NDI_RA_PASS)
14310Sstevel@tonic-gate 						!= NDI_SUCCESS) {
14320Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
14330Sstevel@tonic-gate 				if (request.ra_flags ==
14340Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
14350Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
14360Sstevel@tonic-gate 					    "non relocatable address 0x%p\n",
14370Sstevel@tonic-gate 					    (void *) request.ra_addr);
14380Sstevel@tonic-gate 				return (1);
14390Sstevel@tonic-gate 			}
14400Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
14410Sstevel@tonic-gate 			    "64 addr = [0x%x.%x] len [0x%x]\n",
14420Sstevel@tonic-gate 			    HIADDR(answer),
14430Sstevel@tonic-gate 			    LOADDR(answer),
14440Sstevel@tonic-gate 			    alen);
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 			/* program the low word */
14470Sstevel@tonic-gate 
14480Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 			/* program the high word with value zero */
14510Sstevel@tonic-gate 			v += 4;
14520Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, HIADDR(answer));
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
14550Sstevel@tonic-gate 			phys_spec.pci_phys_mid = HIADDR(answer);
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 			break;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
14600Sstevel@tonic-gate 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
14630Sstevel@tonic-gate 				/*
14640Sstevel@tonic-gate 				 * If it is a non relocatable address,
14650Sstevel@tonic-gate 				 * then specify the address we want.
14660Sstevel@tonic-gate 				 */
14670Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
14680Sstevel@tonic-gate 				request.ra_addr = (uint64_t)
14690Sstevel@tonic-gate 				    phys_spec.pci_phys_low;
14700Sstevel@tonic-gate 			}
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate 			/* allocate memory space from the allocator */
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
14750Sstevel@tonic-gate 				&request, &answer, &alen,
14760Sstevel@tonic-gate 				NDI_RA_TYPE_MEM, NDI_RA_PASS)
14770Sstevel@tonic-gate 						!= NDI_SUCCESS) {
14780Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
14790Sstevel@tonic-gate 				if (request.ra_flags ==
14800Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
14810Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
14820Sstevel@tonic-gate 					    "non relocatable address 0x%p\n",
14830Sstevel@tonic-gate 					    (void *) request.ra_addr);
14840Sstevel@tonic-gate 				return (1);
14850Sstevel@tonic-gate 			}
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
14880Sstevel@tonic-gate 			    "32 addr = [0x%x.%x] len [0x%x]\n",
14890Sstevel@tonic-gate 			    HIADDR(answer),
14900Sstevel@tonic-gate 			    LOADDR(answer),
14910Sstevel@tonic-gate 			    alen);
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 			/* program the low word */
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 			break;
15000Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
15010Sstevel@tonic-gate 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
15040Sstevel@tonic-gate 				/*
15050Sstevel@tonic-gate 				 * If it is a non relocatable address,
15060Sstevel@tonic-gate 				 * then specify the address we want.
15070Sstevel@tonic-gate 				 */
15080Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
15090Sstevel@tonic-gate 				request.ra_addr = (uint64_t)
15100Sstevel@tonic-gate 				    phys_spec.pci_phys_low;
15110Sstevel@tonic-gate 			}
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 			/* allocate I/O space from the allocator */
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
15160Sstevel@tonic-gate 				&request, &answer, &alen,
15170Sstevel@tonic-gate 				NDI_RA_TYPE_IO, NDI_RA_PASS)
15180Sstevel@tonic-gate 						!= NDI_SUCCESS) {
15190Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
15200Sstevel@tonic-gate 				if (request.ra_flags ==
15210Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
15220Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
15230Sstevel@tonic-gate 					    "non relocatable IO Space 0x%p\n",
15240Sstevel@tonic-gate 					    (void *) request.ra_addr);
15250Sstevel@tonic-gate 				return (1);
15260Sstevel@tonic-gate 			}
15270Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
15280Sstevel@tonic-gate 			    "I/O addr = [0x%x.%x] len [0x%x]\n",
15290Sstevel@tonic-gate 			    HIADDR(answer),
15300Sstevel@tonic-gate 			    LOADDR(answer),
15310Sstevel@tonic-gate 			    alen);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 			break;
15380Sstevel@tonic-gate 		default:
15390Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
15400Sstevel@tonic-gate 			return (1);
15410Sstevel@tonic-gate 		} /* switch */
15420Sstevel@tonic-gate 	}
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	/*
15450Sstevel@tonic-gate 	 * Now that memory locations are assigned,
15460Sstevel@tonic-gate 	 * update the assigned address property.
15470Sstevel@tonic-gate 	 */
15480Sstevel@tonic-gate 	if (pfc_update_assigned_prop(dip, &phys_spec)) {
15490Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
15500Sstevel@tonic-gate 		return (1);
15510Sstevel@tonic-gate 	}
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 	return (0);
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate int
15590Sstevel@tonic-gate pci_free_resource(dev_info_t *dip, pci_regspec_t phys_spec)
15600Sstevel@tonic-gate {
15610Sstevel@tonic-gate 	int offset, tmp;
15620Sstevel@tonic-gate 	pci_regspec_t config;
15630Sstevel@tonic-gate 	caddr_t virt, v;
15640Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
15650Sstevel@tonic-gate 	ddi_acc_handle_t h;
15660Sstevel@tonic-gate 	ndi_ra_request_t request;
15670Sstevel@tonic-gate 	int l, error, flags = 0;
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
15720Sstevel@tonic-gate 	config.pci_phys_hi &= ~PCI_REG_REG_M;
15730Sstevel@tonic-gate 	config.pci_phys_mid = config.pci_phys_low = 0;
15740Sstevel@tonic-gate 	config.pci_size_hi = config.pci_size_low = 0;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	/*
15770Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
15780Sstevel@tonic-gate 	 */
15790Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15800Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
15810Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) {
15840Sstevel@tonic-gate 		return (1);
15850Sstevel@tonic-gate 	}
15860Sstevel@tonic-gate 	if (fcpci_indirect_map(dip) == DDI_SUCCESS)
15870Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
15900Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
15910Sstevel@tonic-gate 		error = DDI_SUCCESS;
15920Sstevel@tonic-gate 	} else
15930Sstevel@tonic-gate 		error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp);
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
15960Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
15970Sstevel@tonic-gate 			error = DDI_FAILURE;
15980Sstevel@tonic-gate 		}
15990Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
16000Sstevel@tonic-gate 		return (1);
16010Sstevel@tonic-gate 	}
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	v = virt + offset;
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/*
16090Sstevel@tonic-gate 	 * Pick up the size to be freed. It may be different from
16100Sstevel@tonic-gate 	 * what probe finds.
16110Sstevel@tonic-gate 	 */
16120Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
16150Sstevel@tonic-gate 		/* free memory back to the allocator */
16160Sstevel@tonic-gate 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
16170Sstevel@tonic-gate 		    l, NDI_RA_TYPE_MEM,
16180Sstevel@tonic-gate 		    NDI_RA_PASS) != NDI_SUCCESS) {
16190Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
16200Sstevel@tonic-gate 			return (1);
16210Sstevel@tonic-gate 		}
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 		/* Unmap the BAR by writing a zero */
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, 0);
16260Sstevel@tonic-gate 	} else {
16270Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
16280Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
16290Sstevel@tonic-gate 			/* free memory back to the allocator */
16300Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16310Sstevel@tonic-gate 			    LADDR(phys_spec.pci_phys_low,
16320Sstevel@tonic-gate 			    phys_spec.pci_phys_mid),
16330Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
16340Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16350Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16360Sstevel@tonic-gate 				return (1);
16370Sstevel@tonic-gate 			}
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 			break;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
16420Sstevel@tonic-gate 			/* free memory back to the allocator */
16430Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16440Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
16450Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
16460Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16470Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16480Sstevel@tonic-gate 				return (1);
16490Sstevel@tonic-gate 			}
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 			break;
16520Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
16530Sstevel@tonic-gate 			/* free I/O space back to the allocator */
16540Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16550Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
16560Sstevel@tonic-gate 			    l, NDI_RA_TYPE_IO,
16570Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16580Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16590Sstevel@tonic-gate 				return (1);
16600Sstevel@tonic-gate 			}
16610Sstevel@tonic-gate 			break;
16620Sstevel@tonic-gate 		default:
16630Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
16640Sstevel@tonic-gate 			return (1);
16650Sstevel@tonic-gate 		} /* switch */
16660Sstevel@tonic-gate 	}
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	/*
16690Sstevel@tonic-gate 	 * Now that memory locations are assigned,
16700Sstevel@tonic-gate 	 * update the assigned address property.
16710Sstevel@tonic-gate 	 */
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	FC_DEBUG1(1, CE_CONT, "updating assigned-addresss for %x\n",
16740Sstevel@tonic-gate 	    phys_spec.pci_phys_hi);
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 	if (pfc_remove_assigned_prop(dip, &phys_spec)) {
16770Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
16780Sstevel@tonic-gate 		return (1);
16790Sstevel@tonic-gate 	}
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	return (0);
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate int
16880Sstevel@tonic-gate pci_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
16890Sstevel@tonic-gate 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
16900Sstevel@tonic-gate 	ddi_acc_handle_t *handlep)
16910Sstevel@tonic-gate {
16920Sstevel@tonic-gate 	ddi_map_req_t mr;
16930Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
16940Sstevel@tonic-gate 	int result;
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
16970Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
16980Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
16990Sstevel@tonic-gate 	hp->ah_dip = dip;
17000Sstevel@tonic-gate 	hp->ah_rnumber = 0;
17010Sstevel@tonic-gate 	hp->ah_offset = 0;
17020Sstevel@tonic-gate 	hp->ah_len = 0;
17030Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
17060Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
17070Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)phys_spec;
17080Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
17090Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
17100Sstevel@tonic-gate 	mr.map_handlep = hp;
17110Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	result = ddi_map(dip, &mr, 0, 0, addrp);
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
17160Sstevel@tonic-gate 		impl_acc_hdl_free(*handlep);
17170Sstevel@tonic-gate 		*handlep = (ddi_acc_handle_t)NULL;
17180Sstevel@tonic-gate 	} else {
17190Sstevel@tonic-gate 		hp->ah_addr = *addrp;
17200Sstevel@tonic-gate 	}
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	return (result);
17230Sstevel@tonic-gate }
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate void
17260Sstevel@tonic-gate pci_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
17270Sstevel@tonic-gate {
17280Sstevel@tonic-gate 	ddi_map_req_t mr;
17290Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
17320Sstevel@tonic-gate 	ASSERT(hp);
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
17350Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
17360Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)ph;
17370Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
17380Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
17390Sstevel@tonic-gate 	mr.map_handlep = hp;
17400Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
17430Sstevel@tonic-gate 		hp->ah_len, &hp->ah_addr);
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate int
17520Sstevel@tonic-gate pfc_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
17530Sstevel@tonic-gate {
17540Sstevel@tonic-gate 	int		alen;
17550Sstevel@tonic-gate 	pci_regspec_t	*assigned;
17560Sstevel@tonic-gate 	caddr_t		newreg;
17570Sstevel@tonic-gate 	uint_t		status;
17580Sstevel@tonic-gate 
1759*506Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
17600Sstevel@tonic-gate 		"assigned-addresses", (caddr_t)&assigned, &alen);
17610Sstevel@tonic-gate 	switch (status) {
17620Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
17630Sstevel@tonic-gate 		break;
17640Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
17650Sstevel@tonic-gate 			return (1);
17660Sstevel@tonic-gate 		default:
17670Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
17680Sstevel@tonic-gate 			"assigned-addresses", (int *)newone,
17690Sstevel@tonic-gate 				sizeof (*newone)/sizeof (int));
17700Sstevel@tonic-gate 			return (0);
17710Sstevel@tonic-gate 	}
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	/*
17740Sstevel@tonic-gate 	 * Allocate memory for the existing
17750Sstevel@tonic-gate 	 * assigned-addresses(s) plus one and then
17760Sstevel@tonic-gate 	 * build it.
17770Sstevel@tonic-gate 	 */
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	bcopy(assigned, newreg, alen);
17820Sstevel@tonic-gate 	bcopy(newone, newreg + alen, sizeof (*newone));
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 	/*
17850Sstevel@tonic-gate 	 * Write out the new "assigned-addresses" spec
17860Sstevel@tonic-gate 	 */
17870Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
17880Sstevel@tonic-gate 		"assigned-addresses", (int *)newreg,
17890Sstevel@tonic-gate 		(alen + sizeof (*newone))/sizeof (int));
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	return (0);
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate int
17960Sstevel@tonic-gate pfc_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
17970Sstevel@tonic-gate {
17980Sstevel@tonic-gate 	int		alen, new_len, num_entries, i;
17990Sstevel@tonic-gate 	pci_regspec_t	*assigned;
18000Sstevel@tonic-gate 	uint_t		status;
18010Sstevel@tonic-gate 
1802*506Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
18030Sstevel@tonic-gate 		"assigned-addresses", (caddr_t)&assigned, &alen);
18040Sstevel@tonic-gate 	switch (status) {
18050Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
18060Sstevel@tonic-gate 		break;
18070Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
18080Sstevel@tonic-gate 			return (1);
18090Sstevel@tonic-gate 		default:
18100Sstevel@tonic-gate 			return (0);
18110Sstevel@tonic-gate 	}
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	num_entries = alen / sizeof (pci_regspec_t);
18140Sstevel@tonic-gate 	new_len = alen - sizeof (pci_regspec_t);
18150Sstevel@tonic-gate 
18160Sstevel@tonic-gate 	/*
18170Sstevel@tonic-gate 	 * Search for the memory being removed.
18180Sstevel@tonic-gate 	 */
18190Sstevel@tonic-gate 	for (i = 0; i < num_entries; i++) {
18200Sstevel@tonic-gate 		if (assigned[i].pci_phys_hi == oldone->pci_phys_hi) {
18210Sstevel@tonic-gate 			if (new_len == 0) {
18220Sstevel@tonic-gate 				(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
18230Sstevel@tonic-gate 				    "assigned-addresses");
18240Sstevel@tonic-gate 				break;
18250Sstevel@tonic-gate 			}
18260Sstevel@tonic-gate 			if ((new_len - (i * sizeof (pci_regspec_t)))
18270Sstevel@tonic-gate 			    == 0) {
18280Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
18290Sstevel@tonic-gate 				    "%x removed from property (last entry)\n",
18300Sstevel@tonic-gate 				    oldone->pci_phys_hi);
18310Sstevel@tonic-gate 			} else {
18320Sstevel@tonic-gate 				bcopy((void *)(assigned + i + 1),
18330Sstevel@tonic-gate 				    (void *)(assigned + i),
18340Sstevel@tonic-gate 				    (new_len - (i * sizeof (pci_regspec_t))));
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
18370Sstevel@tonic-gate 				    "%x removed from property\n",
18380Sstevel@tonic-gate 				    oldone->pci_phys_hi);
18390Sstevel@tonic-gate 			}
18400Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
18410Sstevel@tonic-gate 			    dip, "assigned-addresses", (int *)assigned,
18420Sstevel@tonic-gate 			    (new_len/sizeof (int)));
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 			break;
18450Sstevel@tonic-gate 		}
18460Sstevel@tonic-gate 	}
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	return (0);
18490Sstevel@tonic-gate }
18500Sstevel@tonic-gate /*
18510Sstevel@tonic-gate  * we recognize the non transparent bridge child nodes with the
18520Sstevel@tonic-gate  * following property. This is specific to this implementation only.
18530Sstevel@tonic-gate  * This property is specific to AP nodes only.
18540Sstevel@tonic-gate  */
18550Sstevel@tonic-gate #define	PCICFG_DEV_CONF_MAP_PROP		"pci-parent-indirect"
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate /*
18580Sstevel@tonic-gate  * If a non transparent bridge drives a hotplug/hotswap bus, then
18590Sstevel@tonic-gate  * the following property must be defined for the node either by
18600Sstevel@tonic-gate  * the driver or the OBP.
18610Sstevel@tonic-gate  */
18620Sstevel@tonic-gate #define	PCICFG_BUS_CONF_MAP_PROP		"pci-conf-indirect"
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate /*
18650Sstevel@tonic-gate  * this function is called only for SPARC platforms, where we may have
18660Sstevel@tonic-gate  * a mix n' match of direct vs indirectly mapped configuration space.
18670Sstevel@tonic-gate  */
18680Sstevel@tonic-gate /*ARGSUSED*/
18690Sstevel@tonic-gate static int
18700Sstevel@tonic-gate fcpci_indirect_map(dev_info_t *dip)
18710Sstevel@tonic-gate {
18720Sstevel@tonic-gate 	int rc = DDI_FAILURE;
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS,
18750Sstevel@tonic-gate 			PCICFG_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
18760Sstevel@tonic-gate 		rc = DDI_SUCCESS;
18770Sstevel@tonic-gate 	else
18780Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
18790Sstevel@tonic-gate 				DDI_PROP_DONTPASS, PCICFG_BUS_CONF_MAP_PROP,
18800Sstevel@tonic-gate 				DDI_FAILURE) != DDI_FAILURE)
18810Sstevel@tonic-gate 			rc = DDI_SUCCESS;
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	return (rc);
18840Sstevel@tonic-gate }
1885