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