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