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