xref: /onnv-gate/usr/src/uts/sun4/io/efcode/fcpci.c (revision 11584:c37f0e59295e)
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*11584SZachary.Kissel@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * fcpci.c: Framework PCI fcode ops
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/pci.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/sunndi.h>
370Sstevel@tonic-gate #include <sys/ddidmareq.h>
380Sstevel@tonic-gate #include <sys/pci.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
410Sstevel@tonic-gate #include <sys/fcode.h>
420Sstevel@tonic-gate #include <sys/promif.h>
430Sstevel@tonic-gate #include <sys/promimpl.h>
441106Smrj #include <sys/ddi_implfuncs.h>
450Sstevel@tonic-gate 
463743Saa72041 #define	PCI_NPT_bits		(PCI_RELOCAT_B | PCI_PREFETCH_B | PCI_ALIAS_B)
473743Saa72041 #define	PCI_BDF_bits		(PCI_REG_BDFR_M & ~PCI_REG_REG_M)
483743Saa72041 
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 = {
1127799SRichard.Bean@Sun.COM 	&mod_miscops, "FCode pci bus functions"
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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
pci_fc_ops_alloc_handle(dev_info_t * ap,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,struct pci_ops_bus_args * up)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
pci_fc_ops_free_handle(fco_handle_t rp)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
pci_fc_ops(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_dma_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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",
364*11584SZachary.Kissel@Sun.COM 	    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
pfc_dma_sync(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_dma_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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 *
next_dma_resource(fco_handle_t rp)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
pfc_dma_cleanup(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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",
521*11584SZachary.Kissel@Sun.COM 		    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
pfc_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_register_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_register_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
pfc_config_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)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
8593743Saa72041 	 * ss must be zero.
8600Sstevel@tonic-gate 	 */
8613743Saa72041 	if ((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) {
8620Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_fetch: "
8630Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
8640Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
8650Sstevel@tonic-gate 	}
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * Extract the register number from the config address and
8690Sstevel@tonic-gate 	 * remove the register number from the physical address.
8700Sstevel@tonic-gate 	 */
8713743Saa72041 
8723743Saa72041 	reg = (p.pci_phys_hi & PCI_REG_REG_M) |
8733743Saa72041 	    (((p.pci_phys_hi & PCI_REG_EXTREG_M) >> PCI_REG_EXTREG_SHIFT) << 8);
8743743Saa72041 
8753743Saa72041 	p.pci_phys_hi &= PCI_BDF_bits;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	/*
8780Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 9th
8790Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	switch (*(name + 7)) {
8820Sstevel@tonic-gate 	case 'l':	len = sizeof (l); break;
8830Sstevel@tonic-gate 	case 'w':	len = sizeof (w); break;
8840Sstevel@tonic-gate 	case 'b':	len = sizeof (b); break;
8850Sstevel@tonic-gate 	}
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	/*
8880Sstevel@tonic-gate 	 * Verify that the access is properly aligned
8890Sstevel@tonic-gate 	 */
8900Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
8910Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	/*
8940Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
8950Sstevel@tonic-gate 	 */
8960Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
8970Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
8980Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (error)  {
9030Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
9070Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
9100Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
9110Sstevel@tonic-gate 		error = DDI_SUCCESS;
9120Sstevel@tonic-gate 	} else
9130Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
9140Sstevel@tonic-gate 
9150Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
9160Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
9170Sstevel@tonic-gate 			error = DDI_FAILURE;
9180Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpcii: conf probe failed.l=%x", tmp);
9190Sstevel@tonic-gate 		}
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
9220Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config fetch failed"));
9230Sstevel@tonic-gate 	}
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	/*
9270Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
9280Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
9290Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
9300Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
9310Sstevel@tonic-gate 	 */
9320Sstevel@tonic-gate 	v = virt + reg;
9330Sstevel@tonic-gate 	switch (len) {
9340Sstevel@tonic-gate 	case sizeof (l):
9350Sstevel@tonic-gate 		l = (int32_t)ddi_get32(h, (uint32_t *)v);
9360Sstevel@tonic-gate 		break;
9370Sstevel@tonic-gate 	case sizeof (w):
9380Sstevel@tonic-gate 		w = (int16_t)ddi_get16(h, (uint16_t *)v);
9390Sstevel@tonic-gate 		break;
9400Sstevel@tonic-gate 	case sizeof (b):
9410Sstevel@tonic-gate 		b = (int8_t)ddi_get8(h, (uint8_t *)v);
9420Sstevel@tonic-gate 		break;
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	/*
9460Sstevel@tonic-gate 	 * Remove the temporary config space mapping
9470Sstevel@tonic-gate 	 */
9480Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	if (error) {
9510Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
9550Sstevel@tonic-gate 	switch (len) {
9560Sstevel@tonic-gate 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
9570Sstevel@tonic-gate 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
9580Sstevel@tonic-gate 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate static int
pfc_config_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)9650Sstevel@tonic-gate pfc_config_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 	caddr_t virt, v;
9680Sstevel@tonic-gate 	int error, reg, flags = 0;
9690Sstevel@tonic-gate 	size_t len;
9700Sstevel@tonic-gate 	uint32_t l, tmp;
9710Sstevel@tonic-gate 	uint16_t w;
9720Sstevel@tonic-gate 	uint8_t b;
9730Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
9740Sstevel@tonic-gate 	pci_regspec_t p;
9750Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
9760Sstevel@tonic-gate 	ddi_acc_handle_t h;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
9790Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	/*
9820Sstevel@tonic-gate 	 * Construct a config address pci reg property from the args.
9830Sstevel@tonic-gate 	 * arg[0] is the configuration address. arg[1] is the data.
9840Sstevel@tonic-gate 	 */
9850Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0));
9860Sstevel@tonic-gate 	p.pci_phys_mid = p.pci_phys_low = 0;
9870Sstevel@tonic-gate 	p.pci_size_hi = p.pci_size_low = 0;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	/*
9900Sstevel@tonic-gate 	 * Verify that the address is a configuration space address
9913743Saa72041 	 * ss must be zero.
9920Sstevel@tonic-gate 	 */
9933743Saa72041 	if ((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) {
9940Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_store: "
9950Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
9960Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	/*
10000Sstevel@tonic-gate 	 * Extract the register number from the config address and
10010Sstevel@tonic-gate 	 * remove the register number from the physical address.
10020Sstevel@tonic-gate 	 */
10033743Saa72041 	reg = (p.pci_phys_hi & PCI_REG_REG_M) |
10043743Saa72041 	    (((p.pci_phys_hi & PCI_REG_EXTREG_M) >> PCI_REG_EXTREG_SHIFT) << 8);
10053743Saa72041 
10063743Saa72041 	p.pci_phys_hi &= PCI_BDF_bits;
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	/*
10090Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 8th
10100Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
10110Sstevel@tonic-gate 	 */
10120Sstevel@tonic-gate 	switch (*(name + 7)) {
10130Sstevel@tonic-gate 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
10140Sstevel@tonic-gate 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
10150Sstevel@tonic-gate 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	/*
10190Sstevel@tonic-gate 	 * Verify that the access is properly aligned
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
10220Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	/*
10250Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
10260Sstevel@tonic-gate 	 */
10270Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
10280Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
10290Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	if (error)  {
10340Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
10350Sstevel@tonic-gate 	}
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
10380Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
10410Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
10420Sstevel@tonic-gate 		error = DDI_SUCCESS;
10430Sstevel@tonic-gate 	} else
10440Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
10470Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
10480Sstevel@tonic-gate 			error = DDI_FAILURE;
10490Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpci: conf probe failed.l=%x", tmp);
10500Sstevel@tonic-gate 		}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
10530Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config store failed"));
10540Sstevel@tonic-gate 	}
10550Sstevel@tonic-gate 
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	/*
10580Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
10590Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
10600Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
10610Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
10620Sstevel@tonic-gate 	 */
10630Sstevel@tonic-gate 	v = virt + reg;
10640Sstevel@tonic-gate 	switch (len) {
10650Sstevel@tonic-gate 	case sizeof (l):
10660Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, (uint32_t)l);
10670Sstevel@tonic-gate 		break;
10680Sstevel@tonic-gate 	case sizeof (w):
10690Sstevel@tonic-gate 		ddi_put16(h, (uint16_t *)v, (uint16_t)w);
10700Sstevel@tonic-gate 		break;
10710Sstevel@tonic-gate 	case sizeof (b):
10720Sstevel@tonic-gate 		ddi_put8(h, (uint8_t *)v, (uint8_t)b);
10730Sstevel@tonic-gate 		break;
10740Sstevel@tonic-gate 	}
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	/*
10770Sstevel@tonic-gate 	 * Remove the temporary config space mapping
10780Sstevel@tonic-gate 	 */
10790Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	if (error) {
10820Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
10830Sstevel@tonic-gate 	}
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
10860Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate static int
pfc_get_fcode(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)10910Sstevel@tonic-gate pfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
10920Sstevel@tonic-gate {
10930Sstevel@tonic-gate 	caddr_t name_virt, fcode_virt;
10940Sstevel@tonic-gate 	char *name, *fcode;
10950Sstevel@tonic-gate 	int fcode_len, status;
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
10980Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
11010Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	name_virt = fc_cell2ptr(fc_arg(cp, 0));
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	fcode_len = fc_cell2int(fc_arg(cp, 2));
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(name_virt), name,
11120Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
11130Sstevel@tonic-gate 		status = 0;
11140Sstevel@tonic-gate 	} else {
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 		if ((status = prom_get_fcode(name, fcode)) != 0) {
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 			if (copyout((void *)fcode, (void *)fcode_virt,
11210Sstevel@tonic-gate 			    fcode_len)) {
11220Sstevel@tonic-gate 				cmn_err(CE_WARN, " pfc_get_fcode: Unable "
11230Sstevel@tonic-gate 				    "to copy out fcode image\n");
11240Sstevel@tonic-gate 				status = 0;
11250Sstevel@tonic-gate 			}
11260Sstevel@tonic-gate 		}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 		kmem_free(fcode, fcode_len);
11290Sstevel@tonic-gate 	}
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
11340Sstevel@tonic-gate 	fc_result(cp, 0) = status;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate static int
pfc_get_fcode_size(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)11400Sstevel@tonic-gate pfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11410Sstevel@tonic-gate {
11420Sstevel@tonic-gate 	caddr_t virt;
11430Sstevel@tonic-gate 	char *name;
11440Sstevel@tonic-gate 	int len;
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
11470Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
11500Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(virt), name,
11570Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
11580Sstevel@tonic-gate 		len = 0;
11590Sstevel@tonic-gate 	} else {
11600Sstevel@tonic-gate 		len = prom_get_fcode_size(name);
11610Sstevel@tonic-gate 	}
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
11660Sstevel@tonic-gate 	fc_result(cp, 0) = len;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate  * Return the physical probe address: lo=0, mid=0, hi-config-addr
11730Sstevel@tonic-gate  */
11740Sstevel@tonic-gate static int
pfc_probe_address(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)11750Sstevel@tonic-gate pfc_probe_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
11780Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 2)
11810Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 3"));
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	cp->nresults = fc_int2cell(2);
11840Sstevel@tonic-gate 	fc_result(cp, 1) = fc_int2cell(0);	/* phys.lo */
11850Sstevel@tonic-gate 	fc_result(cp, 0) = fc_int2cell(0);	/* phys.mid */
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate /*
11910Sstevel@tonic-gate  * Return the phys.hi component of the probe address.
11920Sstevel@tonic-gate  */
11930Sstevel@tonic-gate static int
pfc_probe_space(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)11940Sstevel@tonic-gate pfc_probe_space(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
11950Sstevel@tonic-gate {
11960Sstevel@tonic-gate 	struct pci_ops_bus_args *ba = rp->bus_args;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	ASSERT(ba);
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
12010Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
12040Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
12070Sstevel@tonic-gate 	fc_result(cp, 0) = fc_uint32_t2cell(ba->config_address); /* phys.hi */
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
12100Sstevel@tonic-gate }
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate static int
pfc_config_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)12130Sstevel@tonic-gate pfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	fc_phandle_t h;
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
12180Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
12210Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
12260Sstevel@tonic-gate 	fc_result(cp, 0) = fc_phandle2cell(h);
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate int
pci_alloc_mem_chunk(dev_info_t * dip,uint64_t mem_align,uint64_t * mem_size,uint64_t * mem_answer)12320Sstevel@tonic-gate pci_alloc_mem_chunk(dev_info_t *dip, uint64_t mem_align, uint64_t *mem_size,
12330Sstevel@tonic-gate     uint64_t *mem_answer)
12340Sstevel@tonic-gate {
12350Sstevel@tonic-gate 	ndi_ra_request_t req;
12360Sstevel@tonic-gate 	int rval;
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
12390Sstevel@tonic-gate 	req.ra_flags = NDI_RA_ALLOC_BOUNDED;
12400Sstevel@tonic-gate 	req.ra_boundbase = 0;
12410Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
12420Sstevel@tonic-gate 	req.ra_len = *mem_size;
12430Sstevel@tonic-gate 	req.ra_align_mask = mem_align - 1;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, mem_answer, mem_size,
12460Sstevel@tonic-gate 	    NDI_RA_TYPE_MEM, NDI_RA_PASS);
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	return (rval);
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate int
pci_alloc_io_chunk(dev_info_t * dip,uint64_t io_align,uint64_t * io_size,uint64_t * io_answer)12510Sstevel@tonic-gate pci_alloc_io_chunk(dev_info_t *dip, uint64_t io_align, uint64_t *io_size,
12520Sstevel@tonic-gate     uint64_t *io_answer)
12530Sstevel@tonic-gate {
12540Sstevel@tonic-gate 	ndi_ra_request_t req;
12550Sstevel@tonic-gate 	int rval;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
12580Sstevel@tonic-gate 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
12590Sstevel@tonic-gate 	req.ra_boundbase = 0;
12600Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
12610Sstevel@tonic-gate 	req.ra_len = *io_size;
12620Sstevel@tonic-gate 	req.ra_align_mask = io_align - 1;
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, io_answer, io_size,
12650Sstevel@tonic-gate 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	return (rval);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate int
pci_alloc_resource(dev_info_t * dip,pci_regspec_t phys_spec)12710Sstevel@tonic-gate pci_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate 	uint64_t answer;
12740Sstevel@tonic-gate 	uint64_t alen;
12750Sstevel@tonic-gate 	int offset, tmp;
12760Sstevel@tonic-gate 	pci_regspec_t config;
12770Sstevel@tonic-gate 	caddr_t virt, v;
12780Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
12790Sstevel@tonic-gate 	ddi_acc_handle_t h;
12800Sstevel@tonic-gate 	ndi_ra_request_t request;
12810Sstevel@tonic-gate 	pci_regspec_t *assigned;
12820Sstevel@tonic-gate 	int assigned_len, entries, i, l, flags = 0, error;
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
12870Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
12880Sstevel@tonic-gate 	    &assigned_len) == DDI_PROP_SUCCESS) {
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 		entries = assigned_len / (sizeof (pci_regspec_t));
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		/*
12930Sstevel@tonic-gate 		 * Walk through the assigned-addresses entries. If there is
12940Sstevel@tonic-gate 		 * a match, there is no need to allocate the resource.
12950Sstevel@tonic-gate 		 */
12960Sstevel@tonic-gate 		for (i = 0; i < entries; i++) {
12970Sstevel@tonic-gate 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
12980Sstevel@tonic-gate 				if (assigned[i].pci_size_low >=
12990Sstevel@tonic-gate 				    phys_spec.pci_size_low) {
13000Sstevel@tonic-gate 					kmem_free(assigned, assigned_len);
13010Sstevel@tonic-gate 					return (0);
13020Sstevel@tonic-gate 				}
13030Sstevel@tonic-gate 				/*
13040Sstevel@tonic-gate 				 * Fcode wants to assign more than what
13050Sstevel@tonic-gate 				 * probe found.
13060Sstevel@tonic-gate 				 */
13070Sstevel@tonic-gate 				(void) pci_free_resource(dip, assigned[i]);
13080Sstevel@tonic-gate 				/*
13090Sstevel@tonic-gate 				 * Go on to allocate resources.
13100Sstevel@tonic-gate 				 */
13110Sstevel@tonic-gate 				break;
13120Sstevel@tonic-gate 			}
13130Sstevel@tonic-gate 			/*
13140Sstevel@tonic-gate 			 * Check if Fcode wants to map using different
13150Sstevel@tonic-gate 			 * NPT bits.
13160Sstevel@tonic-gate 			 */
13170Sstevel@tonic-gate 			if (PCI_REG_BDFR_G(assigned[i].pci_phys_hi) ==
13180Sstevel@tonic-gate 			    PCI_REG_BDFR_G(phys_spec.pci_phys_hi)) {
13190Sstevel@tonic-gate 				/*
13200Sstevel@tonic-gate 				 * It is an error to change SS bits
13210Sstevel@tonic-gate 				 */
13220Sstevel@tonic-gate 				if (PCI_REG_ADDR_G(assigned[i].pci_phys_hi) !=
13230Sstevel@tonic-gate 				    PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
13240Sstevel@tonic-gate 
13251983Sjj156685 					FC_DEBUG2(2, CE_WARN, "Fcode changing "
13261983Sjj156685 					    "ss bits in reg %x -- %x",
13270Sstevel@tonic-gate 					    assigned[i].pci_phys_hi,
13280Sstevel@tonic-gate 					    phys_spec.pci_phys_hi);
13290Sstevel@tonic-gate 				}
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 				/*
13320Sstevel@tonic-gate 				 * Allocate enough
13330Sstevel@tonic-gate 				 */
13340Sstevel@tonic-gate 				l = MAX(assigned[i].pci_size_low,
13350Sstevel@tonic-gate 				    phys_spec.pci_size_low);
13360Sstevel@tonic-gate 
13379556SZhijun.Fu@Sun.COM 				phys_spec.pci_size_low = l;
13389556SZhijun.Fu@Sun.COM 
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),
1400*11584SZachary.Kissel@Sun.COM 		    &request, &answer, &alen, NDI_RA_TYPE_MEM,
1401*11584SZachary.Kissel@Sun.COM 		    NDI_RA_PASS) != NDI_SUCCESS) {
14020Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
14030Sstevel@tonic-gate 			return (1);
14040Sstevel@tonic-gate 		}
14050Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "ROM addr = [0x%x.%x] len [0x%x]\n",
1406*11584SZachary.Kissel@Sun.COM 		    HIADDR(answer), LOADDR(answer), alen);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 		/* program the low word */
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, LOADDR(answer));
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 		phys_spec.pci_phys_low = LOADDR(answer);
14130Sstevel@tonic-gate 		phys_spec.pci_phys_mid = HIADDR(answer);
14140Sstevel@tonic-gate 	} else {
14150Sstevel@tonic-gate 		request.ra_len = l;
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
14180Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
14190Sstevel@tonic-gate 			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
14220Sstevel@tonic-gate 				/*
14230Sstevel@tonic-gate 				 * If it is a non relocatable address,
14240Sstevel@tonic-gate 				 * then specify the address we want.
14250Sstevel@tonic-gate 				 */
14260Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
14270Sstevel@tonic-gate 				request.ra_addr = (uint64_t)LADDR(
14280Sstevel@tonic-gate 				    phys_spec.pci_phys_low,
14290Sstevel@tonic-gate 				    phys_spec.pci_phys_mid);
14300Sstevel@tonic-gate 			}
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 			/* allocate memory space from the allocator */
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
1435*11584SZachary.Kissel@Sun.COM 			    &request, &answer, &alen, NDI_RA_TYPE_MEM,
1436*11584SZachary.Kissel@Sun.COM 			    NDI_RA_PASS) != NDI_SUCCESS) {
14370Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1438*11584SZachary.Kissel@Sun.COM 				if (request.ra_flags == 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);
14601983Sjj156685 			/*
14611983Sjj156685 			 * currently support 32b address space
14621983Sjj156685 			 * assignments only.
14631983Sjj156685 			 */
14641983Sjj156685 			phys_spec.pci_phys_hi ^= PCI_ADDR_MEM64 ^
1465*11584SZachary.Kissel@Sun.COM 			    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),
1485*11584SZachary.Kissel@Sun.COM 			    &request, &answer, &alen, NDI_RA_TYPE_MEM,
1486*11584SZachary.Kissel@Sun.COM 			    NDI_RA_PASS) != NDI_SUCCESS) {
14870Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1488*11584SZachary.Kissel@Sun.COM 				if (request.ra_flags == NDI_RA_ALLOC_SPECIFIED)
14890Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
14900Sstevel@tonic-gate 					    "non relocatable address 0x%p\n",
14910Sstevel@tonic-gate 					    (void *) request.ra_addr);
14920Sstevel@tonic-gate 				return (1);
14930Sstevel@tonic-gate 			}
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
14960Sstevel@tonic-gate 			    "32 addr = [0x%x.%x] len [0x%x]\n",
14970Sstevel@tonic-gate 			    HIADDR(answer),
14980Sstevel@tonic-gate 			    LOADDR(answer),
14990Sstevel@tonic-gate 			    alen);
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 			/* program the low word */
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 			break;
15080Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
15090Sstevel@tonic-gate 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
15120Sstevel@tonic-gate 				/*
15130Sstevel@tonic-gate 				 * If it is a non relocatable address,
15140Sstevel@tonic-gate 				 * then specify the address we want.
15150Sstevel@tonic-gate 				 */
15160Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
15170Sstevel@tonic-gate 				request.ra_addr = (uint64_t)
15180Sstevel@tonic-gate 				    phys_spec.pci_phys_low;
15190Sstevel@tonic-gate 			}
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 			/* allocate I/O space from the allocator */
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
1524*11584SZachary.Kissel@Sun.COM 			    &request, &answer, &alen, NDI_RA_TYPE_IO,
1525*11584SZachary.Kissel@Sun.COM 			    NDI_RA_PASS) != NDI_SUCCESS) {
15260Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
15270Sstevel@tonic-gate 				if (request.ra_flags ==
15280Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
15290Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
15300Sstevel@tonic-gate 					    "non relocatable IO Space 0x%p\n",
15310Sstevel@tonic-gate 					    (void *) request.ra_addr);
15320Sstevel@tonic-gate 				return (1);
15330Sstevel@tonic-gate 			}
15340Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
15350Sstevel@tonic-gate 			    "I/O addr = [0x%x.%x] len [0x%x]\n",
15360Sstevel@tonic-gate 			    HIADDR(answer),
15370Sstevel@tonic-gate 			    LOADDR(answer),
15380Sstevel@tonic-gate 			    alen);
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 			break;
15450Sstevel@tonic-gate 		default:
15460Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
15470Sstevel@tonic-gate 			return (1);
15480Sstevel@tonic-gate 		} /* switch */
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	/*
15520Sstevel@tonic-gate 	 * Now that memory locations are assigned,
15530Sstevel@tonic-gate 	 * update the assigned address property.
15540Sstevel@tonic-gate 	 */
15550Sstevel@tonic-gate 	if (pfc_update_assigned_prop(dip, &phys_spec)) {
15560Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
15570Sstevel@tonic-gate 		return (1);
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 	return (0);
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate int
pci_free_resource(dev_info_t * dip,pci_regspec_t phys_spec)15660Sstevel@tonic-gate pci_free_resource(dev_info_t *dip, pci_regspec_t phys_spec)
15670Sstevel@tonic-gate {
15680Sstevel@tonic-gate 	int offset, tmp;
15690Sstevel@tonic-gate 	pci_regspec_t config;
15700Sstevel@tonic-gate 	caddr_t virt, v;
15710Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
15720Sstevel@tonic-gate 	ddi_acc_handle_t h;
15730Sstevel@tonic-gate 	ndi_ra_request_t request;
15740Sstevel@tonic-gate 	int l, error, flags = 0;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
15790Sstevel@tonic-gate 	config.pci_phys_hi &= ~PCI_REG_REG_M;
15800Sstevel@tonic-gate 	config.pci_phys_mid = config.pci_phys_low = 0;
15810Sstevel@tonic-gate 	config.pci_size_hi = config.pci_size_low = 0;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	/*
15840Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
15850Sstevel@tonic-gate 	 */
15860Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
15870Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
15880Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) {
15910Sstevel@tonic-gate 		return (1);
15920Sstevel@tonic-gate 	}
15930Sstevel@tonic-gate 	if (fcpci_indirect_map(dip) == DDI_SUCCESS)
15940Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
15970Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
15980Sstevel@tonic-gate 		error = DDI_SUCCESS;
15990Sstevel@tonic-gate 	} else
16000Sstevel@tonic-gate 		error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp);
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
16030Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
16040Sstevel@tonic-gate 			error = DDI_FAILURE;
16050Sstevel@tonic-gate 		}
16060Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
16070Sstevel@tonic-gate 		return (1);
16080Sstevel@tonic-gate 	}
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	v = virt + offset;
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	/*
16160Sstevel@tonic-gate 	 * Pick up the size to be freed. It may be different from
16170Sstevel@tonic-gate 	 * what probe finds.
16180Sstevel@tonic-gate 	 */
16190Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
16220Sstevel@tonic-gate 		/* free memory back to the allocator */
16230Sstevel@tonic-gate 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
16240Sstevel@tonic-gate 		    l, NDI_RA_TYPE_MEM,
16250Sstevel@tonic-gate 		    NDI_RA_PASS) != NDI_SUCCESS) {
16260Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
16270Sstevel@tonic-gate 			return (1);
16280Sstevel@tonic-gate 		}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 		/* Unmap the BAR by writing a zero */
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, 0);
16330Sstevel@tonic-gate 	} else {
16340Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
16350Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
16360Sstevel@tonic-gate 			/* free memory back to the allocator */
16370Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16380Sstevel@tonic-gate 			    LADDR(phys_spec.pci_phys_low,
16390Sstevel@tonic-gate 			    phys_spec.pci_phys_mid),
16400Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
16410Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16420Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16430Sstevel@tonic-gate 				return (1);
16440Sstevel@tonic-gate 			}
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 			break;
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
16490Sstevel@tonic-gate 			/* free memory back to the allocator */
16500Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16510Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
16520Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
16530Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16540Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16550Sstevel@tonic-gate 				return (1);
16560Sstevel@tonic-gate 			}
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 			break;
16590Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
16600Sstevel@tonic-gate 			/* free I/O space back to the allocator */
16610Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
16620Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
16630Sstevel@tonic-gate 			    l, NDI_RA_TYPE_IO,
16640Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
16650Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
16660Sstevel@tonic-gate 				return (1);
16670Sstevel@tonic-gate 			}
16680Sstevel@tonic-gate 			break;
16690Sstevel@tonic-gate 		default:
16700Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
16710Sstevel@tonic-gate 			return (1);
16720Sstevel@tonic-gate 		} /* switch */
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	/*
16760Sstevel@tonic-gate 	 * Now that memory locations are assigned,
16770Sstevel@tonic-gate 	 * update the assigned address property.
16780Sstevel@tonic-gate 	 */
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	FC_DEBUG1(1, CE_CONT, "updating assigned-addresss for %x\n",
16810Sstevel@tonic-gate 	    phys_spec.pci_phys_hi);
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	if (pfc_remove_assigned_prop(dip, &phys_spec)) {
16840Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
16850Sstevel@tonic-gate 		return (1);
16860Sstevel@tonic-gate 	}
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	return (0);
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate int
pci_map_phys(dev_info_t * dip,pci_regspec_t * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)16950Sstevel@tonic-gate pci_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
16960Sstevel@tonic-gate 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
16970Sstevel@tonic-gate 	ddi_acc_handle_t *handlep)
16980Sstevel@tonic-gate {
16990Sstevel@tonic-gate 	ddi_map_req_t mr;
17000Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
17010Sstevel@tonic-gate 	int result;
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
17040Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
17050Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
17060Sstevel@tonic-gate 	hp->ah_dip = dip;
17070Sstevel@tonic-gate 	hp->ah_rnumber = 0;
17080Sstevel@tonic-gate 	hp->ah_offset = 0;
17090Sstevel@tonic-gate 	hp->ah_len = 0;
17100Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
17130Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
17140Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)phys_spec;
17150Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
17160Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
17170Sstevel@tonic-gate 	mr.map_handlep = hp;
17180Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	result = ddi_map(dip, &mr, 0, 0, addrp);
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
17230Sstevel@tonic-gate 		impl_acc_hdl_free(*handlep);
17240Sstevel@tonic-gate 		*handlep = (ddi_acc_handle_t)NULL;
17250Sstevel@tonic-gate 	} else {
17260Sstevel@tonic-gate 		hp->ah_addr = *addrp;
17270Sstevel@tonic-gate 	}
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	return (result);
17300Sstevel@tonic-gate }
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate void
pci_unmap_phys(ddi_acc_handle_t * handlep,pci_regspec_t * ph)17330Sstevel@tonic-gate pci_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
17340Sstevel@tonic-gate {
17350Sstevel@tonic-gate 	ddi_map_req_t mr;
17360Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
17390Sstevel@tonic-gate 	ASSERT(hp);
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
17420Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
17430Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)ph;
17440Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
17450Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
17460Sstevel@tonic-gate 	mr.map_handlep = hp;
17470Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
1750*11584SZachary.Kissel@Sun.COM 	    hp->ah_len, &hp->ah_addr);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
17560Sstevel@tonic-gate }
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate int
pfc_update_assigned_prop(dev_info_t * dip,pci_regspec_t * newone)17590Sstevel@tonic-gate pfc_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
17600Sstevel@tonic-gate {
17610Sstevel@tonic-gate 	int		alen;
17620Sstevel@tonic-gate 	pci_regspec_t	*assigned;
17630Sstevel@tonic-gate 	caddr_t		newreg;
17640Sstevel@tonic-gate 	uint_t		status;
17650Sstevel@tonic-gate 
1766506Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1767*11584SZachary.Kissel@Sun.COM 	    "assigned-addresses", (caddr_t)&assigned, &alen);
17680Sstevel@tonic-gate 	switch (status) {
17690Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
17700Sstevel@tonic-gate 		break;
17710Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
17720Sstevel@tonic-gate 			return (1);
17730Sstevel@tonic-gate 		default:
17740Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1775*11584SZachary.Kissel@Sun.COM 			    "assigned-addresses", (int *)newone,
1776*11584SZachary.Kissel@Sun.COM 			    sizeof (*newone)/sizeof (int));
17770Sstevel@tonic-gate 			return (0);
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	/*
17810Sstevel@tonic-gate 	 * Allocate memory for the existing
17820Sstevel@tonic-gate 	 * assigned-addresses(s) plus one and then
17830Sstevel@tonic-gate 	 * build it.
17840Sstevel@tonic-gate 	 */
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	bcopy(assigned, newreg, alen);
17890Sstevel@tonic-gate 	bcopy(newone, newreg + alen, sizeof (*newone));
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	/*
17920Sstevel@tonic-gate 	 * Write out the new "assigned-addresses" spec
17930Sstevel@tonic-gate 	 */
17940Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1795*11584SZachary.Kissel@Sun.COM 	    "assigned-addresses", (int *)newreg,
1796*11584SZachary.Kissel@Sun.COM 	    (alen + sizeof (*newone))/sizeof (int));
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
1799*11584SZachary.Kissel@Sun.COM 	kmem_free(assigned, alen);
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	return (0);
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate int
pfc_remove_assigned_prop(dev_info_t * dip,pci_regspec_t * oldone)18040Sstevel@tonic-gate pfc_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
18050Sstevel@tonic-gate {
18060Sstevel@tonic-gate 	int		alen, new_len, num_entries, i;
18070Sstevel@tonic-gate 	pci_regspec_t	*assigned;
18080Sstevel@tonic-gate 	uint_t		status;
18090Sstevel@tonic-gate 
1810506Scth 	status = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1811*11584SZachary.Kissel@Sun.COM 	    "assigned-addresses", (caddr_t)&assigned, &alen);
18120Sstevel@tonic-gate 	switch (status) {
18130Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
18140Sstevel@tonic-gate 		break;
18150Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
18160Sstevel@tonic-gate 			return (1);
18170Sstevel@tonic-gate 		default:
18180Sstevel@tonic-gate 			return (0);
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	num_entries = alen / sizeof (pci_regspec_t);
18220Sstevel@tonic-gate 	new_len = alen - sizeof (pci_regspec_t);
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	/*
18250Sstevel@tonic-gate 	 * Search for the memory being removed.
18260Sstevel@tonic-gate 	 */
18270Sstevel@tonic-gate 	for (i = 0; i < num_entries; i++) {
18280Sstevel@tonic-gate 		if (assigned[i].pci_phys_hi == oldone->pci_phys_hi) {
18290Sstevel@tonic-gate 			if (new_len == 0) {
18300Sstevel@tonic-gate 				(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
18310Sstevel@tonic-gate 				    "assigned-addresses");
18320Sstevel@tonic-gate 				break;
18330Sstevel@tonic-gate 			}
18340Sstevel@tonic-gate 			if ((new_len - (i * sizeof (pci_regspec_t)))
18350Sstevel@tonic-gate 			    == 0) {
18360Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
18370Sstevel@tonic-gate 				    "%x removed from property (last entry)\n",
18380Sstevel@tonic-gate 				    oldone->pci_phys_hi);
18390Sstevel@tonic-gate 			} else {
18400Sstevel@tonic-gate 				bcopy((void *)(assigned + i + 1),
18410Sstevel@tonic-gate 				    (void *)(assigned + i),
18420Sstevel@tonic-gate 				    (new_len - (i * sizeof (pci_regspec_t))));
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
18450Sstevel@tonic-gate 				    "%x removed from property\n",
18460Sstevel@tonic-gate 				    oldone->pci_phys_hi);
18470Sstevel@tonic-gate 			}
18480Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
18490Sstevel@tonic-gate 			    dip, "assigned-addresses", (int *)assigned,
18500Sstevel@tonic-gate 			    (new_len/sizeof (int)));
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 			break;
18530Sstevel@tonic-gate 		}
18540Sstevel@tonic-gate 	}
18550Sstevel@tonic-gate 
1856*11584SZachary.Kissel@Sun.COM 	kmem_free(assigned, alen);
1857*11584SZachary.Kissel@Sun.COM 
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
fcpci_indirect_map(dev_info_t * dip)18800Sstevel@tonic-gate fcpci_indirect_map(dev_info_t *dip)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	int rc = DDI_FAILURE;
18830Sstevel@tonic-gate 
18841983Sjj156685 	if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), 0,
1885*11584SZachary.Kissel@Sun.COM 	    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*11584SZachary.Kissel@Sun.COM 		    0, PCICFG_BUS_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
18900Sstevel@tonic-gate 			rc = DDI_SUCCESS;
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	return (rc);
18930Sstevel@tonic-gate }
1894