xref: /onnv-gate/usr/src/uts/sun4u/starcat/io/fcgp2.c (revision 7799:05fc7b266484)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*7799SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel /*
281708Sstevel  * fcgp2.c: Framework gp2 (Safari) fcode ops
291708Sstevel  */
301708Sstevel #include <sys/types.h>
311708Sstevel #include <sys/kmem.h>
321708Sstevel #include <sys/systm.h>
331708Sstevel #include <sys/pci.h>
341708Sstevel #include <sys/ddi.h>
351708Sstevel #include <sys/sunddi.h>
361708Sstevel #include <sys/sunndi.h>
371708Sstevel #include <sys/ddidmareq.h>
381708Sstevel #include <sys/modctl.h>
391708Sstevel #include <sys/ndi_impldefs.h>
401708Sstevel #include <sys/fcode.h>
411708Sstevel #include <sys/promif.h>
421708Sstevel #include <sys/promimpl.h>
431708Sstevel 
441708Sstevel static int gfc_map_in(dev_info_t *, fco_handle_t, fc_ci_t *);
451708Sstevel static int gfc_map_out(dev_info_t *, fco_handle_t, fc_ci_t *);
461708Sstevel static int gfc_register_fetch(dev_info_t *, fco_handle_t, fc_ci_t *);
471708Sstevel static int gfc_register_store(dev_info_t *, fco_handle_t, fc_ci_t *);
481708Sstevel static int gfc_claim_address(dev_info_t *, fco_handle_t, fc_ci_t *);
491708Sstevel static int gfc_claim_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
501708Sstevel static int gfc_release_memory(dev_info_t *, fco_handle_t, fc_ci_t *);
511708Sstevel static int gfc_vtop(dev_info_t *, fco_handle_t, fc_ci_t *);
521708Sstevel static int gfc_master_intr(dev_info_t *, fco_handle_t, fc_ci_t *);
531708Sstevel 
541708Sstevel static int gfc_config_child(dev_info_t *, fco_handle_t, fc_ci_t *);
551708Sstevel 
561708Sstevel static int gfc_get_fcode_size(dev_info_t *, fco_handle_t, fc_ci_t *);
571708Sstevel static int gfc_get_fcode(dev_info_t *, fco_handle_t, fc_ci_t *);
581708Sstevel 
591708Sstevel int prom_get_fcode_size(char *);
601708Sstevel int prom_get_fcode(char *, char *);
611708Sstevel 
621708Sstevel int fcpci_unloadable;
631708Sstevel int no_advisory_dma;
641708Sstevel 
651708Sstevel #define	HIADDR(n) ((uint32_t)(((uint64_t)(n) & 0xFFFFFFFF00000000)>> 32))
661708Sstevel #define	LOADDR(n)((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
671708Sstevel #define	LADDR(lo, hi)    (((uint64_t)(hi) << 32) | (uint32_t)(lo))
681708Sstevel #define	PCI_4GIG_LIMIT 0xFFFFFFFFUL
691708Sstevel 
701708Sstevel 
711708Sstevel /*
721708Sstevel  * Module linkage information for the kernel.
731708Sstevel  */
741708Sstevel static struct modlmisc modlmisc = {
75*7799SRichard.Bean@Sun.COM 	&mod_miscops, "FCode gp2 (safari) bus functions"
761708Sstevel };
771708Sstevel 
781708Sstevel static struct modlinkage modlinkage = {
791708Sstevel 	MODREV_1, (void *)&modlmisc, NULL
801708Sstevel };
811708Sstevel 
821708Sstevel int
_init(void)831708Sstevel _init(void)
841708Sstevel {
851708Sstevel 	return (mod_install(&modlinkage));
861708Sstevel }
871708Sstevel 
881708Sstevel int
_fini(void)891708Sstevel _fini(void)
901708Sstevel {
911708Sstevel 	if (fcpci_unloadable)
921708Sstevel 		return (mod_remove(&modlinkage));
931708Sstevel 	return (EBUSY);
941708Sstevel }
951708Sstevel 
961708Sstevel int
_info(struct modinfo * modinfop)971708Sstevel _info(struct modinfo *modinfop)
981708Sstevel {
991708Sstevel 	return (mod_info(&modlinkage, modinfop));
1001708Sstevel }
1011708Sstevel 
1021708Sstevel 
1031708Sstevel struct gfc_ops_v {
1041708Sstevel 	char *svc_name;
1051708Sstevel 	fc_ops_t *f;
1061708Sstevel };
1071708Sstevel 
1081708Sstevel struct gfc_ops_v gp2_pov[] = {
1091708Sstevel 	{	"map-in",		gfc_map_in},
1101708Sstevel 	{	"map-out",		gfc_map_out},
1111708Sstevel 	{	"rx@",			gfc_register_fetch},
1121708Sstevel 	{	"rl@",			gfc_register_fetch},
1131708Sstevel 	{	"rw@",			gfc_register_fetch},
1141708Sstevel 	{	"rb@",			gfc_register_fetch},
1151708Sstevel 	{	"rx!",			gfc_register_store},
1161708Sstevel 	{	"rl!",			gfc_register_store},
1171708Sstevel 	{	"rw!",			gfc_register_store},
1181708Sstevel 	{	"rb!",			gfc_register_store},
1191708Sstevel 	{	"claim-address",	gfc_claim_address},
1201708Sstevel 	{	"master-interrupt",	gfc_master_intr},
1211772Sjl139090 	{	"claim-memory",		gfc_claim_memory},
1221772Sjl139090 	{	"release-memory",	gfc_release_memory},
1231772Sjl139090 	{	"vtop",			gfc_vtop},
1241708Sstevel 	{	FC_CONFIG_CHILD,	gfc_config_child},
1251708Sstevel 	{	FC_GET_FCODE_SIZE,	gfc_get_fcode_size},
1261708Sstevel 	{	FC_GET_FCODE,		gfc_get_fcode},
1271708Sstevel 	{	NULL,			NULL}
1281708Sstevel };
1291708Sstevel 
1301708Sstevel struct gfc_ops_v gp2_shared_pov[] = {
1311708Sstevel 	{	NULL,			NULL}
1321708Sstevel };
1331708Sstevel 
1341708Sstevel static int gp2_map_phys(dev_info_t *, struct regspec *,  caddr_t *,
1351708Sstevel     ddi_device_acc_attr_t *, ddi_acc_handle_t *);
1361708Sstevel static void gp2_unmap_phys(ddi_acc_handle_t *);
1371708Sstevel 
1381708Sstevel fco_handle_t
gp2_fc_ops_alloc_handle(dev_info_t * ap,dev_info_t * child,void * fcode,size_t fcode_size,char * unit_address,char * my_args)1391708Sstevel gp2_fc_ops_alloc_handle(dev_info_t *ap, dev_info_t *child,
1401708Sstevel     void *fcode, size_t fcode_size, char *unit_address,
1411708Sstevel     char *my_args)
1421708Sstevel {
1431708Sstevel 	fco_handle_t rp;
1441708Sstevel 	phandle_t h;
1451708Sstevel 
1461708Sstevel 	rp = kmem_zalloc(sizeof (struct fc_resource_list), KM_SLEEP);
1471708Sstevel 	rp->next_handle = fc_ops_alloc_handle(ap, child, fcode, fcode_size,
1481708Sstevel 	    unit_address, NULL);
1491708Sstevel 	rp->ap = ap;
1501708Sstevel 	rp->child = child;
1511708Sstevel 	rp->fcode = fcode;
1521708Sstevel 	rp->fcode_size = fcode_size;
1531708Sstevel 	rp->my_args = my_args;
1541708Sstevel 
1551708Sstevel 	if (unit_address) {
1561708Sstevel 		char *buf;
1571708Sstevel 
1581708Sstevel 		buf = kmem_zalloc(strlen(unit_address) + 1, KM_SLEEP);
1591708Sstevel 		(void) strcpy(buf, unit_address);
1601708Sstevel 		rp->unit_address = buf;
1611708Sstevel 	}
1621708Sstevel 
1631708Sstevel 	/*
1641708Sstevel 	 * Add the child's nodeid to our table...
1651708Sstevel 	 */
1661708Sstevel 	h = ddi_get_nodeid(rp->child);
1671708Sstevel 	fc_add_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child, h);
1681708Sstevel 
1691708Sstevel 	return (rp);
1701708Sstevel }
1711708Sstevel 
1721708Sstevel void
gp2_fc_ops_free_handle(fco_handle_t rp)1731708Sstevel gp2_fc_ops_free_handle(fco_handle_t rp)
1741708Sstevel {
1751708Sstevel 	struct fc_resource *ip, *np;
1761708Sstevel 
1771708Sstevel 	ASSERT(rp);
1781708Sstevel 
1791708Sstevel 	if (rp->next_handle)
1801708Sstevel 		fc_ops_free_handle(rp->next_handle);
1811708Sstevel 	if (rp->unit_address)
1821708Sstevel 		kmem_free(rp->unit_address, strlen(rp->unit_address) + 1);
1831708Sstevel 	if (rp->my_args != NULL)
1841708Sstevel 		kmem_free(rp->my_args, strlen(rp->my_args) + 1);
1851708Sstevel 
1861708Sstevel 	/*
1871708Sstevel 	 * Release all the resources from the resource list
1881708Sstevel 	 */
1891708Sstevel 	for (ip = rp->head; ip != NULL; ip = np) {
1901708Sstevel 		np = ip->next;
1911708Sstevel 		switch (ip->type) {
1921708Sstevel 		case RT_MAP:
1931708Sstevel 			FC_DEBUG1(1, CE_CONT, "gp2_fc_ops_free: "
1941708Sstevel 			    " map handle - %p\n", ip->fc_map_handle);
1951708Sstevel 			break;
1961708Sstevel 		case RT_DMA:
1971708Sstevel 			/* DMA has to be freed up at exit time */
1981708Sstevel 			cmn_err(CE_CONT, "gfc_fc_ops_free: DMA seen!\n");
1991708Sstevel 			break;
2001708Sstevel 		case RT_CONTIGIOUS:
2011708Sstevel 			FC_DEBUG2(1, CE_CONT, "gp2_fc_ops_free: "
2021708Sstevel 			    "Free claim-memory resource 0x%lx size 0x%x\n",
2031708Sstevel 			    ip->fc_contig_virt, ip->fc_contig_len);
2041708Sstevel 
2051708Sstevel 			(void) ndi_ra_free(ddi_root_node(),
2061708Sstevel 			    (uint64_t)ip->fc_contig_virt,
2071708Sstevel 			    ip->fc_contig_len, "gptwo-contigousmem",
2081708Sstevel 			    NDI_RA_PASS);
2091708Sstevel 
2101708Sstevel 			break;
2111708Sstevel 		default:
2121708Sstevel 			cmn_err(CE_CONT, "gp2_fc_ops_free: "
2131708Sstevel 			    "unknown resource type %d\n", ip->type);
2141708Sstevel 			break;
2151708Sstevel 		}
2161708Sstevel 		fc_rem_resource(rp, ip);
2171708Sstevel 		kmem_free(ip, sizeof (struct fc_resource));
2181708Sstevel 	}
2191708Sstevel 	kmem_free(rp, sizeof (struct fc_resource_list));
2201708Sstevel }
2211708Sstevel 
2221708Sstevel int
gp2_fc_ops(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2231708Sstevel gp2_fc_ops(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2241708Sstevel {
2251708Sstevel 	struct gfc_ops_v *pv;
2261708Sstevel 	char *name = fc_cell2ptr(cp->svc_name);
2271708Sstevel 
2281708Sstevel 	ASSERT(rp);
2291708Sstevel 
2301708Sstevel 	/*
2311708Sstevel 	 * First try the generic fc_ops. If the ops is a shared op,
2321708Sstevel 	 * also call our local function.
2331708Sstevel 	 */
2341708Sstevel 	if (fc_ops(ap, rp->next_handle, cp) == 0) {
2351708Sstevel 		for (pv = gp2_shared_pov; pv->svc_name != NULL; ++pv)
2361708Sstevel 			if (strcmp(pv->svc_name, name) == 0)
2371708Sstevel 				return (pv->f(ap, rp, cp));
2381708Sstevel 		return (0);
2391708Sstevel 	}
2401708Sstevel 
2411708Sstevel 	for (pv = gp2_pov; pv->svc_name != NULL; ++pv)
2421708Sstevel 		if (strcmp(pv->svc_name, name) == 0)
2431708Sstevel 			return (pv->f(ap, rp, cp));
2441708Sstevel 
2451708Sstevel 	FC_DEBUG1(9, CE_CONT, "gp2_fc_ops: <%s> not serviced\n", name);
2461708Sstevel 
2471708Sstevel 	return (-1);
2481708Sstevel }
2491708Sstevel 
2501708Sstevel /*
2511708Sstevel  * map-in  (phys.lo phys.hi size -- virt )
2521708Sstevel  */
2531708Sstevel static int
gfc_map_in(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)2541708Sstevel gfc_map_in(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
2551708Sstevel {
2561708Sstevel 	size_t len;
2571708Sstevel 	int error;
2581708Sstevel 	caddr_t virt;
2591708Sstevel 	struct fc_resource *ip;
2601708Sstevel 	struct regspec r;
2611708Sstevel 	ddi_device_acc_attr_t acc;
2621708Sstevel 	ddi_acc_handle_t h;
2631708Sstevel 
2641708Sstevel 	if (fc_cell2int(cp->nargs) != 3)
2651708Sstevel 		return (fc_syntax_error(cp, "nargs must be 3"));
2661708Sstevel 
2671708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
2681708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
2691708Sstevel 
2701708Sstevel 	r.regspec_size = len = fc_cell2size(fc_arg(cp, 0));
2711708Sstevel 	r.regspec_bustype = fc_cell2uint(fc_arg(cp, 1));
2721708Sstevel 	r.regspec_addr = fc_cell2uint(fc_arg(cp, 2));
2731708Sstevel 
2741708Sstevel 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2751708Sstevel 	acc.devacc_attr_endian_flags = DDI_STRUCTURE_BE_ACC;
2761708Sstevel 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2771708Sstevel 
2781708Sstevel 	FC_DEBUG3(1, CE_CONT, "gfc_map_in: attempting map in "
2791708Sstevel 	    "address 0x%08x.%08x length %x\n", r.regspec_bustype,
2801708Sstevel 	    r.regspec_addr, r.regspec_size);
2811708Sstevel 
2821708Sstevel 	error = gp2_map_phys(rp->child, &r, &virt, &acc, &h);
2831708Sstevel 
2841708Sstevel 	if (error)  {
2851708Sstevel 		FC_DEBUG3(1, CE_CONT, "gfc_map_in: map in failed - "
2861708Sstevel 		    "address 0x%08x.%08x length %x\n", r.regspec_bustype,
2871708Sstevel 		    r.regspec_addr, r.regspec_size);
2881708Sstevel 
2891708Sstevel 		return (fc_priv_error(cp, "gp2 map-in failed"));
2901708Sstevel 	}
2911708Sstevel 
2921708Sstevel 	FC_DEBUG1(3, CE_CONT, "gp2_map_in: returning virt %p\n", virt);
2931708Sstevel 
2941708Sstevel 	cp->nresults = fc_int2cell(1);
2951708Sstevel 	fc_result(cp, 0) = fc_ptr2cell(virt);
2961708Sstevel 
2971708Sstevel 	/*
2981708Sstevel 	 * Log this resource ...
2991708Sstevel 	 */
3001708Sstevel 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
3011708Sstevel 	ip->type = RT_MAP;
3021708Sstevel 	ip->fc_map_virt = virt;
3031708Sstevel 	ip->fc_map_len = len;
3041708Sstevel 	ip->fc_map_handle = h;
3051708Sstevel 	fc_add_resource(rp, ip);
3061708Sstevel 
3071708Sstevel 	return (fc_success_op(ap, rp, cp));
3081708Sstevel }
3091708Sstevel 
3101708Sstevel /*
3111708Sstevel  * map-out ( virt size -- )
3121708Sstevel  */
3131708Sstevel static int
gfc_map_out(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3141708Sstevel gfc_map_out(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3151708Sstevel {
3161708Sstevel 	caddr_t virt;
3171708Sstevel 	size_t len;
3181708Sstevel 	struct fc_resource *ip;
3191708Sstevel 
3201708Sstevel 	if (fc_cell2int(cp->nargs) != 2)
3211708Sstevel 		return (fc_syntax_error(cp, "nargs must be 2"));
3221708Sstevel 
3231708Sstevel 	virt = fc_cell2ptr(fc_arg(cp, 1));
3241708Sstevel 
3251708Sstevel 	len = fc_cell2size(fc_arg(cp, 0));
3261708Sstevel 
3271708Sstevel 	FC_DEBUG2(1, CE_CONT, "gp2_map_out: attempting map out %p %x\n",
3281708Sstevel 	    virt, len);
3291708Sstevel 
3301708Sstevel 	/*
3311708Sstevel 	 * Find if this request matches a mapping resource we set up.
3321708Sstevel 	 */
3331708Sstevel 	fc_lock_resource_list(rp);
3341708Sstevel 	for (ip = rp->head; ip != NULL; ip = ip->next) {
3351708Sstevel 		if (ip->type != RT_MAP)
3361708Sstevel 			continue;
3371708Sstevel 		if (ip->fc_map_virt != virt)
3381708Sstevel 			continue;
3391708Sstevel 		if (ip->fc_map_len == len)
3401708Sstevel 			break;
3411708Sstevel 	}
3421708Sstevel 	fc_unlock_resource_list(rp);
3431708Sstevel 
3441708Sstevel 	if (ip == NULL)
3451708Sstevel 		return (fc_priv_error(cp, "request doesn't match a "
3461708Sstevel 		    "known mapping"));
3471708Sstevel 
3481708Sstevel 	gp2_unmap_phys(&ip->fc_map_handle);
3491708Sstevel 
3501708Sstevel 	/*
3511708Sstevel 	 * remove the resource from the list and release it.
3521708Sstevel 	 */
3531708Sstevel 	fc_rem_resource(rp, ip);
3541708Sstevel 	kmem_free(ip, sizeof (struct fc_resource));
3551708Sstevel 
3561708Sstevel 	cp->nresults = fc_int2cell(0);
3571708Sstevel 	return (fc_success_op(ap, rp, cp));
3581708Sstevel }
3591708Sstevel 
3601708Sstevel static int
gfc_register_fetch(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)3611708Sstevel gfc_register_fetch(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
3621708Sstevel {
3631708Sstevel 	size_t len;
3641708Sstevel 	caddr_t virt;
3651708Sstevel 	int error = 0;
3661708Sstevel 	uint64_t x;
3671708Sstevel 	uint32_t l;
3681708Sstevel 	uint16_t w;
3691708Sstevel 	uint8_t b;
3701708Sstevel 	char *name = fc_cell2ptr(cp->svc_name);
3711708Sstevel 	struct fc_resource *ip;
3721708Sstevel 
3731708Sstevel 	if (fc_cell2int(cp->nargs) != 1)
3741708Sstevel 		return (fc_syntax_error(cp, "nargs must be 1"));
3751708Sstevel 
3761708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
3771708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
3781708Sstevel 
3791708Sstevel 	virt = fc_cell2ptr(fc_arg(cp, 0));
3801708Sstevel 
3811708Sstevel 	/*
3821708Sstevel 	 * Determine the access width .. we can switch on the 2nd
3831708Sstevel 	 * character of the name which is "rx@", "rl@", "rb@" or "rw@"
3841708Sstevel 	 */
3851708Sstevel 	switch (*(name + 1)) {
3861708Sstevel 	case 'x':	len = sizeof (x); break;
3871708Sstevel 	case 'l':	len = sizeof (l); break;
3881708Sstevel 	case 'w':	len = sizeof (w); break;
3891708Sstevel 	case 'b':	len = sizeof (b); break;
3901708Sstevel 	}
3911708Sstevel 
3921708Sstevel 	/*
3931708Sstevel 	 * Check the alignment ...
3941708Sstevel 	 */
3951708Sstevel 	if (((intptr_t)virt & (len - 1)) != 0)
3961708Sstevel 		return (fc_priv_error(cp, "unaligned access"));
3971708Sstevel 
3981708Sstevel 	/*
3991708Sstevel 	 * Find if this virt is 'within' a request we know about
4001708Sstevel 	 */
4011708Sstevel 	fc_lock_resource_list(rp);
4021708Sstevel 	for (ip = rp->head; ip != NULL; ip = ip->next) {
4031708Sstevel 		if (ip->type == RT_MAP) {
4041708Sstevel 		    if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
4051708Sstevel 			((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
4061708Sstevel 				break;
4071708Sstevel 		} else if (ip->type == RT_CONTIGIOUS) {
4081708Sstevel 		    if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
4091708Sstevel 			<= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
4101708Sstevel 				break;
4111708Sstevel 		}
4121708Sstevel 	}
4131708Sstevel 	fc_unlock_resource_list(rp);
4141708Sstevel 
4151708Sstevel 	if (ip == NULL) {
4161708Sstevel 		return (fc_priv_error(cp, "request not within a "
4171708Sstevel 		    "known mapping or contigious adddress"));
4181708Sstevel 	}
4191708Sstevel 
4201708Sstevel 	switch (len) {
4211708Sstevel 	case sizeof (x):
4221708Sstevel 		if (ip->type == RT_MAP)
4231708Sstevel 		    error = ddi_peek64(rp->child,
4241708Sstevel 			(int64_t *)virt, (int64_t *)&x);
4251708Sstevel 		else /* RT_CONTIGIOUS */
4261708Sstevel 		    x = *(int64_t *)virt;
4271708Sstevel 		break;
4281708Sstevel 	case sizeof (l):
4291708Sstevel 		if (ip->type == RT_MAP)
4301708Sstevel 		    error = ddi_peek32(rp->child,
4311708Sstevel 			(int32_t *)virt, (int32_t *)&l);
4321708Sstevel 		else /* RT_CONTIGIOUS */
4331708Sstevel 		    l = *(int32_t *)virt;
4341708Sstevel 		break;
4351708Sstevel 	case sizeof (w):
4361708Sstevel 		if (ip->type == RT_MAP)
4371708Sstevel 		    error = ddi_peek16(rp->child,
4381708Sstevel 			(int16_t *)virt, (int16_t *)&w);
4391708Sstevel 		else /* RT_CONTIGIOUS */
4401708Sstevel 		    w = *(int16_t *)virt;
4411708Sstevel 		break;
4421708Sstevel 	case sizeof (b):
4431708Sstevel 		if (ip->type == RT_MAP)
4441708Sstevel 		    error = ddi_peek8(rp->child,
4451708Sstevel 			(int8_t *)virt, (int8_t *)&b);
4461708Sstevel 		else /* RT_CONTIGIOUS */
4471708Sstevel 		    b = *(int8_t *)virt;
4481708Sstevel 		break;
4491708Sstevel 	}
4501708Sstevel 
4511708Sstevel 	if (error) {
4521708Sstevel 		FC_DEBUG2(1, CE_CONT, "gfc_register_fetch: access error "
4531708Sstevel 		    "accessing virt %p len %d\n", virt, len);
4541708Sstevel 		return (fc_priv_error(cp, "access error"));
4551708Sstevel 	}
4561708Sstevel 
4571708Sstevel 	cp->nresults = fc_int2cell(1);
4581708Sstevel 	switch (len) {
4591708Sstevel 	case sizeof (x): fc_result(cp, 0) = x; break;
4601708Sstevel 	case sizeof (l): fc_result(cp, 0) = fc_uint32_t2cell(l); break;
4611708Sstevel 	case sizeof (w): fc_result(cp, 0) = fc_uint16_t2cell(w); break;
4621708Sstevel 	case sizeof (b): fc_result(cp, 0) = fc_uint8_t2cell(b); break;
4631708Sstevel 	}
4641708Sstevel 	return (fc_success_op(ap, rp, cp));
4651708Sstevel }
4661708Sstevel 
4671708Sstevel static int
gfc_register_store(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)4681708Sstevel gfc_register_store(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
4691708Sstevel {
4701708Sstevel 	size_t len;
4711708Sstevel 	caddr_t virt;
4721708Sstevel 	uint64_t x;
4731708Sstevel 	uint32_t l;
4741708Sstevel 	uint16_t w;
4751708Sstevel 	uint8_t b;
4761708Sstevel 	char *name = fc_cell2ptr(cp->svc_name);
4771708Sstevel 	struct fc_resource *ip;
4781708Sstevel 	int error = 0;
4791708Sstevel 
4801708Sstevel 	if (fc_cell2int(cp->nargs) != 2)
4811708Sstevel 		return (fc_syntax_error(cp, "nargs must be 2"));
4821708Sstevel 
4831708Sstevel 	virt = fc_cell2ptr(fc_arg(cp, 0));
4841708Sstevel 
4851708Sstevel 	/*
4861708Sstevel 	 * Determine the access width .. we can switch on the 2nd
4871708Sstevel 	 * character of the name which is "rx!", "rl!", "rb!" or "rw!"
4881708Sstevel 	 */
4891708Sstevel 	switch (*(name + 1)) {
4901708Sstevel 	case 'x': len = sizeof (x); x = fc_arg(cp, 1); break;
4911708Sstevel 	case 'l': len = sizeof (l); l = fc_cell2uint32_t(fc_arg(cp, 1)); break;
4921708Sstevel 	case 'w': len = sizeof (w); w = fc_cell2uint16_t(fc_arg(cp, 1)); break;
4931708Sstevel 	case 'b': len = sizeof (b); b = fc_cell2uint8_t(fc_arg(cp, 1)); break;
4941708Sstevel 	}
4951708Sstevel 
4961708Sstevel 	/*
4971708Sstevel 	 * Check the alignment ...
4981708Sstevel 	 */
4991708Sstevel 	if (((intptr_t)virt & (len - 1)) != 0)
5001708Sstevel 		return (fc_priv_error(cp, "unaligned access"));
5011708Sstevel 
5021708Sstevel 	/*
5031708Sstevel 	 * Find if this virt is 'within' a request we know about
5041708Sstevel 	 */
5051708Sstevel 	fc_lock_resource_list(rp);
5061708Sstevel 	for (ip = rp->head; ip != NULL; ip = ip->next) {
5071708Sstevel 		if (ip->type == RT_MAP) {
5081708Sstevel 		    if ((virt >= (caddr_t)ip->fc_map_virt) && ((virt + len) <=
5091708Sstevel 			((caddr_t)ip->fc_map_virt + ip->fc_map_len)))
5101708Sstevel 				break;
5111708Sstevel 		} else if (ip->type == RT_CONTIGIOUS) {
5121708Sstevel 		    if ((virt >= (caddr_t)ip->fc_contig_virt) && ((virt + len)
5131708Sstevel 			<= ((caddr_t)ip->fc_contig_virt + ip->fc_contig_len)))
5141708Sstevel 				break;
5151708Sstevel 		}
5161708Sstevel 	}
5171708Sstevel 	fc_unlock_resource_list(rp);
5181708Sstevel 
5191708Sstevel 	if (ip == NULL)
5201708Sstevel 		return (fc_priv_error(cp, "request not within a "
5211708Sstevel 		    "known mapping or contigious address"));
5221708Sstevel 
5231708Sstevel 	switch (len) {
5241708Sstevel 	case sizeof (x):
5251708Sstevel 		if (ip->type == RT_MAP)
5261708Sstevel 			error = ddi_poke64(rp->child, (int64_t *)virt, x);
5271708Sstevel 		else if (ip->type == RT_CONTIGIOUS)
5281708Sstevel 			*(uint64_t *)virt = x;
5291708Sstevel 		break;
5301708Sstevel 	case sizeof (l):
5311708Sstevel 		if (ip->type == RT_MAP)
5321708Sstevel 			error = ddi_poke32(rp->child, (int32_t *)virt, l);
5331708Sstevel 		else if (ip->type == RT_CONTIGIOUS)
5341708Sstevel 			*(uint32_t *)virt = l;
5351708Sstevel 		break;
5361708Sstevel 	case sizeof (w):
5371708Sstevel 		if (ip->type == RT_MAP)
5381708Sstevel 			error = ddi_poke16(rp->child, (int16_t *)virt, w);
5391708Sstevel 		else if (ip->type == RT_CONTIGIOUS)
5401708Sstevel 			*(uint16_t *)virt = w;
5411708Sstevel 		break;
5421708Sstevel 	case sizeof (b):
5431708Sstevel 		if (ip->type == RT_MAP)
5441708Sstevel 			error = ddi_poke8(rp->child, (int8_t *)virt, b);
5451708Sstevel 		else if (ip->type == RT_CONTIGIOUS)
5461708Sstevel 			*(uint8_t *)virt = b;
5471708Sstevel 		break;
5481708Sstevel 	}
5491708Sstevel 
5501708Sstevel 	if (error == DDI_FAILURE) {
5511708Sstevel 		FC_DEBUG2(1, CE_CONT, "gfc_register_store: access error "
5521708Sstevel 		    "accessing virt %p len %d\n", virt, len);
5531708Sstevel 		return (fc_priv_error(cp, "access error"));
5541708Sstevel 	}
5551708Sstevel 
5561708Sstevel 	cp->nresults = fc_int2cell(0);
5571708Sstevel 	return (fc_success_op(ap, rp, cp));
5581708Sstevel }
5591708Sstevel 
5601708Sstevel static int
gfc_master_intr(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)5611708Sstevel gfc_master_intr(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5621708Sstevel {
5631708Sstevel 	int xt, portid;
5641708Sstevel 
5651708Sstevel 	if (fc_cell2int(cp->nargs) != 2)
5661708Sstevel 		return (fc_syntax_error(cp, "nargs must be 4"));
5671708Sstevel 
5681708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
5691708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
5701708Sstevel 
5711708Sstevel 	xt = fc_cell2int(fc_arg(cp, 1));
5721708Sstevel 	portid = fc_cell2int(fc_arg(cp, 0));
5731708Sstevel 
5741708Sstevel 	FC_DEBUG2(1, CE_CONT, "gfc_master_intr: reset-int-xt=%x portid=%x",
5751708Sstevel 	    xt, portid);
5761708Sstevel 
5771708Sstevel 	cp->nresults = fc_int2cell(1);
5781708Sstevel 	fc_result(cp, 0) = 0;
5791708Sstevel 
5801708Sstevel 	return (fc_success_op(ap, rp, cp));
5811708Sstevel }
5821708Sstevel 
5831708Sstevel /*
5841708Sstevel  * gfc_claim_address
5851708Sstevel  *
5861708Sstevel  * claim-address (size.lo size.hi type align bar portid -- base.lo base.hi )
5871708Sstevel  */
5881708Sstevel static int
gfc_claim_address(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)5891708Sstevel gfc_claim_address(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
5901708Sstevel {
5911708Sstevel 	int bar, portid;
5921708Sstevel 	uint64_t exp, slot, port, slice;
5931708Sstevel 	uint64_t paddr;
5941708Sstevel 
5951708Sstevel 	if (fc_cell2int(cp->nargs) != 6)
5961708Sstevel 		return (fc_syntax_error(cp, "nargs must be 6"));
5971708Sstevel 
5981708Sstevel 	if (fc_cell2int(cp->nresults) < 2)
5991708Sstevel 		return (fc_syntax_error(cp, "nresults must be 2"));
6001708Sstevel 
6011708Sstevel 	bar = fc_cell2int(fc_arg(cp, 1));
6021708Sstevel 	portid = fc_cell2int(fc_arg(cp, 0));
6031708Sstevel 
6041708Sstevel 	exp = portid >> 5;
6051708Sstevel 	slot = (0x8 & portid) >> 3;
6061708Sstevel 	port = portid & 0x1;
6071708Sstevel 
6081708Sstevel 	switch (bar) {
6091708Sstevel 	case 0: /* PCI IO Bus A */
6101708Sstevel 		paddr = (exp << 28) | (port << 26) | (slot << 27) |
6111708Sstevel 		    ((uint64_t)0x402 << 32);
6121708Sstevel 
6131708Sstevel 		break;
6141708Sstevel 	case 1: /* PCI Memory Bus A */
6151708Sstevel 		slice = (exp * 2) + slot + 1;
6161708Sstevel 
6171708Sstevel 		paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
6181708Sstevel 		    ((uint64_t)port << 33);
6191708Sstevel 
6201708Sstevel 		break;
6211708Sstevel 	case 2: /* PCI IO Bus B */
6221708Sstevel 		paddr = (exp << 28) | (port << 26) | (slot << 27) |
6231708Sstevel 		    ((uint64_t)0x402 << 32)  | (1 << 25);
6241708Sstevel 
6251708Sstevel 		break;
6261708Sstevel 	case 3: /* PCI Memory Bus B */
6271708Sstevel 		slice = (exp * 2) + slot + 1;
6281708Sstevel 
6291708Sstevel 		paddr = ((uint64_t)1 << 42) | ((uint64_t)slice << 34) |
6301708Sstevel 		    ((uint64_t)port << 33);
6311708Sstevel 
6321708Sstevel 		paddr |= ((uint64_t)1 << 32);
6331708Sstevel 
6341708Sstevel 		break;
6351708Sstevel 	default:
6361708Sstevel 		cmn_err(CE_WARN,
6371708Sstevel 		    "gfc_claim_address - invalid BAR=0x%x\n", bar);
6381708Sstevel 
6391708Sstevel 		return (fc_syntax_error(cp, "invalid argument"));
6401708Sstevel 	}
6411708Sstevel 
6421708Sstevel 	FC_DEBUG1(1, CE_CONT, "gfc_claim_address: returning 0x%lx\n", paddr);
6431708Sstevel 
6441708Sstevel 	cp->nresults = fc_int2cell(2);
6451708Sstevel 	fc_result(cp, 0) = LOADDR(paddr);
6461708Sstevel 	fc_result(cp, 1) = HIADDR(paddr);
6471708Sstevel 
6481708Sstevel 	return (fc_success_op(ap, rp, cp));
6491708Sstevel }
6501708Sstevel 
6511708Sstevel /*
6521708Sstevel  * gfc_claim_memory
6531708Sstevel  *
6541772Sjl139090  * claim-memory ( align size vhint -- vaddr)
6551708Sstevel  */
6561708Sstevel static int
gfc_claim_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)6571708Sstevel gfc_claim_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
6581708Sstevel {
6591708Sstevel 	int align, size, vhint;
6601708Sstevel 	ndi_ra_request_t request;
6611708Sstevel 	uint64_t answer, alen;
6621708Sstevel 	struct fc_resource *ip;
6631708Sstevel 
6641708Sstevel 	if (fc_cell2int(cp->nargs) != 3)
6651708Sstevel 		return (fc_syntax_error(cp, "nargs must be 3"));
6661708Sstevel 
6671708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
6681708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
6691708Sstevel 
6701708Sstevel 	vhint = fc_cell2int(fc_arg(cp, 2));
6711708Sstevel 	size = fc_cell2int(fc_arg(cp, 1));
6721708Sstevel 	align = fc_cell2int(fc_arg(cp, 0));
6731708Sstevel 
6741708Sstevel 	FC_DEBUG3(1, CE_CONT, "gfc_claim_memory: align=0x%x size=0x%x "
6751708Sstevel 	    "vhint=0x%x\n", align, size, vhint);
6761708Sstevel 
6771708Sstevel 	if (size == 0) {
6781708Sstevel 		cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
6791708Sstevel 		    "contigiuos memory of size zero\n");
6801708Sstevel 		return (fc_priv_error(cp, "allocation error"));
6811708Sstevel 	}
6821708Sstevel 
6831708Sstevel 	if (vhint) {
6841708Sstevel 		cmn_err(CE_WARN, "gfc_claim_memory - vhint is not zero "
6851708Sstevel 		    "vhint=0x%x - Ignoring Argument\n", vhint);
6861708Sstevel 	}
6871708Sstevel 
6881708Sstevel 	bzero((caddr_t)&request, sizeof (ndi_ra_request_t));
6891708Sstevel 	request.ra_flags  = NDI_RA_ALLOC_BOUNDED;
6901708Sstevel 	request.ra_boundbase = 0;
6911708Sstevel 	request.ra_boundlen = 0xffffffff;
6921708Sstevel 	request.ra_len = size;
6931708Sstevel 	request.ra_align_mask = align - 1;
6941708Sstevel 
6951708Sstevel 	if (ndi_ra_alloc(ddi_root_node(), &request, &answer, &alen,
6961708Sstevel 	    "gptwo-contigousmem", NDI_RA_PASS) != NDI_SUCCESS) {
6971708Sstevel 		cmn_err(CE_WARN, " gfc_claim_memory - unable to allocate "
6981708Sstevel 		    "contigiuos memory\n");
6991708Sstevel 		return (fc_priv_error(cp, "allocation error"));
7001708Sstevel 
7011708Sstevel 	}
7021708Sstevel 
7031708Sstevel 	FC_DEBUG2(1, CE_CONT, "gfc_claim_memory: address allocated=0x%lx "
7041708Sstevel 	    "size=0x%x\n", answer, alen);
7051708Sstevel 
7061708Sstevel 	cp->nresults = fc_int2cell(1);
7071708Sstevel 	fc_result(cp, 0) = answer;
7081708Sstevel 
7091708Sstevel 	/*
7101708Sstevel 	 * Log this resource ...
7111708Sstevel 	 */
7121708Sstevel 	ip = kmem_zalloc(sizeof (struct fc_resource), KM_SLEEP);
7131708Sstevel 	ip->type = RT_CONTIGIOUS;
7141708Sstevel 	ip->fc_contig_virt = (void *)answer;
7151708Sstevel 	ip->fc_contig_len = size;
7161708Sstevel 	fc_add_resource(rp, ip);
7171708Sstevel 
7181708Sstevel 	return (fc_success_op(ap, rp, cp));
7191708Sstevel }
7201708Sstevel 
7211708Sstevel /*
7221708Sstevel  * gfc_release_memory
7231708Sstevel  *
7241772Sjl139090  * release-memory ( size vaddr -- )
7251708Sstevel  */
7261708Sstevel static int
gfc_release_memory(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7271708Sstevel gfc_release_memory(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7281708Sstevel {
7291708Sstevel 	int32_t vaddr, size;
7301708Sstevel 	struct fc_resource *ip;
7311708Sstevel 
7321708Sstevel 	if (fc_cell2int(cp->nargs) != 2)
7331708Sstevel 		return (fc_syntax_error(cp, "nargs must be 2"));
7341708Sstevel 
7351708Sstevel 	if (fc_cell2int(cp->nresults) != 0)
7361708Sstevel 		return (fc_syntax_error(cp, "nresults must be 0"));
7371708Sstevel 
7381708Sstevel 	vaddr = fc_cell2int(fc_arg(cp, 1));
7391708Sstevel 	size = fc_cell2int(fc_arg(cp, 0));
7401708Sstevel 
7411708Sstevel 	FC_DEBUG2(1, CE_CONT, "gfc_release_memory: vaddr=0x%x size=0x%x\n",
7421708Sstevel 	    vaddr, size);
7431708Sstevel 	/*
7441708Sstevel 	 * Find if this request matches a mapping resource we set up.
7451708Sstevel 	 */
7461708Sstevel 	fc_lock_resource_list(rp);
7471708Sstevel 	for (ip = rp->head; ip != NULL; ip = ip->next) {
7481708Sstevel 		if (ip->type != RT_CONTIGIOUS)
7491708Sstevel 			continue;
7501708Sstevel 		if (ip->fc_contig_virt != (void *)(uintptr_t)vaddr)
7511708Sstevel 			continue;
7521708Sstevel 		if (ip->fc_contig_len == size)
7531708Sstevel 			break;
7541708Sstevel 	}
7551708Sstevel 	fc_unlock_resource_list(rp);
7561708Sstevel 
7571708Sstevel 	if (ip == NULL)
7581708Sstevel 		return (fc_priv_error(cp, "request doesn't match a "
7591708Sstevel 		    "known mapping"));
7601708Sstevel 
7611708Sstevel 	(void) ndi_ra_free(ddi_root_node(), vaddr, size,
7621708Sstevel 	    "gptwo-contigousmem", NDI_RA_PASS);
7631708Sstevel 
7641708Sstevel 	/*
7651708Sstevel 	 * remove the resource from the list and release it.
7661708Sstevel 	 */
7671708Sstevel 	fc_rem_resource(rp, ip);
7681708Sstevel 	kmem_free(ip, sizeof (struct fc_resource));
7691708Sstevel 
7701708Sstevel 	cp->nresults = fc_int2cell(0);
7711708Sstevel 
7721708Sstevel 	return (fc_success_op(ap, rp, cp));
7731708Sstevel }
7741708Sstevel 
7751708Sstevel /*
7761708Sstevel  * gfc_vtop
7771708Sstevel  *
7781772Sjl139090  * vtop ( vaddr -- paddr.lo paddr.hi)
7791708Sstevel  */
7801708Sstevel static int
gfc_vtop(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)7811708Sstevel gfc_vtop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
7821708Sstevel {
7831708Sstevel 	int vaddr;
7841708Sstevel 	uint64_t paddr;
7851708Sstevel 	struct fc_resource *ip;
7861708Sstevel 
7871708Sstevel 	if (fc_cell2int(cp->nargs) != 1)
7881708Sstevel 		return (fc_syntax_error(cp, "nargs must be 1"));
7891708Sstevel 
7901708Sstevel 	if (fc_cell2int(cp->nresults) >= 3)
7911708Sstevel 		return (fc_syntax_error(cp, "nresults must be less than 2"));
7921708Sstevel 
7931708Sstevel 	vaddr = fc_cell2int(fc_arg(cp, 0));
7941708Sstevel 
7951708Sstevel 	/*
7961708Sstevel 	 * Find if this request matches a mapping resource we set up.
7971708Sstevel 	 */
7981708Sstevel 	fc_lock_resource_list(rp);
7991708Sstevel 	for (ip = rp->head; ip != NULL; ip = ip->next) {
8001708Sstevel 		if (ip->type != RT_CONTIGIOUS)
8011708Sstevel 			continue;
8021708Sstevel 		if (ip->fc_contig_virt == (void *)(uintptr_t)vaddr)
8031708Sstevel 				break;
8041708Sstevel 	}
8051708Sstevel 	fc_unlock_resource_list(rp);
8061708Sstevel 
8071708Sstevel 	if (ip == NULL)
8081708Sstevel 		return (fc_priv_error(cp, "request doesn't match a "
8091708Sstevel 		    "known mapping"));
8101708Sstevel 
8111708Sstevel 
8121708Sstevel 	paddr = va_to_pa((void *)(uintptr_t)vaddr);
8131708Sstevel 
8141708Sstevel 	FC_DEBUG2(1, CE_CONT, "gfc_vtop: vaddr=0x%x paddr=0x%x\n",
8151708Sstevel 	    vaddr, paddr);
8161708Sstevel 
8171708Sstevel 	cp->nresults = fc_int2cell(2);
8181708Sstevel 
8191708Sstevel 	fc_result(cp, 0) = paddr;
8201708Sstevel 	fc_result(cp, 1) = 0;
8211708Sstevel 
8221708Sstevel 	return (fc_success_op(ap, rp, cp));
8231708Sstevel }
8241708Sstevel 
8251708Sstevel static int
gfc_config_child(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8261708Sstevel gfc_config_child(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8271708Sstevel {
8281708Sstevel 	fc_phandle_t h;
8291708Sstevel 
8301708Sstevel 	if (fc_cell2int(cp->nargs) != 0)
8311708Sstevel 		return (fc_syntax_error(cp, "nargs must be 0"));
8321708Sstevel 
8331708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
8341708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
8351708Sstevel 
8361708Sstevel 	h = fc_dip_to_phandle(fc_handle_to_phandle_head(rp), rp->child);
8371708Sstevel 
8381708Sstevel 	cp->nresults = fc_int2cell(1);
8391708Sstevel 	fc_result(cp, 0) = fc_phandle2cell(h);
8401708Sstevel 
8411708Sstevel 	return (fc_success_op(ap, rp, cp));
8421708Sstevel }
8431708Sstevel 
8441708Sstevel static int
gfc_get_fcode(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8451708Sstevel gfc_get_fcode(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8461708Sstevel {
8471708Sstevel 	caddr_t name_virt, fcode_virt;
8481708Sstevel 	char *name, *fcode;
8491708Sstevel 	int fcode_len, status;
8501708Sstevel 
8511708Sstevel 	if (fc_cell2int(cp->nargs) != 3)
8521708Sstevel 		return (fc_syntax_error(cp, "nargs must be 3"));
8531708Sstevel 
8541708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
8551708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
8561708Sstevel 
8571708Sstevel 	name_virt = fc_cell2ptr(fc_arg(cp, 0));
8581708Sstevel 
8591708Sstevel 	fcode_virt = fc_cell2ptr(fc_arg(cp, 1));
8601708Sstevel 
8611708Sstevel 	fcode_len = fc_cell2int(fc_arg(cp, 2));
8621708Sstevel 
8631708Sstevel 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
8641708Sstevel 
8651708Sstevel 	if (copyinstr(fc_cell2ptr(name_virt), name,
8661708Sstevel 	    FC_SVC_NAME_LEN - 1, NULL))  {
8671708Sstevel 		FC_DEBUG1(1, CE_CONT, "gfc_get_fcode: "
8681708Sstevel 		    "fault copying in drop in name %p\n", name_virt);
8691708Sstevel 		status = 0;
8701708Sstevel 	} else {
8711708Sstevel 
8721708Sstevel 		fcode = kmem_zalloc(fcode_len, KM_SLEEP);
8731708Sstevel 
8741708Sstevel 		if ((status = prom_get_fcode(name, fcode)) != 0) {
8751708Sstevel 
8761708Sstevel 			if (copyout((void *)fcode, (void *)fcode_virt,
8771708Sstevel 			    fcode_len)) {
8781708Sstevel 				cmn_err(CE_WARN, " gfc_get_fcode: Unable "
8791708Sstevel 				    "to copy out fcode image\n");
8801708Sstevel 				status = 0;
8811708Sstevel 			}
8821708Sstevel 		}
8831708Sstevel 
8841708Sstevel 		kmem_free(fcode, fcode_len);
8851708Sstevel 	}
8861708Sstevel 
8871708Sstevel 	kmem_free(name, FC_SVC_NAME_LEN);
8881708Sstevel 
8891708Sstevel 	cp->nresults = fc_int2cell(1);
8901708Sstevel 	fc_result(cp, 0) = status;
8911708Sstevel 
8921708Sstevel 	return (fc_success_op(ap, rp, cp));
8931708Sstevel }
8941708Sstevel 
8951708Sstevel static int
gfc_get_fcode_size(dev_info_t * ap,fco_handle_t rp,fc_ci_t * cp)8961708Sstevel gfc_get_fcode_size(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
8971708Sstevel {
8981708Sstevel 	caddr_t virt;
8991708Sstevel 	char *name;
9001708Sstevel 	int len;
9011708Sstevel 
9021708Sstevel 	if (fc_cell2int(cp->nargs) != 1)
9031708Sstevel 		return (fc_syntax_error(cp, "nargs must be 1"));
9041708Sstevel 
9051708Sstevel 	if (fc_cell2int(cp->nresults) < 1)
9061708Sstevel 		return (fc_syntax_error(cp, "nresults must be >= 1"));
9071708Sstevel 
9081708Sstevel 	virt = fc_cell2ptr(fc_arg(cp, 0));
9091708Sstevel 
9101708Sstevel 	name = kmem_zalloc(FC_SVC_NAME_LEN, KM_SLEEP);
9111708Sstevel 
9121708Sstevel 	if (copyinstr(fc_cell2ptr(virt), name,
9131708Sstevel 	    FC_SVC_NAME_LEN - 1, NULL))  {
9141708Sstevel 		FC_DEBUG1(1, CE_CONT, "gfc_get_fcode_size: "
9151708Sstevel 		    "fault copying in drop in name %p\n", virt);
9161708Sstevel 		len = 0;
9171708Sstevel 	} else {
9181708Sstevel 
9191708Sstevel 		len = prom_get_fcode_size(name);
9201708Sstevel 	}
9211708Sstevel 
9221708Sstevel 	kmem_free(name, FC_SVC_NAME_LEN);
9231708Sstevel 
9241708Sstevel 	cp->nresults = fc_int2cell(1);
9251708Sstevel 	fc_result(cp, 0) = len;
9261708Sstevel 
9271708Sstevel 	return (fc_success_op(ap, rp, cp));
9281708Sstevel }
9291708Sstevel 
9301708Sstevel static int
gp2_map_phys(dev_info_t * dip,struct regspec * phys_spec,caddr_t * addrp,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handlep)9311708Sstevel gp2_map_phys(dev_info_t *dip, struct regspec *phys_spec,
9321708Sstevel 	caddr_t *addrp, ddi_device_acc_attr_t *accattrp,
9331708Sstevel 	ddi_acc_handle_t *handlep)
9341708Sstevel {
9351708Sstevel 	ddi_map_req_t mr;
9361708Sstevel 	ddi_acc_hdl_t *hp;
9371708Sstevel 	int result;
9381708Sstevel 	struct regspec *ph;
9391708Sstevel 
9401708Sstevel 	*handlep = impl_acc_hdl_alloc(KM_SLEEP, NULL);
9411708Sstevel 	hp = impl_acc_hdl_get(*handlep);
9421708Sstevel 	hp->ah_vers = VERS_ACCHDL;
9431708Sstevel 	hp->ah_dip = dip;
9441708Sstevel 	hp->ah_rnumber = 0;
9451708Sstevel 	hp->ah_offset = 0;
9461708Sstevel 	hp->ah_len = 0;
9471708Sstevel 	hp->ah_acc = *accattrp;
9481708Sstevel 	ph = kmem_zalloc(sizeof (struct regspec), KM_SLEEP);
9491708Sstevel 	*ph = *phys_spec;
9501708Sstevel 	hp->ah_bus_private = ph;	/* cache a copy of the reg spec */
9511708Sstevel 
9521708Sstevel 	mr.map_op = DDI_MO_MAP_LOCKED;
9531708Sstevel 	mr.map_type = DDI_MT_REGSPEC;
9541708Sstevel 	mr.map_obj.rp = (struct regspec *)phys_spec;
9551708Sstevel 	mr.map_prot = PROT_READ | PROT_WRITE;
9561708Sstevel 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
9571708Sstevel 	mr.map_handlep = hp;
9581708Sstevel 	mr.map_vers = DDI_MAP_VERSION;
9591708Sstevel 
9601708Sstevel 	result = ddi_map(dip, &mr, 0, 0, addrp);
9611708Sstevel 
9621708Sstevel 	if (result != DDI_SUCCESS) {
9631708Sstevel 		impl_acc_hdl_free(*handlep);
9641708Sstevel 		*handlep = (ddi_acc_handle_t)NULL;
9651708Sstevel 	} else {
9661708Sstevel 		hp->ah_addr = *addrp;
9671708Sstevel 	}
9681708Sstevel 
9691708Sstevel 	return (result);
9701708Sstevel }
9711708Sstevel 
9721708Sstevel static void
gp2_unmap_phys(ddi_acc_handle_t * handlep)9731708Sstevel gp2_unmap_phys(ddi_acc_handle_t *handlep)
9741708Sstevel {
9751708Sstevel 	ddi_map_req_t mr;
9761708Sstevel 	ddi_acc_hdl_t *hp;
9771708Sstevel 	struct regspec_t *ph;
9781708Sstevel 
9791708Sstevel 	hp = impl_acc_hdl_get(*handlep);
9801708Sstevel 	ASSERT(hp);
9811708Sstevel 	ph = hp->ah_bus_private;
9821708Sstevel 
9831708Sstevel 	mr.map_op = DDI_MO_UNMAP;
9841708Sstevel 	mr.map_type = DDI_MT_REGSPEC;
9851708Sstevel 	mr.map_obj.rp = (struct regspec *)ph;
9861708Sstevel 	mr.map_prot = PROT_READ | PROT_WRITE;
9871708Sstevel 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
9881708Sstevel 	mr.map_handlep = hp;
9891708Sstevel 	mr.map_vers = DDI_MAP_VERSION;
9901708Sstevel 
9911708Sstevel 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
9921708Sstevel 		hp->ah_len, &hp->ah_addr);
9931708Sstevel 
9941708Sstevel 	impl_acc_hdl_free(*handlep);
9951708Sstevel 	kmem_free(ph, sizeof (struct regspec));	/* Free the cached copy */
9961708Sstevel 	*handlep = (ddi_acc_handle_t)NULL;
9971708Sstevel }
998