1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2000-2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * fcpci.c: Framework PCI fcode ops
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/kmem.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>
35*0Sstevel@tonic-gate #include <sys/pci.h>
36*0Sstevel@tonic-gate #include <sys/ddi.h>
37*0Sstevel@tonic-gate #include <sys/sunddi.h>
38*0Sstevel@tonic-gate #include <sys/sunndi.h>
39*0Sstevel@tonic-gate #include <sys/ddidmareq.h>
40*0Sstevel@tonic-gate #include <sys/pci.h>
41*0Sstevel@tonic-gate #include <sys/modctl.h>
42*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h>
43*0Sstevel@tonic-gate #include <sys/fcode.h>
44*0Sstevel@tonic-gate #include <sys/promif.h>
45*0Sstevel@tonic-gate #include <sys/promimpl.h>
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate #define	PCI_NPT_bits	(PCI_RELOCAT_B | PCI_PREFETCH_B | PCI_ALIAS_B)
48*0Sstevel@tonic-gate #define	PCICFG_CONF_INDIRECT_MAP	1
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static int pfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
51*0Sstevel@tonic-gate static int pfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
52*0Sstevel@tonic-gate static int pfc_dma_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
53*0Sstevel@tonic-gate static int pfc_dma_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
54*0Sstevel@tonic-gate static int pfc_dma_sync(dev_info_t *, fco_handle_t, fc_ci_t *);
55*0Sstevel@tonic-gate static int pfc_dma_cleanup(dev_info_t *, fco_handle_t, fc_ci_t *);
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate static int pfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
58*0Sstevel@tonic-gate static int pfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
59*0Sstevel@tonic-gate static int pfc_config_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
60*0Sstevel@tonic-gate static int pfc_config_store(dev_info_t *, fco_handle_t, fc_ci_t *);
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate static int pfc_probe_address(dev_info_t *, fco_handle_t, fc_ci_t *);
63*0Sstevel@tonic-gate static int pfc_probe_space(dev_info_t *, fco_handle_t, fc_ci_t *);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate static int pfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
66*0Sstevel@tonic-gate static int pfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
67*0Sstevel@tonic-gate static int pfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
68*0Sstevel@tonic-gate int prom_get_fcode_size(char *);
69*0Sstevel@tonic-gate int prom_get_fcode(char *, char *);
70*0Sstevel@tonic-gate int pfc_update_assigned_prop(dev_info_t *, pci_regspec_t *);
71*0Sstevel@tonic-gate int pfc_remove_assigned_prop(dev_info_t *, pci_regspec_t *);
72*0Sstevel@tonic-gate int pci_alloc_resource(dev_info_t *, pci_regspec_t);
73*0Sstevel@tonic-gate int pci_free_resource(dev_info_t *, pci_regspec_t);
74*0Sstevel@tonic-gate int pci_alloc_mem_chunk(dev_info_t *,  uint64_t, uint64_t *,  uint64_t *);
75*0Sstevel@tonic-gate int pci_alloc_io_chunk(dev_info_t *,  uint64_t,  uint64_t *, uint64_t *);
76*0Sstevel@tonic-gate static int fcpci_indirect_map(dev_info_t *);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate int fcpci_unloadable;
79*0Sstevel@tonic-gate int no_advisory_dma;
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate #ifndef	lint
82*0Sstevel@tonic-gate static char _depends_on[] = "misc/fcodem misc/busra";
83*0Sstevel@tonic-gate #endif
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate #define	HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
86*0Sstevel@tonic-gate #define	LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
87*0Sstevel@tonic-gate #define	LADDR(lo, hi)    (((uint64_t)(hi) << 32) | (uint32_t)(lo))
88*0Sstevel@tonic-gate #define	PCI_4GIG_LIMIT 0xFFFFFFFFUL
89*0Sstevel@tonic-gate #define	PCI_MEMGRAN 0x100000
90*0Sstevel@tonic-gate #define	PCI_IOGRAN 0x1000
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate /*
94*0Sstevel@tonic-gate  * Module linkage information for the kernel.
95*0Sstevel@tonic-gate  */
96*0Sstevel@tonic-gate static struct modlmisc modlmisc = {
97*0Sstevel@tonic-gate 	&mod_miscops, "FCode pci bus functions %I%"
98*0Sstevel@tonic-gate };
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
101*0Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
102*0Sstevel@tonic-gate };
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate int
105*0Sstevel@tonic-gate _init(void)
106*0Sstevel@tonic-gate {
107*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
108*0Sstevel@tonic-gate }
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate int
111*0Sstevel@tonic-gate _fini(void)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	if (fcpci_unloadable)
114*0Sstevel@tonic-gate 		return (mod_remove(&modlinkage));
115*0Sstevel@tonic-gate 	return (EBUSY);
116*0Sstevel@tonic-gate }
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate int
119*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate struct pfc_ops_v {
126*0Sstevel@tonic-gate 	char *svc_name;
127*0Sstevel@tonic-gate 	fc_ops_t *f;
128*0Sstevel@tonic-gate };
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate static struct pfc_ops_v pov[] = {
131*0Sstevel@tonic-gate 	{	"map-in",		pfc_map_in},
132*0Sstevel@tonic-gate 	{	"map-out",		pfc_map_out},
133*0Sstevel@tonic-gate 	{	"dma-map-in",		pfc_dma_map_in},
134*0Sstevel@tonic-gate 	{	"dma-map-out",		pfc_dma_map_out},
135*0Sstevel@tonic-gate 	{	"dma-sync",		pfc_dma_sync},
136*0Sstevel@tonic-gate 	{	"rx@",			pfc_register_fetch},
137*0Sstevel@tonic-gate 	{	"rl@",			pfc_register_fetch},
138*0Sstevel@tonic-gate 	{	"rw@",			pfc_register_fetch},
139*0Sstevel@tonic-gate 	{	"rb@",			pfc_register_fetch},
140*0Sstevel@tonic-gate 	{	"rx!",			pfc_register_store},
141*0Sstevel@tonic-gate 	{	"rl!",			pfc_register_store},
142*0Sstevel@tonic-gate 	{	"rw!",			pfc_register_store},
143*0Sstevel@tonic-gate 	{	"rb!",			pfc_register_store},
144*0Sstevel@tonic-gate 	{	"config-l@",		pfc_config_fetch},
145*0Sstevel@tonic-gate 	{	"config-w@",		pfc_config_fetch},
146*0Sstevel@tonic-gate 	{	"config-b@",		pfc_config_fetch},
147*0Sstevel@tonic-gate 	{	"config-l!",		pfc_config_store},
148*0Sstevel@tonic-gate 	{	"config-w!",		pfc_config_store},
149*0Sstevel@tonic-gate 	{	"config-b!",		pfc_config_store},
150*0Sstevel@tonic-gate 	{	FC_PROBE_ADDRESS,	pfc_probe_address},
151*0Sstevel@tonic-gate 	{	FC_PROBE_SPACE,		pfc_probe_space},
152*0Sstevel@tonic-gate 	{	FC_SVC_EXIT,		pfc_dma_cleanup},
153*0Sstevel@tonic-gate 	{	FC_CONFIG_CHILD,	pfc_config_child},
154*0Sstevel@tonic-gate 	{	FC_GET_FCODE_SIZE,	pfc_get_fcode_size},
155*0Sstevel@tonic-gate 	{	FC_GET_FCODE,		pfc_get_fcode},
156*0Sstevel@tonic-gate 	{	NULL,			NULL}
157*0Sstevel@tonic-gate };
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate static struct pfc_ops_v shared_pov[] = {
160*0Sstevel@tonic-gate 	{	FC_SVC_EXIT,		pfc_dma_cleanup},
161*0Sstevel@tonic-gate 	{	NULL,			NULL}
162*0Sstevel@tonic-gate };
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate int pci_map_phys(dev_info_t *, pci_regspec_t *,
165*0Sstevel@tonic-gate     caddr_t *, ddi_device_acc_attr_t *, ddi_acc_handle_t *);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate void pci_unmap_phys(ddi_acc_handle_t *, pci_regspec_t *);
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate fco_handle_t
170*0Sstevel@tonic-gate pci_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
171*0Sstevel@tonic-gate     void *fcode, size_t fcode_size, char *unit_address,
172*0Sstevel@tonic-gate     struct pci_ops_bus_args *up)
173*0Sstevel@tonic-gate {
174*0Sstevel@tonic-gate 	fco_handle_t rp;
175*0Sstevel@tonic-gate 	struct pci_ops_bus_args *bp = NULL;
176*0Sstevel@tonic-gate 	phandle_t h;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
179*0Sstevel@tonic-gate 	rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size,
180*0Sstevel@tonic-gate 	    unit_address, NULL);
181*0Sstevel@tonic-gate 	rp->ap = ap;
182*0Sstevel@tonic-gate 	rp->child = child;
183*0Sstevel@tonic-gate 	rp->fcode = fcode;
184*0Sstevel@tonic-gate 	rp->fcode_size = fcode_size;
185*0Sstevel@tonic-gate 	if (unit_address) {
186*0Sstevel@tonic-gate 		char *buf;
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 		buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
189*0Sstevel@tonic-gate 		(void) strcpy(buf, unit_address);
190*0Sstevel@tonic-gate 		rp->unit_address = buf;
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	bp = kmem_zalloc(sizeof (struct pci_ops_bus_args), KM_SLEEP);
194*0Sstevel@tonic-gate 	*bp = *up;
195*0Sstevel@tonic-gate 	rp->bus_args = bp;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/*
198*0Sstevel@tonic-gate 	 * Add the child's nodeid to our table...
199*0Sstevel@tonic-gate 	 */
200*0Sstevel@tonic-gate 	h = ddi_get_nodeid(rp->child);
201*0Sstevel@tonic-gate 	fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	return (rp);
204*0Sstevel@tonic-gate }
205*0Sstevel@tonic-gate 
206*0Sstevel@tonic-gate void
207*0Sstevel@tonic-gate pci_fc_ops_free_handle(fco_handle_t rp)
208*0Sstevel@tonic-gate {
209*0Sstevel@tonic-gate 	struct pci_ops_bus_args *bp;
210*0Sstevel@tonic-gate 	struct fc_resource *ip, *np;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	ASSERT(rp);
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	if (rp->next_handle)
215*0Sstevel@tonic-gate 		fc_ops_free_handle(rp->next_handle);
216*0Sstevel@tonic-gate 	if (rp->unit_address)
217*0Sstevel@tonic-gate 		kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
218*0Sstevel@tonic-gate 	if ((bp = rp->bus_args) != NULL)
219*0Sstevel@tonic-gate 		kmem_free(bp, sizeof (struct pci_ops_bus_args));
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/*
222*0Sstevel@tonic-gate 	 * Release all the resources from the resource list
223*0Sstevel@tonic-gate 	 * XXX: We don't handle 'unknown' types, but we don't create them.
224*0Sstevel@tonic-gate 	 */
225*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = np) {
226*0Sstevel@tonic-gate 		np = ip->next;
227*0Sstevel@tonic-gate 		switch (ip->type) {
228*0Sstevel@tonic-gate 		case RT_MAP:
229*0Sstevel@tonic-gate 			FC_DEBUG1(1, CE_CONT, "pci_fc_ops_free: "
230*0Sstevel@tonic-gate 			    "pci_unmap_phys(%p)\n", ip->fc_map_handle);
231*0Sstevel@tonic-gate 			pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec);
232*0Sstevel@tonic-gate 			kmem_free(ip->fc_regspec, sizeof (pci_regspec_t));
233*0Sstevel@tonic-gate 			break;
234*0Sstevel@tonic-gate 		case RT_DMA:
235*0Sstevel@tonic-gate 			/* DMA has to be freed up at exit time */
236*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "pfc_fc_ops_free: DMA seen!\n");
237*0Sstevel@tonic-gate 			break;
238*0Sstevel@tonic-gate 		default:
239*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "pci_fc_ops_free: "
240*0Sstevel@tonic-gate 			    "unknown resource type %d\n", ip->type);
241*0Sstevel@tonic-gate 			break;
242*0Sstevel@tonic-gate 		}
243*0Sstevel@tonic-gate 		fc_rem_resource(rp, ip);
244*0Sstevel@tonic-gate 		kmem_free(ip, sizeof (struct fc_resource));
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 	kmem_free(rp, sizeof (struct fc_resource_list));
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate int
250*0Sstevel@tonic-gate pci_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	struct pfc_ops_v *pv;
253*0Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	ASSERT(rp);
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	/*
258*0Sstevel@tonic-gate 	 * First try the generic fc_ops. If the ops is a shared op,
259*0Sstevel@tonic-gate 	 * also call our local function.
260*0Sstevel@tonic-gate 	 */
261*0Sstevel@tonic-gate 	if (fc_ops(ap, rp->next_handle, cp) == 0) {
262*0Sstevel@tonic-gate 		for (pv = shared_pov; pv->svc_name != NULL; ++pv)
263*0Sstevel@tonic-gate 			if (strcmp(pv->svc_name, name) == 0)
264*0Sstevel@tonic-gate 				return (pv->f(ap, rp, cp));
265*0Sstevel@tonic-gate 		return (0);
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	for (pv = pov; pv->svc_name != NULL; ++pv)
269*0Sstevel@tonic-gate 		if (strcmp(pv->svc_name, name) == 0)
270*0Sstevel@tonic-gate 			return (pv->f(ap, rp, cp));
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pci_fc_ops: <%s> not serviced\n", name);
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	return (-1);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate /*
278*0Sstevel@tonic-gate  * Create a dma mapping for a given user address.
279*0Sstevel@tonic-gate  */
280*0Sstevel@tonic-gate static int
281*0Sstevel@tonic-gate pfc_dma_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
282*0Sstevel@tonic-gate {
283*0Sstevel@tonic-gate 	ddi_dma_handle_t h;
284*0Sstevel@tonic-gate 	int error;
285*0Sstevel@tonic-gate 	caddr_t virt;
286*0Sstevel@tonic-gate 	size_t len;
287*0Sstevel@tonic-gate 	uint_t flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
288*0Sstevel@tonic-gate 	struct fc_resource *ip;
289*0Sstevel@tonic-gate 	ddi_dma_cookie_t c;
290*0Sstevel@tonic-gate 	struct buf *bp;
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
293*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
296*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	/*
299*0Sstevel@tonic-gate 	 * XXX: It's not clear what we should do with a non-cacheable request
300*0Sstevel@tonic-gate 	 */
301*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
302*0Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 1));
303*0Sstevel@tonic-gate #ifdef	notdef
304*0Sstevel@tonic-gate 	cacheable = fc_cell2int(fc_arg(cp, 0));	/* XXX: do what? */
305*0Sstevel@tonic-gate #endif
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	FC_DEBUG2(6, CE_CONT, "pcf_dma_map_in: virt %p, len %d\n", virt, len);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/*
310*0Sstevel@tonic-gate 	 * Set up the address space for physio from userland
311*0Sstevel@tonic-gate 	 */
312*0Sstevel@tonic-gate 	error = fc_physio_setup(&bp, virt, len);
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 	if (error)  {
315*0Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: fc_physio_setup failed "
316*0Sstevel@tonic-gate 		    "error: %d  virt: %p  len %d\n", error, virt, len);
317*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "fc_physio_setup failed"));
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	if (no_advisory_dma == 0) {
321*0Sstevel@tonic-gate 		/*
322*0Sstevel@tonic-gate 		 * First try the advisory call to see if it's legal ..
323*0Sstevel@tonic-gate 		 * for advisory dma, don't pass in a ptr to a dma handle.
324*0Sstevel@tonic-gate 		 */
325*0Sstevel@tonic-gate 		FC_DEBUG0(9, CE_CONT, "pfc_dma_map_in: advisory dma_map_in\n");
326*0Sstevel@tonic-gate 		error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP,
327*0Sstevel@tonic-gate 		    NULL, NULL, NULL);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		if (error)  {
330*0Sstevel@tonic-gate 			FC_DEBUG3(9, CE_CONT, "pfc_dma_map_in: advisory "
331*0Sstevel@tonic-gate 			    "dma-map-in failed error: %d  virt: %p  len %d\n",
332*0Sstevel@tonic-gate 			    error, virt, len);
333*0Sstevel@tonic-gate 			return (fc_priv_error(cp, "advisory dma-map-in "
334*0Sstevel@tonic-gate 			    "failed"));
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: dma_map_in; bp = %p\n", bp);
339*0Sstevel@tonic-gate 	error = ddi_dma_buf_setup(ap, bp, flags, DDI_DMA_SLEEP,
340*0Sstevel@tonic-gate 	    NULL, NULL, &h);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	if (error)  {
343*0Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "pfc_dma_map_in: real dma-map-in failed "
344*0Sstevel@tonic-gate 		    "error: %d  virt: %p  len %d\n", error, virt, len);
345*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "real dma-map-in failed"));
346*0Sstevel@tonic-gate 	}
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	/*
349*0Sstevel@tonic-gate 	 * Now that the resource is mapped in, we need the dma cookie
350*0Sstevel@tonic-gate 	 * so we can return it to the driver.
351*0Sstevel@tonic-gate 	 */
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	error = fc_ddi_dma_htoc(ap, h, 0, &c);
354*0Sstevel@tonic-gate 	if (error)  {
355*0Sstevel@tonic-gate 		(void) fc_ddi_dma_free(ap, h);
356*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "ddi_dma_htoc failed"));
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	if (c.dmac_size < len)  {
360*0Sstevel@tonic-gate 		(void) fc_ddi_dma_free(ap, h);
361*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "ddi_dma_htoc size < len"));
362*0Sstevel@tonic-gate 	}
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	FC_DEBUG1(9, CE_CONT, "pfc_dma_map_in: returning devaddr %x\n",
365*0Sstevel@tonic-gate 		c.dmac_address);
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
368*0Sstevel@tonic-gate 	fc_result(cp, 0) = fc_uint32_t2cell(c.dmac_address);	/* XXX size */
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	/*
371*0Sstevel@tonic-gate 	 * Now we have to log this resource saving the handle and buf header
372*0Sstevel@tonic-gate 	 */
373*0Sstevel@tonic-gate 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
374*0Sstevel@tonic-gate 	ip->type = RT_DMA;
375*0Sstevel@tonic-gate 	ip->fc_dma_virt = virt;
376*0Sstevel@tonic-gate 	ip->fc_dma_len = len;
377*0Sstevel@tonic-gate 	ip->fc_dma_handle = h;
378*0Sstevel@tonic-gate 	ip->fc_dma_devaddr = c.dmac_address;
379*0Sstevel@tonic-gate 	ip->fc_dma_bp = bp;
380*0Sstevel@tonic-gate 	fc_add_resource(rp, ip);
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate static int
386*0Sstevel@tonic-gate pfc_dma_sync(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
387*0Sstevel@tonic-gate {
388*0Sstevel@tonic-gate 	void *virt;
389*0Sstevel@tonic-gate 	size_t len;
390*0Sstevel@tonic-gate 	uint32_t devaddr;
391*0Sstevel@tonic-gate 	int error;
392*0Sstevel@tonic-gate 	struct fc_resource *ip;
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
395*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
398*0Sstevel@tonic-gate 	devaddr = fc_cell2uint32_t(fc_arg(cp, 1));
399*0Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	/*
402*0Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
403*0Sstevel@tonic-gate 	 */
404*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
405*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
406*0Sstevel@tonic-gate 		if (ip->type != RT_DMA)
407*0Sstevel@tonic-gate 			continue;
408*0Sstevel@tonic-gate 		if (ip->fc_dma_devaddr != devaddr)
409*0Sstevel@tonic-gate 			continue;
410*0Sstevel@tonic-gate 		if (((char *)virt >= (char *)ip->fc_dma_virt) &&
411*0Sstevel@tonic-gate 		    (((char *)virt + len) <=
412*0Sstevel@tonic-gate 		    ((char *)ip->fc_dma_virt + ip->fc_dma_len)))
413*0Sstevel@tonic-gate 			break;
414*0Sstevel@tonic-gate 	}
415*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	if (ip == NULL)
418*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
419*0Sstevel@tonic-gate 		    "known dma mapping"));
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	/*
422*0Sstevel@tonic-gate 	 * We know about this request, so we trust it enough to sync it.
423*0Sstevel@tonic-gate 	 * Unfortunately, we don't know which direction, so we'll do
424*0Sstevel@tonic-gate 	 * both directions.
425*0Sstevel@tonic-gate 	 */
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	error = fc_ddi_dma_sync(ip->fc_dma_handle,
428*0Sstevel@tonic-gate 	    (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORCPU);
429*0Sstevel@tonic-gate 	error |= fc_ddi_dma_sync(ip->fc_dma_handle,
430*0Sstevel@tonic-gate 	    (char *)virt - (char *)ip->fc_dma_virt, len, DDI_DMA_SYNC_FORDEV);
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	if (error)
433*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "Call to ddi_dma_sync failed"));
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
436*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate static int
440*0Sstevel@tonic-gate pfc_dma_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	void *virt;
443*0Sstevel@tonic-gate 	size_t len;
444*0Sstevel@tonic-gate 	uint32_t devaddr;
445*0Sstevel@tonic-gate 	struct fc_resource *ip;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
448*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 2));
451*0Sstevel@tonic-gate 	devaddr = fc_cell2uint32_t(fc_arg(cp, 1));
452*0Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	/*
455*0Sstevel@tonic-gate 	 * Find if this virt matches a request we know about
456*0Sstevel@tonic-gate 	 */
457*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
458*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
459*0Sstevel@tonic-gate 		if (ip->type != RT_DMA)
460*0Sstevel@tonic-gate 			continue;
461*0Sstevel@tonic-gate 		if (ip->fc_dma_devaddr != devaddr)
462*0Sstevel@tonic-gate 			continue;
463*0Sstevel@tonic-gate 		if (ip->fc_dma_virt != virt)
464*0Sstevel@tonic-gate 			continue;
465*0Sstevel@tonic-gate 		if (len == ip->fc_dma_len)
466*0Sstevel@tonic-gate 			break;
467*0Sstevel@tonic-gate 	}
468*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	if (ip == NULL)
471*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "request doesn't match a "
472*0Sstevel@tonic-gate 		    "known dma mapping"));
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	/*
475*0Sstevel@tonic-gate 	 * ddi_dma_free does an implied sync ...
476*0Sstevel@tonic-gate 	 */
477*0Sstevel@tonic-gate 	if (fc_ddi_dma_free(ap, ip->fc_dma_handle))
478*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_dma_map_out: ddi_dma_free failed!\n");
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	/*
481*0Sstevel@tonic-gate 	 * Tear down the physio mappings
482*0Sstevel@tonic-gate 	 */
483*0Sstevel@tonic-gate 	fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len);
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	/*
486*0Sstevel@tonic-gate 	 * remove the resource from the list and release it.
487*0Sstevel@tonic-gate 	 */
488*0Sstevel@tonic-gate 	fc_rem_resource(rp, ip);
489*0Sstevel@tonic-gate 	kmem_free(ip, sizeof (struct fc_resource));
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
492*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
493*0Sstevel@tonic-gate }
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate static struct fc_resource *
496*0Sstevel@tonic-gate next_dma_resource(fco_handle_t rp)
497*0Sstevel@tonic-gate {
498*0Sstevel@tonic-gate 	struct fc_resource *ip;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
501*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next)
502*0Sstevel@tonic-gate 		if (ip->type == RT_DMA)
503*0Sstevel@tonic-gate 			break;
504*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	return (ip);
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate static int
510*0Sstevel@tonic-gate pfc_dma_cleanup(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
511*0Sstevel@tonic-gate {
512*0Sstevel@tonic-gate 	struct fc_resource *ip;
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	while ((ip = next_dma_resource(rp)) != NULL) {
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 		FC_DEBUG2(9, CE_CONT, "pfc_dma_cleanup: virt %x len %x\n",
517*0Sstevel@tonic-gate 			ip->fc_dma_virt, ip->fc_dma_len);
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 		/*
520*0Sstevel@tonic-gate 		 * Free the dma handle
521*0Sstevel@tonic-gate 		 */
522*0Sstevel@tonic-gate 		if (fc_ddi_dma_free(ap, ip->fc_dma_handle))
523*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "pfc_dma_cleanup: "
524*0Sstevel@tonic-gate 			    "ddi_dma_free failed!\n");
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 		/*
527*0Sstevel@tonic-gate 		 * Tear down the userland mapping and free the buf header
528*0Sstevel@tonic-gate 		 */
529*0Sstevel@tonic-gate 		fc_physio_free(&ip->fc_dma_bp, ip->fc_dma_virt, ip->fc_dma_len);
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 		fc_rem_resource(rp, ip);
532*0Sstevel@tonic-gate 		kmem_free(ip, sizeof (struct fc_resource));
533*0Sstevel@tonic-gate 	}
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
536*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate static int
540*0Sstevel@tonic-gate pfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
541*0Sstevel@tonic-gate {
542*0Sstevel@tonic-gate 	size_t len;
543*0Sstevel@tonic-gate 	int error;
544*0Sstevel@tonic-gate 	caddr_t virt;
545*0Sstevel@tonic-gate 	pci_regspec_t p, *ph;
546*0Sstevel@tonic-gate 	struct fc_resource *ip;
547*0Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
548*0Sstevel@tonic-gate 	ddi_acc_handle_t h;
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 4)
551*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 4"));
552*0Sstevel@tonic-gate 
553*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
554*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	p.pci_size_hi = 0;
557*0Sstevel@tonic-gate 	p.pci_size_low = len = fc_cell2size(fc_arg(cp, 0));
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 1));
560*0Sstevel@tonic-gate 	p.pci_phys_mid = fc_cell2uint(fc_arg(cp, 2));
561*0Sstevel@tonic-gate 	p.pci_phys_low = fc_cell2uint(fc_arg(cp, 3));
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	/*
566*0Sstevel@tonic-gate 	 * Fcode is expecting the bytes are not swapped.
567*0Sstevel@tonic-gate 	 */
568*0Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
569*0Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	/*
572*0Sstevel@tonic-gate 	 * First We need to allocate the PCI Resource.
573*0Sstevel@tonic-gate 	 */
574*0Sstevel@tonic-gate 	error = pci_alloc_resource(rp->child, p);
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	if (error)  {
577*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci map-in failed"));
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 	if (error)  {
583*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci map-in failed"));
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
587*0Sstevel@tonic-gate 	fc_result(cp, 0) = fc_ptr2cell(virt);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	/*
590*0Sstevel@tonic-gate 	 * Log this resource ...
591*0Sstevel@tonic-gate 	 */
592*0Sstevel@tonic-gate 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
593*0Sstevel@tonic-gate 	ip->type = RT_MAP;
594*0Sstevel@tonic-gate 	ip->fc_map_virt = virt;
595*0Sstevel@tonic-gate 	ip->fc_map_len = len;
596*0Sstevel@tonic-gate 	ip->fc_map_handle = h;
597*0Sstevel@tonic-gate 	ph = kmem_zalloc(sizeof (pci_regspec_t), KM_SLEEP);
598*0Sstevel@tonic-gate 	*ph = p;
599*0Sstevel@tonic-gate 	ip->fc_regspec = ph;	/* cache a copy of the reg spec */
600*0Sstevel@tonic-gate 	fc_add_resource(rp, ip);
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
603*0Sstevel@tonic-gate }
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate static int
606*0Sstevel@tonic-gate pfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
607*0Sstevel@tonic-gate {
608*0Sstevel@tonic-gate 	caddr_t virt;
609*0Sstevel@tonic-gate 	size_t len;
610*0Sstevel@tonic-gate 	struct fc_resource *ip;
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
613*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 1));
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	len = fc_cell2size(fc_arg(cp, 0));
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	/*
620*0Sstevel@tonic-gate 	 * Find if this request matches a mapping resource we set up.
621*0Sstevel@tonic-gate 	 */
622*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
623*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
624*0Sstevel@tonic-gate 		if (ip->type != RT_MAP)
625*0Sstevel@tonic-gate 			continue;
626*0Sstevel@tonic-gate 		if (ip->fc_map_virt != virt)
627*0Sstevel@tonic-gate 			continue;
628*0Sstevel@tonic-gate 		if (ip->fc_map_len == len)
629*0Sstevel@tonic-gate 			break;
630*0Sstevel@tonic-gate 	}
631*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	if (ip == NULL)
634*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "request doesn't match a "
635*0Sstevel@tonic-gate 		    "known mapping"));
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	pci_unmap_phys(&ip->fc_map_handle, ip->fc_regspec);
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	kmem_free(ip->fc_regspec, sizeof (pci_regspec_t));
640*0Sstevel@tonic-gate 
641*0Sstevel@tonic-gate 	/*
642*0Sstevel@tonic-gate 	 * remove the resource from the list and release it.
643*0Sstevel@tonic-gate 	 */
644*0Sstevel@tonic-gate 	fc_rem_resource(rp, ip);
645*0Sstevel@tonic-gate 	kmem_free(ip, sizeof (struct fc_resource));
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
648*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
649*0Sstevel@tonic-gate }
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate static int
652*0Sstevel@tonic-gate pfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
653*0Sstevel@tonic-gate {
654*0Sstevel@tonic-gate 	size_t len;
655*0Sstevel@tonic-gate 	caddr_t virt;
656*0Sstevel@tonic-gate 	int error;
657*0Sstevel@tonic-gate 	uint64_t x;
658*0Sstevel@tonic-gate 	uint32_t l;
659*0Sstevel@tonic-gate 	uint16_t w;
660*0Sstevel@tonic-gate 	uint8_t b;
661*0Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
662*0Sstevel@tonic-gate 	struct fc_resource *ip;
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
665*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
668*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	/*
673*0Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 2nd
674*0Sstevel@tonic-gate 	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
675*0Sstevel@tonic-gate 	 */
676*0Sstevel@tonic-gate 	switch (*(name + 1)) {
677*0Sstevel@tonic-gate 	case 'x':	len = sizeof (x); break;
678*0Sstevel@tonic-gate 	case 'l':	len = sizeof (l); break;
679*0Sstevel@tonic-gate 	case 'w':	len = sizeof (w); break;
680*0Sstevel@tonic-gate 	case 'b':	len = sizeof (b); break;
681*0Sstevel@tonic-gate 	}
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 	/*
684*0Sstevel@tonic-gate 	 * Check the alignment ...
685*0Sstevel@tonic-gate 	 */
686*0Sstevel@tonic-gate 	if (((intptr_t)virt & (len - 1)) != 0)
687*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate 	/*
690*0Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
691*0Sstevel@tonic-gate 	 */
692*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
693*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
694*0Sstevel@tonic-gate 		if (ip->type != RT_MAP)
695*0Sstevel@tonic-gate 			continue;
696*0Sstevel@tonic-gate 		if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
697*0Sstevel@tonic-gate 		    ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
698*0Sstevel@tonic-gate 			break;
699*0Sstevel@tonic-gate 	}
700*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
701*0Sstevel@tonic-gate 
702*0Sstevel@tonic-gate 	if (ip == NULL)
703*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
704*0Sstevel@tonic-gate 		    "known mapping"));
705*0Sstevel@tonic-gate 
706*0Sstevel@tonic-gate 	/*
707*0Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
708*0Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
709*0Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
710*0Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
711*0Sstevel@tonic-gate 	 */
712*0Sstevel@tonic-gate 	switch (len) {
713*0Sstevel@tonic-gate 	case sizeof (x):
714*0Sstevel@tonic-gate 		error = ddi_peek64(rp->child, (int64_t *)virt, (int64_t *)&x);
715*0Sstevel@tonic-gate 		break;
716*0Sstevel@tonic-gate 	case sizeof (l):
717*0Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&l);
718*0Sstevel@tonic-gate 		break;
719*0Sstevel@tonic-gate 	case sizeof (w):
720*0Sstevel@tonic-gate 		error = ddi_peek16(rp->child, (int16_t *)virt, (int16_t *)&w);
721*0Sstevel@tonic-gate 		break;
722*0Sstevel@tonic-gate 	case sizeof (b):
723*0Sstevel@tonic-gate 		error = ddi_peek8(rp->child, (int8_t *)virt, (int8_t *)&b);
724*0Sstevel@tonic-gate 		break;
725*0Sstevel@tonic-gate 	}
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	if (error) {
728*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
732*0Sstevel@tonic-gate 	switch (len) {
733*0Sstevel@tonic-gate 	case sizeof (x): fc_result(cp, 0) = x; break;
734*0Sstevel@tonic-gate 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
735*0Sstevel@tonic-gate 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
736*0Sstevel@tonic-gate 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
737*0Sstevel@tonic-gate 	}
738*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
739*0Sstevel@tonic-gate }
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate static int
742*0Sstevel@tonic-gate pfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
743*0Sstevel@tonic-gate {
744*0Sstevel@tonic-gate 	size_t len;
745*0Sstevel@tonic-gate 	caddr_t virt;
746*0Sstevel@tonic-gate 	int error;
747*0Sstevel@tonic-gate 	uint64_t x;
748*0Sstevel@tonic-gate 	uint32_t l;
749*0Sstevel@tonic-gate 	uint16_t w;
750*0Sstevel@tonic-gate 	uint8_t b;
751*0Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
752*0Sstevel@tonic-gate 	struct fc_resource *ip;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
755*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	/*
760*0Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 2nd
761*0Sstevel@tonic-gate 	 * character of the name which is "rl!", "rb!" or "rw!"
762*0Sstevel@tonic-gate 	 */
763*0Sstevel@tonic-gate 	switch (*(name + 1)) {
764*0Sstevel@tonic-gate 	case 'x': len = sizeof (x); x = fc_arg(cp, 1); break;
765*0Sstevel@tonic-gate 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
766*0Sstevel@tonic-gate 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
767*0Sstevel@tonic-gate 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	/*
771*0Sstevel@tonic-gate 	 * Check the alignment ...
772*0Sstevel@tonic-gate 	 */
773*0Sstevel@tonic-gate 	if (((intptr_t)virt & (len - 1)) != 0)
774*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 	/*
777*0Sstevel@tonic-gate 	 * Find if this virt is 'within' a request we know about
778*0Sstevel@tonic-gate 	 */
779*0Sstevel@tonic-gate 	fc_lock_resource_list(rp);
780*0Sstevel@tonic-gate 	for (ip = rp->head; ip != NULL; ip = ip->next) {
781*0Sstevel@tonic-gate 		if (ip->type != RT_MAP)
782*0Sstevel@tonic-gate 			continue;
783*0Sstevel@tonic-gate 		if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
784*0Sstevel@tonic-gate 		    ((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
785*0Sstevel@tonic-gate 			break;
786*0Sstevel@tonic-gate 	}
787*0Sstevel@tonic-gate 	fc_unlock_resource_list(rp);
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	if (ip == NULL)
790*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "request not within a "
791*0Sstevel@tonic-gate 		    "known mapping"));
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	/*
794*0Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
795*0Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
796*0Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
797*0Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
798*0Sstevel@tonic-gate 	 */
799*0Sstevel@tonic-gate 	switch (len) {
800*0Sstevel@tonic-gate 	case sizeof (x):
801*0Sstevel@tonic-gate 		error = ddi_poke64(rp->child, (int64_t *)virt, x);
802*0Sstevel@tonic-gate 		break;
803*0Sstevel@tonic-gate 	case sizeof (l):
804*0Sstevel@tonic-gate 		error = ddi_poke32(rp->child, (int32_t *)virt, l);
805*0Sstevel@tonic-gate 		break;
806*0Sstevel@tonic-gate 	case sizeof (w):
807*0Sstevel@tonic-gate 		error = ddi_poke16(rp->child, (int16_t *)virt, w);
808*0Sstevel@tonic-gate 		break;
809*0Sstevel@tonic-gate 	case sizeof (b):
810*0Sstevel@tonic-gate 		error = ddi_poke8(rp->child, (int8_t *)virt, b);
811*0Sstevel@tonic-gate 		break;
812*0Sstevel@tonic-gate 	}
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	if (error) {
815*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
819*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
820*0Sstevel@tonic-gate }
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate static int
823*0Sstevel@tonic-gate pfc_config_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
824*0Sstevel@tonic-gate {
825*0Sstevel@tonic-gate 	caddr_t virt, v;
826*0Sstevel@tonic-gate 	int error, reg, flags = 0;
827*0Sstevel@tonic-gate 	size_t len;
828*0Sstevel@tonic-gate 	uint32_t l, tmp;
829*0Sstevel@tonic-gate 	uint16_t w;
830*0Sstevel@tonic-gate 	uint8_t b;
831*0Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
832*0Sstevel@tonic-gate 	pci_regspec_t p;
833*0Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
834*0Sstevel@tonic-gate 	ddi_acc_handle_t h;
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
837*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
840*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	/*
843*0Sstevel@tonic-gate 	 * Construct a config address pci reg property from the args.
844*0Sstevel@tonic-gate 	 * arg[0] is the configuration address.
845*0Sstevel@tonic-gate 	 */
846*0Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0));
847*0Sstevel@tonic-gate 	p.pci_phys_mid = p.pci_phys_low = 0;
848*0Sstevel@tonic-gate 	p.pci_size_hi = p.pci_size_low = 0;
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	/*
851*0Sstevel@tonic-gate 	 * Verify that the address is a configuration space address
852*0Sstevel@tonic-gate 	 * ss must be zero, n,p,t must be zero.
853*0Sstevel@tonic-gate 	 */
854*0Sstevel@tonic-gate 	if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) ||
855*0Sstevel@tonic-gate 	    ((p.pci_phys_hi & PCI_NPT_bits) != 0)) {
856*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_fetch: "
857*0Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
858*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
859*0Sstevel@tonic-gate 	}
860*0Sstevel@tonic-gate 
861*0Sstevel@tonic-gate 	/*
862*0Sstevel@tonic-gate 	 * Extract the register number from the config address and
863*0Sstevel@tonic-gate 	 * remove the register number from the physical address.
864*0Sstevel@tonic-gate 	 */
865*0Sstevel@tonic-gate 	reg = p.pci_phys_hi & PCI_REG_REG_M;
866*0Sstevel@tonic-gate 	p.pci_phys_hi &= ~PCI_REG_REG_M;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	/*
869*0Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 9th
870*0Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
871*0Sstevel@tonic-gate 	 */
872*0Sstevel@tonic-gate 	switch (*(name + 7)) {
873*0Sstevel@tonic-gate 	case 'l':	len = sizeof (l); break;
874*0Sstevel@tonic-gate 	case 'w':	len = sizeof (w); break;
875*0Sstevel@tonic-gate 	case 'b':	len = sizeof (b); break;
876*0Sstevel@tonic-gate 	}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	/*
879*0Sstevel@tonic-gate 	 * Verify that the access is properly aligned
880*0Sstevel@tonic-gate 	 */
881*0Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
882*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
883*0Sstevel@tonic-gate 
884*0Sstevel@tonic-gate 	/*
885*0Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
886*0Sstevel@tonic-gate 	 */
887*0Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
888*0Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
889*0Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	if (error)  {
894*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
895*0Sstevel@tonic-gate 	}
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
898*0Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
901*0Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
902*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
903*0Sstevel@tonic-gate 	} else
904*0Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
907*0Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
908*0Sstevel@tonic-gate 			error = DDI_FAILURE;
909*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpcii: conf probe failed.l=%x", tmp);
910*0Sstevel@tonic-gate 		}
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
913*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config fetch failed"));
914*0Sstevel@tonic-gate 	}
915*0Sstevel@tonic-gate 
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/*
918*0Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
919*0Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
920*0Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
921*0Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
922*0Sstevel@tonic-gate 	 */
923*0Sstevel@tonic-gate 	v = virt + reg;
924*0Sstevel@tonic-gate 	switch (len) {
925*0Sstevel@tonic-gate 	case sizeof (l):
926*0Sstevel@tonic-gate 		l = (int32_t)ddi_get32(h, (uint32_t *)v);
927*0Sstevel@tonic-gate 		break;
928*0Sstevel@tonic-gate 	case sizeof (w):
929*0Sstevel@tonic-gate 		w = (int16_t)ddi_get16(h, (uint16_t *)v);
930*0Sstevel@tonic-gate 		break;
931*0Sstevel@tonic-gate 	case sizeof (b):
932*0Sstevel@tonic-gate 		b = (int8_t)ddi_get8(h, (uint8_t *)v);
933*0Sstevel@tonic-gate 		break;
934*0Sstevel@tonic-gate 	}
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate 	/*
937*0Sstevel@tonic-gate 	 * Remove the temporary config space mapping
938*0Sstevel@tonic-gate 	 */
939*0Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
940*0Sstevel@tonic-gate 
941*0Sstevel@tonic-gate 	if (error) {
942*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
943*0Sstevel@tonic-gate 	}
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
946*0Sstevel@tonic-gate 	switch (len) {
947*0Sstevel@tonic-gate 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
948*0Sstevel@tonic-gate 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
949*0Sstevel@tonic-gate 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
950*0Sstevel@tonic-gate 	}
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
953*0Sstevel@tonic-gate }
954*0Sstevel@tonic-gate 
955*0Sstevel@tonic-gate static int
956*0Sstevel@tonic-gate pfc_config_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
957*0Sstevel@tonic-gate {
958*0Sstevel@tonic-gate 	caddr_t virt, v;
959*0Sstevel@tonic-gate 	int error, reg, flags = 0;
960*0Sstevel@tonic-gate 	size_t len;
961*0Sstevel@tonic-gate 	uint32_t l, tmp;
962*0Sstevel@tonic-gate 	uint16_t w;
963*0Sstevel@tonic-gate 	uint8_t b;
964*0Sstevel@tonic-gate 	char *name = fc_cell2ptr(cp->svc_name);
965*0Sstevel@tonic-gate 	pci_regspec_t p;
966*0Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
967*0Sstevel@tonic-gate 	ddi_acc_handle_t h;
968*0Sstevel@tonic-gate 
969*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 2)
970*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 2"));
971*0Sstevel@tonic-gate 
972*0Sstevel@tonic-gate 	/*
973*0Sstevel@tonic-gate 	 * Construct a config address pci reg property from the args.
974*0Sstevel@tonic-gate 	 * arg[0] is the configuration address. arg[1] is the data.
975*0Sstevel@tonic-gate 	 */
976*0Sstevel@tonic-gate 	p.pci_phys_hi = fc_cell2uint(fc_arg(cp, 0));
977*0Sstevel@tonic-gate 	p.pci_phys_mid = p.pci_phys_low = 0;
978*0Sstevel@tonic-gate 	p.pci_size_hi = p.pci_size_low = 0;
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	/*
981*0Sstevel@tonic-gate 	 * Verify that the address is a configuration space address
982*0Sstevel@tonic-gate 	 * ss must be zero, n,p,t must be zero.
983*0Sstevel@tonic-gate 	 */
984*0Sstevel@tonic-gate 	if (((p.pci_phys_hi & PCI_ADDR_MASK) != PCI_ADDR_CONFIG) ||
985*0Sstevel@tonic-gate 	    ((p.pci_phys_hi & PCI_NPT_bits) != 0)) {
986*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "pfc_config_store: "
987*0Sstevel@tonic-gate 		    "invalid config addr: %x\n", p.pci_phys_hi);
988*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "non-config addr"));
989*0Sstevel@tonic-gate 	}
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 	/*
992*0Sstevel@tonic-gate 	 * Extract the register number from the config address and
993*0Sstevel@tonic-gate 	 * remove the register number from the physical address.
994*0Sstevel@tonic-gate 	 */
995*0Sstevel@tonic-gate 	reg = p.pci_phys_hi & PCI_REG_REG_M;
996*0Sstevel@tonic-gate 	p.pci_phys_hi &= ~PCI_REG_REG_M;
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate 	/*
999*0Sstevel@tonic-gate 	 * Determine the access width .. we can switch on the 8th
1000*0Sstevel@tonic-gate 	 * character of the name which is "config-{l,w,b}@"
1001*0Sstevel@tonic-gate 	 */
1002*0Sstevel@tonic-gate 	switch (*(name + 7)) {
1003*0Sstevel@tonic-gate 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
1004*0Sstevel@tonic-gate 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
1005*0Sstevel@tonic-gate 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
1006*0Sstevel@tonic-gate 	}
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	/*
1009*0Sstevel@tonic-gate 	 * Verify that the access is properly aligned
1010*0Sstevel@tonic-gate 	 */
1011*0Sstevel@tonic-gate 	if ((reg & (len - 1)) != 0)
1012*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "unaligned access"));
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	/*
1015*0Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
1016*0Sstevel@tonic-gate 	 */
1017*0Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1018*0Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1019*0Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1020*0Sstevel@tonic-gate 
1021*0Sstevel@tonic-gate 	error = pci_map_phys(rp->child, &p, &virt, &acc, &h);
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	if (error)  {
1024*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config map-in failed"));
1025*0Sstevel@tonic-gate 	}
1026*0Sstevel@tonic-gate 
1027*0Sstevel@tonic-gate 	if (fcpci_indirect_map(rp->child) == DDI_SUCCESS)
1028*0Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
1031*0Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
1032*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
1033*0Sstevel@tonic-gate 	} else
1034*0Sstevel@tonic-gate 		error = ddi_peek32(rp->child, (int32_t *)virt, (int32_t *)&tmp);
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
1037*0Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
1038*0Sstevel@tonic-gate 			error = DDI_FAILURE;
1039*0Sstevel@tonic-gate 			cmn_err(CE_CONT, "fcpci: conf probe failed.l=%x", tmp);
1040*0Sstevel@tonic-gate 		}
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
1043*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "pci config store failed"));
1044*0Sstevel@tonic-gate 	}
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	/*
1048*0Sstevel@tonic-gate 	 * XXX: We need access handle versions of peek/poke to move
1049*0Sstevel@tonic-gate 	 * beyond the prototype ... we assume that we have hardware
1050*0Sstevel@tonic-gate 	 * byte swapping enabled for pci register access here which
1051*0Sstevel@tonic-gate 	 * is a huge dependency on the current implementation.
1052*0Sstevel@tonic-gate 	 */
1053*0Sstevel@tonic-gate 	v = virt + reg;
1054*0Sstevel@tonic-gate 	switch (len) {
1055*0Sstevel@tonic-gate 	case sizeof (l):
1056*0Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, (uint32_t)l);
1057*0Sstevel@tonic-gate 		break;
1058*0Sstevel@tonic-gate 	case sizeof (w):
1059*0Sstevel@tonic-gate 		ddi_put16(h, (uint16_t *)v, (uint16_t)w);
1060*0Sstevel@tonic-gate 		break;
1061*0Sstevel@tonic-gate 	case sizeof (b):
1062*0Sstevel@tonic-gate 		ddi_put8(h, (uint8_t *)v, (uint8_t)b);
1063*0Sstevel@tonic-gate 		break;
1064*0Sstevel@tonic-gate 	}
1065*0Sstevel@tonic-gate 
1066*0Sstevel@tonic-gate 	/*
1067*0Sstevel@tonic-gate 	 * Remove the temporary config space mapping
1068*0Sstevel@tonic-gate 	 */
1069*0Sstevel@tonic-gate 	pci_unmap_phys(&h, &p);
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 	if (error) {
1072*0Sstevel@tonic-gate 		return (fc_priv_error(cp, "access error"));
1073*0Sstevel@tonic-gate 	}
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(0);
1076*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1077*0Sstevel@tonic-gate }
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate static int
1081*0Sstevel@tonic-gate pfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
1082*0Sstevel@tonic-gate {
1083*0Sstevel@tonic-gate 	caddr_t name_virt, fcode_virt;
1084*0Sstevel@tonic-gate 	char *name, *fcode;
1085*0Sstevel@tonic-gate 	int fcode_len, status;
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 3)
1088*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 3"));
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
1091*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 	name_virt = fc_cell2ptr(fc_arg(cp, 0));
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 	fcode_len = fc_cell2int(fc_arg(cp, 2));
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(name_virt), name,
1102*0Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
1103*0Sstevel@tonic-gate 		status = 0;
1104*0Sstevel@tonic-gate 	} else {
1105*0Sstevel@tonic-gate 
1106*0Sstevel@tonic-gate 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
1107*0Sstevel@tonic-gate 
1108*0Sstevel@tonic-gate 		if ((status = prom_get_fcode(name, fcode)) != 0) {
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate 			if (copyout((void *)fcode, (void *)fcode_virt,
1111*0Sstevel@tonic-gate 			    fcode_len)) {
1112*0Sstevel@tonic-gate 				cmn_err(CE_WARN, " pfc_get_fcode: Unable "
1113*0Sstevel@tonic-gate 				    "to copy out fcode image\n");
1114*0Sstevel@tonic-gate 				status = 0;
1115*0Sstevel@tonic-gate 			}
1116*0Sstevel@tonic-gate 		}
1117*0Sstevel@tonic-gate 
1118*0Sstevel@tonic-gate 		kmem_free(fcode, fcode_len);
1119*0Sstevel@tonic-gate 	}
1120*0Sstevel@tonic-gate 
1121*0Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
1124*0Sstevel@tonic-gate 	fc_result(cp, 0) = status;
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1127*0Sstevel@tonic-gate }
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate static int
1130*0Sstevel@tonic-gate pfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
1131*0Sstevel@tonic-gate {
1132*0Sstevel@tonic-gate 	caddr_t virt;
1133*0Sstevel@tonic-gate 	char *name;
1134*0Sstevel@tonic-gate 	int len;
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 1)
1137*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 1"));
1138*0Sstevel@tonic-gate 
1139*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
1140*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 	virt = fc_cell2ptr(fc_arg(cp, 0));
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	if (copyinstr(fc_cell2ptr(virt), name,
1147*0Sstevel@tonic-gate 	    FC_SVC_NAME_LEN - 1, NULL))  {
1148*0Sstevel@tonic-gate 		len = 0;
1149*0Sstevel@tonic-gate 	} else {
1150*0Sstevel@tonic-gate 		len = prom_get_fcode_size(name);
1151*0Sstevel@tonic-gate 	}
1152*0Sstevel@tonic-gate 
1153*0Sstevel@tonic-gate 	kmem_free(name, FC_SVC_NAME_LEN);
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
1156*0Sstevel@tonic-gate 	fc_result(cp, 0) = len;
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1159*0Sstevel@tonic-gate }
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate /*
1162*0Sstevel@tonic-gate  * Return the physical probe address: lo=0, mid=0, hi-config-addr
1163*0Sstevel@tonic-gate  */
1164*0Sstevel@tonic-gate static int
1165*0Sstevel@tonic-gate pfc_probe_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
1166*0Sstevel@tonic-gate {
1167*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
1168*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
1169*0Sstevel@tonic-gate 
1170*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 2)
1171*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 3"));
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(2);
1174*0Sstevel@tonic-gate 	fc_result(cp, 1) = fc_int2cell(0);	/* phys.lo */
1175*0Sstevel@tonic-gate 	fc_result(cp, 0) = fc_int2cell(0);	/* phys.mid */
1176*0Sstevel@tonic-gate 
1177*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1178*0Sstevel@tonic-gate }
1179*0Sstevel@tonic-gate 
1180*0Sstevel@tonic-gate /*
1181*0Sstevel@tonic-gate  * Return the phys.hi component of the probe address.
1182*0Sstevel@tonic-gate  */
1183*0Sstevel@tonic-gate static int
1184*0Sstevel@tonic-gate pfc_probe_space(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
1185*0Sstevel@tonic-gate {
1186*0Sstevel@tonic-gate 	struct pci_ops_bus_args *ba = rp->bus_args;
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	ASSERT(ba);
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
1191*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
1192*0Sstevel@tonic-gate 
1193*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
1194*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
1195*0Sstevel@tonic-gate 
1196*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
1197*0Sstevel@tonic-gate 	fc_result(cp, 0) = fc_uint32_t2cell(ba->config_address); /* phys.hi */
1198*0Sstevel@tonic-gate 
1199*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1200*0Sstevel@tonic-gate }
1201*0Sstevel@tonic-gate 
1202*0Sstevel@tonic-gate static int
1203*0Sstevel@tonic-gate pfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
1204*0Sstevel@tonic-gate {
1205*0Sstevel@tonic-gate 	fc_phandle_t h;
1206*0Sstevel@tonic-gate 
1207*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nargs) != 0)
1208*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nargs must be 0"));
1209*0Sstevel@tonic-gate 
1210*0Sstevel@tonic-gate 	if (fc_cell2int(cp->nresults) < 1)
1211*0Sstevel@tonic-gate 		return (fc_syntax_error(cp, "nresults must be >= 1"));
1212*0Sstevel@tonic-gate 
1213*0Sstevel@tonic-gate 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
1214*0Sstevel@tonic-gate 
1215*0Sstevel@tonic-gate 	cp->nresults = fc_int2cell(1);
1216*0Sstevel@tonic-gate 	fc_result(cp, 0) = fc_phandle2cell(h);
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate 	return (fc_success_op(ap, rp, cp));
1219*0Sstevel@tonic-gate }
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate int
1222*0Sstevel@tonic-gate pci_alloc_mem_chunk(dev_info_t *dip, uint64_t mem_align, uint64_t *mem_size,
1223*0Sstevel@tonic-gate     uint64_t *mem_answer)
1224*0Sstevel@tonic-gate {
1225*0Sstevel@tonic-gate 	ndi_ra_request_t req;
1226*0Sstevel@tonic-gate 	int rval;
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
1229*0Sstevel@tonic-gate 	req.ra_flags = NDI_RA_ALLOC_BOUNDED;
1230*0Sstevel@tonic-gate 	req.ra_boundbase = 0;
1231*0Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
1232*0Sstevel@tonic-gate 	req.ra_len = *mem_size;
1233*0Sstevel@tonic-gate 	req.ra_align_mask = mem_align - 1;
1234*0Sstevel@tonic-gate 
1235*0Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, mem_answer, mem_size,
1236*0Sstevel@tonic-gate 	    NDI_RA_TYPE_MEM, NDI_RA_PASS);
1237*0Sstevel@tonic-gate 
1238*0Sstevel@tonic-gate 	return (rval);
1239*0Sstevel@tonic-gate }
1240*0Sstevel@tonic-gate int
1241*0Sstevel@tonic-gate pci_alloc_io_chunk(dev_info_t *dip, uint64_t io_align, uint64_t *io_size,
1242*0Sstevel@tonic-gate     uint64_t *io_answer)
1243*0Sstevel@tonic-gate {
1244*0Sstevel@tonic-gate 	ndi_ra_request_t req;
1245*0Sstevel@tonic-gate 	int rval;
1246*0Sstevel@tonic-gate 
1247*0Sstevel@tonic-gate 	bzero((caddr_t)&req, sizeof (ndi_ra_request_t));
1248*0Sstevel@tonic-gate 	req.ra_flags = (NDI_RA_ALLOC_BOUNDED | NDI_RA_ALLOC_PARTIAL_OK);
1249*0Sstevel@tonic-gate 	req.ra_boundbase = 0;
1250*0Sstevel@tonic-gate 	req.ra_boundlen = PCI_4GIG_LIMIT;
1251*0Sstevel@tonic-gate 	req.ra_len = *io_size;
1252*0Sstevel@tonic-gate 	req.ra_align_mask = io_align - 1;
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 	rval = ndi_ra_alloc(dip, &req, io_answer, io_size,
1255*0Sstevel@tonic-gate 	    NDI_RA_TYPE_IO, NDI_RA_PASS);
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	return (rval);
1258*0Sstevel@tonic-gate }
1259*0Sstevel@tonic-gate 
1260*0Sstevel@tonic-gate int
1261*0Sstevel@tonic-gate pci_alloc_resource(dev_info_t *dip, pci_regspec_t phys_spec)
1262*0Sstevel@tonic-gate {
1263*0Sstevel@tonic-gate 	uint64_t answer;
1264*0Sstevel@tonic-gate 	uint64_t alen;
1265*0Sstevel@tonic-gate 	int offset, tmp;
1266*0Sstevel@tonic-gate 	pci_regspec_t config;
1267*0Sstevel@tonic-gate 	caddr_t virt, v;
1268*0Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
1269*0Sstevel@tonic-gate 	ddi_acc_handle_t h;
1270*0Sstevel@tonic-gate 	ndi_ra_request_t request;
1271*0Sstevel@tonic-gate 	pci_regspec_t *assigned;
1272*0Sstevel@tonic-gate 	int assigned_len, entries, i, l, flags = 0, error;
1273*0Sstevel@tonic-gate 
1274*0Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1277*0Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "assigned-addresses", (caddr_t)&assigned,
1278*0Sstevel@tonic-gate 	    &assigned_len) == DDI_PROP_SUCCESS) {
1279*0Sstevel@tonic-gate 
1280*0Sstevel@tonic-gate 		entries = assigned_len / (sizeof (pci_regspec_t));
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 		/*
1283*0Sstevel@tonic-gate 		 * Walk through the assigned-addresses entries. If there is
1284*0Sstevel@tonic-gate 		 * a match, there is no need to allocate the resource.
1285*0Sstevel@tonic-gate 		 */
1286*0Sstevel@tonic-gate 		for (i = 0; i < entries; i++) {
1287*0Sstevel@tonic-gate 			if (assigned[i].pci_phys_hi == phys_spec.pci_phys_hi) {
1288*0Sstevel@tonic-gate 				if (assigned[i].pci_size_low >=
1289*0Sstevel@tonic-gate 				    phys_spec.pci_size_low) {
1290*0Sstevel@tonic-gate 					kmem_free(assigned, assigned_len);
1291*0Sstevel@tonic-gate 					return (0);
1292*0Sstevel@tonic-gate 				}
1293*0Sstevel@tonic-gate 				/*
1294*0Sstevel@tonic-gate 				 * Fcode wants to assign more than what
1295*0Sstevel@tonic-gate 				 * probe found.
1296*0Sstevel@tonic-gate 				 */
1297*0Sstevel@tonic-gate 				(void) pci_free_resource(dip, assigned[i]);
1298*0Sstevel@tonic-gate 				/*
1299*0Sstevel@tonic-gate 				 * Go on to allocate resources.
1300*0Sstevel@tonic-gate 				 */
1301*0Sstevel@tonic-gate 				break;
1302*0Sstevel@tonic-gate 			}
1303*0Sstevel@tonic-gate 			/*
1304*0Sstevel@tonic-gate 			 * Check if Fcode wants to map using different
1305*0Sstevel@tonic-gate 			 * NPT bits.
1306*0Sstevel@tonic-gate 			 */
1307*0Sstevel@tonic-gate 			if (PCI_REG_BDFR_G(assigned[i].pci_phys_hi) ==
1308*0Sstevel@tonic-gate 			    PCI_REG_BDFR_G(phys_spec.pci_phys_hi)) {
1309*0Sstevel@tonic-gate 				/*
1310*0Sstevel@tonic-gate 				 * It is an error to change SS bits
1311*0Sstevel@tonic-gate 				 */
1312*0Sstevel@tonic-gate 				if (PCI_REG_ADDR_G(assigned[i].pci_phys_hi) !=
1313*0Sstevel@tonic-gate 				    PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 					cmn_err(CE_WARN, "Fcode changing ss "
1316*0Sstevel@tonic-gate 					    "bits in reg %x -- %x",
1317*0Sstevel@tonic-gate 					    assigned[i].pci_phys_hi,
1318*0Sstevel@tonic-gate 					    phys_spec.pci_phys_hi);
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 					kmem_free(assigned, assigned_len);
1321*0Sstevel@tonic-gate 					return (1);
1322*0Sstevel@tonic-gate 				}
1323*0Sstevel@tonic-gate 
1324*0Sstevel@tonic-gate 				/*
1325*0Sstevel@tonic-gate 				 * Allocate enough
1326*0Sstevel@tonic-gate 				 */
1327*0Sstevel@tonic-gate 				l = MAX(assigned[i].pci_size_low,
1328*0Sstevel@tonic-gate 				    phys_spec.pci_size_low);
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate 				(void) pci_free_resource(dip, assigned[i]);
1331*0Sstevel@tonic-gate 				/*
1332*0Sstevel@tonic-gate 				 * Go on to allocate resources.
1333*0Sstevel@tonic-gate 				 */
1334*0Sstevel@tonic-gate 				break;
1335*0Sstevel@tonic-gate 			}
1336*0Sstevel@tonic-gate 		}
1337*0Sstevel@tonic-gate 		kmem_free(assigned, assigned_len);
1338*0Sstevel@tonic-gate 	}
1339*0Sstevel@tonic-gate 
1340*0Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
1341*0Sstevel@tonic-gate 
1342*0Sstevel@tonic-gate 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
1343*0Sstevel@tonic-gate 	config.pci_phys_hi &= ~PCI_REG_REG_M;
1344*0Sstevel@tonic-gate 	config.pci_phys_mid = config.pci_phys_low = 0;
1345*0Sstevel@tonic-gate 	config.pci_size_hi = config.pci_size_low = 0;
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	/*
1348*0Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
1349*0Sstevel@tonic-gate 	 */
1350*0Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1351*0Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1352*0Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 	if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) {
1355*0Sstevel@tonic-gate 		return (1);
1356*0Sstevel@tonic-gate 	}
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 	if (fcpci_indirect_map(dip) == DDI_SUCCESS)
1359*0Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
1362*0Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
1363*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
1364*0Sstevel@tonic-gate 	} else
1365*0Sstevel@tonic-gate 		error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp);
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
1368*0Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
1369*0Sstevel@tonic-gate 			error = DDI_FAILURE;
1370*0Sstevel@tonic-gate 		}
1371*0Sstevel@tonic-gate 
1372*0Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
1373*0Sstevel@tonic-gate 		return (1);
1374*0Sstevel@tonic-gate 	}
1375*0Sstevel@tonic-gate 
1376*0Sstevel@tonic-gate 	request.ra_flags |= NDI_RA_ALIGN_SIZE;
1377*0Sstevel@tonic-gate 	request.ra_boundbase = 0;
1378*0Sstevel@tonic-gate 	request.ra_boundlen = PCI_4GIG_LIMIT;
1379*0Sstevel@tonic-gate 
1380*0Sstevel@tonic-gate 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 	v = virt + offset;
1383*0Sstevel@tonic-gate 
1384*0Sstevel@tonic-gate 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
1385*0Sstevel@tonic-gate 		request.ra_len = l;
1386*0Sstevel@tonic-gate 		request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
1387*0Sstevel@tonic-gate 
1388*0Sstevel@tonic-gate 		/* allocate memory space from the allocator */
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 		if (ndi_ra_alloc(ddi_get_parent(dip),
1391*0Sstevel@tonic-gate 			&request, &answer, &alen,
1392*0Sstevel@tonic-gate 			NDI_RA_TYPE_MEM, NDI_RA_PASS)
1393*0Sstevel@tonic-gate 					!= NDI_SUCCESS) {
1394*0Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
1395*0Sstevel@tonic-gate 			return (1);
1396*0Sstevel@tonic-gate 		}
1397*0Sstevel@tonic-gate 		FC_DEBUG3(1, CE_CONT, "ROM addr = [0x%x.%x] len [0x%x]\n",
1398*0Sstevel@tonic-gate 			HIADDR(answer),
1399*0Sstevel@tonic-gate 			LOADDR(answer),
1400*0Sstevel@tonic-gate 			alen);
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate 		/* program the low word */
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, LOADDR(answer));
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 		phys_spec.pci_phys_low = LOADDR(answer);
1407*0Sstevel@tonic-gate 		phys_spec.pci_phys_mid = HIADDR(answer);
1408*0Sstevel@tonic-gate 	} else {
1409*0Sstevel@tonic-gate 		request.ra_len = l;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
1412*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
1413*0Sstevel@tonic-gate 			request.ra_flags ^= NDI_RA_ALLOC_BOUNDED;
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
1416*0Sstevel@tonic-gate 				/*
1417*0Sstevel@tonic-gate 				 * If it is a non relocatable address,
1418*0Sstevel@tonic-gate 				 * then specify the address we want.
1419*0Sstevel@tonic-gate 				 */
1420*0Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
1421*0Sstevel@tonic-gate 				request.ra_addr = (uint64_t)LADDR(
1422*0Sstevel@tonic-gate 				    phys_spec.pci_phys_low,
1423*0Sstevel@tonic-gate 				    phys_spec.pci_phys_mid);
1424*0Sstevel@tonic-gate 			}
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 			/* allocate memory space from the allocator */
1427*0Sstevel@tonic-gate 
1428*0Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
1429*0Sstevel@tonic-gate 				&request, &answer, &alen,
1430*0Sstevel@tonic-gate 				NDI_RA_TYPE_MEM, NDI_RA_PASS)
1431*0Sstevel@tonic-gate 						!= NDI_SUCCESS) {
1432*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1433*0Sstevel@tonic-gate 				if (request.ra_flags ==
1434*0Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
1435*0Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
1436*0Sstevel@tonic-gate 					    "non relocatable address 0x%p\n",
1437*0Sstevel@tonic-gate 					    (void *) request.ra_addr);
1438*0Sstevel@tonic-gate 				return (1);
1439*0Sstevel@tonic-gate 			}
1440*0Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
1441*0Sstevel@tonic-gate 			    "64 addr = [0x%x.%x] len [0x%x]\n",
1442*0Sstevel@tonic-gate 			    HIADDR(answer),
1443*0Sstevel@tonic-gate 			    LOADDR(answer),
1444*0Sstevel@tonic-gate 			    alen);
1445*0Sstevel@tonic-gate 
1446*0Sstevel@tonic-gate 			/* program the low word */
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
1449*0Sstevel@tonic-gate 
1450*0Sstevel@tonic-gate 			/* program the high word with value zero */
1451*0Sstevel@tonic-gate 			v += 4;
1452*0Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, HIADDR(answer));
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
1455*0Sstevel@tonic-gate 			phys_spec.pci_phys_mid = HIADDR(answer);
1456*0Sstevel@tonic-gate 
1457*0Sstevel@tonic-gate 			break;
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1460*0Sstevel@tonic-gate 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
1461*0Sstevel@tonic-gate 
1462*0Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
1463*0Sstevel@tonic-gate 				/*
1464*0Sstevel@tonic-gate 				 * If it is a non relocatable address,
1465*0Sstevel@tonic-gate 				 * then specify the address we want.
1466*0Sstevel@tonic-gate 				 */
1467*0Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
1468*0Sstevel@tonic-gate 				request.ra_addr = (uint64_t)
1469*0Sstevel@tonic-gate 				    phys_spec.pci_phys_low;
1470*0Sstevel@tonic-gate 			}
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 			/* allocate memory space from the allocator */
1473*0Sstevel@tonic-gate 
1474*0Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
1475*0Sstevel@tonic-gate 				&request, &answer, &alen,
1476*0Sstevel@tonic-gate 				NDI_RA_TYPE_MEM, NDI_RA_PASS)
1477*0Sstevel@tonic-gate 						!= NDI_SUCCESS) {
1478*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1479*0Sstevel@tonic-gate 				if (request.ra_flags ==
1480*0Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
1481*0Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
1482*0Sstevel@tonic-gate 					    "non relocatable address 0x%p\n",
1483*0Sstevel@tonic-gate 					    (void *) request.ra_addr);
1484*0Sstevel@tonic-gate 				return (1);
1485*0Sstevel@tonic-gate 			}
1486*0Sstevel@tonic-gate 
1487*0Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
1488*0Sstevel@tonic-gate 			    "32 addr = [0x%x.%x] len [0x%x]\n",
1489*0Sstevel@tonic-gate 			    HIADDR(answer),
1490*0Sstevel@tonic-gate 			    LOADDR(answer),
1491*0Sstevel@tonic-gate 			    alen);
1492*0Sstevel@tonic-gate 
1493*0Sstevel@tonic-gate 			/* program the low word */
1494*0Sstevel@tonic-gate 
1495*0Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
1496*0Sstevel@tonic-gate 
1497*0Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 			break;
1500*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
1501*0Sstevel@tonic-gate 			request.ra_flags |= NDI_RA_ALLOC_BOUNDED;
1502*0Sstevel@tonic-gate 
1503*0Sstevel@tonic-gate 			if (phys_spec.pci_phys_hi & PCI_REG_REL_M) {
1504*0Sstevel@tonic-gate 				/*
1505*0Sstevel@tonic-gate 				 * If it is a non relocatable address,
1506*0Sstevel@tonic-gate 				 * then specify the address we want.
1507*0Sstevel@tonic-gate 				 */
1508*0Sstevel@tonic-gate 				request.ra_flags = NDI_RA_ALLOC_SPECIFIED;
1509*0Sstevel@tonic-gate 				request.ra_addr = (uint64_t)
1510*0Sstevel@tonic-gate 				    phys_spec.pci_phys_low;
1511*0Sstevel@tonic-gate 			}
1512*0Sstevel@tonic-gate 
1513*0Sstevel@tonic-gate 			/* allocate I/O space from the allocator */
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 			if (ndi_ra_alloc(ddi_get_parent(dip),
1516*0Sstevel@tonic-gate 				&request, &answer, &alen,
1517*0Sstevel@tonic-gate 				NDI_RA_TYPE_IO, NDI_RA_PASS)
1518*0Sstevel@tonic-gate 						!= NDI_SUCCESS) {
1519*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1520*0Sstevel@tonic-gate 				if (request.ra_flags ==
1521*0Sstevel@tonic-gate 				    NDI_RA_ALLOC_SPECIFIED)
1522*0Sstevel@tonic-gate 					cmn_err(CE_WARN, "Unable to allocate "
1523*0Sstevel@tonic-gate 					    "non relocatable IO Space 0x%p\n",
1524*0Sstevel@tonic-gate 					    (void *) request.ra_addr);
1525*0Sstevel@tonic-gate 				return (1);
1526*0Sstevel@tonic-gate 			}
1527*0Sstevel@tonic-gate 			FC_DEBUG3(1, CE_CONT,
1528*0Sstevel@tonic-gate 			    "I/O addr = [0x%x.%x] len [0x%x]\n",
1529*0Sstevel@tonic-gate 			    HIADDR(answer),
1530*0Sstevel@tonic-gate 			    LOADDR(answer),
1531*0Sstevel@tonic-gate 			    alen);
1532*0Sstevel@tonic-gate 
1533*0Sstevel@tonic-gate 			ddi_put32(h, (uint32_t *)v, LOADDR(answer));
1534*0Sstevel@tonic-gate 
1535*0Sstevel@tonic-gate 			phys_spec.pci_phys_low = LOADDR(answer);
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 			break;
1538*0Sstevel@tonic-gate 		default:
1539*0Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
1540*0Sstevel@tonic-gate 			return (1);
1541*0Sstevel@tonic-gate 		} /* switch */
1542*0Sstevel@tonic-gate 	}
1543*0Sstevel@tonic-gate 
1544*0Sstevel@tonic-gate 	/*
1545*0Sstevel@tonic-gate 	 * Now that memory locations are assigned,
1546*0Sstevel@tonic-gate 	 * update the assigned address property.
1547*0Sstevel@tonic-gate 	 */
1548*0Sstevel@tonic-gate 	if (pfc_update_assigned_prop(dip, &phys_spec)) {
1549*0Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
1550*0Sstevel@tonic-gate 		return (1);
1551*0Sstevel@tonic-gate 	}
1552*0Sstevel@tonic-gate 
1553*0Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 	return (0);
1556*0Sstevel@tonic-gate }
1557*0Sstevel@tonic-gate 
1558*0Sstevel@tonic-gate int
1559*0Sstevel@tonic-gate pci_free_resource(dev_info_t *dip, pci_regspec_t phys_spec)
1560*0Sstevel@tonic-gate {
1561*0Sstevel@tonic-gate 	int offset, tmp;
1562*0Sstevel@tonic-gate 	pci_regspec_t config;
1563*0Sstevel@tonic-gate 	caddr_t virt, v;
1564*0Sstevel@tonic-gate 	ddi_device_acc_attr_t acc;
1565*0Sstevel@tonic-gate 	ddi_acc_handle_t h;
1566*0Sstevel@tonic-gate 	ndi_ra_request_t request;
1567*0Sstevel@tonic-gate 	int l, error, flags = 0;
1568*0Sstevel@tonic-gate 
1569*0Sstevel@tonic-gate 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate 	config.pci_phys_hi = PCI_CONF_ADDR_MASK & phys_spec.pci_phys_hi;
1572*0Sstevel@tonic-gate 	config.pci_phys_hi &= ~PCI_REG_REG_M;
1573*0Sstevel@tonic-gate 	config.pci_phys_mid = config.pci_phys_low = 0;
1574*0Sstevel@tonic-gate 	config.pci_size_hi = config.pci_size_low = 0;
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 	/*
1577*0Sstevel@tonic-gate 	 * Map in configuration space (temporarily)
1578*0Sstevel@tonic-gate 	 */
1579*0Sstevel@tonic-gate 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1580*0Sstevel@tonic-gate 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
1581*0Sstevel@tonic-gate 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1582*0Sstevel@tonic-gate 
1583*0Sstevel@tonic-gate 	if (error = pci_map_phys(dip, &config, &virt, &acc, &h)) {
1584*0Sstevel@tonic-gate 		return (1);
1585*0Sstevel@tonic-gate 	}
1586*0Sstevel@tonic-gate 	if (fcpci_indirect_map(dip) == DDI_SUCCESS)
1587*0Sstevel@tonic-gate 		flags |= PCICFG_CONF_INDIRECT_MAP;
1588*0Sstevel@tonic-gate 
1589*0Sstevel@tonic-gate 	if (flags & PCICFG_CONF_INDIRECT_MAP) {
1590*0Sstevel@tonic-gate 		tmp = (int32_t)ddi_get32(h, (uint32_t *)virt);
1591*0Sstevel@tonic-gate 		error = DDI_SUCCESS;
1592*0Sstevel@tonic-gate 	} else
1593*0Sstevel@tonic-gate 		error = ddi_peek32(dip, (int32_t *)virt, (int32_t *)&tmp);
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	if (error == DDI_SUCCESS)
1596*0Sstevel@tonic-gate 		if ((tmp == (int32_t)0xffffffff) || (tmp == -1)) {
1597*0Sstevel@tonic-gate 			error = DDI_FAILURE;
1598*0Sstevel@tonic-gate 		}
1599*0Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
1600*0Sstevel@tonic-gate 		return (1);
1601*0Sstevel@tonic-gate 	}
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 
1604*0Sstevel@tonic-gate 	offset = PCI_REG_REG_G(phys_spec.pci_phys_hi);
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate 	v = virt + offset;
1607*0Sstevel@tonic-gate 
1608*0Sstevel@tonic-gate 	/*
1609*0Sstevel@tonic-gate 	 * Pick up the size to be freed. It may be different from
1610*0Sstevel@tonic-gate 	 * what probe finds.
1611*0Sstevel@tonic-gate 	 */
1612*0Sstevel@tonic-gate 	l = phys_spec.pci_size_low;
1613*0Sstevel@tonic-gate 
1614*0Sstevel@tonic-gate 	if (PCI_REG_REG_G(phys_spec.pci_phys_hi) == PCI_CONF_ROM) {
1615*0Sstevel@tonic-gate 		/* free memory back to the allocator */
1616*0Sstevel@tonic-gate 		if (ndi_ra_free(ddi_get_parent(dip), phys_spec.pci_phys_low,
1617*0Sstevel@tonic-gate 		    l, NDI_RA_TYPE_MEM,
1618*0Sstevel@tonic-gate 		    NDI_RA_PASS) != NDI_SUCCESS) {
1619*0Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
1620*0Sstevel@tonic-gate 			return (1);
1621*0Sstevel@tonic-gate 		}
1622*0Sstevel@tonic-gate 
1623*0Sstevel@tonic-gate 		/* Unmap the BAR by writing a zero */
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 		ddi_put32(h, (uint32_t *)v, 0);
1626*0Sstevel@tonic-gate 	} else {
1627*0Sstevel@tonic-gate 		switch (PCI_REG_ADDR_G(phys_spec.pci_phys_hi)) {
1628*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM64):
1629*0Sstevel@tonic-gate 			/* free memory back to the allocator */
1630*0Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
1631*0Sstevel@tonic-gate 			    LADDR(phys_spec.pci_phys_low,
1632*0Sstevel@tonic-gate 			    phys_spec.pci_phys_mid),
1633*0Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
1634*0Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
1635*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1636*0Sstevel@tonic-gate 				return (1);
1637*0Sstevel@tonic-gate 			}
1638*0Sstevel@tonic-gate 
1639*0Sstevel@tonic-gate 			break;
1640*0Sstevel@tonic-gate 
1641*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_MEM32):
1642*0Sstevel@tonic-gate 			/* free memory back to the allocator */
1643*0Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
1644*0Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
1645*0Sstevel@tonic-gate 			    l, NDI_RA_TYPE_MEM,
1646*0Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
1647*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1648*0Sstevel@tonic-gate 				return (1);
1649*0Sstevel@tonic-gate 			}
1650*0Sstevel@tonic-gate 
1651*0Sstevel@tonic-gate 			break;
1652*0Sstevel@tonic-gate 		case PCI_REG_ADDR_G(PCI_ADDR_IO):
1653*0Sstevel@tonic-gate 			/* free I/O space back to the allocator */
1654*0Sstevel@tonic-gate 			if (ndi_ra_free(ddi_get_parent(dip),
1655*0Sstevel@tonic-gate 			    phys_spec.pci_phys_low,
1656*0Sstevel@tonic-gate 			    l, NDI_RA_TYPE_IO,
1657*0Sstevel@tonic-gate 			    NDI_RA_PASS) != NDI_SUCCESS) {
1658*0Sstevel@tonic-gate 				pci_unmap_phys(&h, &config);
1659*0Sstevel@tonic-gate 				return (1);
1660*0Sstevel@tonic-gate 			}
1661*0Sstevel@tonic-gate 			break;
1662*0Sstevel@tonic-gate 		default:
1663*0Sstevel@tonic-gate 			pci_unmap_phys(&h, &config);
1664*0Sstevel@tonic-gate 			return (1);
1665*0Sstevel@tonic-gate 		} /* switch */
1666*0Sstevel@tonic-gate 	}
1667*0Sstevel@tonic-gate 
1668*0Sstevel@tonic-gate 	/*
1669*0Sstevel@tonic-gate 	 * Now that memory locations are assigned,
1670*0Sstevel@tonic-gate 	 * update the assigned address property.
1671*0Sstevel@tonic-gate 	 */
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate 	FC_DEBUG1(1, CE_CONT, "updating assigned-addresss for %x\n",
1674*0Sstevel@tonic-gate 	    phys_spec.pci_phys_hi);
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate 	if (pfc_remove_assigned_prop(dip, &phys_spec)) {
1677*0Sstevel@tonic-gate 		pci_unmap_phys(&h, &config);
1678*0Sstevel@tonic-gate 		return (1);
1679*0Sstevel@tonic-gate 	}
1680*0Sstevel@tonic-gate 
1681*0Sstevel@tonic-gate 	pci_unmap_phys(&h, &config);
1682*0Sstevel@tonic-gate 
1683*0Sstevel@tonic-gate 	return (0);
1684*0Sstevel@tonic-gate }
1685*0Sstevel@tonic-gate 
1686*0Sstevel@tonic-gate 
1687*0Sstevel@tonic-gate int
1688*0Sstevel@tonic-gate pci_map_phys(dev_info_t *dip, pci_regspec_t *phys_spec,
1689*0Sstevel@tonic-gate 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
1690*0Sstevel@tonic-gate 	ddi_acc_handle_t *handlep)
1691*0Sstevel@tonic-gate {
1692*0Sstevel@tonic-gate 	ddi_map_req_t mr;
1693*0Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
1694*0Sstevel@tonic-gate 	int result;
1695*0Sstevel@tonic-gate 
1696*0Sstevel@tonic-gate 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
1697*0Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
1698*0Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
1699*0Sstevel@tonic-gate 	hp->ah_dip = dip;
1700*0Sstevel@tonic-gate 	hp->ah_rnumber = 0;
1701*0Sstevel@tonic-gate 	hp->ah_offset = 0;
1702*0Sstevel@tonic-gate 	hp->ah_len = 0;
1703*0Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
1704*0Sstevel@tonic-gate 
1705*0Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
1706*0Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
1707*0Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)phys_spec;
1708*0Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
1709*0Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
1710*0Sstevel@tonic-gate 	mr.map_handlep = hp;
1711*0Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
1712*0Sstevel@tonic-gate 
1713*0Sstevel@tonic-gate 	result = ddi_map(dip, &mr, 0, 0, addrp);
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
1716*0Sstevel@tonic-gate 		impl_acc_hdl_free(*handlep);
1717*0Sstevel@tonic-gate 		*handlep = (ddi_acc_handle_t)NULL;
1718*0Sstevel@tonic-gate 	} else {
1719*0Sstevel@tonic-gate 		hp->ah_addr = *addrp;
1720*0Sstevel@tonic-gate 	}
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 	return (result);
1723*0Sstevel@tonic-gate }
1724*0Sstevel@tonic-gate 
1725*0Sstevel@tonic-gate void
1726*0Sstevel@tonic-gate pci_unmap_phys(ddi_acc_handle_t *handlep, pci_regspec_t *ph)
1727*0Sstevel@tonic-gate {
1728*0Sstevel@tonic-gate 	ddi_map_req_t mr;
1729*0Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
1730*0Sstevel@tonic-gate 
1731*0Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
1732*0Sstevel@tonic-gate 	ASSERT(hp);
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
1735*0Sstevel@tonic-gate 	mr.map_type = DDI_MT_REGSPEC;
1736*0Sstevel@tonic-gate 	mr.map_obj.rp = (struct regspec *)ph;
1737*0Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
1738*0Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
1739*0Sstevel@tonic-gate 	mr.map_handlep = hp;
1740*0Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
1741*0Sstevel@tonic-gate 
1742*0Sstevel@tonic-gate 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
1743*0Sstevel@tonic-gate 		hp->ah_len, &hp->ah_addr);
1744*0Sstevel@tonic-gate 
1745*0Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
1746*0Sstevel@tonic-gate 
1747*0Sstevel@tonic-gate 
1748*0Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
1749*0Sstevel@tonic-gate }
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate int
1752*0Sstevel@tonic-gate pfc_update_assigned_prop(dev_info_t *dip, pci_regspec_t *newone)
1753*0Sstevel@tonic-gate {
1754*0Sstevel@tonic-gate 	int		alen;
1755*0Sstevel@tonic-gate 	pci_regspec_t	*assigned;
1756*0Sstevel@tonic-gate 	caddr_t		newreg;
1757*0Sstevel@tonic-gate 	uint_t		status;
1758*0Sstevel@tonic-gate 
1759*0Sstevel@tonic-gate 	status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1760*0Sstevel@tonic-gate 		"assigned-addresses", (caddr_t)&assigned, &alen);
1761*0Sstevel@tonic-gate 	switch (status) {
1762*0Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
1763*0Sstevel@tonic-gate 		break;
1764*0Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
1765*0Sstevel@tonic-gate 			return (1);
1766*0Sstevel@tonic-gate 		default:
1767*0Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1768*0Sstevel@tonic-gate 			"assigned-addresses", (int *)newone,
1769*0Sstevel@tonic-gate 				sizeof (*newone)/sizeof (int));
1770*0Sstevel@tonic-gate 			return (0);
1771*0Sstevel@tonic-gate 	}
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate 	/*
1774*0Sstevel@tonic-gate 	 * Allocate memory for the existing
1775*0Sstevel@tonic-gate 	 * assigned-addresses(s) plus one and then
1776*0Sstevel@tonic-gate 	 * build it.
1777*0Sstevel@tonic-gate 	 */
1778*0Sstevel@tonic-gate 
1779*0Sstevel@tonic-gate 	newreg = kmem_zalloc(alen+sizeof (*newone), KM_SLEEP);
1780*0Sstevel@tonic-gate 
1781*0Sstevel@tonic-gate 	bcopy(assigned, newreg, alen);
1782*0Sstevel@tonic-gate 	bcopy(newone, newreg + alen, sizeof (*newone));
1783*0Sstevel@tonic-gate 
1784*0Sstevel@tonic-gate 	/*
1785*0Sstevel@tonic-gate 	 * Write out the new "assigned-addresses" spec
1786*0Sstevel@tonic-gate 	 */
1787*0Sstevel@tonic-gate 	(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1788*0Sstevel@tonic-gate 		"assigned-addresses", (int *)newreg,
1789*0Sstevel@tonic-gate 		(alen + sizeof (*newone))/sizeof (int));
1790*0Sstevel@tonic-gate 
1791*0Sstevel@tonic-gate 	kmem_free((caddr_t)newreg, alen+sizeof (*newone));
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	return (0);
1794*0Sstevel@tonic-gate }
1795*0Sstevel@tonic-gate int
1796*0Sstevel@tonic-gate pfc_remove_assigned_prop(dev_info_t *dip, pci_regspec_t *oldone)
1797*0Sstevel@tonic-gate {
1798*0Sstevel@tonic-gate 	int		alen, new_len, num_entries, i;
1799*0Sstevel@tonic-gate 	pci_regspec_t	*assigned;
1800*0Sstevel@tonic-gate 	uint_t		status;
1801*0Sstevel@tonic-gate 
1802*0Sstevel@tonic-gate 	status = ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1803*0Sstevel@tonic-gate 		"assigned-addresses", (caddr_t)&assigned, &alen);
1804*0Sstevel@tonic-gate 	switch (status) {
1805*0Sstevel@tonic-gate 		case DDI_PROP_SUCCESS:
1806*0Sstevel@tonic-gate 		break;
1807*0Sstevel@tonic-gate 		case DDI_PROP_NO_MEMORY:
1808*0Sstevel@tonic-gate 			return (1);
1809*0Sstevel@tonic-gate 		default:
1810*0Sstevel@tonic-gate 			return (0);
1811*0Sstevel@tonic-gate 	}
1812*0Sstevel@tonic-gate 
1813*0Sstevel@tonic-gate 	num_entries = alen / sizeof (pci_regspec_t);
1814*0Sstevel@tonic-gate 	new_len = alen - sizeof (pci_regspec_t);
1815*0Sstevel@tonic-gate 
1816*0Sstevel@tonic-gate 	/*
1817*0Sstevel@tonic-gate 	 * Search for the memory being removed.
1818*0Sstevel@tonic-gate 	 */
1819*0Sstevel@tonic-gate 	for (i = 0; i < num_entries; i++) {
1820*0Sstevel@tonic-gate 		if (assigned[i].pci_phys_hi == oldone->pci_phys_hi) {
1821*0Sstevel@tonic-gate 			if (new_len == 0) {
1822*0Sstevel@tonic-gate 				(void) ndi_prop_remove(DDI_DEV_T_NONE, dip,
1823*0Sstevel@tonic-gate 				    "assigned-addresses");
1824*0Sstevel@tonic-gate 				break;
1825*0Sstevel@tonic-gate 			}
1826*0Sstevel@tonic-gate 			if ((new_len - (i * sizeof (pci_regspec_t)))
1827*0Sstevel@tonic-gate 			    == 0) {
1828*0Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
1829*0Sstevel@tonic-gate 				    "%x removed from property (last entry)\n",
1830*0Sstevel@tonic-gate 				    oldone->pci_phys_hi);
1831*0Sstevel@tonic-gate 			} else {
1832*0Sstevel@tonic-gate 				bcopy((void *)(assigned + i + 1),
1833*0Sstevel@tonic-gate 				    (void *)(assigned + i),
1834*0Sstevel@tonic-gate 				    (new_len - (i * sizeof (pci_regspec_t))));
1835*0Sstevel@tonic-gate 
1836*0Sstevel@tonic-gate 				FC_DEBUG1(1, CE_CONT, "assigned-address entry "
1837*0Sstevel@tonic-gate 				    "%x removed from property\n",
1838*0Sstevel@tonic-gate 				    oldone->pci_phys_hi);
1839*0Sstevel@tonic-gate 			}
1840*0Sstevel@tonic-gate 			(void) ndi_prop_update_int_array(DDI_DEV_T_NONE,
1841*0Sstevel@tonic-gate 			    dip, "assigned-addresses", (int *)assigned,
1842*0Sstevel@tonic-gate 			    (new_len/sizeof (int)));
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate 			break;
1845*0Sstevel@tonic-gate 		}
1846*0Sstevel@tonic-gate 	}
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 	return (0);
1849*0Sstevel@tonic-gate }
1850*0Sstevel@tonic-gate /*
1851*0Sstevel@tonic-gate  * we recognize the non transparent bridge child nodes with the
1852*0Sstevel@tonic-gate  * following property. This is specific to this implementation only.
1853*0Sstevel@tonic-gate  * This property is specific to AP nodes only.
1854*0Sstevel@tonic-gate  */
1855*0Sstevel@tonic-gate #define	PCICFG_DEV_CONF_MAP_PROP		"pci-parent-indirect"
1856*0Sstevel@tonic-gate 
1857*0Sstevel@tonic-gate /*
1858*0Sstevel@tonic-gate  * If a non transparent bridge drives a hotplug/hotswap bus, then
1859*0Sstevel@tonic-gate  * the following property must be defined for the node either by
1860*0Sstevel@tonic-gate  * the driver or the OBP.
1861*0Sstevel@tonic-gate  */
1862*0Sstevel@tonic-gate #define	PCICFG_BUS_CONF_MAP_PROP		"pci-conf-indirect"
1863*0Sstevel@tonic-gate 
1864*0Sstevel@tonic-gate /*
1865*0Sstevel@tonic-gate  * this function is called only for SPARC platforms, where we may have
1866*0Sstevel@tonic-gate  * a mix n' match of direct vs indirectly mapped configuration space.
1867*0Sstevel@tonic-gate  */
1868*0Sstevel@tonic-gate /*ARGSUSED*/
1869*0Sstevel@tonic-gate static int
1870*0Sstevel@tonic-gate fcpci_indirect_map(dev_info_t *dip)
1871*0Sstevel@tonic-gate {
1872*0Sstevel@tonic-gate 	int rc = DDI_FAILURE;
1873*0Sstevel@tonic-gate 
1874*0Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip), DDI_PROP_DONTPASS,
1875*0Sstevel@tonic-gate 			PCICFG_DEV_CONF_MAP_PROP, DDI_FAILURE) != DDI_FAILURE)
1876*0Sstevel@tonic-gate 		rc = DDI_SUCCESS;
1877*0Sstevel@tonic-gate 	else
1878*0Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(dip),
1879*0Sstevel@tonic-gate 				DDI_PROP_DONTPASS, PCICFG_BUS_CONF_MAP_PROP,
1880*0Sstevel@tonic-gate 				DDI_FAILURE) != DDI_FAILURE)
1881*0Sstevel@tonic-gate 			rc = DDI_SUCCESS;
1882*0Sstevel@tonic-gate 
1883*0Sstevel@tonic-gate 	return (rc);
1884*0Sstevel@tonic-gate }
1885