xref: /titanic_53/usr/src/uts/i86pc/io/rootnex.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * Intel PC root nexus driver
31*7c478bd9Sstevel@tonic-gate  *	based on sun4c root nexus driver 1.30
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/psw.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/devops.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
45*7c478bd9Sstevel@tonic-gate #include <vm/seg.h>
46*7c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
47*7c478bd9Sstevel@tonic-gate #include <vm/seg_dev.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
50*7c478bd9Sstevel@tonic-gate #include <vm/hat.h>
51*7c478bd9Sstevel@tonic-gate #include <vm/as.h>
52*7c478bd9Sstevel@tonic-gate #include <vm/page.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/avintr.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/psm.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/ontrap.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define	ptob64(x)		(((uint64_t)(x)) << PAGESHIFT)
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate extern void	i86_pp_map(page_t *, caddr_t);
65*7c478bd9Sstevel@tonic-gate extern void	i86_va_map(caddr_t, struct as *, caddr_t);
66*7c478bd9Sstevel@tonic-gate extern int	(*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
67*7c478bd9Sstevel@tonic-gate 		    psm_intr_op_t, int *);
68*7c478bd9Sstevel@tonic-gate extern int	isa_resource_setup(void);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* Semi-temporary patchables to phase in bug fixes */
71*7c478bd9Sstevel@tonic-gate int rootnex_bind_fail = 1;
72*7c478bd9Sstevel@tonic-gate int rootnex_bind_warn = 1;
73*7c478bd9Sstevel@tonic-gate uint8_t *rootnex_warn_list;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /* bitmasks for rootnex_warn_list. Up to 8 different warnings with uint8_t */
76*7c478bd9Sstevel@tonic-gate #define	ROOTNEX_BIND_WARNING	(0x1 << 0)
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate  * DMA related static data
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate static uintptr_t dvma_call_list_id = 0;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * Use device arena to use for device control register mappings.
85*7c478bd9Sstevel@tonic-gate  * Various kernel memory walkers (debugger, dtrace) need to know
86*7c478bd9Sstevel@tonic-gate  * to avoid this address range to prevent undesired device activity.
87*7c478bd9Sstevel@tonic-gate  */
88*7c478bd9Sstevel@tonic-gate extern void *device_arena_alloc(size_t size, int vm_flag);
89*7c478bd9Sstevel@tonic-gate extern void device_arena_free(void * vaddr, size_t size);
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /*
93*7c478bd9Sstevel@tonic-gate  * Hack to handle poke faults on Calvin-class machines
94*7c478bd9Sstevel@tonic-gate  */
95*7c478bd9Sstevel@tonic-gate extern int pokefault;
96*7c478bd9Sstevel@tonic-gate static kmutex_t pokefault_mutex;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * Internal functions
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate static int
103*7c478bd9Sstevel@tonic-gate rootnex_ctl_children(dev_info_t *dip, dev_info_t *rdip,
104*7c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, dev_info_t *child);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static int
107*7c478bd9Sstevel@tonic-gate rootnex_ctlops_poke(peekpoke_ctlops_t *in_args);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static int
110*7c478bd9Sstevel@tonic-gate rootnex_ctlops_peek(peekpoke_ctlops_t *in_args, void *result);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /*
113*7c478bd9Sstevel@tonic-gate  * config information
114*7c478bd9Sstevel@tonic-gate  */
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate static int
117*7c478bd9Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
118*7c478bd9Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *vaddrp);
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate static int
121*7c478bd9Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip,
122*7c478bd9Sstevel@tonic-gate     struct hat *hat, struct seg *seg, caddr_t addr,
123*7c478bd9Sstevel@tonic-gate     struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate static int
126*7c478bd9Sstevel@tonic-gate rootnex_dma_allochdl(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
127*7c478bd9Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate static int
130*7c478bd9Sstevel@tonic-gate rootnex_dma_freehdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static int
133*7c478bd9Sstevel@tonic-gate rootnex_dma_bindhdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
134*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate static int
137*7c478bd9Sstevel@tonic-gate rootnex_dma_unbindhdl(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static int
140*7c478bd9Sstevel@tonic-gate rootnex_dma_flush(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
141*7c478bd9Sstevel@tonic-gate     off_t, size_t, uint_t);
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate static int
144*7c478bd9Sstevel@tonic-gate rootnex_dma_win(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
145*7c478bd9Sstevel@tonic-gate     uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate static int
148*7c478bd9Sstevel@tonic-gate rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip,
149*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate static int
152*7c478bd9Sstevel@tonic-gate rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
153*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
154*7c478bd9Sstevel@tonic-gate     off_t *offp, size_t *lenp, caddr_t *objp, uint_t cache_flags);
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static int
157*7c478bd9Sstevel@tonic-gate rootnex_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *);
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static struct intrspec *
160*7c478bd9Sstevel@tonic-gate rootnex_get_ispec(dev_info_t *rdip, int inum);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static int
163*7c478bd9Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
164*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *, void *);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate static struct bus_ops rootnex_bus_ops = {
167*7c478bd9Sstevel@tonic-gate 	BUSO_REV,
168*7c478bd9Sstevel@tonic-gate 	rootnex_map,
169*7c478bd9Sstevel@tonic-gate 	NULL,
170*7c478bd9Sstevel@tonic-gate 	NULL,
171*7c478bd9Sstevel@tonic-gate 	NULL,
172*7c478bd9Sstevel@tonic-gate 	rootnex_map_fault,
173*7c478bd9Sstevel@tonic-gate 	rootnex_dma_map,
174*7c478bd9Sstevel@tonic-gate 	rootnex_dma_allochdl,
175*7c478bd9Sstevel@tonic-gate 	rootnex_dma_freehdl,
176*7c478bd9Sstevel@tonic-gate 	rootnex_dma_bindhdl,
177*7c478bd9Sstevel@tonic-gate 	rootnex_dma_unbindhdl,
178*7c478bd9Sstevel@tonic-gate 	rootnex_dma_flush,
179*7c478bd9Sstevel@tonic-gate 	rootnex_dma_win,
180*7c478bd9Sstevel@tonic-gate 	rootnex_dma_mctl,
181*7c478bd9Sstevel@tonic-gate 	rootnex_ctlops,
182*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
183*7c478bd9Sstevel@tonic-gate 	i_ddi_rootnex_get_eventcookie,
184*7c478bd9Sstevel@tonic-gate 	i_ddi_rootnex_add_eventcall,
185*7c478bd9Sstevel@tonic-gate 	i_ddi_rootnex_remove_eventcall,
186*7c478bd9Sstevel@tonic-gate 	i_ddi_rootnex_post_event,
187*7c478bd9Sstevel@tonic-gate 	0,			/* bus_intr_ctl */
188*7c478bd9Sstevel@tonic-gate 	0,			/* bus_config */
189*7c478bd9Sstevel@tonic-gate 	0,			/* bus_unconfig */
190*7c478bd9Sstevel@tonic-gate 	NULL,			/* bus_fm_init */
191*7c478bd9Sstevel@tonic-gate 	NULL,			/* bus_fm_fini */
192*7c478bd9Sstevel@tonic-gate 	NULL,			/* bus_fm_access_enter */
193*7c478bd9Sstevel@tonic-gate 	NULL,			/* bus_fm_access_exit */
194*7c478bd9Sstevel@tonic-gate 	NULL,			/* bus_powr */
195*7c478bd9Sstevel@tonic-gate 	rootnex_intr_ops	/* bus_intr_op */
196*7c478bd9Sstevel@tonic-gate };
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate struct priv_handle {
199*7c478bd9Sstevel@tonic-gate 	caddr_t	ph_vaddr;
200*7c478bd9Sstevel@tonic-gate 	union {
201*7c478bd9Sstevel@tonic-gate 		page_t *pp;
202*7c478bd9Sstevel@tonic-gate 		struct as *asp;
203*7c478bd9Sstevel@tonic-gate 	}ph_u;
204*7c478bd9Sstevel@tonic-gate 	uint_t  ph_mapinfo;
205*7c478bd9Sstevel@tonic-gate 	uint64_t ph_padr;
206*7c478bd9Sstevel@tonic-gate };
207*7c478bd9Sstevel@tonic-gate static uint64_t rootnex_get_phyaddr();
208*7c478bd9Sstevel@tonic-gate static int rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
209*7c478bd9Sstevel@tonic-gate static int rootnex_io_rdsync(ddi_dma_impl_t *hp);
210*7c478bd9Sstevel@tonic-gate static int rootnex_io_wtsync(ddi_dma_impl_t *hp, int);
211*7c478bd9Sstevel@tonic-gate static int rootnex_io_brkup_attr(dev_info_t *dip, dev_info_t *rdip,
212*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t handle,
213*7c478bd9Sstevel@tonic-gate     struct priv_handle *php);
214*7c478bd9Sstevel@tonic-gate static int rootnex_io_brkup_lim(dev_info_t *dip, dev_info_t *rdip,
215*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep,
216*7c478bd9Sstevel@tonic-gate     ddi_dma_lim_t *dma_lim, struct priv_handle *php);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate static struct dev_ops rootnex_ops = {
219*7c478bd9Sstevel@tonic-gate 	DEVO_REV,
220*7c478bd9Sstevel@tonic-gate 	0,		/* refcnt */
221*7c478bd9Sstevel@tonic-gate 	ddi_no_info,	/* info */
222*7c478bd9Sstevel@tonic-gate 	nulldev,
223*7c478bd9Sstevel@tonic-gate 	nulldev,	/* probe */
224*7c478bd9Sstevel@tonic-gate 	rootnex_attach,
225*7c478bd9Sstevel@tonic-gate 	nulldev,	/* detach */
226*7c478bd9Sstevel@tonic-gate 	nulldev,	/* reset */
227*7c478bd9Sstevel@tonic-gate 	0,		/* cb_ops */
228*7c478bd9Sstevel@tonic-gate 	&rootnex_bus_ops
229*7c478bd9Sstevel@tonic-gate };
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate /*
232*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
233*7c478bd9Sstevel@tonic-gate  */
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
236*7c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This one is a nexus driver */
237*7c478bd9Sstevel@tonic-gate 	"i86pc root nexus %I%",
238*7c478bd9Sstevel@tonic-gate 	&rootnex_ops,	/* Driver ops */
239*7c478bd9Sstevel@tonic-gate };
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
242*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
243*7c478bd9Sstevel@tonic-gate };
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate int
247*7c478bd9Sstevel@tonic-gate _init(void)
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
250*7c478bd9Sstevel@tonic-gate }
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate int
253*7c478bd9Sstevel@tonic-gate _fini(void)
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate int
259*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
260*7c478bd9Sstevel@tonic-gate {
261*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate /*
265*7c478bd9Sstevel@tonic-gate  * rootnex_attach:
266*7c478bd9Sstevel@tonic-gate  *
267*7c478bd9Sstevel@tonic-gate  *	attach the root nexus.
268*7c478bd9Sstevel@tonic-gate  */
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate static void add_root_props(dev_info_t *);
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
273*7c478bd9Sstevel@tonic-gate static int
274*7c478bd9Sstevel@tonic-gate rootnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
275*7c478bd9Sstevel@tonic-gate {
276*7c478bd9Sstevel@tonic-gate 	mutex_init(&pokefault_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(15));
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	add_root_props(devi);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "?root nexus = %s\n", ddi_get_name(devi));
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 	i_ddi_rootnex_init_events(devi);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	/*
285*7c478bd9Sstevel@tonic-gate 	 * allocate array to track which major numbers we have printed warnings
286*7c478bd9Sstevel@tonic-gate 	 * for.
287*7c478bd9Sstevel@tonic-gate 	 */
288*7c478bd9Sstevel@tonic-gate 	rootnex_warn_list = kmem_zalloc(devcnt * sizeof (*rootnex_warn_list),
289*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * Add statically defined root properties to this list...
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate static const int pagesize = PAGESIZE;
300*7c478bd9Sstevel@tonic-gate static const int mmu_pagesize = MMU_PAGESIZE;
301*7c478bd9Sstevel@tonic-gate static const int mmu_pageoffset = MMU_PAGEOFFSET;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate struct prop_def {
304*7c478bd9Sstevel@tonic-gate 	char *prop_name;
305*7c478bd9Sstevel@tonic-gate 	caddr_t prop_value;
306*7c478bd9Sstevel@tonic-gate };
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate static struct prop_def root_props[] = {
309*7c478bd9Sstevel@tonic-gate 	{ "PAGESIZE",		(caddr_t)&pagesize },
310*7c478bd9Sstevel@tonic-gate 	{ "MMU_PAGESIZE",	(caddr_t)&mmu_pagesize},
311*7c478bd9Sstevel@tonic-gate 	{ "MMU_PAGEOFFSET",	(caddr_t)&mmu_pageoffset},
312*7c478bd9Sstevel@tonic-gate };
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate #define	NROOT_PROPS	(sizeof (root_props) / sizeof (struct prop_def))
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate static void
317*7c478bd9Sstevel@tonic-gate add_root_props(dev_info_t *devi)
318*7c478bd9Sstevel@tonic-gate {
319*7c478bd9Sstevel@tonic-gate 	int i;
320*7c478bd9Sstevel@tonic-gate 	struct prop_def *rpp;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	/*
323*7c478bd9Sstevel@tonic-gate 	 * Note this for loop works because all of the root_prop
324*7c478bd9Sstevel@tonic-gate 	 * properties are integers - if this changes, the for
325*7c478bd9Sstevel@tonic-gate 	 * loop will have to change.
326*7c478bd9Sstevel@tonic-gate 	 */
327*7c478bd9Sstevel@tonic-gate 	for (i = 0, rpp = root_props; i < NROOT_PROPS; ++i, ++rpp) {
328*7c478bd9Sstevel@tonic-gate 		(void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi,
329*7c478bd9Sstevel@tonic-gate 		    rpp->prop_name, *((int *)rpp->prop_value));
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	/*
333*7c478bd9Sstevel@tonic-gate 	 * Create the root node "boolean" property
334*7c478bd9Sstevel@tonic-gate 	 * corresponding to addressing type supported in the root node:
335*7c478bd9Sstevel@tonic-gate 	 *
336*7c478bd9Sstevel@tonic-gate 	 * Choices are:
337*7c478bd9Sstevel@tonic-gate 	 *	"relative-addressing" (OBP PROMS)
338*7c478bd9Sstevel@tonic-gate 	 *	"generic-addressing"  (Sun4 -- pseudo OBP/DDI)
339*7c478bd9Sstevel@tonic-gate 	 */
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	(void) e_ddi_prop_update_int(DDI_DEV_T_NONE, devi,
342*7c478bd9Sstevel@tonic-gate 	    DDI_RELATIVE_ADDRESSING, 1);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /*
347*7c478bd9Sstevel@tonic-gate  * #define	DDI_MAP_DEBUG (c.f. ddi_impl.c)
348*7c478bd9Sstevel@tonic-gate  */
349*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
350*7c478bd9Sstevel@tonic-gate extern int ddi_map_debug_flag;
351*7c478bd9Sstevel@tonic-gate #define	ddi_map_debug	if (ddi_map_debug_flag) prom_printf
352*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate /*
356*7c478bd9Sstevel@tonic-gate  * we don't support mapping of I/O cards above 4Gb
357*7c478bd9Sstevel@tonic-gate  */
358*7c478bd9Sstevel@tonic-gate static int
359*7c478bd9Sstevel@tonic-gate rootnex_map_regspec(ddi_map_req_t *mp, caddr_t *vaddrp)
360*7c478bd9Sstevel@tonic-gate {
361*7c478bd9Sstevel@tonic-gate 	ulong_t base;
362*7c478bd9Sstevel@tonic-gate 	void *cvaddr;
363*7c478bd9Sstevel@tonic-gate 	uint_t npages, pgoffset;
364*7c478bd9Sstevel@tonic-gate 	struct regspec *rp;
365*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
366*7c478bd9Sstevel@tonic-gate 	ddi_acc_impl_t *ap;
367*7c478bd9Sstevel@tonic-gate 	uint_t	hat_acc_flags;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	rp = mp->map_obj.rp;
370*7c478bd9Sstevel@tonic-gate 	hp = mp->map_handlep;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
373*7c478bd9Sstevel@tonic-gate 	ddi_map_debug(
374*7c478bd9Sstevel@tonic-gate 	    "rootnex_map_regspec: <0x%x 0x%x 0x%x> handle 0x%x\n",
375*7c478bd9Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr,
376*7c478bd9Sstevel@tonic-gate 	    rp->regspec_size, mp->map_handlep);
377*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/*
380*7c478bd9Sstevel@tonic-gate 	 * I/O or memory mapping
381*7c478bd9Sstevel@tonic-gate 	 *
382*7c478bd9Sstevel@tonic-gate 	 *	<bustype=0, addr=x, len=x>: memory
383*7c478bd9Sstevel@tonic-gate 	 *	<bustype=1, addr=x, len=x>: i/o
384*7c478bd9Sstevel@tonic-gate 	 *	<bustype>1, addr=0, len=x>: x86-compatibility i/o
385*7c478bd9Sstevel@tonic-gate 	 */
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) {
388*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "rootnex: invalid register spec"
389*7c478bd9Sstevel@tonic-gate 		    " <0x%x, 0x%x, 0x%x>", rp->regspec_bustype,
390*7c478bd9Sstevel@tonic-gate 		    rp->regspec_addr, rp->regspec_size);
391*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype != 0) {
395*7c478bd9Sstevel@tonic-gate 		/*
396*7c478bd9Sstevel@tonic-gate 		 * I/O space - needs a handle.
397*7c478bd9Sstevel@tonic-gate 		 */
398*7c478bd9Sstevel@tonic-gate 		if (hp == NULL) {
399*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
400*7c478bd9Sstevel@tonic-gate 		}
401*7c478bd9Sstevel@tonic-gate 		ap = (ddi_acc_impl_t *)hp->ah_platform_private;
402*7c478bd9Sstevel@tonic-gate 		ap->ahi_acc_attr |= DDI_ACCATTR_IO_SPACE;
403*7c478bd9Sstevel@tonic-gate 		impl_acc_hdl_init(hp);
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		if (mp->map_flags & DDI_MF_DEVICE_MAPPING) {
406*7c478bd9Sstevel@tonic-gate #ifdef  DDI_MAP_DEBUG
407*7c478bd9Sstevel@tonic-gate 			ddi_map_debug("rootnex_map_regspec: mmap() \
408*7c478bd9Sstevel@tonic-gate to I/O space is not supported.\n");
409*7c478bd9Sstevel@tonic-gate #endif  /* DDI_MAP_DEBUG */
410*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_INVAL);
411*7c478bd9Sstevel@tonic-gate 		} else {
412*7c478bd9Sstevel@tonic-gate 			/*
413*7c478bd9Sstevel@tonic-gate 			 * 1275-compliant vs. compatibility i/o mapping
414*7c478bd9Sstevel@tonic-gate 			 */
415*7c478bd9Sstevel@tonic-gate 			*vaddrp =
416*7c478bd9Sstevel@tonic-gate 			    (rp->regspec_bustype > 1 && rp->regspec_addr == 0) ?
417*7c478bd9Sstevel@tonic-gate 				((caddr_t)(uintptr_t)rp->regspec_bustype) :
418*7c478bd9Sstevel@tonic-gate 				((caddr_t)(uintptr_t)rp->regspec_addr);
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
422*7c478bd9Sstevel@tonic-gate 		ddi_map_debug(
423*7c478bd9Sstevel@tonic-gate 	    "rootnex_map_regspec: \"Mapping\" %d bytes I/O space at 0x%x\n",
424*7c478bd9Sstevel@tonic-gate 		    rp->regspec_size, *vaddrp);
425*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
426*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	/*
430*7c478bd9Sstevel@tonic-gate 	 * Memory space
431*7c478bd9Sstevel@tonic-gate 	 */
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (hp != NULL) {
434*7c478bd9Sstevel@tonic-gate 		/*
435*7c478bd9Sstevel@tonic-gate 		 * hat layer ignores
436*7c478bd9Sstevel@tonic-gate 		 * hp->ah_acc.devacc_attr_endian_flags.
437*7c478bd9Sstevel@tonic-gate 		 */
438*7c478bd9Sstevel@tonic-gate 		switch (hp->ah_acc.devacc_attr_dataorder) {
439*7c478bd9Sstevel@tonic-gate 		case DDI_STRICTORDER_ACC:
440*7c478bd9Sstevel@tonic-gate 			hat_acc_flags = HAT_STRICTORDER;
441*7c478bd9Sstevel@tonic-gate 			break;
442*7c478bd9Sstevel@tonic-gate 		case DDI_UNORDERED_OK_ACC:
443*7c478bd9Sstevel@tonic-gate 			hat_acc_flags = HAT_UNORDERED_OK;
444*7c478bd9Sstevel@tonic-gate 			break;
445*7c478bd9Sstevel@tonic-gate 		case DDI_MERGING_OK_ACC:
446*7c478bd9Sstevel@tonic-gate 			hat_acc_flags = HAT_MERGING_OK;
447*7c478bd9Sstevel@tonic-gate 			break;
448*7c478bd9Sstevel@tonic-gate 		case DDI_LOADCACHING_OK_ACC:
449*7c478bd9Sstevel@tonic-gate 			hat_acc_flags = HAT_LOADCACHING_OK;
450*7c478bd9Sstevel@tonic-gate 			break;
451*7c478bd9Sstevel@tonic-gate 		case DDI_STORECACHING_OK_ACC:
452*7c478bd9Sstevel@tonic-gate 			hat_acc_flags = HAT_STORECACHING_OK;
453*7c478bd9Sstevel@tonic-gate 			break;
454*7c478bd9Sstevel@tonic-gate 		}
455*7c478bd9Sstevel@tonic-gate 		ap = (ddi_acc_impl_t *)hp->ah_platform_private;
456*7c478bd9Sstevel@tonic-gate 		ap->ahi_acc_attr |= DDI_ACCATTR_CPU_VADDR;
457*7c478bd9Sstevel@tonic-gate 		impl_acc_hdl_init(hp);
458*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags = hat_acc_flags;
459*7c478bd9Sstevel@tonic-gate 	} else {
460*7c478bd9Sstevel@tonic-gate 		hat_acc_flags = HAT_STRICTORDER;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */
464*7c478bd9Sstevel@tonic-gate 	pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET; /* offset */
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_size == 0) {
467*7c478bd9Sstevel@tonic-gate #ifdef  DDI_MAP_DEBUG
468*7c478bd9Sstevel@tonic-gate 		ddi_map_debug("rootnex_map_regspec: zero regspec_size\n");
469*7c478bd9Sstevel@tonic-gate #endif  /* DDI_MAP_DEBUG */
470*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	if (mp->map_flags & DDI_MF_DEVICE_MAPPING) {
474*7c478bd9Sstevel@tonic-gate 		*vaddrp = (caddr_t)mmu_btop(base);
475*7c478bd9Sstevel@tonic-gate 	} else {
476*7c478bd9Sstevel@tonic-gate 		npages = mmu_btopr(rp->regspec_size + pgoffset);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
479*7c478bd9Sstevel@tonic-gate 		ddi_map_debug("rootnex_map_regspec: Mapping %d pages \
480*7c478bd9Sstevel@tonic-gate physical %x ",
481*7c478bd9Sstevel@tonic-gate 		    npages, base);
482*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 		cvaddr = device_arena_alloc(ptob(npages), VM_NOSLEEP);
485*7c478bd9Sstevel@tonic-gate 		if (cvaddr == NULL)
486*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_NORESOURCES);
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 		/*
489*7c478bd9Sstevel@tonic-gate 		 * Now map in the pages we've allocated...
490*7c478bd9Sstevel@tonic-gate 		 */
491*7c478bd9Sstevel@tonic-gate 		hat_devload(kas.a_hat, cvaddr, mmu_ptob(npages), mmu_btop(base),
492*7c478bd9Sstevel@tonic-gate 		    mp->map_prot | hat_acc_flags, HAT_LOAD_LOCK);
493*7c478bd9Sstevel@tonic-gate 		*vaddrp = (caddr_t)cvaddr + pgoffset;
494*7c478bd9Sstevel@tonic-gate 	}
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
497*7c478bd9Sstevel@tonic-gate 	ddi_map_debug("at virtual 0x%x\n", *vaddrp);
498*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
499*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
500*7c478bd9Sstevel@tonic-gate }
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate static int
503*7c478bd9Sstevel@tonic-gate rootnex_unmap_regspec(ddi_map_req_t *mp, caddr_t *vaddrp)
504*7c478bd9Sstevel@tonic-gate {
505*7c478bd9Sstevel@tonic-gate 	caddr_t addr = (caddr_t)*vaddrp;
506*7c478bd9Sstevel@tonic-gate 	uint_t npages, pgoffset;
507*7c478bd9Sstevel@tonic-gate 	struct regspec *rp;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	if (mp->map_flags & DDI_MF_DEVICE_MAPPING)
510*7c478bd9Sstevel@tonic-gate 		return (0);
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	rp = mp->map_obj.rp;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_size == 0) {
515*7c478bd9Sstevel@tonic-gate #ifdef  DDI_MAP_DEBUG
516*7c478bd9Sstevel@tonic-gate 		ddi_map_debug("rootnex_unmap_regspec: zero regspec_size\n");
517*7c478bd9Sstevel@tonic-gate #endif  /* DDI_MAP_DEBUG */
518*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	/*
522*7c478bd9Sstevel@tonic-gate 	 * I/O or memory mapping:
523*7c478bd9Sstevel@tonic-gate 	 *
524*7c478bd9Sstevel@tonic-gate 	 *	<bustype=0, addr=x, len=x>: memory
525*7c478bd9Sstevel@tonic-gate 	 *	<bustype=1, addr=x, len=x>: i/o
526*7c478bd9Sstevel@tonic-gate 	 *	<bustype>1, addr=0, len=x>: x86-compatibility i/o
527*7c478bd9Sstevel@tonic-gate 	 */
528*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype != 0) {
529*7c478bd9Sstevel@tonic-gate 		/*
530*7c478bd9Sstevel@tonic-gate 		 * This is I/O space, which requires no particular
531*7c478bd9Sstevel@tonic-gate 		 * processing on unmap since it isn't mapped in the
532*7c478bd9Sstevel@tonic-gate 		 * first place.
533*7c478bd9Sstevel@tonic-gate 		 */
534*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
535*7c478bd9Sstevel@tonic-gate 	}
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	/*
538*7c478bd9Sstevel@tonic-gate 	 * Memory space
539*7c478bd9Sstevel@tonic-gate 	 */
540*7c478bd9Sstevel@tonic-gate 	pgoffset = (uintptr_t)addr & MMU_PAGEOFFSET;
541*7c478bd9Sstevel@tonic-gate 	npages = mmu_btopr(rp->regspec_size + pgoffset);
542*7c478bd9Sstevel@tonic-gate 	hat_unload(kas.a_hat, addr - pgoffset, ptob(npages), HAT_UNLOAD_UNLOCK);
543*7c478bd9Sstevel@tonic-gate 	device_arena_free(addr - pgoffset, ptob(npages));
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	/*
546*7c478bd9Sstevel@tonic-gate 	 * Destroy the pointer - the mapping has logically gone
547*7c478bd9Sstevel@tonic-gate 	 */
548*7c478bd9Sstevel@tonic-gate 	*vaddrp = NULL;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate static int
554*7c478bd9Sstevel@tonic-gate rootnex_map_handle(ddi_map_req_t *mp)
555*7c478bd9Sstevel@tonic-gate {
556*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
557*7c478bd9Sstevel@tonic-gate 	ulong_t base;
558*7c478bd9Sstevel@tonic-gate 	uint_t pgoffset;
559*7c478bd9Sstevel@tonic-gate 	struct regspec *rp;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	rp = mp->map_obj.rp;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
564*7c478bd9Sstevel@tonic-gate 	ddi_map_debug(
565*7c478bd9Sstevel@tonic-gate 	    "rootnex_map_handle: <0x%x 0x%x 0x%x> handle 0x%x\n",
566*7c478bd9Sstevel@tonic-gate 	    rp->regspec_bustype, rp->regspec_addr,
567*7c478bd9Sstevel@tonic-gate 	    rp->regspec_size, mp->map_handlep);
568*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 	/*
571*7c478bd9Sstevel@tonic-gate 	 * I/O or memory mapping:
572*7c478bd9Sstevel@tonic-gate 	 *
573*7c478bd9Sstevel@tonic-gate 	 *	<bustype=0, addr=x, len=x>: memory
574*7c478bd9Sstevel@tonic-gate 	 *	<bustype=1, addr=x, len=x>: i/o
575*7c478bd9Sstevel@tonic-gate 	 *	<bustype>1, addr=0, len=x>: x86-compatibility i/o
576*7c478bd9Sstevel@tonic-gate 	 */
577*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype != 0) {
578*7c478bd9Sstevel@tonic-gate 		/*
579*7c478bd9Sstevel@tonic-gate 		 * This refers to I/O space, and we don't support "mapping"
580*7c478bd9Sstevel@tonic-gate 		 * I/O space to a user.
581*7c478bd9Sstevel@tonic-gate 		 */
582*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/*
586*7c478bd9Sstevel@tonic-gate 	 * Set up the hat_flags for the mapping.
587*7c478bd9Sstevel@tonic-gate 	 */
588*7c478bd9Sstevel@tonic-gate 	hp = mp->map_handlep;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	switch (hp->ah_acc.devacc_attr_endian_flags) {
591*7c478bd9Sstevel@tonic-gate 	case DDI_NEVERSWAP_ACC:
592*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags = HAT_NEVERSWAP | HAT_STRICTORDER;
593*7c478bd9Sstevel@tonic-gate 		break;
594*7c478bd9Sstevel@tonic-gate 	case DDI_STRUCTURE_LE_ACC:
595*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags = HAT_STRUCTURE_LE;
596*7c478bd9Sstevel@tonic-gate 		break;
597*7c478bd9Sstevel@tonic-gate 	case DDI_STRUCTURE_BE_ACC:
598*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
599*7c478bd9Sstevel@tonic-gate 	default:
600*7c478bd9Sstevel@tonic-gate 		return (DDI_REGS_ACC_CONFLICT);
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	switch (hp->ah_acc.devacc_attr_dataorder) {
604*7c478bd9Sstevel@tonic-gate 	case DDI_STRICTORDER_ACC:
605*7c478bd9Sstevel@tonic-gate 		break;
606*7c478bd9Sstevel@tonic-gate 	case DDI_UNORDERED_OK_ACC:
607*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags |= HAT_UNORDERED_OK;
608*7c478bd9Sstevel@tonic-gate 		break;
609*7c478bd9Sstevel@tonic-gate 	case DDI_MERGING_OK_ACC:
610*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags |= HAT_MERGING_OK;
611*7c478bd9Sstevel@tonic-gate 		break;
612*7c478bd9Sstevel@tonic-gate 	case DDI_LOADCACHING_OK_ACC:
613*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags |= HAT_LOADCACHING_OK;
614*7c478bd9Sstevel@tonic-gate 		break;
615*7c478bd9Sstevel@tonic-gate 	case DDI_STORECACHING_OK_ACC:
616*7c478bd9Sstevel@tonic-gate 		hp->ah_hat_flags |= HAT_STORECACHING_OK;
617*7c478bd9Sstevel@tonic-gate 		break;
618*7c478bd9Sstevel@tonic-gate 	default:
619*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	base = (ulong_t)rp->regspec_addr & (~MMU_PAGEOFFSET); /* base addr */
623*7c478bd9Sstevel@tonic-gate 	pgoffset = (ulong_t)rp->regspec_addr & MMU_PAGEOFFSET; /* offset */
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_size == 0)
626*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	hp->ah_pfn = mmu_btop(base);
629*7c478bd9Sstevel@tonic-gate 	hp->ah_pnum = mmu_btopr(rp->regspec_size + pgoffset);
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate static int
635*7c478bd9Sstevel@tonic-gate rootnex_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
636*7c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
637*7c478bd9Sstevel@tonic-gate {
638*7c478bd9Sstevel@tonic-gate 	struct regspec *rp, tmp_reg;
639*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr = *mp;		/* Get private copy of request */
640*7c478bd9Sstevel@tonic-gate 	int error;
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	mp = &mr;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 	switch (mp->map_op)  {
645*7c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_LOCKED:
646*7c478bd9Sstevel@tonic-gate 	case DDI_MO_UNMAP:
647*7c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_HANDLE:
648*7c478bd9Sstevel@tonic-gate 		break;
649*7c478bd9Sstevel@tonic-gate 	default:
650*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
651*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "rootnex_map: unimplemented map op %d.",
652*7c478bd9Sstevel@tonic-gate 		    mp->map_op);
653*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
654*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNIMPLEMENTED);
655*7c478bd9Sstevel@tonic-gate 	}
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate 	if (mp->map_flags & DDI_MF_USER_MAPPING)  {
658*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
659*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "rootnex_map: unimplemented map type: user.");
660*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
661*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNIMPLEMENTED);
662*7c478bd9Sstevel@tonic-gate 	}
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	/*
665*7c478bd9Sstevel@tonic-gate 	 * First, if given an rnumber, convert it to a regspec...
666*7c478bd9Sstevel@tonic-gate 	 * (Presumably, this is on behalf of a child of the root node?)
667*7c478bd9Sstevel@tonic-gate 	 */
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)  {
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		int rnumber = mp->map_obj.rnumber;
672*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
673*7c478bd9Sstevel@tonic-gate 		static char *out_of_range =
674*7c478bd9Sstevel@tonic-gate 		    "rootnex_map: Out of range rnumber <%d>, device <%s>";
675*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 		rp = i_ddi_rnumber_to_regspec(rdip, rnumber);
678*7c478bd9Sstevel@tonic-gate 		if (rp == NULL)  {
679*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
680*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, out_of_range, rnumber,
681*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(rdip));
682*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
683*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
684*7c478bd9Sstevel@tonic-gate 		}
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 		/*
687*7c478bd9Sstevel@tonic-gate 		 * Convert the given ddi_map_req_t from rnumber to regspec...
688*7c478bd9Sstevel@tonic-gate 		 */
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 		mp->map_type = DDI_MT_REGSPEC;
691*7c478bd9Sstevel@tonic-gate 		mp->map_obj.rp = rp;
692*7c478bd9Sstevel@tonic-gate 	}
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	/*
695*7c478bd9Sstevel@tonic-gate 	 * Adjust offset and length correspnding to called values...
696*7c478bd9Sstevel@tonic-gate 	 * XXX: A non-zero length means override the one in the regspec
697*7c478bd9Sstevel@tonic-gate 	 * XXX: (regardless of what's in the parent's range?)
698*7c478bd9Sstevel@tonic-gate 	 */
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	tmp_reg = *(mp->map_obj.rp);		/* Preserve underlying data */
701*7c478bd9Sstevel@tonic-gate 	rp = mp->map_obj.rp = &tmp_reg;		/* Use tmp_reg in request */
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
704*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT,
705*7c478bd9Sstevel@tonic-gate 		"rootnex: <%s,%s> <0x%x, 0x%x, 0x%d>"
706*7c478bd9Sstevel@tonic-gate 		" offset %d len %d handle 0x%x\n",
707*7c478bd9Sstevel@tonic-gate 		ddi_get_name(dip), ddi_get_name(rdip),
708*7c478bd9Sstevel@tonic-gate 		rp->regspec_bustype, rp->regspec_addr, rp->regspec_size,
709*7c478bd9Sstevel@tonic-gate 		offset, len, mp->map_handlep);
710*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	/*
713*7c478bd9Sstevel@tonic-gate 	 * I/O or memory mapping:
714*7c478bd9Sstevel@tonic-gate 	 *
715*7c478bd9Sstevel@tonic-gate 	 *	<bustype=0, addr=x, len=x>: memory
716*7c478bd9Sstevel@tonic-gate 	 *	<bustype=1, addr=x, len=x>: i/o
717*7c478bd9Sstevel@tonic-gate 	 *	<bustype>1, addr=0, len=x>: x86-compatibility i/o
718*7c478bd9Sstevel@tonic-gate 	 */
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype > 1 && rp->regspec_addr != 0) {
721*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "<%s,%s> invalid register spec"
722*7c478bd9Sstevel@tonic-gate 		    " <0x%x, 0x%x, 0x%x>", ddi_get_name(dip),
723*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), rp->regspec_bustype,
724*7c478bd9Sstevel@tonic-gate 		    rp->regspec_addr, rp->regspec_size);
725*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
726*7c478bd9Sstevel@tonic-gate 	}
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	if (rp->regspec_bustype > 1 && rp->regspec_addr == 0) {
729*7c478bd9Sstevel@tonic-gate 		/*
730*7c478bd9Sstevel@tonic-gate 		 * compatibility i/o mapping
731*7c478bd9Sstevel@tonic-gate 		 */
732*7c478bd9Sstevel@tonic-gate 		rp->regspec_bustype += (uint_t)offset;
733*7c478bd9Sstevel@tonic-gate 	} else {
734*7c478bd9Sstevel@tonic-gate 		/*
735*7c478bd9Sstevel@tonic-gate 		 * Normal memory or i/o mapping
736*7c478bd9Sstevel@tonic-gate 		 */
737*7c478bd9Sstevel@tonic-gate 		rp->regspec_addr += (uint_t)offset;
738*7c478bd9Sstevel@tonic-gate 	}
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	if (len != 0)
741*7c478bd9Sstevel@tonic-gate 		rp->regspec_size = (uint_t)len;
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
744*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT,
745*7c478bd9Sstevel@tonic-gate 		"             <%s,%s> <0x%x, 0x%x, 0x%d>"
746*7c478bd9Sstevel@tonic-gate 		" offset %d len %d handle 0x%x\n",
747*7c478bd9Sstevel@tonic-gate 		ddi_get_name(dip), ddi_get_name(rdip),
748*7c478bd9Sstevel@tonic-gate 		rp->regspec_bustype, rp->regspec_addr, rp->regspec_size,
749*7c478bd9Sstevel@tonic-gate 		offset, len, mp->map_handlep);
750*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	/*
753*7c478bd9Sstevel@tonic-gate 	 * Apply any parent ranges at this level, if applicable.
754*7c478bd9Sstevel@tonic-gate 	 * (This is where nexus specific regspec translation takes place.
755*7c478bd9Sstevel@tonic-gate 	 * Use of this function is implicit agreement that translation is
756*7c478bd9Sstevel@tonic-gate 	 * provided via ddi_apply_range.)
757*7c478bd9Sstevel@tonic-gate 	 */
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
760*7c478bd9Sstevel@tonic-gate 	ddi_map_debug("applying range of parent <%s> to child <%s>...\n",
761*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(dip), ddi_get_name(rdip));
762*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	if ((error = i_ddi_apply_range(dip, rdip, mp->map_obj.rp)) != 0)
765*7c478bd9Sstevel@tonic-gate 		return (error);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	switch (mp->map_op)  {
768*7c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_LOCKED:
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 		/*
771*7c478bd9Sstevel@tonic-gate 		 * Set up the locked down kernel mapping to the regspec...
772*7c478bd9Sstevel@tonic-gate 		 */
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 		return (rootnex_map_regspec(mp, vaddrp));
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	case DDI_MO_UNMAP:
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 		/*
779*7c478bd9Sstevel@tonic-gate 		 * Release mapping...
780*7c478bd9Sstevel@tonic-gate 		 */
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 		return (rootnex_unmap_regspec(mp, vaddrp));
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	case DDI_MO_MAP_HANDLE:
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 		return (rootnex_map_handle(mp));
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	default:
789*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNIMPLEMENTED);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate }
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate /*
795*7c478bd9Sstevel@tonic-gate  * rootnex_map_fault:
796*7c478bd9Sstevel@tonic-gate  *
797*7c478bd9Sstevel@tonic-gate  *	fault in mappings for requestors
798*7c478bd9Sstevel@tonic-gate  */
799*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
800*7c478bd9Sstevel@tonic-gate static int
801*7c478bd9Sstevel@tonic-gate rootnex_map_fault(dev_info_t *dip, dev_info_t *rdip,
802*7c478bd9Sstevel@tonic-gate 	struct hat *hat, struct seg *seg, caddr_t addr,
803*7c478bd9Sstevel@tonic-gate 	struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
804*7c478bd9Sstevel@tonic-gate {
805*7c478bd9Sstevel@tonic-gate 	extern struct seg_ops segdev_ops;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate #ifdef	DDI_MAP_DEBUG
808*7c478bd9Sstevel@tonic-gate 	ddi_map_debug("rootnex_map_fault: address <%x> pfn <%x>", addr, pfn);
809*7c478bd9Sstevel@tonic-gate 	ddi_map_debug(" Seg <%s>\n",
810*7c478bd9Sstevel@tonic-gate 	    seg->s_ops == &segdev_ops ? "segdev" :
811*7c478bd9Sstevel@tonic-gate 	    seg == &kvseg ? "segkmem" : "NONE!");
812*7c478bd9Sstevel@tonic-gate #endif	/* DDI_MAP_DEBUG */
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	/*
815*7c478bd9Sstevel@tonic-gate 	 * This is all terribly broken, but it is a start
816*7c478bd9Sstevel@tonic-gate 	 *
817*7c478bd9Sstevel@tonic-gate 	 * XXX	Note that this test means that segdev_ops
818*7c478bd9Sstevel@tonic-gate 	 *	must be exported from seg_dev.c.
819*7c478bd9Sstevel@tonic-gate 	 * XXX	What about devices with their own segment drivers?
820*7c478bd9Sstevel@tonic-gate 	 */
821*7c478bd9Sstevel@tonic-gate 	if (seg->s_ops == &segdev_ops) {
822*7c478bd9Sstevel@tonic-gate 		struct segdev_data *sdp =
823*7c478bd9Sstevel@tonic-gate 			(struct segdev_data *)seg->s_data;
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 		if (hat == NULL) {
826*7c478bd9Sstevel@tonic-gate 			/*
827*7c478bd9Sstevel@tonic-gate 			 * This is one plausible interpretation of
828*7c478bd9Sstevel@tonic-gate 			 * a null hat i.e. use the first hat on the
829*7c478bd9Sstevel@tonic-gate 			 * address space hat list which by convention is
830*7c478bd9Sstevel@tonic-gate 			 * the hat of the system MMU.  At alternative
831*7c478bd9Sstevel@tonic-gate 			 * would be to panic .. this might well be better ..
832*7c478bd9Sstevel@tonic-gate 			 */
833*7c478bd9Sstevel@tonic-gate 			ASSERT(AS_READ_HELD(seg->s_as, &seg->s_as->a_lock));
834*7c478bd9Sstevel@tonic-gate 			hat = seg->s_as->a_hat;
835*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "rootnex_map_fault: nil hat");
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate 		hat_devload(hat, addr, MMU_PAGESIZE, pfn, prot | sdp->hat_attr,
838*7c478bd9Sstevel@tonic-gate 		    (lock ? HAT_LOAD_LOCK : HAT_LOAD));
839*7c478bd9Sstevel@tonic-gate 	} else if (seg == &kvseg && dp == NULL) {
840*7c478bd9Sstevel@tonic-gate 		hat_devload(kas.a_hat, addr, MMU_PAGESIZE, pfn, prot,
841*7c478bd9Sstevel@tonic-gate 		    HAT_LOAD_LOCK);
842*7c478bd9Sstevel@tonic-gate 	} else
843*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
844*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate /*
849*7c478bd9Sstevel@tonic-gate  * DMA routines- for all 80x86 machines.
850*7c478bd9Sstevel@tonic-gate  */
851*7c478bd9Sstevel@tonic-gate 
852*7c478bd9Sstevel@tonic-gate /*
853*7c478bd9Sstevel@tonic-gate  * Shorthand defines
854*7c478bd9Sstevel@tonic-gate  */
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate #define	MAP	0
857*7c478bd9Sstevel@tonic-gate #define	BIND	1
858*7c478bd9Sstevel@tonic-gate #define	MAX_INT_BUF	(16*MMU_PAGESIZE)
859*7c478bd9Sstevel@tonic-gate #define	AHI_LIM		dma_lim->dlim_addr_hi
860*7c478bd9Sstevel@tonic-gate #define	AHI_ATTR	dma_attr->dma_attr_addr_hi
861*7c478bd9Sstevel@tonic-gate #define	OBJSIZE		dmareq->dmar_object.dmao_size
862*7c478bd9Sstevel@tonic-gate #define	OBJTYPE		dmareq->dmar_object.dmao_type
863*7c478bd9Sstevel@tonic-gate #define	FOURG		0x100000000ULL
864*7c478bd9Sstevel@tonic-gate #define	SIXTEEN_MB	0x1000000
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate /* #define	DMADEBUG */
867*7c478bd9Sstevel@tonic-gate #if defined(DEBUG) || defined(lint)
868*7c478bd9Sstevel@tonic-gate #define	DMADEBUG
869*7c478bd9Sstevel@tonic-gate static int dmadebug = 0;
870*7c478bd9Sstevel@tonic-gate #define	DMAPRINT(a)	if (dmadebug) prom_printf a
871*7c478bd9Sstevel@tonic-gate #else
872*7c478bd9Sstevel@tonic-gate #define	DMAPRINT(a)	{ }
873*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate /*
878*7c478bd9Sstevel@tonic-gate  * allocate DMA handle
879*7c478bd9Sstevel@tonic-gate  */
880*7c478bd9Sstevel@tonic-gate static int
881*7c478bd9Sstevel@tonic-gate rootnex_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
882*7c478bd9Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
883*7c478bd9Sstevel@tonic-gate {
884*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp;
885*7c478bd9Sstevel@tonic-gate 	uint64_t maxsegmentsize_ll;
886*7c478bd9Sstevel@tonic-gate 	uint_t maxsegmentsize;
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate #ifdef lint
889*7c478bd9Sstevel@tonic-gate 	dip = dip;
890*7c478bd9Sstevel@tonic-gate #endif
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	/*
893*7c478bd9Sstevel@tonic-gate 	 * Validate the dma request.
894*7c478bd9Sstevel@tonic-gate 	 */
895*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG
896*7c478bd9Sstevel@tonic-gate 	if (attr->dma_attr_seg < MMU_PAGEOFFSET ||
897*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_count_max < MMU_PAGEOFFSET ||
898*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_granular > MMU_PAGESIZE ||
899*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_maxxfer < MMU_PAGESIZE) {
900*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits\n"));
901*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADLIMITS);
902*7c478bd9Sstevel@tonic-gate 	}
903*7c478bd9Sstevel@tonic-gate #endif
904*7c478bd9Sstevel@tonic-gate 	/*
905*7c478bd9Sstevel@tonic-gate 	 * validate the attribute structure. For now we do not support
906*7c478bd9Sstevel@tonic-gate 	 * negative sgllen.
907*7c478bd9Sstevel@tonic-gate 	 */
908*7c478bd9Sstevel@tonic-gate 	if ((attr->dma_attr_addr_hi <= attr->dma_attr_addr_lo) ||
909*7c478bd9Sstevel@tonic-gate 	    (attr->dma_attr_sgllen <= 0)) {
910*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADATTR);
911*7c478bd9Sstevel@tonic-gate 	}
912*7c478bd9Sstevel@tonic-gate 	if ((attr->dma_attr_seg & MMU_PAGEOFFSET) != MMU_PAGEOFFSET ||
913*7c478bd9Sstevel@tonic-gate 	    MMU_PAGESIZE & (attr->dma_attr_granular - 1) ||
914*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_sgllen < 0) {
915*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADATTR);
916*7c478bd9Sstevel@tonic-gate 	}
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	maxsegmentsize_ll = MIN(attr->dma_attr_seg,
920*7c478bd9Sstevel@tonic-gate 	    MIN((attr->dma_attr_count_max + 1) *
921*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_minxfer,
922*7c478bd9Sstevel@tonic-gate 	    attr->dma_attr_maxxfer) - 1) + 1;
923*7c478bd9Sstevel@tonic-gate 	/*
924*7c478bd9Sstevel@tonic-gate 	 * We will calculate a 64 bit segment size, if the segment size
925*7c478bd9Sstevel@tonic-gate 	 * is greater that 4G, we will limit it to (4G - 1).
926*7c478bd9Sstevel@tonic-gate 	 * The size of dma object (ddi_dma_obj_t.dmao_size)
927*7c478bd9Sstevel@tonic-gate 	 * is 32 bits.
928*7c478bd9Sstevel@tonic-gate 	 */
929*7c478bd9Sstevel@tonic-gate 	if (maxsegmentsize_ll == 0 || (maxsegmentsize_ll > FOURG))
930*7c478bd9Sstevel@tonic-gate 		maxsegmentsize = FOURG - 1;
931*7c478bd9Sstevel@tonic-gate 	else
932*7c478bd9Sstevel@tonic-gate 		maxsegmentsize = maxsegmentsize_ll;
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	/*
935*7c478bd9Sstevel@tonic-gate 	 * We should be able to DMA into every byte offset in a page.
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	if (maxsegmentsize < MMU_PAGESIZE) {
938*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits, maxsegmentsize\n"));
939*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADLIMITS);
940*7c478bd9Sstevel@tonic-gate 	}
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	hp = kmem_zalloc(sizeof (*hp),
944*7c478bd9Sstevel@tonic-gate 	    (waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
945*7c478bd9Sstevel@tonic-gate 	if (hp == NULL) {
946*7c478bd9Sstevel@tonic-gate 		if (waitfp != DDI_DMA_DONTWAIT) {
947*7c478bd9Sstevel@tonic-gate 			ddi_set_callback(waitfp, arg, &dvma_call_list_id);
948*7c478bd9Sstevel@tonic-gate 		}
949*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NORESOURCES);
950*7c478bd9Sstevel@tonic-gate 	}
951*7c478bd9Sstevel@tonic-gate 	/*
952*7c478bd9Sstevel@tonic-gate 	 * Preallocate space for cookie structures. We will use this when
953*7c478bd9Sstevel@tonic-gate 	 * the request does not span more than (DMAI_SOMEMORE_COOKIES - 1)
954*7c478bd9Sstevel@tonic-gate 	 * pages.
955*7c478bd9Sstevel@tonic-gate 	 */
956*7c478bd9Sstevel@tonic-gate 	hp->dmai_additionalcookiep =
957*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (ddi_dma_cookie_t) * DMAI_SOMEMORE_COOKIES,
958*7c478bd9Sstevel@tonic-gate 		(waitfp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	/*
961*7c478bd9Sstevel@tonic-gate 	 * Save requestor's information
962*7c478bd9Sstevel@tonic-gate 	 */
963*7c478bd9Sstevel@tonic-gate 	hp->dmai_wins = NULL;
964*7c478bd9Sstevel@tonic-gate 	hp->dmai_kaddr =
965*7c478bd9Sstevel@tonic-gate 	hp->dmai_ibufp = NULL;
966*7c478bd9Sstevel@tonic-gate 	hp->dmai_inuse = 0;
967*7c478bd9Sstevel@tonic-gate 	hp->dmai_minxfer = attr->dma_attr_minxfer;
968*7c478bd9Sstevel@tonic-gate 	hp->dmai_burstsizes = attr->dma_attr_burstsizes;
969*7c478bd9Sstevel@tonic-gate 	hp->dmai_minfo = NULL;
970*7c478bd9Sstevel@tonic-gate 	hp->dmai_rdip = rdip;
971*7c478bd9Sstevel@tonic-gate 	hp->dmai_attr = *attr;
972*7c478bd9Sstevel@tonic-gate 	hp->dmai_mctl = rootnex_dma_mctl;
973*7c478bd9Sstevel@tonic-gate 	hp->dmai_segmentsize = maxsegmentsize;
974*7c478bd9Sstevel@tonic-gate 	*handlep = (ddi_dma_handle_t)hp;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
977*7c478bd9Sstevel@tonic-gate }
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
980*7c478bd9Sstevel@tonic-gate static int
981*7c478bd9Sstevel@tonic-gate rootnex_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
982*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle)
983*7c478bd9Sstevel@tonic-gate {
984*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 	/*
987*7c478bd9Sstevel@tonic-gate 	 * free the additional cookie space.
988*7c478bd9Sstevel@tonic-gate 	 */
989*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_additionalcookiep)
990*7c478bd9Sstevel@tonic-gate 	    kmem_free(hp->dmai_additionalcookiep,
991*7c478bd9Sstevel@tonic-gate 		sizeof (ddi_dma_cookie_t) * DMAI_SOMEMORE_COOKIES);
992*7c478bd9Sstevel@tonic-gate 
993*7c478bd9Sstevel@tonic-gate 	kmem_free(hp, sizeof (*hp));
994*7c478bd9Sstevel@tonic-gate 	if (dvma_call_list_id)
995*7c478bd9Sstevel@tonic-gate 		ddi_run_callback(&dvma_call_list_id);
996*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
997*7c478bd9Sstevel@tonic-gate }
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate static int
1000*7c478bd9Sstevel@tonic-gate rootnex_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1001*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1002*7c478bd9Sstevel@tonic-gate     ddi_dma_cookie_t *cookiep, uint_t *ccountp)
1003*7c478bd9Sstevel@tonic-gate {
1004*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
1005*7c478bd9Sstevel@tonic-gate 	ddi_dma_attr_t *dma_attr = &hp->dmai_attr;
1006*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cp;
1007*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *segp;
1008*7c478bd9Sstevel@tonic-gate 	uint_t segcount = 1;
1009*7c478bd9Sstevel@tonic-gate 	int rval;
1010*7c478bd9Sstevel@tonic-gate 	struct priv_handle php;
1011*7c478bd9Sstevel@tonic-gate 	uint_t	size, offset;
1012*7c478bd9Sstevel@tonic-gate 	uint64_t padr;
1013*7c478bd9Sstevel@tonic-gate 	major_t mnum;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	/*
1016*7c478bd9Sstevel@tonic-gate 	 * no mutex for speed
1017*7c478bd9Sstevel@tonic-gate 	 */
1018*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_inuse) {
1019*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_INUSE);
1020*7c478bd9Sstevel@tonic-gate 	}
1021*7c478bd9Sstevel@tonic-gate 	hp->dmai_inuse = 1;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	size = OBJSIZE;
1024*7c478bd9Sstevel@tonic-gate 	/*
1025*7c478bd9Sstevel@tonic-gate 	 * get the physical address of the first page of an object
1026*7c478bd9Sstevel@tonic-gate 	 * defined through 'dmareq' structure.
1027*7c478bd9Sstevel@tonic-gate 	 */
1028*7c478bd9Sstevel@tonic-gate 	padr = rootnex_get_phyaddr(dmareq, 0, &php);
1029*7c478bd9Sstevel@tonic-gate 	offset = padr & MMU_PAGEOFFSET;
1030*7c478bd9Sstevel@tonic-gate 	if (offset & (dma_attr->dma_attr_minxfer - 1)) {
1031*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits/mapping\n"));
1032*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
1033*7c478bd9Sstevel@tonic-gate 	} else if ((dma_attr->dma_attr_sgllen > 1) &&
1034*7c478bd9Sstevel@tonic-gate 	    (size <= MMU_PAGESIZE) && (padr < AHI_ATTR)) {
1035*7c478bd9Sstevel@tonic-gate 		/*
1036*7c478bd9Sstevel@tonic-gate 		 * The object is not more than a PAGESIZE and we could DMA into
1037*7c478bd9Sstevel@tonic-gate 		 * the physical page.
1038*7c478bd9Sstevel@tonic-gate 		 * The cache is completely coherent, set the NOSYNC flag.
1039*7c478bd9Sstevel@tonic-gate 		 */
1040*7c478bd9Sstevel@tonic-gate 		hp->dmai_rflags = (dmareq->dmar_flags & DMP_DDIFLAGS) |
1041*7c478bd9Sstevel@tonic-gate 			DMP_NOSYNC;
1042*7c478bd9Sstevel@tonic-gate 		/*
1043*7c478bd9Sstevel@tonic-gate 		 * Fill in the physical address in the cookie pointer.
1044*7c478bd9Sstevel@tonic-gate 		 */
1045*7c478bd9Sstevel@tonic-gate 		cookiep->dmac_type = php.ph_mapinfo;
1046*7c478bd9Sstevel@tonic-gate 		cookiep->dmac_laddress = padr;
1047*7c478bd9Sstevel@tonic-gate 		if ((offset + size) <= MMU_PAGESIZE) {
1048*7c478bd9Sstevel@tonic-gate 		    cookiep->dmac_size = size;
1049*7c478bd9Sstevel@tonic-gate 		    hp->dmai_cookie = NULL;
1050*7c478bd9Sstevel@tonic-gate 		    *ccountp = 1;
1051*7c478bd9Sstevel@tonic-gate 		} else if (hp->dmai_additionalcookiep) {
1052*7c478bd9Sstevel@tonic-gate 		/*
1053*7c478bd9Sstevel@tonic-gate 		 * The object spans a page boundary. We will use the space
1054*7c478bd9Sstevel@tonic-gate 		 * that we preallocated to store the additional cookie.
1055*7c478bd9Sstevel@tonic-gate 		 */
1056*7c478bd9Sstevel@tonic-gate 		    cookiep->dmac_size = MMU_PAGESIZE - offset;
1057*7c478bd9Sstevel@tonic-gate 		    hp->dmai_cookie = hp->dmai_additionalcookiep;
1058*7c478bd9Sstevel@tonic-gate 		    padr = rootnex_get_phyaddr(dmareq,
1059*7c478bd9Sstevel@tonic-gate 			(uint_t)cookiep->dmac_size, &php);
1060*7c478bd9Sstevel@tonic-gate 		    if (padr > AHI_ATTR) {
1061*7c478bd9Sstevel@tonic-gate 			/*
1062*7c478bd9Sstevel@tonic-gate 			 * We can not DMA into this physical page. We will
1063*7c478bd9Sstevel@tonic-gate 			 * need intermediate buffers. Reset the state in
1064*7c478bd9Sstevel@tonic-gate 			 * the php structure.
1065*7c478bd9Sstevel@tonic-gate 			 */
1066*7c478bd9Sstevel@tonic-gate 			padr = rootnex_get_phyaddr(dmareq, 0, &php);
1067*7c478bd9Sstevel@tonic-gate 			goto io_brkup_attr;
1068*7c478bd9Sstevel@tonic-gate 		    }
1069*7c478bd9Sstevel@tonic-gate 		    hp->dmai_additionalcookiep->dmac_type = php.ph_mapinfo;
1070*7c478bd9Sstevel@tonic-gate 		    hp->dmai_additionalcookiep->dmac_laddress = padr;
1071*7c478bd9Sstevel@tonic-gate 		    hp->dmai_additionalcookiep->dmac_size =
1072*7c478bd9Sstevel@tonic-gate 			size - cookiep->dmac_size;
1073*7c478bd9Sstevel@tonic-gate 		    *ccountp = 2;
1074*7c478bd9Sstevel@tonic-gate 		} else {
1075*7c478bd9Sstevel@tonic-gate 			goto io_brkup_attr;
1076*7c478bd9Sstevel@tonic-gate 		}
1077*7c478bd9Sstevel@tonic-gate 		hp->dmai_kaddr = NULL;
1078*7c478bd9Sstevel@tonic-gate 		hp->dmai_segp = NULL;
1079*7c478bd9Sstevel@tonic-gate 		hp->dmai_ibufp = NULL;
1080*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_MAPPED);
1081*7c478bd9Sstevel@tonic-gate 	}
1082*7c478bd9Sstevel@tonic-gate io_brkup_attr:
1083*7c478bd9Sstevel@tonic-gate 	/*
1084*7c478bd9Sstevel@tonic-gate 	 * The function rootnex_get_phyaddr() does not save the physical
1085*7c478bd9Sstevel@tonic-gate 	 * address in the php structure. Save it here for
1086*7c478bd9Sstevel@tonic-gate 	 * rootnext_io_brkup_attr().
1087*7c478bd9Sstevel@tonic-gate 	 */
1088*7c478bd9Sstevel@tonic-gate 	php.ph_padr = padr;
1089*7c478bd9Sstevel@tonic-gate 	rval =  rootnex_io_brkup_attr(dip, rdip, dmareq, handle, &php);
1090*7c478bd9Sstevel@tonic-gate 	if (rval && (rval != DDI_DMA_PARTIAL_MAP)) {
1091*7c478bd9Sstevel@tonic-gate 		hp->dmai_inuse = 0;
1092*7c478bd9Sstevel@tonic-gate 		return (rval);
1093*7c478bd9Sstevel@tonic-gate 	}
1094*7c478bd9Sstevel@tonic-gate 	hp->dmai_wins = segp = hp->dmai_hds;
1095*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_ibufp) {
1096*7c478bd9Sstevel@tonic-gate 		(void) rootnex_io_wtsync(hp, BIND);
1097*7c478bd9Sstevel@tonic-gate 	}
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	while ((segp->dmais_flags & DMAIS_WINEND) == 0) {
1100*7c478bd9Sstevel@tonic-gate 		segp = segp->dmais_link;
1101*7c478bd9Sstevel@tonic-gate 		segcount++;
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 	*ccountp = segcount;
1104*7c478bd9Sstevel@tonic-gate 	cp = hp->dmai_cookie;
1105*7c478bd9Sstevel@tonic-gate 	ASSERT(cp);
1106*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_type = cp->dmac_type;
1107*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_laddress = cp->dmac_laddress;
1108*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_size = cp->dmac_size;
1109*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie++;
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	/*
1112*7c478bd9Sstevel@tonic-gate 	 * If we ended up with more cookies that the caller specified as
1113*7c478bd9Sstevel@tonic-gate 	 * the maximum that it can handle (sgllen), and they didn't specify
1114*7c478bd9Sstevel@tonic-gate 	 * DDI_DMA_PARTIAL, cleanup and return failure.
1115*7c478bd9Sstevel@tonic-gate 	 *
1116*7c478bd9Sstevel@tonic-gate 	 * Not the cleanest fix, but lowest risk. The DMA code in
1117*7c478bd9Sstevel@tonic-gate 	 * this file should get a good cleaning for some performance
1118*7c478bd9Sstevel@tonic-gate 	 * improvement. This should be cleaned up also during that work.
1119*7c478bd9Sstevel@tonic-gate 	 */
1120*7c478bd9Sstevel@tonic-gate 	if ((dma_attr->dma_attr_sgllen < *ccountp) &&
1121*7c478bd9Sstevel@tonic-gate 	    ((dmareq->dmar_flags & DDI_DMA_PARTIAL) == 0)) {
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 		mnum = ddi_driver_major(rdip);
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 		/*
1126*7c478bd9Sstevel@tonic-gate 		 * patchable which allows us to print one warning per major
1127*7c478bd9Sstevel@tonic-gate 		 * number.
1128*7c478bd9Sstevel@tonic-gate 		 */
1129*7c478bd9Sstevel@tonic-gate 		if ((rootnex_bind_warn) &&
1130*7c478bd9Sstevel@tonic-gate 		    ((rootnex_warn_list[mnum] & ROOTNEX_BIND_WARNING) == 0)) {
1131*7c478bd9Sstevel@tonic-gate 			rootnex_warn_list[mnum] |= ROOTNEX_BIND_WARNING;
1132*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "!%s: coding error detected, the "
1133*7c478bd9Sstevel@tonic-gate 			    "driver is using ddi_dma_attr(9S) incorrectly. "
1134*7c478bd9Sstevel@tonic-gate 			    "There is a small risk of data corruption in "
1135*7c478bd9Sstevel@tonic-gate 			    "particular with large I/Os. The driver should be "
1136*7c478bd9Sstevel@tonic-gate 			    "replaced with a corrected version for proper "
1137*7c478bd9Sstevel@tonic-gate 			    "system operation. To disable this warning, add "
1138*7c478bd9Sstevel@tonic-gate 			    "'set rootnex:rootnex_bind_warn=0' to "
1139*7c478bd9Sstevel@tonic-gate 			    "/etc/system(4).", ddi_driver_name(rdip));
1140*7c478bd9Sstevel@tonic-gate 		}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 		/*
1143*7c478bd9Sstevel@tonic-gate 		 * Patchable which allows us to fail or pass the bind. The
1144*7c478bd9Sstevel@tonic-gate 		 * correct behavior should be to fail the bind. To be safe for
1145*7c478bd9Sstevel@tonic-gate 		 * now, the patchable allows the previous behavior to be set
1146*7c478bd9Sstevel@tonic-gate 		 * via /etc/system
1147*7c478bd9Sstevel@tonic-gate 		 */
1148*7c478bd9Sstevel@tonic-gate 		if (rootnex_bind_fail) {
1149*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_ibufp)
1150*7c478bd9Sstevel@tonic-gate 				ddi_mem_free(hp->dmai_ibufp);
1151*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_kaddr)
1152*7c478bd9Sstevel@tonic-gate 				vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE);
1153*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_segp)
1154*7c478bd9Sstevel@tonic-gate 				kmem_free(hp->dmai_segp, hp->dmai_kmsize);
1155*7c478bd9Sstevel@tonic-gate 			hp->dmai_inuse = 0;
1156*7c478bd9Sstevel@tonic-gate 			*ccountp = 0;
1157*7c478bd9Sstevel@tonic-gate 
1158*7c478bd9Sstevel@tonic-gate 			return (DDI_DMA_TOOBIG);
1159*7c478bd9Sstevel@tonic-gate 		}
1160*7c478bd9Sstevel@tonic-gate 	}
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	return (rval);
1163*7c478bd9Sstevel@tonic-gate }
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1166*7c478bd9Sstevel@tonic-gate static int
1167*7c478bd9Sstevel@tonic-gate rootnex_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1168*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle)
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
1171*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_ibufp) {
1174*7c478bd9Sstevel@tonic-gate 		rval = rootnex_io_rdsync(hp);
1175*7c478bd9Sstevel@tonic-gate 		ddi_mem_free(hp->dmai_ibufp);
1176*7c478bd9Sstevel@tonic-gate 	}
1177*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_kaddr)
1178*7c478bd9Sstevel@tonic-gate 		vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE);
1179*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_segp)
1180*7c478bd9Sstevel@tonic-gate 		kmem_free(hp->dmai_segp, hp->dmai_kmsize);
1181*7c478bd9Sstevel@tonic-gate 	if (dvma_call_list_id)
1182*7c478bd9Sstevel@tonic-gate 		ddi_run_callback(&dvma_call_list_id);
1183*7c478bd9Sstevel@tonic-gate 	hp->dmai_inuse = 0;
1184*7c478bd9Sstevel@tonic-gate 	return (rval);
1185*7c478bd9Sstevel@tonic-gate }
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1188*7c478bd9Sstevel@tonic-gate static int
1189*7c478bd9Sstevel@tonic-gate rootnex_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1190*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, off_t off, size_t len,
1191*7c478bd9Sstevel@tonic-gate     uint_t cache_flags)
1192*7c478bd9Sstevel@tonic-gate {
1193*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
1194*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_ibufp) {
1197*7c478bd9Sstevel@tonic-gate 		if (cache_flags == DDI_DMA_SYNC_FORDEV) {
1198*7c478bd9Sstevel@tonic-gate 			rval = rootnex_io_wtsync(hp, MAP);
1199*7c478bd9Sstevel@tonic-gate 		} else {
1200*7c478bd9Sstevel@tonic-gate 			rval =  rootnex_io_rdsync(hp);
1201*7c478bd9Sstevel@tonic-gate 		}
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 	return (rval);
1204*7c478bd9Sstevel@tonic-gate }
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1207*7c478bd9Sstevel@tonic-gate static int
1208*7c478bd9Sstevel@tonic-gate rootnex_dma_win(dev_info_t *dip, dev_info_t *rdip,
1209*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, uint_t win, off_t *offp,
1210*7c478bd9Sstevel@tonic-gate     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
1211*7c478bd9Sstevel@tonic-gate {
1212*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
1213*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *segp, *winp = hp->dmai_hds;
1214*7c478bd9Sstevel@tonic-gate 	uint_t len, segcount = 1;
1215*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cp;
1216*7c478bd9Sstevel@tonic-gate 	int i;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	/*
1219*7c478bd9Sstevel@tonic-gate 	 * win is in the range [0 .. dmai_nwin-1]
1220*7c478bd9Sstevel@tonic-gate 	 */
1221*7c478bd9Sstevel@tonic-gate 	if (win >= hp->dmai_nwin) {
1222*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_wins && hp->dmai_ibufp) {
1225*7c478bd9Sstevel@tonic-gate 		(void) rootnex_io_rdsync(hp);
1226*7c478bd9Sstevel@tonic-gate 	}
1227*7c478bd9Sstevel@tonic-gate 	ASSERT(winp->dmais_flags & DMAIS_WINSTRT);
1228*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < win; i++) {
1229*7c478bd9Sstevel@tonic-gate 		winp = winp->_win._dmais_nex;
1230*7c478bd9Sstevel@tonic-gate 		ASSERT(winp);
1231*7c478bd9Sstevel@tonic-gate 		ASSERT(winp->dmais_flags & DMAIS_WINSTRT);
1232*7c478bd9Sstevel@tonic-gate 	}
1233*7c478bd9Sstevel@tonic-gate 
1234*7c478bd9Sstevel@tonic-gate 	hp->dmai_wins = (impl_dma_segment_t *)winp;
1235*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_ibufp)
1236*7c478bd9Sstevel@tonic-gate 		(void) rootnex_io_wtsync(hp, BIND);
1237*7c478bd9Sstevel@tonic-gate 	segp = winp;
1238*7c478bd9Sstevel@tonic-gate 	len = segp->dmais_size;
1239*7c478bd9Sstevel@tonic-gate 	*offp = segp->dmais_ofst;
1240*7c478bd9Sstevel@tonic-gate 	while ((segp->dmais_flags & DMAIS_WINEND) == 0) {
1241*7c478bd9Sstevel@tonic-gate 		segp = segp->dmais_link;
1242*7c478bd9Sstevel@tonic-gate 		len += segp->dmais_size;
1243*7c478bd9Sstevel@tonic-gate 		segcount++;
1244*7c478bd9Sstevel@tonic-gate 	}
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	*lenp = len;
1247*7c478bd9Sstevel@tonic-gate 	*ccountp = segcount;
1248*7c478bd9Sstevel@tonic-gate 	cp = hp->dmai_cookie = winp->dmais_cookie;
1249*7c478bd9Sstevel@tonic-gate 	ASSERT(cp);
1250*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_type = cp->dmac_type;
1251*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_laddress = cp->dmac_laddress;
1252*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_size = cp->dmac_size;
1253*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie++;
1254*7c478bd9Sstevel@tonic-gate 	DMAPRINT(("getwin win %p mapping %llx size %lx\n",
1255*7c478bd9Sstevel@tonic-gate 	    (void *)winp, (unsigned long long)cp->dmac_laddress,
1256*7c478bd9Sstevel@tonic-gate 	    cp->dmac_size));
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1259*7c478bd9Sstevel@tonic-gate }
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate static int
1262*7c478bd9Sstevel@tonic-gate rootnex_dma_map(dev_info_t *dip, dev_info_t *rdip,
1263*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep)
1264*7c478bd9Sstevel@tonic-gate {
1265*7c478bd9Sstevel@tonic-gate 	ddi_dma_lim_t *dma_lim = dmareq->dmar_limits;
1266*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *segmentp;
1267*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp;
1268*7c478bd9Sstevel@tonic-gate 	struct priv_handle php;
1269*7c478bd9Sstevel@tonic-gate 	uint64_t padr;
1270*7c478bd9Sstevel@tonic-gate 	uint_t offset, size;
1271*7c478bd9Sstevel@tonic-gate 	int sizehandle;
1272*7c478bd9Sstevel@tonic-gate 	int mapinfo;
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate #ifdef lint
1275*7c478bd9Sstevel@tonic-gate 	dip = dip;
1276*7c478bd9Sstevel@tonic-gate #endif
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 	DMAPRINT(("dma_map: %s (%s) reqp %p ", (handlep)? "alloc" : "advisory",
1279*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), (void *)dmareq));
1280*7c478bd9Sstevel@tonic-gate 
1281*7c478bd9Sstevel@tonic-gate #ifdef	DMADEBUG
1282*7c478bd9Sstevel@tonic-gate 	/*
1283*7c478bd9Sstevel@tonic-gate 	 * Validate range checks on DMA limits
1284*7c478bd9Sstevel@tonic-gate 	 */
1285*7c478bd9Sstevel@tonic-gate 	if ((dma_lim->dlim_adreg_max & MMU_PAGEOFFSET) != MMU_PAGEOFFSET ||
1286*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_granular > MMU_PAGESIZE ||
1287*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_sgllen <= 0) {
1288*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits\n"));
1289*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADLIMITS);
1290*7c478bd9Sstevel@tonic-gate 	}
1291*7c478bd9Sstevel@tonic-gate #endif
1292*7c478bd9Sstevel@tonic-gate 	size = OBJSIZE;
1293*7c478bd9Sstevel@tonic-gate 	/*
1294*7c478bd9Sstevel@tonic-gate 	 * get the physical address of the first page of an object
1295*7c478bd9Sstevel@tonic-gate 	 * defined through 'dmareq' structure.
1296*7c478bd9Sstevel@tonic-gate 	 */
1297*7c478bd9Sstevel@tonic-gate 	padr = rootnex_get_phyaddr(dmareq, 0, &php);
1298*7c478bd9Sstevel@tonic-gate 	mapinfo = php.ph_mapinfo;
1299*7c478bd9Sstevel@tonic-gate 	offset = padr & MMU_PAGEOFFSET;
1300*7c478bd9Sstevel@tonic-gate 	if (offset & (dma_lim->dlim_minxfer - 1)) {
1301*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits/mapping\n"));
1302*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
1303*7c478bd9Sstevel@tonic-gate 	} else if (((offset + size) < MMU_PAGESIZE) && (padr < AHI_LIM)) {
1304*7c478bd9Sstevel@tonic-gate 		/*
1305*7c478bd9Sstevel@tonic-gate 		 * The object is less than a PAGESIZE and we could DMA into
1306*7c478bd9Sstevel@tonic-gate 		 * the physical page.
1307*7c478bd9Sstevel@tonic-gate 		 */
1308*7c478bd9Sstevel@tonic-gate 		if (!handlep)
1309*7c478bd9Sstevel@tonic-gate 			return (DDI_DMA_MAPOK);
1310*7c478bd9Sstevel@tonic-gate 		sizehandle = sizeof (ddi_dma_impl_t) +
1311*7c478bd9Sstevel@tonic-gate 		    sizeof (impl_dma_segment_t);
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 		hp = kmem_alloc(sizehandle, (dmareq->dmar_fp == DDI_DMA_SLEEP) ?
1314*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP : KM_NOSLEEP);
1315*7c478bd9Sstevel@tonic-gate 		if (!hp) {
1316*7c478bd9Sstevel@tonic-gate 			/* let other routine do callback */
1317*7c478bd9Sstevel@tonic-gate 			goto breakup_req;
1318*7c478bd9Sstevel@tonic-gate 		}
1319*7c478bd9Sstevel@tonic-gate 		hp->dmai_kmsize = sizehandle;
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate 		/*
1322*7c478bd9Sstevel@tonic-gate 		 * locate segments after dma_impl handle structure
1323*7c478bd9Sstevel@tonic-gate 		 */
1324*7c478bd9Sstevel@tonic-gate 		segmentp = (impl_dma_segment_t *)(hp + 1);
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 		/* FMA related initialization */
1327*7c478bd9Sstevel@tonic-gate 		hp->dmai_fault = 0;
1328*7c478bd9Sstevel@tonic-gate 		hp->dmai_fault_check = NULL;
1329*7c478bd9Sstevel@tonic-gate 		hp->dmai_fault_notify = NULL;
1330*7c478bd9Sstevel@tonic-gate 		hp->dmai_error.err_ena = 0;
1331*7c478bd9Sstevel@tonic-gate 		hp->dmai_error.err_status = DDI_FM_OK;
1332*7c478bd9Sstevel@tonic-gate 		hp->dmai_error.err_expected = DDI_FM_ERR_UNEXPECTED;
1333*7c478bd9Sstevel@tonic-gate 		hp->dmai_error.err_ontrap = NULL;
1334*7c478bd9Sstevel@tonic-gate 		hp->dmai_error.err_fep = NULL;
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 		/*
1337*7c478bd9Sstevel@tonic-gate 		 * Save requestor's information
1338*7c478bd9Sstevel@tonic-gate 		 */
1339*7c478bd9Sstevel@tonic-gate 		hp->dmai_minxfer = dma_lim->dlim_minxfer;
1340*7c478bd9Sstevel@tonic-gate 		hp->dmai_burstsizes = dma_lim->dlim_burstsizes;
1341*7c478bd9Sstevel@tonic-gate 		hp->dmai_rdip = rdip;
1342*7c478bd9Sstevel@tonic-gate 		hp->dmai_mctl = rootnex_dma_mctl;
1343*7c478bd9Sstevel@tonic-gate 		hp->dmai_wins = NULL;
1344*7c478bd9Sstevel@tonic-gate 		hp->dmai_kaddr = hp->dmai_ibufp = NULL;
1345*7c478bd9Sstevel@tonic-gate 		hp->dmai_hds = segmentp;
1346*7c478bd9Sstevel@tonic-gate 		hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS;
1347*7c478bd9Sstevel@tonic-gate 		hp->dmai_minfo = (void *)(uintptr_t)mapinfo;
1348*7c478bd9Sstevel@tonic-gate 		hp->dmai_object = dmareq->dmar_object;
1349*7c478bd9Sstevel@tonic-gate 		if (mapinfo == DMAMI_PAGES) {
1350*7c478bd9Sstevel@tonic-gate 			segmentp->_vdmu._dmais_pp = php.ph_u.pp;
1351*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_ofst = (uint_t)offset;
1352*7c478bd9Sstevel@tonic-gate 		} else {
1353*7c478bd9Sstevel@tonic-gate 			segmentp->_vdmu._dmais_va = php.ph_vaddr;
1354*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_ofst = 0;
1355*7c478bd9Sstevel@tonic-gate 		}
1356*7c478bd9Sstevel@tonic-gate 		segmentp->_win._dmais_nex = NULL;
1357*7c478bd9Sstevel@tonic-gate 		segmentp->dmais_link = NULL;
1358*7c478bd9Sstevel@tonic-gate 		segmentp->_pdmu._dmais_lpd = padr;
1359*7c478bd9Sstevel@tonic-gate 		segmentp->dmais_size = size;
1360*7c478bd9Sstevel@tonic-gate 		segmentp->dmais_flags = DMAIS_WINSTRT | DMAIS_WINEND;
1361*7c478bd9Sstevel@tonic-gate 		segmentp->dmais_hndl = hp;
1362*7c478bd9Sstevel@tonic-gate 		*handlep = (ddi_dma_handle_t)hp;
1363*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("	QUICKIE handle %p\n", (void *)hp));
1364*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_MAPPED);
1365*7c478bd9Sstevel@tonic-gate 	} else if (!handlep) {
1366*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
1367*7c478bd9Sstevel@tonic-gate 	}
1368*7c478bd9Sstevel@tonic-gate breakup_req:
1369*7c478bd9Sstevel@tonic-gate 	/*
1370*7c478bd9Sstevel@tonic-gate 	 * The function rootnex_get_phyaddr() does not save the physical
1371*7c478bd9Sstevel@tonic-gate 	 * address in the php structure. Save it here for
1372*7c478bd9Sstevel@tonic-gate 	 * rootnext_io_brkup_attr().
1373*7c478bd9Sstevel@tonic-gate 	 */
1374*7c478bd9Sstevel@tonic-gate 	php.ph_padr = padr;
1375*7c478bd9Sstevel@tonic-gate 	return (rootnex_io_brkup_lim(dip, rdip,  dmareq, handlep,
1376*7c478bd9Sstevel@tonic-gate 		dma_lim, &php));
1377*7c478bd9Sstevel@tonic-gate }
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate /* CSTYLED */
1380*7c478bd9Sstevel@tonic-gate #define	CAN_COMBINE(psegp, paddr, segsize, sgsize,  mxsegsize, attr, flg) \
1381*7c478bd9Sstevel@tonic-gate ((psegp)								&& \
1382*7c478bd9Sstevel@tonic-gate ((psegp)->_pdmu._dmais_lpd + (psegp)->dmais_size) == (paddr)	&& \
1383*7c478bd9Sstevel@tonic-gate (((psegp)->dmais_flags & (DMAIS_NEEDINTBUF | DMAIS_COMPLEMENT)) == 0) && \
1384*7c478bd9Sstevel@tonic-gate (((flg) & DMAIS_NEEDINTBUF) == 0)					&& \
1385*7c478bd9Sstevel@tonic-gate (((psegp)->dmais_size + (segsize)) <= (mxsegsize))			&& \
1386*7c478bd9Sstevel@tonic-gate ((paddr) & (attr)->dma_attr_seg))
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate /* CSTYLED */
1389*7c478bd9Sstevel@tonic-gate #define	MARK_WIN_END(segp, prvwinp, cwinp) \
1390*7c478bd9Sstevel@tonic-gate (segp)->dmais_flags |= DMAIS_WINEND;	\
1391*7c478bd9Sstevel@tonic-gate (prvwinp) = (cwinp);			\
1392*7c478bd9Sstevel@tonic-gate (cwinp)->dmais_flags |= DMAIS_WINUIB;	\
1393*7c478bd9Sstevel@tonic-gate (cwinp) = NULL;
1394*7c478bd9Sstevel@tonic-gate 
1395*7c478bd9Sstevel@tonic-gate /*
1396*7c478bd9Sstevel@tonic-gate  * This function works with the ddi_dma_attr structure.
1397*7c478bd9Sstevel@tonic-gate  * Bugs fixed
1398*7c478bd9Sstevel@tonic-gate  * 1. The old code would ignore the size of the first segment when
1399*7c478bd9Sstevel@tonic-gate  *	computing the total size of the reuqest (sglistsize) for sgllen == 1
1400*7c478bd9Sstevel@tonic-gate  */
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1403*7c478bd9Sstevel@tonic-gate int
1404*7c478bd9Sstevel@tonic-gate rootnex_io_brkup_attr(dev_info_t *dip, dev_info_t *rdip,
1405*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t handle,
1406*7c478bd9Sstevel@tonic-gate     struct priv_handle *php)
1407*7c478bd9Sstevel@tonic-gate {
1408*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *segmentp;
1409*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *curwinp;
1410*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *previousp;
1411*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *prewinp;
1412*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cookiep;
1413*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
1414*7c478bd9Sstevel@tonic-gate 	caddr_t basevadr;
1415*7c478bd9Sstevel@tonic-gate 	caddr_t segmentvadr;
1416*7c478bd9Sstevel@tonic-gate 	uint64_t segmentpadr;
1417*7c478bd9Sstevel@tonic-gate 	uint_t maxsegmentsize, sizesegment, residual_size;
1418*7c478bd9Sstevel@tonic-gate 	uint_t offset, needintbuf, sglistsize, trim;
1419*7c478bd9Sstevel@tonic-gate 	int nsegments;
1420*7c478bd9Sstevel@tonic-gate 	int mapinfo;
1421*7c478bd9Sstevel@tonic-gate 	int reqneedintbuf;
1422*7c478bd9Sstevel@tonic-gate 	int rval;
1423*7c478bd9Sstevel@tonic-gate 	int segment_flags, win_flags;
1424*7c478bd9Sstevel@tonic-gate 	int sgcount;
1425*7c478bd9Sstevel@tonic-gate 	int wcount;
1426*7c478bd9Sstevel@tonic-gate 	ddi_dma_attr_t *dma_attr = &hp->dmai_attr;
1427*7c478bd9Sstevel@tonic-gate 	int sizehandle;
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate #ifdef lint
1430*7c478bd9Sstevel@tonic-gate 	dip = dip;
1431*7c478bd9Sstevel@tonic-gate #endif
1432*7c478bd9Sstevel@tonic-gate 
1433*7c478bd9Sstevel@tonic-gate 	/*
1434*7c478bd9Sstevel@tonic-gate 	 * Initialize our local variables from the php structure.
1435*7c478bd9Sstevel@tonic-gate 	 * rootnex_get_phyaddr() has populated php structure on its
1436*7c478bd9Sstevel@tonic-gate 	 * previous invocation in rootnex_dma_bindhdl().
1437*7c478bd9Sstevel@tonic-gate 	 */
1438*7c478bd9Sstevel@tonic-gate 	residual_size = OBJSIZE;
1439*7c478bd9Sstevel@tonic-gate 	mapinfo = php->ph_mapinfo;
1440*7c478bd9Sstevel@tonic-gate 	segmentpadr = php->ph_padr;
1441*7c478bd9Sstevel@tonic-gate 	segmentvadr =  php->ph_vaddr;
1442*7c478bd9Sstevel@tonic-gate 	basevadr = (mapinfo == DMAMI_PAGES) ? 0 : segmentvadr;
1443*7c478bd9Sstevel@tonic-gate 	offset = segmentpadr & MMU_PAGEOFFSET;
1444*7c478bd9Sstevel@tonic-gate 	/*
1445*7c478bd9Sstevel@tonic-gate 	 * maxsegmentsize was computed and saved in rootnex_dma_allochdl().
1446*7c478bd9Sstevel@tonic-gate 	 */
1447*7c478bd9Sstevel@tonic-gate 	maxsegmentsize = hp->dmai_segmentsize;
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	/*
1450*7c478bd9Sstevel@tonic-gate 	 * The number of segments is the number of 4k pages that the
1451*7c478bd9Sstevel@tonic-gate 	 * object spans.
1452*7c478bd9Sstevel@tonic-gate 	 * Each 4k segment may need another segment to satisfy
1453*7c478bd9Sstevel@tonic-gate 	 * device granularity reqirements.
1454*7c478bd9Sstevel@tonic-gate 	 * We will never need more than two segments per page.
1455*7c478bd9Sstevel@tonic-gate 	 * This may be an overestimate in some cases but it avoids
1456*7c478bd9Sstevel@tonic-gate 	 * 64 bit divide operations.
1457*7c478bd9Sstevel@tonic-gate 	 */
1458*7c478bd9Sstevel@tonic-gate 	nsegments = (offset + residual_size + MMU_PAGEOFFSET) >>
1459*7c478bd9Sstevel@tonic-gate 	    (MMU_PAGESHIFT - 1);
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate 
1463*7c478bd9Sstevel@tonic-gate 	sizehandle = nsegments * (sizeof (impl_dma_segment_t) +
1464*7c478bd9Sstevel@tonic-gate 		    sizeof (ddi_dma_cookie_t));
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate 	hp->dmai_segp = kmem_zalloc(sizehandle,
1467*7c478bd9Sstevel@tonic-gate 	    (dmareq->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1468*7c478bd9Sstevel@tonic-gate 	if (!hp->dmai_segp) {
1469*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_NORESOURCES;
1470*7c478bd9Sstevel@tonic-gate 		goto bad;
1471*7c478bd9Sstevel@tonic-gate 	}
1472*7c478bd9Sstevel@tonic-gate 	hp->dmai_kmsize = sizehandle;
1473*7c478bd9Sstevel@tonic-gate 	segmentp = (impl_dma_segment_t *)hp->dmai_segp;
1474*7c478bd9Sstevel@tonic-gate 	cookiep = (ddi_dma_cookie_t *)(segmentp + nsegments);
1475*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie = cookiep;
1476*7c478bd9Sstevel@tonic-gate 	hp->dmai_wins = NULL;
1477*7c478bd9Sstevel@tonic-gate 	hp->dmai_kaddr = hp->dmai_ibufp = NULL;
1478*7c478bd9Sstevel@tonic-gate 	hp->dmai_hds = prewinp = segmentp;
1479*7c478bd9Sstevel@tonic-gate 	hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS;
1480*7c478bd9Sstevel@tonic-gate 	hp->dmai_minfo = (void *)(uintptr_t)mapinfo;
1481*7c478bd9Sstevel@tonic-gate 	hp->dmai_object = dmareq->dmar_object;
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 	/*
1484*7c478bd9Sstevel@tonic-gate 	 * Breakup the memory object
1485*7c478bd9Sstevel@tonic-gate 	 * and build an i/o segment at each boundary condition
1486*7c478bd9Sstevel@tonic-gate 	 */
1487*7c478bd9Sstevel@tonic-gate 	curwinp = 0;
1488*7c478bd9Sstevel@tonic-gate 	needintbuf = 0;
1489*7c478bd9Sstevel@tonic-gate 	previousp = 0;
1490*7c478bd9Sstevel@tonic-gate 	reqneedintbuf = 0;
1491*7c478bd9Sstevel@tonic-gate 	sglistsize = 0;
1492*7c478bd9Sstevel@tonic-gate 	wcount = 0;
1493*7c478bd9Sstevel@tonic-gate 	sgcount = 1;
1494*7c478bd9Sstevel@tonic-gate 	do {
1495*7c478bd9Sstevel@tonic-gate 		sizesegment = MIN((MMU_PAGESIZE - offset), residual_size);
1496*7c478bd9Sstevel@tonic-gate 		segment_flags = (segmentpadr > AHI_ATTR) ? DMAIS_NEEDINTBUF : 0;
1497*7c478bd9Sstevel@tonic-gate 		sglistsize += sizesegment;
1498*7c478bd9Sstevel@tonic-gate 		if (sglistsize >= dma_attr->dma_attr_maxxfer) {
1499*7c478bd9Sstevel@tonic-gate 			/*
1500*7c478bd9Sstevel@tonic-gate 			 * limit the number of bytes to dma_attr_maxxfer
1501*7c478bd9Sstevel@tonic-gate 			 */
1502*7c478bd9Sstevel@tonic-gate 			sizesegment -=
1503*7c478bd9Sstevel@tonic-gate 			    (sglistsize - dma_attr->dma_attr_maxxfer);
1504*7c478bd9Sstevel@tonic-gate 			sglistsize = dma_attr->dma_attr_maxxfer;
1505*7c478bd9Sstevel@tonic-gate 			sgcount = dma_attr->dma_attr_sgllen + 1;
1506*7c478bd9Sstevel@tonic-gate 		}
1507*7c478bd9Sstevel@tonic-gate 		if ((dma_attr->dma_attr_sgllen == 1) &&
1508*7c478bd9Sstevel@tonic-gate 		    (segmentpadr & (dma_attr->dma_attr_granular - 1)) &&
1509*7c478bd9Sstevel@tonic-gate 		    (residual_size != sizesegment)) {
1510*7c478bd9Sstevel@tonic-gate 			/*
1511*7c478bd9Sstevel@tonic-gate 			 * _no_ scatter/gather capability,
1512*7c478bd9Sstevel@tonic-gate 			 * so ensure that size of each segment is a
1513*7c478bd9Sstevel@tonic-gate 			 * multiple of dma_attr_granular (== sector size)
1514*7c478bd9Sstevel@tonic-gate 			 */
1515*7c478bd9Sstevel@tonic-gate 			sizesegment = MIN((uint_t)MMU_PAGESIZE, residual_size);
1516*7c478bd9Sstevel@tonic-gate 			segment_flags |= DMAIS_NEEDINTBUF;
1517*7c478bd9Sstevel@tonic-gate 			sglistsize = sizesegment;
1518*7c478bd9Sstevel@tonic-gate 		}
1519*7c478bd9Sstevel@tonic-gate 		if (CAN_COMBINE(previousp, segmentpadr, sizesegment,
1520*7c478bd9Sstevel@tonic-gate 		    sglistsize, maxsegmentsize, dma_attr, segment_flags)) {
1521*7c478bd9Sstevel@tonic-gate 		    previousp->dmais_flags |= segment_flags;
1522*7c478bd9Sstevel@tonic-gate 		    previousp->dmais_size += sizesegment;
1523*7c478bd9Sstevel@tonic-gate 		    previousp->dmais_cookie->dmac_size += sizesegment;
1524*7c478bd9Sstevel@tonic-gate 		} else {
1525*7c478bd9Sstevel@tonic-gate 		    if (dma_attr->dma_attr_sgllen == 1)
1526*7c478bd9Sstevel@tonic-gate 			/*
1527*7c478bd9Sstevel@tonic-gate 			 * If we can not combine this segment with the
1528*7c478bd9Sstevel@tonic-gate 			 * previous segment or if there are no previous
1529*7c478bd9Sstevel@tonic-gate 			 * segments, sglistsize should be set to
1530*7c478bd9Sstevel@tonic-gate 			 * segmentsize.
1531*7c478bd9Sstevel@tonic-gate 			 */
1532*7c478bd9Sstevel@tonic-gate 			sglistsize = sizesegment;
1533*7c478bd9Sstevel@tonic-gate 
1534*7c478bd9Sstevel@tonic-gate 		    if (previousp) {
1535*7c478bd9Sstevel@tonic-gate 			previousp->dmais_link = segmentp;
1536*7c478bd9Sstevel@tonic-gate 		    }
1537*7c478bd9Sstevel@tonic-gate 		    segmentp->dmais_cookie = cookiep;
1538*7c478bd9Sstevel@tonic-gate 		    segmentp->dmais_hndl = hp;
1539*7c478bd9Sstevel@tonic-gate 		    if (curwinp == 0) {
1540*7c478bd9Sstevel@tonic-gate 			prewinp->_win._dmais_nex = curwinp = segmentp;
1541*7c478bd9Sstevel@tonic-gate 			segment_flags |= DMAIS_WINSTRT;
1542*7c478bd9Sstevel@tonic-gate 			win_flags = segment_flags;
1543*7c478bd9Sstevel@tonic-gate 			wcount++;
1544*7c478bd9Sstevel@tonic-gate 		    } else {
1545*7c478bd9Sstevel@tonic-gate 			segmentp->_win._dmais_cur = curwinp;
1546*7c478bd9Sstevel@tonic-gate 			win_flags |= segment_flags;
1547*7c478bd9Sstevel@tonic-gate 		    }
1548*7c478bd9Sstevel@tonic-gate 		    segmentp->dmais_ofst = segmentvadr - basevadr;
1549*7c478bd9Sstevel@tonic-gate 		    if (mapinfo == DMAMI_PAGES)
1550*7c478bd9Sstevel@tonic-gate 			segmentp->_vdmu._dmais_pp = php->ph_u.pp;
1551*7c478bd9Sstevel@tonic-gate 		    else
1552*7c478bd9Sstevel@tonic-gate 			segmentp->_vdmu._dmais_va = (caddr_t)segmentvadr;
1553*7c478bd9Sstevel@tonic-gate 		    segmentp->_pdmu._dmais_lpd = segmentpadr;
1554*7c478bd9Sstevel@tonic-gate 		    segmentp->dmais_flags = (ushort_t)segment_flags;
1555*7c478bd9Sstevel@tonic-gate 		    segmentp->dmais_size = sizesegment;
1556*7c478bd9Sstevel@tonic-gate 		    cookiep->dmac_laddress = segmentpadr;
1557*7c478bd9Sstevel@tonic-gate 		    cookiep->dmac_type = (ulong_t)segmentp;
1558*7c478bd9Sstevel@tonic-gate 		    cookiep->dmac_size = sizesegment;
1559*7c478bd9Sstevel@tonic-gate 		    cookiep++;
1560*7c478bd9Sstevel@tonic-gate 		    --nsegments;
1561*7c478bd9Sstevel@tonic-gate 		    if (dma_attr->dma_attr_sgllen > 1)
1562*7c478bd9Sstevel@tonic-gate 			sgcount++;
1563*7c478bd9Sstevel@tonic-gate 		    if (segment_flags & DMAIS_NEEDINTBUF) {
1564*7c478bd9Sstevel@tonic-gate 			if ((dma_attr->dma_attr_sgllen > 1) &&
1565*7c478bd9Sstevel@tonic-gate 			    (needintbuf += ptob(btopr(sizesegment)))
1566*7c478bd9Sstevel@tonic-gate 				== MAX_INT_BUF) {
1567*7c478bd9Sstevel@tonic-gate 				/*
1568*7c478bd9Sstevel@tonic-gate 				 * Intermediate buffers need not be contiguous.
1569*7c478bd9Sstevel@tonic-gate 				 * we allocate a page of intermediate buffer
1570*7c478bd9Sstevel@tonic-gate 				 * for every segment.
1571*7c478bd9Sstevel@tonic-gate 				 */
1572*7c478bd9Sstevel@tonic-gate 			    reqneedintbuf = needintbuf;
1573*7c478bd9Sstevel@tonic-gate 			    needintbuf = 0;
1574*7c478bd9Sstevel@tonic-gate 			    sgcount = dma_attr->dma_attr_sgllen + 1;
1575*7c478bd9Sstevel@tonic-gate 			    MARK_WIN_END(segmentp, prewinp, curwinp);
1576*7c478bd9Sstevel@tonic-gate 			} else if (dma_attr->dma_attr_sgllen == 1) {
1577*7c478bd9Sstevel@tonic-gate 			    needintbuf = MMU_PAGESIZE;
1578*7c478bd9Sstevel@tonic-gate 			    MARK_WIN_END(segmentp, prewinp, curwinp);
1579*7c478bd9Sstevel@tonic-gate 			}
1580*7c478bd9Sstevel@tonic-gate 		    }
1581*7c478bd9Sstevel@tonic-gate 		    previousp = segmentp++;
1582*7c478bd9Sstevel@tonic-gate 		}
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 		if (sgcount > dma_attr->dma_attr_sgllen) {
1585*7c478bd9Sstevel@tonic-gate 		    previousp->dmais_flags |= DMAIS_COMPLEMENT;
1586*7c478bd9Sstevel@tonic-gate 		    sgcount = 1;
1587*7c478bd9Sstevel@tonic-gate 		    trim = sglistsize & (dma_attr->dma_attr_granular - 1);
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 		    if ((sizesegment != residual_size) &&
1590*7c478bd9Sstevel@tonic-gate 			(trim == sizesegment)) {
1591*7c478bd9Sstevel@tonic-gate 
1592*7c478bd9Sstevel@tonic-gate 			/*
1593*7c478bd9Sstevel@tonic-gate 			 * Normally we would trim the buffer to make it a
1594*7c478bd9Sstevel@tonic-gate 			 * multiple of the granularity. But in this case,
1595*7c478bd9Sstevel@tonic-gate 			 * the size is < the granularity so we'll roll back
1596*7c478bd9Sstevel@tonic-gate 			 * this segment and pick this up the next time around.
1597*7c478bd9Sstevel@tonic-gate 			 *
1598*7c478bd9Sstevel@tonic-gate 			 * This case occurs when sgcount naturally (i.e. not
1599*7c478bd9Sstevel@tonic-gate 			 * forced) is greater than > dma_attr_sgllen. In this
1600*7c478bd9Sstevel@tonic-gate 			 * case, if the very next segment fills up the
1601*7c478bd9Sstevel@tonic-gate 			 * intermediate buffer, and the amount required to fill
1602*7c478bd9Sstevel@tonic-gate 			 * the intermediate buffer < granularity, we would end
1603*7c478bd9Sstevel@tonic-gate 			 * up with a zero sized cookie if we didn't roll back
1604*7c478bd9Sstevel@tonic-gate 			 * the segment.
1605*7c478bd9Sstevel@tonic-gate 			 */
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 			/*
1608*7c478bd9Sstevel@tonic-gate 			 * Make sure we really understand the code path here,
1609*7c478bd9Sstevel@tonic-gate 			 * we should only get here if we are at an end of a
1610*7c478bd9Sstevel@tonic-gate 			 * window which is a single page long < granularity
1611*7c478bd9Sstevel@tonic-gate 			 */
1612*7c478bd9Sstevel@tonic-gate 			ASSERT(previousp->dmais_flags & DMAIS_WINEND);
1613*7c478bd9Sstevel@tonic-gate 			ASSERT(sizesegment == sglistsize);
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 			/* Zero out this segment and add it back to the count */
1616*7c478bd9Sstevel@tonic-gate 			sizesegment = 0;
1617*7c478bd9Sstevel@tonic-gate 			sglistsize = 0;
1618*7c478bd9Sstevel@tonic-gate 			nsegments++;
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate 			/* fix the segment and cookie pointers */
1621*7c478bd9Sstevel@tonic-gate 			segmentp = previousp;
1622*7c478bd9Sstevel@tonic-gate 			bzero(previousp, sizeof (impl_dma_segment_t));
1623*7c478bd9Sstevel@tonic-gate 			previousp--;
1624*7c478bd9Sstevel@tonic-gate 			bzero(cookiep, sizeof (ddi_dma_cookie_t));
1625*7c478bd9Sstevel@tonic-gate 			cookiep--;
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 			/*
1628*7c478bd9Sstevel@tonic-gate 			 * cleanup the new previous pointer. Make sure we
1629*7c478bd9Sstevel@tonic-gate 			 * carry over the WINEND maker.
1630*7c478bd9Sstevel@tonic-gate 			 */
1631*7c478bd9Sstevel@tonic-gate 			previousp->dmais_link = NULL;
1632*7c478bd9Sstevel@tonic-gate 			previousp->dmais_flags |= DMAIS_WINEND;
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 		    } else if ((sizesegment != residual_size) && trim) {
1635*7c478bd9Sstevel@tonic-gate 			/*
1636*7c478bd9Sstevel@tonic-gate 			 * end of a scatter/gather list!
1637*7c478bd9Sstevel@tonic-gate 			 * ensure that total length of list is a
1638*7c478bd9Sstevel@tonic-gate 			 * multiple of granular (sector size)
1639*7c478bd9Sstevel@tonic-gate 			 */
1640*7c478bd9Sstevel@tonic-gate 			previousp->dmais_size -= trim;
1641*7c478bd9Sstevel@tonic-gate 			previousp->dmais_cookie->dmac_size -= trim;
1642*7c478bd9Sstevel@tonic-gate 			sizesegment -= trim;
1643*7c478bd9Sstevel@tonic-gate 		    }
1644*7c478bd9Sstevel@tonic-gate 		    sglistsize = 0;
1645*7c478bd9Sstevel@tonic-gate 		}
1646*7c478bd9Sstevel@tonic-gate 		if (sizesegment && (residual_size -= sizesegment)) {
1647*7c478bd9Sstevel@tonic-gate 			/*
1648*7c478bd9Sstevel@tonic-gate 			 * Get the physical address of the next page in the
1649*7c478bd9Sstevel@tonic-gate 			 * dma object.
1650*7c478bd9Sstevel@tonic-gate 			 */
1651*7c478bd9Sstevel@tonic-gate 			segmentpadr =
1652*7c478bd9Sstevel@tonic-gate 			    rootnex_get_phyaddr(dmareq, sizesegment, php);
1653*7c478bd9Sstevel@tonic-gate 			offset = segmentpadr & MMU_PAGEOFFSET;
1654*7c478bd9Sstevel@tonic-gate 			segmentvadr += sizesegment;
1655*7c478bd9Sstevel@tonic-gate 		}
1656*7c478bd9Sstevel@tonic-gate 	} while (residual_size && nsegments);
1657*7c478bd9Sstevel@tonic-gate 	ASSERT(residual_size == 0);
1658*7c478bd9Sstevel@tonic-gate 
1659*7c478bd9Sstevel@tonic-gate 	previousp->dmais_link = NULL;
1660*7c478bd9Sstevel@tonic-gate 	previousp->dmais_flags |= DMAIS_WINEND;
1661*7c478bd9Sstevel@tonic-gate 	if (curwinp) {
1662*7c478bd9Sstevel@tonic-gate 		if (win_flags & DMAIS_NEEDINTBUF)
1663*7c478bd9Sstevel@tonic-gate 			curwinp->dmais_flags |= DMAIS_WINUIB;
1664*7c478bd9Sstevel@tonic-gate 		curwinp->_win._dmais_nex = NULL;
1665*7c478bd9Sstevel@tonic-gate 	} else
1666*7c478bd9Sstevel@tonic-gate 		prewinp->_win._dmais_nex = NULL;
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 	if ((needintbuf = MAX(needintbuf, reqneedintbuf)) != 0) {
1669*7c478bd9Sstevel@tonic-gate 		uint64_t	saved_align;
1670*7c478bd9Sstevel@tonic-gate 
1671*7c478bd9Sstevel@tonic-gate 		saved_align = dma_attr->dma_attr_align;
1672*7c478bd9Sstevel@tonic-gate 		/*
1673*7c478bd9Sstevel@tonic-gate 		 * Allocate intermediate buffer. To start with we request
1674*7c478bd9Sstevel@tonic-gate 		 * for a page aligned area. This request is satisfied from
1675*7c478bd9Sstevel@tonic-gate 		 * the system page free list pool.
1676*7c478bd9Sstevel@tonic-gate 		 */
1677*7c478bd9Sstevel@tonic-gate 		dma_attr->dma_attr_align = MMU_PAGESIZE;
1678*7c478bd9Sstevel@tonic-gate 		if (i_ddi_mem_alloc(dip, dma_attr, needintbuf,
1679*7c478bd9Sstevel@tonic-gate 		    (dmareq->dmar_fp == DDI_DMA_SLEEP) ? 0x1 : 0, 1, 0,
1680*7c478bd9Sstevel@tonic-gate 		    &hp->dmai_ibufp, (ulong_t *)&hp->dmai_ibfsz,
1681*7c478bd9Sstevel@tonic-gate 		    NULL) != DDI_SUCCESS) {
1682*7c478bd9Sstevel@tonic-gate 			dma_attr->dma_attr_align = saved_align;
1683*7c478bd9Sstevel@tonic-gate 			rval = DDI_DMA_NORESOURCES;
1684*7c478bd9Sstevel@tonic-gate 			goto bad;
1685*7c478bd9Sstevel@tonic-gate 		}
1686*7c478bd9Sstevel@tonic-gate 		if (mapinfo != DMAMI_KVADR) {
1687*7c478bd9Sstevel@tonic-gate 			hp->dmai_kaddr = vmem_alloc(heap_arena, PAGESIZE,
1688*7c478bd9Sstevel@tonic-gate 			    VM_SLEEP);
1689*7c478bd9Sstevel@tonic-gate 		}
1690*7c478bd9Sstevel@tonic-gate 		dma_attr->dma_attr_align = saved_align;
1691*7c478bd9Sstevel@tonic-gate 	}
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 	/*
1694*7c478bd9Sstevel@tonic-gate 	 * return success
1695*7c478bd9Sstevel@tonic-gate 	 */
1696*7c478bd9Sstevel@tonic-gate 	ASSERT(wcount > 0);
1697*7c478bd9Sstevel@tonic-gate 	if (wcount == 1) {
1698*7c478bd9Sstevel@tonic-gate 		hp->dmai_rflags &= ~DDI_DMA_PARTIAL;
1699*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_MAPPED;
1700*7c478bd9Sstevel@tonic-gate 	} else if (hp->dmai_rflags & DDI_DMA_PARTIAL) {
1701*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_PARTIAL_MAP;
1702*7c478bd9Sstevel@tonic-gate 	} else {
1703*7c478bd9Sstevel@tonic-gate 		if (hp->dmai_segp)
1704*7c478bd9Sstevel@tonic-gate 			kmem_free(hp->dmai_segp, hp->dmai_kmsize);
1705*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_TOOBIG);
1706*7c478bd9Sstevel@tonic-gate 	}
1707*7c478bd9Sstevel@tonic-gate 	hp->dmai_nwin = wcount;
1708*7c478bd9Sstevel@tonic-gate 	return (rval);
1709*7c478bd9Sstevel@tonic-gate bad:
1710*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie = NULL;
1711*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_segp)
1712*7c478bd9Sstevel@tonic-gate 		kmem_free(hp->dmai_segp, hp->dmai_kmsize);
1713*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_DMA_NORESOURCES 	&&
1714*7c478bd9Sstevel@tonic-gate 	    dmareq->dmar_fp != DDI_DMA_DONTWAIT &&
1715*7c478bd9Sstevel@tonic-gate 	    dmareq->dmar_fp != DDI_DMA_SLEEP)
1716*7c478bd9Sstevel@tonic-gate 		ddi_set_callback(dmareq->dmar_fp, dmareq->dmar_arg,
1717*7c478bd9Sstevel@tonic-gate 		    &dvma_call_list_id);
1718*7c478bd9Sstevel@tonic-gate 	return (rval);
1719*7c478bd9Sstevel@tonic-gate }
1720*7c478bd9Sstevel@tonic-gate 
1721*7c478bd9Sstevel@tonic-gate /*
1722*7c478bd9Sstevel@tonic-gate  * This function works with the limit structure and does 32 bit arithmetic.
1723*7c478bd9Sstevel@tonic-gate  */
1724*7c478bd9Sstevel@tonic-gate int
1725*7c478bd9Sstevel@tonic-gate rootnex_io_brkup_lim(dev_info_t *dip, dev_info_t *rdip,
1726*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareq, ddi_dma_handle_t *handlep,
1727*7c478bd9Sstevel@tonic-gate     ddi_dma_lim_t *dma_lim, struct priv_handle *php)
1728*7c478bd9Sstevel@tonic-gate {
1729*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *segmentp;
1730*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *curwinp;
1731*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *previousp;
1732*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *prewinp;
1733*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = 0;
1734*7c478bd9Sstevel@tonic-gate 	caddr_t basevadr;
1735*7c478bd9Sstevel@tonic-gate 	caddr_t segmentvadr;
1736*7c478bd9Sstevel@tonic-gate 	uint64_t segmentpadr;
1737*7c478bd9Sstevel@tonic-gate 	uint_t maxsegmentsize, sizesegment;
1738*7c478bd9Sstevel@tonic-gate 	uint_t needintbuf;
1739*7c478bd9Sstevel@tonic-gate 	uint_t offset;
1740*7c478bd9Sstevel@tonic-gate 	uint_t residual_size;
1741*7c478bd9Sstevel@tonic-gate 	uint_t sglistsize;
1742*7c478bd9Sstevel@tonic-gate 	int nsegments;
1743*7c478bd9Sstevel@tonic-gate 	int mapinfo;
1744*7c478bd9Sstevel@tonic-gate 	int reqneedintbuf;
1745*7c478bd9Sstevel@tonic-gate 	int rval;
1746*7c478bd9Sstevel@tonic-gate 	int segment_flags, win_flags;
1747*7c478bd9Sstevel@tonic-gate 	int sgcount;
1748*7c478bd9Sstevel@tonic-gate 	int wcount;
1749*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG
1750*7c478bd9Sstevel@tonic-gate 	int numsegments;
1751*7c478bd9Sstevel@tonic-gate #endif
1752*7c478bd9Sstevel@tonic-gate 	int sizehandle;
1753*7c478bd9Sstevel@tonic-gate 
1754*7c478bd9Sstevel@tonic-gate #ifdef lint
1755*7c478bd9Sstevel@tonic-gate 	dip = dip;
1756*7c478bd9Sstevel@tonic-gate #endif
1757*7c478bd9Sstevel@tonic-gate 
1758*7c478bd9Sstevel@tonic-gate 	/*
1759*7c478bd9Sstevel@tonic-gate 	 * Validate the dma request.
1760*7c478bd9Sstevel@tonic-gate 	 */
1761*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG
1762*7c478bd9Sstevel@tonic-gate 	if (dma_lim->dlim_adreg_max < MMU_PAGEOFFSET ||
1763*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_ctreg_max < MMU_PAGEOFFSET ||
1764*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_granular > MMU_PAGESIZE ||
1765*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_reqsize < MMU_PAGESIZE) {
1766*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits\n"));
1767*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADLIMITS);
1768*7c478bd9Sstevel@tonic-gate 	}
1769*7c478bd9Sstevel@tonic-gate #endif
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 	/*
1772*7c478bd9Sstevel@tonic-gate 	 * Initialize our local variables from the php structure.
1773*7c478bd9Sstevel@tonic-gate 	 * rootnex_get_phyaddr() has populated php structure on its
1774*7c478bd9Sstevel@tonic-gate 	 * previous invocation in rootnex_dma_map().
1775*7c478bd9Sstevel@tonic-gate 	 */
1776*7c478bd9Sstevel@tonic-gate 	residual_size = OBJSIZE;
1777*7c478bd9Sstevel@tonic-gate 	mapinfo = php->ph_mapinfo;
1778*7c478bd9Sstevel@tonic-gate 	segmentpadr = php->ph_padr;
1779*7c478bd9Sstevel@tonic-gate 	segmentvadr =  php->ph_vaddr;
1780*7c478bd9Sstevel@tonic-gate 	basevadr = (mapinfo == DMAMI_PAGES) ? 0 : segmentvadr;
1781*7c478bd9Sstevel@tonic-gate 	offset = segmentpadr & MMU_PAGEOFFSET;
1782*7c478bd9Sstevel@tonic-gate 	if (dma_lim->dlim_sgllen <= 0 ||
1783*7c478bd9Sstevel@tonic-gate 	    (offset & (dma_lim->dlim_minxfer - 1))) {
1784*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits/mapping\n"));
1785*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_NOMAPPING;
1786*7c478bd9Sstevel@tonic-gate 		goto bad;
1787*7c478bd9Sstevel@tonic-gate 	}
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 	maxsegmentsize = MIN(dma_lim->dlim_adreg_max,
1790*7c478bd9Sstevel@tonic-gate 	    MIN((dma_lim->dlim_ctreg_max + 1) * dma_lim->dlim_minxfer,
1791*7c478bd9Sstevel@tonic-gate 	    dma_lim->dlim_reqsize) - 1) + 1;
1792*7c478bd9Sstevel@tonic-gate 	if (maxsegmentsize == 0)
1793*7c478bd9Sstevel@tonic-gate 		maxsegmentsize = FOURG - 1;
1794*7c478bd9Sstevel@tonic-gate 	if (maxsegmentsize < MMU_PAGESIZE) {
1795*7c478bd9Sstevel@tonic-gate 		DMAPRINT((" bad_limits, maxsegmentsize\n"));
1796*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_BADLIMITS;
1797*7c478bd9Sstevel@tonic-gate 		goto bad;
1798*7c478bd9Sstevel@tonic-gate 	}
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 	/*
1802*7c478bd9Sstevel@tonic-gate 	 * The number of segments is the number of 4k pages that the
1803*7c478bd9Sstevel@tonic-gate 	 * object spans.
1804*7c478bd9Sstevel@tonic-gate 	 * Each 4k segment may need another segment to satisfy
1805*7c478bd9Sstevel@tonic-gate 	 * device granularity reqirements.
1806*7c478bd9Sstevel@tonic-gate 	 * We will never need more than two segments per page.
1807*7c478bd9Sstevel@tonic-gate 	 * This may be an overestimate in some cases but it avoids
1808*7c478bd9Sstevel@tonic-gate 	 * 64 bit divide operations.
1809*7c478bd9Sstevel@tonic-gate 	 */
1810*7c478bd9Sstevel@tonic-gate 	nsegments = (offset + residual_size + MMU_PAGEOFFSET) >>
1811*7c478bd9Sstevel@tonic-gate 	    (MMU_PAGESHIFT - 1);
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG
1814*7c478bd9Sstevel@tonic-gate 	numsegments = nsegments;
1815*7c478bd9Sstevel@tonic-gate #endif
1816*7c478bd9Sstevel@tonic-gate 	ASSERT(nsegments > 0);
1817*7c478bd9Sstevel@tonic-gate 
1818*7c478bd9Sstevel@tonic-gate 
1819*7c478bd9Sstevel@tonic-gate 	sizehandle = sizeof (ddi_dma_impl_t) +
1820*7c478bd9Sstevel@tonic-gate 		(nsegments * sizeof (impl_dma_segment_t));
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate 	hp = kmem_alloc(sizehandle,
1823*7c478bd9Sstevel@tonic-gate 	    (dmareq->dmar_fp == DDI_DMA_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1824*7c478bd9Sstevel@tonic-gate 	if (!hp) {
1825*7c478bd9Sstevel@tonic-gate 		rval = DDI_DMA_NORESOURCES;
1826*7c478bd9Sstevel@tonic-gate 		goto bad;
1827*7c478bd9Sstevel@tonic-gate 	}
1828*7c478bd9Sstevel@tonic-gate 	hp->dmai_kmsize = sizehandle;
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate 	/*
1831*7c478bd9Sstevel@tonic-gate 	 * locate segments after dma_impl handle structure
1832*7c478bd9Sstevel@tonic-gate 	 */
1833*7c478bd9Sstevel@tonic-gate 	segmentp = (impl_dma_segment_t *)(hp + 1);
1834*7c478bd9Sstevel@tonic-gate 
1835*7c478bd9Sstevel@tonic-gate 	/* FMA related initialization */
1836*7c478bd9Sstevel@tonic-gate 	hp->dmai_fault = 0;
1837*7c478bd9Sstevel@tonic-gate 	hp->dmai_fault_check = NULL;
1838*7c478bd9Sstevel@tonic-gate 	hp->dmai_fault_notify = NULL;
1839*7c478bd9Sstevel@tonic-gate 	hp->dmai_error.err_ena = 0;
1840*7c478bd9Sstevel@tonic-gate 	hp->dmai_error.err_status = DDI_FM_OK;
1841*7c478bd9Sstevel@tonic-gate 	hp->dmai_error.err_expected = DDI_FM_ERR_UNEXPECTED;
1842*7c478bd9Sstevel@tonic-gate 	hp->dmai_error.err_ontrap = NULL;
1843*7c478bd9Sstevel@tonic-gate 	hp->dmai_error.err_fep = NULL;
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	/*
1846*7c478bd9Sstevel@tonic-gate 	 * Save requestor's information
1847*7c478bd9Sstevel@tonic-gate 	 */
1848*7c478bd9Sstevel@tonic-gate 	hp->dmai_minxfer = dma_lim->dlim_minxfer;
1849*7c478bd9Sstevel@tonic-gate 	hp->dmai_burstsizes = dma_lim->dlim_burstsizes;
1850*7c478bd9Sstevel@tonic-gate 	hp->dmai_rdip = rdip;
1851*7c478bd9Sstevel@tonic-gate 	hp->dmai_mctl = rootnex_dma_mctl;
1852*7c478bd9Sstevel@tonic-gate 	hp->dmai_wins = NULL;
1853*7c478bd9Sstevel@tonic-gate 	hp->dmai_kaddr = hp->dmai_ibufp = NULL;
1854*7c478bd9Sstevel@tonic-gate 	hp->dmai_hds = prewinp = segmentp;
1855*7c478bd9Sstevel@tonic-gate 	hp->dmai_rflags = dmareq->dmar_flags & DMP_DDIFLAGS;
1856*7c478bd9Sstevel@tonic-gate 	hp->dmai_minfo = (void *)(uintptr_t)mapinfo;
1857*7c478bd9Sstevel@tonic-gate 	hp->dmai_object = dmareq->dmar_object;
1858*7c478bd9Sstevel@tonic-gate 
1859*7c478bd9Sstevel@tonic-gate 	/*
1860*7c478bd9Sstevel@tonic-gate 	 * Breakup the memory object
1861*7c478bd9Sstevel@tonic-gate 	 * and build an i/o segment at each boundary condition
1862*7c478bd9Sstevel@tonic-gate 	 */
1863*7c478bd9Sstevel@tonic-gate 	curwinp = 0;
1864*7c478bd9Sstevel@tonic-gate 	needintbuf = 0;
1865*7c478bd9Sstevel@tonic-gate 	previousp = 0;
1866*7c478bd9Sstevel@tonic-gate 	reqneedintbuf = 0;
1867*7c478bd9Sstevel@tonic-gate 	sglistsize = 0;
1868*7c478bd9Sstevel@tonic-gate 	wcount = 0;
1869*7c478bd9Sstevel@tonic-gate 	sgcount = 1;
1870*7c478bd9Sstevel@tonic-gate 	do {
1871*7c478bd9Sstevel@tonic-gate 		sizesegment =
1872*7c478bd9Sstevel@tonic-gate 		    MIN(((uint_t)MMU_PAGESIZE - offset), residual_size);
1873*7c478bd9Sstevel@tonic-gate 		segment_flags = (segmentpadr > AHI_LIM) ? DMAIS_NEEDINTBUF : 0;
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate 		if (dma_lim->dlim_sgllen == 1) {
1876*7c478bd9Sstevel@tonic-gate 			/*
1877*7c478bd9Sstevel@tonic-gate 			 * _no_ scatter/gather capability,
1878*7c478bd9Sstevel@tonic-gate 			 * so ensure that size of each segment is a
1879*7c478bd9Sstevel@tonic-gate 			 * multiple of dlim_granular (== sector size)
1880*7c478bd9Sstevel@tonic-gate 			 */
1881*7c478bd9Sstevel@tonic-gate 			if ((segmentpadr & (dma_lim->dlim_granular - 1)) &&
1882*7c478bd9Sstevel@tonic-gate 			    residual_size != sizesegment) {
1883*7c478bd9Sstevel@tonic-gate 				/*
1884*7c478bd9Sstevel@tonic-gate 				 * this segment needs an intermediate buffer
1885*7c478bd9Sstevel@tonic-gate 				 */
1886*7c478bd9Sstevel@tonic-gate 				sizesegment =
1887*7c478bd9Sstevel@tonic-gate 				    MIN((uint_t)MMU_PAGESIZE, residual_size);
1888*7c478bd9Sstevel@tonic-gate 				segment_flags |= DMAIS_NEEDINTBUF;
1889*7c478bd9Sstevel@tonic-gate 			}
1890*7c478bd9Sstevel@tonic-gate 		}
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 		if (previousp &&
1893*7c478bd9Sstevel@tonic-gate 		    (previousp->_pdmu._dmais_lpd + previousp->dmais_size) ==
1894*7c478bd9Sstevel@tonic-gate 		    segmentpadr &&
1895*7c478bd9Sstevel@tonic-gate 		    (previousp->dmais_flags &
1896*7c478bd9Sstevel@tonic-gate 		    (DMAIS_NEEDINTBUF | DMAIS_COMPLEMENT)) == 0 &&
1897*7c478bd9Sstevel@tonic-gate 		    (segment_flags & DMAIS_NEEDINTBUF) == 0 &&
1898*7c478bd9Sstevel@tonic-gate 		    (previousp->dmais_size + sizesegment) <= maxsegmentsize &&
1899*7c478bd9Sstevel@tonic-gate 		    (segmentpadr & dma_lim->dlim_adreg_max) &&
1900*7c478bd9Sstevel@tonic-gate 		    (sglistsize + sizesegment) <= dma_lim->dlim_reqsize) {
1901*7c478bd9Sstevel@tonic-gate 			/*
1902*7c478bd9Sstevel@tonic-gate 			 * combine new segment with previous segment
1903*7c478bd9Sstevel@tonic-gate 			 */
1904*7c478bd9Sstevel@tonic-gate 			previousp->dmais_flags |= segment_flags;
1905*7c478bd9Sstevel@tonic-gate 			previousp->dmais_size += sizesegment;
1906*7c478bd9Sstevel@tonic-gate 			if ((sglistsize += sizesegment) ==
1907*7c478bd9Sstevel@tonic-gate 			    dma_lim->dlim_reqsize)
1908*7c478bd9Sstevel@tonic-gate 				/*
1909*7c478bd9Sstevel@tonic-gate 				 * force end of scatter/gather list
1910*7c478bd9Sstevel@tonic-gate 				 */
1911*7c478bd9Sstevel@tonic-gate 				sgcount = dma_lim->dlim_sgllen + 1;
1912*7c478bd9Sstevel@tonic-gate 		} else {
1913*7c478bd9Sstevel@tonic-gate 			/*
1914*7c478bd9Sstevel@tonic-gate 			 * add new segment to linked list
1915*7c478bd9Sstevel@tonic-gate 			 */
1916*7c478bd9Sstevel@tonic-gate 			if (previousp) {
1917*7c478bd9Sstevel@tonic-gate 				previousp->dmais_link = segmentp;
1918*7c478bd9Sstevel@tonic-gate 			}
1919*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_hndl = hp;
1920*7c478bd9Sstevel@tonic-gate 			if (curwinp == 0) {
1921*7c478bd9Sstevel@tonic-gate 				prewinp->_win._dmais_nex =
1922*7c478bd9Sstevel@tonic-gate 				    curwinp = segmentp;
1923*7c478bd9Sstevel@tonic-gate 				segment_flags |= DMAIS_WINSTRT;
1924*7c478bd9Sstevel@tonic-gate 				win_flags = segment_flags;
1925*7c478bd9Sstevel@tonic-gate 				wcount++;
1926*7c478bd9Sstevel@tonic-gate 			} else {
1927*7c478bd9Sstevel@tonic-gate 				segmentp->_win._dmais_cur = curwinp;
1928*7c478bd9Sstevel@tonic-gate 				win_flags |= segment_flags;
1929*7c478bd9Sstevel@tonic-gate 			}
1930*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_ofst = segmentvadr - basevadr;
1931*7c478bd9Sstevel@tonic-gate 			if (mapinfo == DMAMI_PAGES) {
1932*7c478bd9Sstevel@tonic-gate 				segmentp->_vdmu._dmais_pp = php->ph_u.pp;
1933*7c478bd9Sstevel@tonic-gate 			} else {
1934*7c478bd9Sstevel@tonic-gate 				segmentp->_vdmu._dmais_va = segmentvadr;
1935*7c478bd9Sstevel@tonic-gate 			}
1936*7c478bd9Sstevel@tonic-gate 			segmentp->_pdmu._dmais_lpd = segmentpadr;
1937*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_flags = (ushort_t)segment_flags;
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 			if (dma_lim->dlim_sgllen > 1) {
1940*7c478bd9Sstevel@tonic-gate 				if (segment_flags & DMAIS_NEEDINTBUF) {
1941*7c478bd9Sstevel@tonic-gate 					needintbuf += ptob(btopr(sizesegment));
1942*7c478bd9Sstevel@tonic-gate 					if (needintbuf >= MAX_INT_BUF) {
1943*7c478bd9Sstevel@tonic-gate 						/*
1944*7c478bd9Sstevel@tonic-gate 						 * limit size of intermediate
1945*7c478bd9Sstevel@tonic-gate 						 * buffer
1946*7c478bd9Sstevel@tonic-gate 						 */
1947*7c478bd9Sstevel@tonic-gate 						reqneedintbuf = MAX_INT_BUF;
1948*7c478bd9Sstevel@tonic-gate 						needintbuf = 0;
1949*7c478bd9Sstevel@tonic-gate 						/*
1950*7c478bd9Sstevel@tonic-gate 						 * end of current window
1951*7c478bd9Sstevel@tonic-gate 						 */
1952*7c478bd9Sstevel@tonic-gate 						segmentp->dmais_flags |=
1953*7c478bd9Sstevel@tonic-gate 						    DMAIS_WINEND;
1954*7c478bd9Sstevel@tonic-gate 						prewinp = curwinp;
1955*7c478bd9Sstevel@tonic-gate 						curwinp->dmais_flags |=
1956*7c478bd9Sstevel@tonic-gate 						    DMAIS_WINUIB;
1957*7c478bd9Sstevel@tonic-gate 						curwinp = NULL;
1958*7c478bd9Sstevel@tonic-gate 						/*
1959*7c478bd9Sstevel@tonic-gate 						 * force end of scatter/gather
1960*7c478bd9Sstevel@tonic-gate 						 * list
1961*7c478bd9Sstevel@tonic-gate 						 */
1962*7c478bd9Sstevel@tonic-gate 						sgcount = dma_lim->dlim_sgllen;
1963*7c478bd9Sstevel@tonic-gate 					}
1964*7c478bd9Sstevel@tonic-gate 				}
1965*7c478bd9Sstevel@tonic-gate 				sglistsize += sizesegment;
1966*7c478bd9Sstevel@tonic-gate 				if (sglistsize >= dma_lim->dlim_reqsize) {
1967*7c478bd9Sstevel@tonic-gate 					/*
1968*7c478bd9Sstevel@tonic-gate 					 * limit size of xfer
1969*7c478bd9Sstevel@tonic-gate 					 */
1970*7c478bd9Sstevel@tonic-gate 					sizesegment -= (sglistsize -
1971*7c478bd9Sstevel@tonic-gate 					    dma_lim->dlim_reqsize);
1972*7c478bd9Sstevel@tonic-gate 					sglistsize = dma_lim->dlim_reqsize;
1973*7c478bd9Sstevel@tonic-gate 					sgcount = dma_lim->dlim_sgllen;
1974*7c478bd9Sstevel@tonic-gate 				}
1975*7c478bd9Sstevel@tonic-gate 				sgcount++;
1976*7c478bd9Sstevel@tonic-gate 			} else {
1977*7c478bd9Sstevel@tonic-gate 				/*
1978*7c478bd9Sstevel@tonic-gate 				 * _no_ scatter/gather capability,
1979*7c478bd9Sstevel@tonic-gate 				 */
1980*7c478bd9Sstevel@tonic-gate 				if (segment_flags & DMAIS_NEEDINTBUF) {
1981*7c478bd9Sstevel@tonic-gate 					/*
1982*7c478bd9Sstevel@tonic-gate 					 * end of window
1983*7c478bd9Sstevel@tonic-gate 					 */
1984*7c478bd9Sstevel@tonic-gate 					needintbuf = MMU_PAGESIZE;
1985*7c478bd9Sstevel@tonic-gate 					segmentp->dmais_flags |= DMAIS_WINEND;
1986*7c478bd9Sstevel@tonic-gate 					prewinp = curwinp;
1987*7c478bd9Sstevel@tonic-gate 					curwinp->dmais_flags |= DMAIS_WINUIB;
1988*7c478bd9Sstevel@tonic-gate 					curwinp = NULL;
1989*7c478bd9Sstevel@tonic-gate 				}
1990*7c478bd9Sstevel@tonic-gate 			}
1991*7c478bd9Sstevel@tonic-gate 			segmentp->dmais_size = sizesegment;
1992*7c478bd9Sstevel@tonic-gate 			previousp = segmentp++;
1993*7c478bd9Sstevel@tonic-gate 			--nsegments;
1994*7c478bd9Sstevel@tonic-gate 		}
1995*7c478bd9Sstevel@tonic-gate 
1996*7c478bd9Sstevel@tonic-gate 		if (sgcount > dma_lim->dlim_sgllen) {
1997*7c478bd9Sstevel@tonic-gate 			/*
1998*7c478bd9Sstevel@tonic-gate 			 * end of a scatter/gather list!
1999*7c478bd9Sstevel@tonic-gate 			 * ensure that total length of list is a
2000*7c478bd9Sstevel@tonic-gate 			 * multiple of granular (sector size)
2001*7c478bd9Sstevel@tonic-gate 			 */
2002*7c478bd9Sstevel@tonic-gate 			if (sizesegment != residual_size) {
2003*7c478bd9Sstevel@tonic-gate 				uint_t trim;
2004*7c478bd9Sstevel@tonic-gate 
2005*7c478bd9Sstevel@tonic-gate 				trim = sglistsize &
2006*7c478bd9Sstevel@tonic-gate 				    (dma_lim->dlim_granular - 1);
2007*7c478bd9Sstevel@tonic-gate 				if (trim >= sizesegment) {
2008*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
2009*7c478bd9Sstevel@tonic-gate 					    "unable to reduce segment size");
2010*7c478bd9Sstevel@tonic-gate 					rval = DDI_DMA_NOMAPPING;
2011*7c478bd9Sstevel@tonic-gate 					goto bad;
2012*7c478bd9Sstevel@tonic-gate 				}
2013*7c478bd9Sstevel@tonic-gate 				previousp->dmais_size -= trim;
2014*7c478bd9Sstevel@tonic-gate 				sizesegment -= trim;
2015*7c478bd9Sstevel@tonic-gate 				/* start new scatter/gather list */
2016*7c478bd9Sstevel@tonic-gate 				sgcount = 1;
2017*7c478bd9Sstevel@tonic-gate 				sglistsize = 0;
2018*7c478bd9Sstevel@tonic-gate 			}
2019*7c478bd9Sstevel@tonic-gate 			previousp->dmais_flags |= DMAIS_COMPLEMENT;
2020*7c478bd9Sstevel@tonic-gate 		}
2021*7c478bd9Sstevel@tonic-gate 		if (sizesegment && (residual_size -= sizesegment)) {
2022*7c478bd9Sstevel@tonic-gate 			segmentpadr =
2023*7c478bd9Sstevel@tonic-gate 			    rootnex_get_phyaddr(dmareq, sizesegment, php);
2024*7c478bd9Sstevel@tonic-gate 			offset = segmentpadr & MMU_PAGEOFFSET;
2025*7c478bd9Sstevel@tonic-gate 			segmentvadr += sizesegment;
2026*7c478bd9Sstevel@tonic-gate 		}
2027*7c478bd9Sstevel@tonic-gate 	} while (residual_size && nsegments);
2028*7c478bd9Sstevel@tonic-gate 	ASSERT(residual_size == 0);
2029*7c478bd9Sstevel@tonic-gate 
2030*7c478bd9Sstevel@tonic-gate 	previousp->dmais_link = NULL;
2031*7c478bd9Sstevel@tonic-gate 	previousp->dmais_flags |= DMAIS_WINEND;
2032*7c478bd9Sstevel@tonic-gate 	if (curwinp) {
2033*7c478bd9Sstevel@tonic-gate 		if (win_flags & DMAIS_NEEDINTBUF)
2034*7c478bd9Sstevel@tonic-gate 			curwinp->dmais_flags |= DMAIS_WINUIB;
2035*7c478bd9Sstevel@tonic-gate 		curwinp->_win._dmais_nex = NULL;
2036*7c478bd9Sstevel@tonic-gate 	} else
2037*7c478bd9Sstevel@tonic-gate 		prewinp->_win._dmais_nex = NULL;
2038*7c478bd9Sstevel@tonic-gate 
2039*7c478bd9Sstevel@tonic-gate 	if ((needintbuf = MAX(needintbuf, reqneedintbuf)) != 0) {
2040*7c478bd9Sstevel@tonic-gate 		ddi_dma_attr_t dma_attr;
2041*7c478bd9Sstevel@tonic-gate 
2042*7c478bd9Sstevel@tonic-gate 
2043*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_version = DMA_ATTR_V0;
2044*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_addr_lo = dma_lim->dlim_addr_lo;
2045*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_addr_hi = dma_lim->dlim_addr_hi;
2046*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_minxfer = dma_lim->dlim_minxfer;
2047*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_seg = dma_lim->dlim_adreg_max;
2048*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_count_max = dma_lim->dlim_ctreg_max;
2049*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_granular = dma_lim->dlim_granular;
2050*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_sgllen = dma_lim->dlim_sgllen;
2051*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_maxxfer = dma_lim->dlim_reqsize;
2052*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_burstsizes = dma_lim->dlim_burstsizes;
2053*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_align = MMU_PAGESIZE;
2054*7c478bd9Sstevel@tonic-gate 		dma_attr.dma_attr_flags = 0;
2055*7c478bd9Sstevel@tonic-gate 
2056*7c478bd9Sstevel@tonic-gate 		/*
2057*7c478bd9Sstevel@tonic-gate 		 * Allocate intermediate buffer.
2058*7c478bd9Sstevel@tonic-gate 		 */
2059*7c478bd9Sstevel@tonic-gate 		if (i_ddi_mem_alloc(dip, &dma_attr, needintbuf,
2060*7c478bd9Sstevel@tonic-gate 		    (dmareq->dmar_fp == DDI_DMA_SLEEP) ? 0x1 : 0, 1, 0,
2061*7c478bd9Sstevel@tonic-gate 		    &hp->dmai_ibufp, (ulong_t *)&hp->dmai_ibfsz,
2062*7c478bd9Sstevel@tonic-gate 		    NULL) != DDI_SUCCESS) {
2063*7c478bd9Sstevel@tonic-gate 			rval = DDI_DMA_NORESOURCES;
2064*7c478bd9Sstevel@tonic-gate 			goto bad;
2065*7c478bd9Sstevel@tonic-gate 		}
2066*7c478bd9Sstevel@tonic-gate 		if (mapinfo != DMAMI_KVADR) {
2067*7c478bd9Sstevel@tonic-gate 			hp->dmai_kaddr = vmem_alloc(heap_arena, PAGESIZE,
2068*7c478bd9Sstevel@tonic-gate 			    VM_SLEEP);
2069*7c478bd9Sstevel@tonic-gate 		}
2070*7c478bd9Sstevel@tonic-gate 	}
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate 	/*
2073*7c478bd9Sstevel@tonic-gate 	 * return success
2074*7c478bd9Sstevel@tonic-gate 	 */
2075*7c478bd9Sstevel@tonic-gate #ifdef DMADEBUG
2076*7c478bd9Sstevel@tonic-gate 	DMAPRINT(("dma_brkup: handle %p nsegments %x \n",
2077*7c478bd9Sstevel@tonic-gate 	    (void *)hp, numsegments - nsegments));
2078*7c478bd9Sstevel@tonic-gate #endif
2079*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie = NULL;
2080*7c478bd9Sstevel@tonic-gate 	*handlep = (ddi_dma_handle_t)hp;
2081*7c478bd9Sstevel@tonic-gate 	return (DDI_DMA_MAPPED);
2082*7c478bd9Sstevel@tonic-gate bad:
2083*7c478bd9Sstevel@tonic-gate 	if (hp)
2084*7c478bd9Sstevel@tonic-gate 		kmem_free(hp, hp->dmai_kmsize);
2085*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_DMA_NORESOURCES 	&&
2086*7c478bd9Sstevel@tonic-gate 	    dmareq->dmar_fp != DDI_DMA_DONTWAIT &&
2087*7c478bd9Sstevel@tonic-gate 	    dmareq->dmar_fp != DDI_DMA_SLEEP)
2088*7c478bd9Sstevel@tonic-gate 		ddi_set_callback(dmareq->dmar_fp, dmareq->dmar_arg,
2089*7c478bd9Sstevel@tonic-gate 		    &dvma_call_list_id);
2090*7c478bd9Sstevel@tonic-gate 	return (rval);
2091*7c478bd9Sstevel@tonic-gate }
2092*7c478bd9Sstevel@tonic-gate 
2093*7c478bd9Sstevel@tonic-gate int
2094*7c478bd9Sstevel@tonic-gate rootnex_io_wtsync(ddi_dma_impl_t *hp, int type)
2095*7c478bd9Sstevel@tonic-gate {
2096*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *sp = hp->dmai_wins;
2097*7c478bd9Sstevel@tonic-gate 	caddr_t	kviradr, addr;
2098*7c478bd9Sstevel@tonic-gate 	caddr_t vsrc;
2099*7c478bd9Sstevel@tonic-gate 	ulong_t segoffset, vsoffset;
2100*7c478bd9Sstevel@tonic-gate 	int cpycnt;
2101*7c478bd9Sstevel@tonic-gate 
2102*7c478bd9Sstevel@tonic-gate 	addr = hp->dmai_ibufp;
2103*7c478bd9Sstevel@tonic-gate 	if ((uintptr_t)addr & MMU_PAGEOFFSET) {
2104*7c478bd9Sstevel@tonic-gate 		addr = (caddr_t)(((uintptr_t)addr + MMU_PAGEOFFSET) &
2105*7c478bd9Sstevel@tonic-gate 		    ~MMU_PAGEOFFSET);
2106*7c478bd9Sstevel@tonic-gate 	}
2107*7c478bd9Sstevel@tonic-gate 	if ((sp->dmais_flags & DMAIS_WINUIB) == 0)
2108*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2109*7c478bd9Sstevel@tonic-gate 
2110*7c478bd9Sstevel@tonic-gate 	switch ((intptr_t)hp->dmai_minfo) {
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate 	case DMAMI_KVADR:
2113*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_rflags & DDI_DMA_WRITE)
2116*7c478bd9Sstevel@tonic-gate 				/*
2117*7c478bd9Sstevel@tonic-gate 				 *  copy from segment to buffer
2118*7c478bd9Sstevel@tonic-gate 				 */
2119*7c478bd9Sstevel@tonic-gate 				bcopy(sp->_vdmu._dmais_va, addr,
2120*7c478bd9Sstevel@tonic-gate 				    sp->dmais_size);
2121*7c478bd9Sstevel@tonic-gate 			/*
2122*7c478bd9Sstevel@tonic-gate 			 * save phys addr of intermediate buffer
2123*7c478bd9Sstevel@tonic-gate 			 */
2124*7c478bd9Sstevel@tonic-gate 			sp->_pdmu._dmais_lpd =
2125*7c478bd9Sstevel@tonic-gate 				ptob64(hat_getpfnum(kas.a_hat, addr));
2126*7c478bd9Sstevel@tonic-gate 			if (type == BIND) {
2127*7c478bd9Sstevel@tonic-gate 				sp->dmais_cookie->dmac_laddress =
2128*7c478bd9Sstevel@tonic-gate 					sp->_pdmu._dmais_lpd;
2129*7c478bd9Sstevel@tonic-gate 			}
2130*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2131*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2132*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2133*7c478bd9Sstevel@tonic-gate 		break;
2134*7c478bd9Sstevel@tonic-gate 
2135*7c478bd9Sstevel@tonic-gate 	case DMAMI_PAGES:
2136*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_rflags & DDI_DMA_WRITE) {
2139*7c478bd9Sstevel@tonic-gate 				/*
2140*7c478bd9Sstevel@tonic-gate 				 * need to mapin page so we can have a
2141*7c478bd9Sstevel@tonic-gate 				 * virtual address to do copying
2142*7c478bd9Sstevel@tonic-gate 				 */
2143*7c478bd9Sstevel@tonic-gate 				i86_pp_map(sp->_vdmu._dmais_pp, hp->dmai_kaddr);
2144*7c478bd9Sstevel@tonic-gate 				/*
2145*7c478bd9Sstevel@tonic-gate 				 *  copy from segment to buffer
2146*7c478bd9Sstevel@tonic-gate 				 */
2147*7c478bd9Sstevel@tonic-gate 				bcopy(hp->dmai_kaddr +
2148*7c478bd9Sstevel@tonic-gate 				    (sp->dmais_ofst & MMU_PAGEOFFSET),
2149*7c478bd9Sstevel@tonic-gate 				    addr, sp->dmais_size);
2150*7c478bd9Sstevel@tonic-gate 				/*
2151*7c478bd9Sstevel@tonic-gate 				 *  need to mapout page
2152*7c478bd9Sstevel@tonic-gate 				 */
2153*7c478bd9Sstevel@tonic-gate 				hat_unload(kas.a_hat, hp->dmai_kaddr,
2154*7c478bd9Sstevel@tonic-gate 				    MMU_PAGESIZE, HAT_UNLOAD);
2155*7c478bd9Sstevel@tonic-gate 			}
2156*7c478bd9Sstevel@tonic-gate 			/*
2157*7c478bd9Sstevel@tonic-gate 			 * save phys addr of intemediate buffer
2158*7c478bd9Sstevel@tonic-gate 			 */
2159*7c478bd9Sstevel@tonic-gate 			sp->_pdmu._dmais_lpd =
2160*7c478bd9Sstevel@tonic-gate 				ptob64(hat_getpfnum(kas.a_hat, addr));
2161*7c478bd9Sstevel@tonic-gate 			if (type == BIND) {
2162*7c478bd9Sstevel@tonic-gate 				sp->dmais_cookie->dmac_laddress =
2163*7c478bd9Sstevel@tonic-gate 					sp->_pdmu._dmais_lpd;
2164*7c478bd9Sstevel@tonic-gate 			}
2165*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2166*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2167*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2168*7c478bd9Sstevel@tonic-gate 		break;
2169*7c478bd9Sstevel@tonic-gate 
2170*7c478bd9Sstevel@tonic-gate 	case DMAMI_UVADR:
2171*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2172*7c478bd9Sstevel@tonic-gate 
2173*7c478bd9Sstevel@tonic-gate 			if (hp->dmai_rflags & DDI_DMA_WRITE) {
2174*7c478bd9Sstevel@tonic-gate 				struct page **pplist;
2175*7c478bd9Sstevel@tonic-gate 				segoffset = 0;
2176*7c478bd9Sstevel@tonic-gate 				do {
2177*7c478bd9Sstevel@tonic-gate 					/*
2178*7c478bd9Sstevel@tonic-gate 					 * need to mapin page so we can have a
2179*7c478bd9Sstevel@tonic-gate 					 * virtual address to do copying
2180*7c478bd9Sstevel@tonic-gate 					 */
2181*7c478bd9Sstevel@tonic-gate 					vsrc = sp->_vdmu._dmais_va + segoffset;
2182*7c478bd9Sstevel@tonic-gate 					vsoffset =
2183*7c478bd9Sstevel@tonic-gate 					    (ulong_t)vsrc & MMU_PAGEOFFSET;
2184*7c478bd9Sstevel@tonic-gate 					pplist = hp->dmai_object.dmao_obj.
2185*7c478bd9Sstevel@tonic-gate 							virt_obj.v_priv;
2186*7c478bd9Sstevel@tonic-gate 					/*
2187*7c478bd9Sstevel@tonic-gate 					 * check if we have to use the
2188*7c478bd9Sstevel@tonic-gate 					 * shadow list or the CPU mapping.
2189*7c478bd9Sstevel@tonic-gate 					 */
2190*7c478bd9Sstevel@tonic-gate 					if (pplist != NULL) {
2191*7c478bd9Sstevel@tonic-gate 						ulong_t base, off;
2192*7c478bd9Sstevel@tonic-gate 
2193*7c478bd9Sstevel@tonic-gate 						base = (ulong_t)hp->dmai_object.
2194*7c478bd9Sstevel@tonic-gate 						    dmao_obj.virt_obj.v_addr;
2195*7c478bd9Sstevel@tonic-gate 						off = (base & MMU_PAGEOFFSET) +
2196*7c478bd9Sstevel@tonic-gate 							(ulong_t)vsrc - base;
2197*7c478bd9Sstevel@tonic-gate 						i86_pp_map(pplist[btop(off)],
2198*7c478bd9Sstevel@tonic-gate 							hp->dmai_kaddr);
2199*7c478bd9Sstevel@tonic-gate 					} else {
2200*7c478bd9Sstevel@tonic-gate 						i86_va_map(vsrc,
2201*7c478bd9Sstevel@tonic-gate 						    hp->dmai_object.dmao_obj.
2202*7c478bd9Sstevel@tonic-gate 							virt_obj.v_as,
2203*7c478bd9Sstevel@tonic-gate 						    hp->dmai_kaddr);
2204*7c478bd9Sstevel@tonic-gate 					}
2205*7c478bd9Sstevel@tonic-gate 					kviradr = hp->dmai_kaddr + vsoffset;
2206*7c478bd9Sstevel@tonic-gate 					cpycnt = sp->dmais_size - segoffset;
2207*7c478bd9Sstevel@tonic-gate 					if (vsoffset + cpycnt > MMU_PAGESIZE)
2208*7c478bd9Sstevel@tonic-gate 						cpycnt = MMU_PAGESIZE -
2209*7c478bd9Sstevel@tonic-gate 						    vsoffset;
2210*7c478bd9Sstevel@tonic-gate 					/*
2211*7c478bd9Sstevel@tonic-gate 					 *  copy from segment to buffer
2212*7c478bd9Sstevel@tonic-gate 					 */
2213*7c478bd9Sstevel@tonic-gate 					bcopy(kviradr, addr + segoffset,
2214*7c478bd9Sstevel@tonic-gate 					    cpycnt);
2215*7c478bd9Sstevel@tonic-gate 					/*
2216*7c478bd9Sstevel@tonic-gate 					 *  need to mapout page
2217*7c478bd9Sstevel@tonic-gate 					 */
2218*7c478bd9Sstevel@tonic-gate 					hat_unload(kas.a_hat, hp->dmai_kaddr,
2219*7c478bd9Sstevel@tonic-gate 					    MMU_PAGESIZE, HAT_UNLOAD);
2220*7c478bd9Sstevel@tonic-gate 					segoffset += cpycnt;
2221*7c478bd9Sstevel@tonic-gate 				} while (segoffset < sp->dmais_size);
2222*7c478bd9Sstevel@tonic-gate 			}
2223*7c478bd9Sstevel@tonic-gate 			/*
2224*7c478bd9Sstevel@tonic-gate 			 * save phys addr of intermediate buffer
2225*7c478bd9Sstevel@tonic-gate 			 */
2226*7c478bd9Sstevel@tonic-gate 			sp->_pdmu._dmais_lpd =
2227*7c478bd9Sstevel@tonic-gate 				ptob64(hat_getpfnum(kas.a_hat, addr));
2228*7c478bd9Sstevel@tonic-gate 			if (type == BIND) {
2229*7c478bd9Sstevel@tonic-gate 				sp->dmais_cookie->dmac_laddress =
2230*7c478bd9Sstevel@tonic-gate 					sp->_pdmu._dmais_lpd;
2231*7c478bd9Sstevel@tonic-gate 			}
2232*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2233*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2234*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2235*7c478bd9Sstevel@tonic-gate 		break;
2236*7c478bd9Sstevel@tonic-gate 
2237*7c478bd9Sstevel@tonic-gate 	default:
2238*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Invalid dma handle/map info");
2239*7c478bd9Sstevel@tonic-gate 	}
2240*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2241*7c478bd9Sstevel@tonic-gate }
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate int
2244*7c478bd9Sstevel@tonic-gate rootnex_io_rdsync(ddi_dma_impl_t *hp)
2245*7c478bd9Sstevel@tonic-gate {
2246*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *sp = hp->dmai_wins;
2247*7c478bd9Sstevel@tonic-gate 	caddr_t	kviradr;
2248*7c478bd9Sstevel@tonic-gate 	caddr_t vdest, addr;
2249*7c478bd9Sstevel@tonic-gate 	ulong_t segoffset, vdoffset;
2250*7c478bd9Sstevel@tonic-gate 	int cpycnt;
2251*7c478bd9Sstevel@tonic-gate 
2252*7c478bd9Sstevel@tonic-gate 	addr = hp->dmai_ibufp;
2253*7c478bd9Sstevel@tonic-gate 	if ((uintptr_t)addr & MMU_PAGEOFFSET) {
2254*7c478bd9Sstevel@tonic-gate 	    addr = (caddr_t)
2255*7c478bd9Sstevel@tonic-gate 		(((uintptr_t)addr + MMU_PAGEOFFSET) & ~MMU_PAGEOFFSET);
2256*7c478bd9Sstevel@tonic-gate 	}
2257*7c478bd9Sstevel@tonic-gate 	if (!(sp->dmais_flags & DMAIS_WINUIB) ||
2258*7c478bd9Sstevel@tonic-gate 			!(hp->dmai_rflags & DDI_DMA_READ))
2259*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2260*7c478bd9Sstevel@tonic-gate 
2261*7c478bd9Sstevel@tonic-gate 	switch ((intptr_t)hp->dmai_minfo) {
2262*7c478bd9Sstevel@tonic-gate 
2263*7c478bd9Sstevel@tonic-gate 	case DMAMI_KVADR:
2264*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2265*7c478bd9Sstevel@tonic-gate 			/*
2266*7c478bd9Sstevel@tonic-gate 			 *  copy from buffer to segment
2267*7c478bd9Sstevel@tonic-gate 			 */
2268*7c478bd9Sstevel@tonic-gate 			bcopy(addr, sp->_vdmu._dmais_va, sp->dmais_size);
2269*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2270*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2271*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2272*7c478bd9Sstevel@tonic-gate 		break;
2273*7c478bd9Sstevel@tonic-gate 
2274*7c478bd9Sstevel@tonic-gate 	case DMAMI_PAGES:
2275*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2276*7c478bd9Sstevel@tonic-gate 			/*
2277*7c478bd9Sstevel@tonic-gate 			 * need to mapin page
2278*7c478bd9Sstevel@tonic-gate 			 */
2279*7c478bd9Sstevel@tonic-gate 			i86_pp_map(sp->_vdmu._dmais_pp, hp->dmai_kaddr);
2280*7c478bd9Sstevel@tonic-gate 			/*
2281*7c478bd9Sstevel@tonic-gate 			 *  copy from buffer to segment
2282*7c478bd9Sstevel@tonic-gate 			 */
2283*7c478bd9Sstevel@tonic-gate 			bcopy(addr,
2284*7c478bd9Sstevel@tonic-gate 			    (hp->dmai_kaddr +
2285*7c478bd9Sstevel@tonic-gate 				(sp->dmais_ofst & MMU_PAGEOFFSET)),
2286*7c478bd9Sstevel@tonic-gate 			    sp->dmais_size);
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate 			/*
2289*7c478bd9Sstevel@tonic-gate 			 *  need to mapout page
2290*7c478bd9Sstevel@tonic-gate 			 */
2291*7c478bd9Sstevel@tonic-gate 			hat_unload(kas.a_hat, hp->dmai_kaddr,
2292*7c478bd9Sstevel@tonic-gate 			    MMU_PAGESIZE, HAT_UNLOAD);
2293*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2294*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2295*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2296*7c478bd9Sstevel@tonic-gate 		break;
2297*7c478bd9Sstevel@tonic-gate 
2298*7c478bd9Sstevel@tonic-gate 	case DMAMI_UVADR:
2299*7c478bd9Sstevel@tonic-gate 		do if (sp->dmais_flags & DMAIS_NEEDINTBUF) {
2300*7c478bd9Sstevel@tonic-gate 			struct page **pplist;
2301*7c478bd9Sstevel@tonic-gate 			segoffset = 0;
2302*7c478bd9Sstevel@tonic-gate 			do {
2303*7c478bd9Sstevel@tonic-gate 				/*
2304*7c478bd9Sstevel@tonic-gate 				 * need to map_in user virtual address
2305*7c478bd9Sstevel@tonic-gate 				 */
2306*7c478bd9Sstevel@tonic-gate 				vdest = sp->_vdmu._dmais_va + segoffset;
2307*7c478bd9Sstevel@tonic-gate 				vdoffset = (ulong_t)vdest & MMU_PAGEOFFSET;
2308*7c478bd9Sstevel@tonic-gate 				pplist = hp->dmai_object.dmao_obj.
2309*7c478bd9Sstevel@tonic-gate 						virt_obj.v_priv;
2310*7c478bd9Sstevel@tonic-gate 				/*
2311*7c478bd9Sstevel@tonic-gate 				 * check if we have to use the
2312*7c478bd9Sstevel@tonic-gate 				 * shadow list or the CPU mapping.
2313*7c478bd9Sstevel@tonic-gate 				 */
2314*7c478bd9Sstevel@tonic-gate 				if (pplist != NULL) {
2315*7c478bd9Sstevel@tonic-gate 					ulong_t base, off;
2316*7c478bd9Sstevel@tonic-gate 
2317*7c478bd9Sstevel@tonic-gate 					base = (ulong_t)hp->dmai_object.
2318*7c478bd9Sstevel@tonic-gate 						dmao_obj.virt_obj.v_addr;
2319*7c478bd9Sstevel@tonic-gate 					off = (base & MMU_PAGEOFFSET) +
2320*7c478bd9Sstevel@tonic-gate 						(ulong_t)vdest - base;
2321*7c478bd9Sstevel@tonic-gate 					i86_pp_map(pplist[btop(off)],
2322*7c478bd9Sstevel@tonic-gate 						hp->dmai_kaddr);
2323*7c478bd9Sstevel@tonic-gate 				} else {
2324*7c478bd9Sstevel@tonic-gate 					i86_va_map(vdest,
2325*7c478bd9Sstevel@tonic-gate 					    hp->dmai_object.dmao_obj.
2326*7c478bd9Sstevel@tonic-gate 						virt_obj.v_as,
2327*7c478bd9Sstevel@tonic-gate 					    hp->dmai_kaddr);
2328*7c478bd9Sstevel@tonic-gate 				}
2329*7c478bd9Sstevel@tonic-gate 				kviradr = hp->dmai_kaddr + vdoffset;
2330*7c478bd9Sstevel@tonic-gate 				cpycnt = sp->dmais_size - segoffset;
2331*7c478bd9Sstevel@tonic-gate 				if (vdoffset + cpycnt > MMU_PAGESIZE)
2332*7c478bd9Sstevel@tonic-gate 					cpycnt = MMU_PAGESIZE - vdoffset;
2333*7c478bd9Sstevel@tonic-gate 				/*
2334*7c478bd9Sstevel@tonic-gate 				 *  copy from buffer to segment
2335*7c478bd9Sstevel@tonic-gate 				 */
2336*7c478bd9Sstevel@tonic-gate 				bcopy(addr + segoffset, kviradr, cpycnt);
2337*7c478bd9Sstevel@tonic-gate 				/*
2338*7c478bd9Sstevel@tonic-gate 				 *  need to map_out page
2339*7c478bd9Sstevel@tonic-gate 				 */
2340*7c478bd9Sstevel@tonic-gate 				hat_unload(kas.a_hat, hp->dmai_kaddr,
2341*7c478bd9Sstevel@tonic-gate 				    MMU_PAGESIZE, HAT_UNLOAD);
2342*7c478bd9Sstevel@tonic-gate 				segoffset += cpycnt;
2343*7c478bd9Sstevel@tonic-gate 			} while (segoffset < sp->dmais_size);
2344*7c478bd9Sstevel@tonic-gate 			addr += MMU_PAGESIZE;
2345*7c478bd9Sstevel@tonic-gate 		} while (!(sp->dmais_flags & DMAIS_WINEND) &&
2346*7c478bd9Sstevel@tonic-gate 		    (sp = sp->dmais_link));
2347*7c478bd9Sstevel@tonic-gate 		break;
2348*7c478bd9Sstevel@tonic-gate 
2349*7c478bd9Sstevel@tonic-gate 	default:
2350*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Invalid dma handle/map info");
2351*7c478bd9Sstevel@tonic-gate 	}
2352*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2353*7c478bd9Sstevel@tonic-gate }
2354*7c478bd9Sstevel@tonic-gate 
2355*7c478bd9Sstevel@tonic-gate static int
2356*7c478bd9Sstevel@tonic-gate rootnex_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
2357*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
2358*7c478bd9Sstevel@tonic-gate     off_t *offp, size_t *lenp,
2359*7c478bd9Sstevel@tonic-gate     caddr_t *objpp, uint_t cache_flags)
2360*7c478bd9Sstevel@tonic-gate {
2361*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
2362*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *sp = (impl_dma_segment_t *)lenp;
2363*7c478bd9Sstevel@tonic-gate 	impl_dma_segment_t *wp = (impl_dma_segment_t *)offp;
2364*7c478bd9Sstevel@tonic-gate #if !defined(__amd64)
2365*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cp;
2366*7c478bd9Sstevel@tonic-gate #endif
2367*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate #ifdef lint
2370*7c478bd9Sstevel@tonic-gate 	dip = dip;
2371*7c478bd9Sstevel@tonic-gate 	rdip = rdip;
2372*7c478bd9Sstevel@tonic-gate #endif
2373*7c478bd9Sstevel@tonic-gate 
2374*7c478bd9Sstevel@tonic-gate 	DMAPRINT(("io_mctl: handle %p ", (void *)hp));
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	switch (request) {
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_SEGTOC:
2379*7c478bd9Sstevel@tonic-gate #if defined(__amd64)
2380*7c478bd9Sstevel@tonic-gate 		/*
2381*7c478bd9Sstevel@tonic-gate 		 * ddi_dma_segtocookie(9F) is Obsolete, and the whole
2382*7c478bd9Sstevel@tonic-gate 		 * passing-the-pointer-through-the-cache-flags thing just
2383*7c478bd9Sstevel@tonic-gate 		 * doesn't work when pointers are 64-bit and cache_flags
2384*7c478bd9Sstevel@tonic-gate 		 * are 32-bit.
2385*7c478bd9Sstevel@tonic-gate 		 */
2386*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("stoc invoked but not implemented.\n"));
2387*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2388*7c478bd9Sstevel@tonic-gate #else
2389*7c478bd9Sstevel@tonic-gate 		/* return device specific dma cookie for segment */
2390*7c478bd9Sstevel@tonic-gate 		sp = (impl_dma_segment_t *)(uintptr_t)cache_flags;
2391*7c478bd9Sstevel@tonic-gate 		if (!sp) {
2392*7c478bd9Sstevel@tonic-gate 			DMAPRINT(("stoc segment %p end\n", (void *)sp));
2393*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2394*7c478bd9Sstevel@tonic-gate 		}
2395*7c478bd9Sstevel@tonic-gate 		cp = (ddi_dma_cookie_t *)objpp;
2396*7c478bd9Sstevel@tonic-gate 
2397*7c478bd9Sstevel@tonic-gate 		/*
2398*7c478bd9Sstevel@tonic-gate 		 * use phys addr of actual buffer or intermediate buffer
2399*7c478bd9Sstevel@tonic-gate 		 */
2400*7c478bd9Sstevel@tonic-gate 		cp->dmac_laddress = sp->_pdmu._dmais_lpd;
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("stoc segment %p mapping %lx size %lx\n",
2403*7c478bd9Sstevel@tonic-gate 		    (void *)sp, (ulong_t)sp->_vdmu._dmais_va, sp->dmais_size));
2404*7c478bd9Sstevel@tonic-gate 
2405*7c478bd9Sstevel@tonic-gate 		cp->dmac_type = (ulong_t)sp;
2406*7c478bd9Sstevel@tonic-gate 		*lenp = cp->dmac_size = sp->dmais_size;
2407*7c478bd9Sstevel@tonic-gate 		*offp = sp->dmais_ofst;
2408*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2409*7c478bd9Sstevel@tonic-gate #endif
2410*7c478bd9Sstevel@tonic-gate 
2411*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_NEXTSEG:	/* get next DMA segment	*/
2412*7c478bd9Sstevel@tonic-gate 		ASSERT(wp->dmais_flags & DMAIS_WINSTRT);
2413*7c478bd9Sstevel@tonic-gate 		if (wp != hp->dmai_wins) {
2414*7c478bd9Sstevel@tonic-gate 			DMAPRINT(("nxseg: not current window %p\n",
2415*7c478bd9Sstevel@tonic-gate 			    (void *)wp));
2416*7c478bd9Sstevel@tonic-gate 			return (DDI_DMA_STALE);
2417*7c478bd9Sstevel@tonic-gate 		}
2418*7c478bd9Sstevel@tonic-gate 		if (!sp) {
2419*7c478bd9Sstevel@tonic-gate 			/*
2420*7c478bd9Sstevel@tonic-gate 			 * reset to first segment in current window
2421*7c478bd9Sstevel@tonic-gate 			 */
2422*7c478bd9Sstevel@tonic-gate 			*objpp = (caddr_t)wp;
2423*7c478bd9Sstevel@tonic-gate 		} else {
2424*7c478bd9Sstevel@tonic-gate 			if (sp->dmais_flags & DMAIS_WINEND) {
2425*7c478bd9Sstevel@tonic-gate 				DMAPRINT(("nxseg: seg %p eow\n", (void *)sp));
2426*7c478bd9Sstevel@tonic-gate 				return (DDI_DMA_DONE);
2427*7c478bd9Sstevel@tonic-gate 			}
2428*7c478bd9Sstevel@tonic-gate 			/* check if segment is really in window */
2429*7c478bd9Sstevel@tonic-gate 			ASSERT((sp->dmais_flags & DMAIS_WINSTRT) && sp == wp ||
2430*7c478bd9Sstevel@tonic-gate 			    !(sp->dmais_flags & DMAIS_WINSTRT) &&
2431*7c478bd9Sstevel@tonic-gate 			    sp->_win._dmais_cur == wp);
2432*7c478bd9Sstevel@tonic-gate 			*objpp = (caddr_t)sp->dmais_link;
2433*7c478bd9Sstevel@tonic-gate 		}
2434*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("nxseg: new seg %p\n", (void *)*objpp));
2435*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2436*7c478bd9Sstevel@tonic-gate 
2437*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_NEXTWIN:	/* get next DMA window	*/
2438*7c478bd9Sstevel@tonic-gate 		if (hp->dmai_wins && hp->dmai_ibufp)
2439*7c478bd9Sstevel@tonic-gate 			/*
2440*7c478bd9Sstevel@tonic-gate 			 * do implied sync on current window
2441*7c478bd9Sstevel@tonic-gate 			 */
2442*7c478bd9Sstevel@tonic-gate 			(void) rootnex_io_rdsync(hp);
2443*7c478bd9Sstevel@tonic-gate 		if (!wp) {
2444*7c478bd9Sstevel@tonic-gate 			/*
2445*7c478bd9Sstevel@tonic-gate 			 * reset to (first segment of) first window
2446*7c478bd9Sstevel@tonic-gate 			 */
2447*7c478bd9Sstevel@tonic-gate 			*objpp = (caddr_t)hp->dmai_hds;
2448*7c478bd9Sstevel@tonic-gate 			DMAPRINT(("nxwin: first win %p\n", (void *)*objpp));
2449*7c478bd9Sstevel@tonic-gate 		} else {
2450*7c478bd9Sstevel@tonic-gate 			ASSERT(wp->dmais_flags & DMAIS_WINSTRT);
2451*7c478bd9Sstevel@tonic-gate 			if (wp != hp->dmai_wins) {
2452*7c478bd9Sstevel@tonic-gate 				DMAPRINT(("nxwin: win %p not current\n",
2453*7c478bd9Sstevel@tonic-gate 				    (void *)wp));
2454*7c478bd9Sstevel@tonic-gate 				return (DDI_DMA_STALE);
2455*7c478bd9Sstevel@tonic-gate 			}
2456*7c478bd9Sstevel@tonic-gate 			if (wp->_win._dmais_nex == 0) {
2457*7c478bd9Sstevel@tonic-gate 				DMAPRINT(("nxwin: win %p end\n", (void *)wp));
2458*7c478bd9Sstevel@tonic-gate 				return (DDI_DMA_DONE);
2459*7c478bd9Sstevel@tonic-gate 			}
2460*7c478bd9Sstevel@tonic-gate 			*objpp = (caddr_t)wp->_win._dmais_nex;
2461*7c478bd9Sstevel@tonic-gate 			DMAPRINT(("nxwin: new win %p\n", (void *)*objpp));
2462*7c478bd9Sstevel@tonic-gate 		}
2463*7c478bd9Sstevel@tonic-gate 		hp->dmai_wins = (impl_dma_segment_t *)*objpp;
2464*7c478bd9Sstevel@tonic-gate 		if (hp->dmai_ibufp)
2465*7c478bd9Sstevel@tonic-gate 			return (rootnex_io_wtsync(hp, MAP));
2466*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2467*7c478bd9Sstevel@tonic-gate 
2468*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_FREE:
2469*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("free handle\n"));
2470*7c478bd9Sstevel@tonic-gate 		if (hp->dmai_ibufp) {
2471*7c478bd9Sstevel@tonic-gate 			rval = rootnex_io_rdsync(hp);
2472*7c478bd9Sstevel@tonic-gate 			ddi_mem_free(hp->dmai_ibufp);
2473*7c478bd9Sstevel@tonic-gate 		}
2474*7c478bd9Sstevel@tonic-gate 		if (hp->dmai_kaddr)
2475*7c478bd9Sstevel@tonic-gate 			vmem_free(heap_arena, hp->dmai_kaddr, PAGESIZE);
2476*7c478bd9Sstevel@tonic-gate 		kmem_free(hp, hp->dmai_kmsize);
2477*7c478bd9Sstevel@tonic-gate 		if (dvma_call_list_id)
2478*7c478bd9Sstevel@tonic-gate 			ddi_run_callback(&dvma_call_list_id);
2479*7c478bd9Sstevel@tonic-gate 		break;
2480*7c478bd9Sstevel@tonic-gate 
2481*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_IOPB_ALLOC:	/* get contiguous DMA-able memory */
2482*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("iopb alloc\n"));
2483*7c478bd9Sstevel@tonic-gate 		rval = i_ddi_mem_alloc_lim(rdip, (ddi_dma_lim_t *)offp,
2484*7c478bd9Sstevel@tonic-gate 		    *lenp, 0, 0, 0, objpp, NULL, NULL);
2485*7c478bd9Sstevel@tonic-gate 		break;
2486*7c478bd9Sstevel@tonic-gate 
2487*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_SMEM_ALLOC:	/* get contiguous DMA-able memory */
2488*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("mem alloc\n"));
2489*7c478bd9Sstevel@tonic-gate 		rval = i_ddi_mem_alloc_lim(rdip, (ddi_dma_lim_t *)offp,
2490*7c478bd9Sstevel@tonic-gate 		    *lenp, cache_flags, 1, 0, objpp, (uint_t *)handle, NULL);
2491*7c478bd9Sstevel@tonic-gate 		break;
2492*7c478bd9Sstevel@tonic-gate 
2493*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_KVADDR:
2494*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("kvaddr of phys mapping\n"));
2495*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2496*7c478bd9Sstevel@tonic-gate 
2497*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_GETERR:
2498*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("geterr\n"));
2499*7c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
2500*7c478bd9Sstevel@tonic-gate 		break;
2501*7c478bd9Sstevel@tonic-gate 
2502*7c478bd9Sstevel@tonic-gate 	case DDI_DMA_COFF:
2503*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("coff off %p mapping %llx size %lx\n",
2504*7c478bd9Sstevel@tonic-gate 		    (void *)*objpp,
2505*7c478bd9Sstevel@tonic-gate 		    (unsigned long long)hp->dmai_wins->_pdmu._dmais_lpd,
2506*7c478bd9Sstevel@tonic-gate 		    hp->dmai_wins->dmais_size));
2507*7c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
2508*7c478bd9Sstevel@tonic-gate 		break;
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate 	default:
2511*7c478bd9Sstevel@tonic-gate 		DMAPRINT(("unknown 0x%x\n", request));
2512*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2513*7c478bd9Sstevel@tonic-gate 	}
2514*7c478bd9Sstevel@tonic-gate 	return (rval);
2515*7c478bd9Sstevel@tonic-gate }
2516*7c478bd9Sstevel@tonic-gate 
2517*7c478bd9Sstevel@tonic-gate /*
2518*7c478bd9Sstevel@tonic-gate  * Root nexus ctl functions
2519*7c478bd9Sstevel@tonic-gate  */
2520*7c478bd9Sstevel@tonic-gate #define	REPORTDEV_BUFSIZE	1024
2521*7c478bd9Sstevel@tonic-gate 
2522*7c478bd9Sstevel@tonic-gate static int
2523*7c478bd9Sstevel@tonic-gate rootnex_ctl_reportdev(dev_info_t *dev)
2524*7c478bd9Sstevel@tonic-gate {
2525*7c478bd9Sstevel@tonic-gate 	int i, n, len, f_len = 0;
2526*7c478bd9Sstevel@tonic-gate 	char *buf;
2527*7c478bd9Sstevel@tonic-gate 
2528*7c478bd9Sstevel@tonic-gate 	buf = kmem_alloc(REPORTDEV_BUFSIZE, KM_SLEEP);
2529*7c478bd9Sstevel@tonic-gate 	f_len += snprintf(buf, REPORTDEV_BUFSIZE,
2530*7c478bd9Sstevel@tonic-gate 	    "%s%d at root", ddi_driver_name(dev), ddi_get_instance(dev));
2531*7c478bd9Sstevel@tonic-gate 	len = strlen(buf);
2532*7c478bd9Sstevel@tonic-gate 
2533*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sparc_pd_getnreg(dev); i++) {
2534*7c478bd9Sstevel@tonic-gate 
2535*7c478bd9Sstevel@tonic-gate 		struct regspec *rp = sparc_pd_getreg(dev, i);
2536*7c478bd9Sstevel@tonic-gate 
2537*7c478bd9Sstevel@tonic-gate 		if (i == 0)
2538*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2539*7c478bd9Sstevel@tonic-gate 			    ": ");
2540*7c478bd9Sstevel@tonic-gate 		else
2541*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2542*7c478bd9Sstevel@tonic-gate 			    " and ");
2543*7c478bd9Sstevel@tonic-gate 		len = strlen(buf);
2544*7c478bd9Sstevel@tonic-gate 
2545*7c478bd9Sstevel@tonic-gate 		switch (rp->regspec_bustype) {
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 		case BTEISA:
2548*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2549*7c478bd9Sstevel@tonic-gate 			    "%s 0x%x", DEVI_EISA_NEXNAME, rp->regspec_addr);
2550*7c478bd9Sstevel@tonic-gate 			break;
2551*7c478bd9Sstevel@tonic-gate 
2552*7c478bd9Sstevel@tonic-gate 		case BTISA:
2553*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2554*7c478bd9Sstevel@tonic-gate 			    "%s 0x%x", DEVI_ISA_NEXNAME, rp->regspec_addr);
2555*7c478bd9Sstevel@tonic-gate 			break;
2556*7c478bd9Sstevel@tonic-gate 
2557*7c478bd9Sstevel@tonic-gate 		default:
2558*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2559*7c478bd9Sstevel@tonic-gate 			    "space %x offset %x",
2560*7c478bd9Sstevel@tonic-gate 			    rp->regspec_bustype, rp->regspec_addr);
2561*7c478bd9Sstevel@tonic-gate 			break;
2562*7c478bd9Sstevel@tonic-gate 		}
2563*7c478bd9Sstevel@tonic-gate 		len = strlen(buf);
2564*7c478bd9Sstevel@tonic-gate 	}
2565*7c478bd9Sstevel@tonic-gate 	for (i = 0, n = sparc_pd_getnintr(dev); i < n; i++) {
2566*7c478bd9Sstevel@tonic-gate 		int pri;
2567*7c478bd9Sstevel@tonic-gate 
2568*7c478bd9Sstevel@tonic-gate 		if (i != 0) {
2569*7c478bd9Sstevel@tonic-gate 			f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2570*7c478bd9Sstevel@tonic-gate 			    ",");
2571*7c478bd9Sstevel@tonic-gate 			len = strlen(buf);
2572*7c478bd9Sstevel@tonic-gate 		}
2573*7c478bd9Sstevel@tonic-gate 		pri = INT_IPL(sparc_pd_getintr(dev, i)->intrspec_pri);
2574*7c478bd9Sstevel@tonic-gate 		f_len += snprintf(buf + len, REPORTDEV_BUFSIZE - len,
2575*7c478bd9Sstevel@tonic-gate 		    " sparc ipl %d", pri);
2576*7c478bd9Sstevel@tonic-gate 		len = strlen(buf);
2577*7c478bd9Sstevel@tonic-gate 	}
2578*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
2579*7c478bd9Sstevel@tonic-gate 	if (f_len + 1 >= REPORTDEV_BUFSIZE) {
2580*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "next message is truncated: "
2581*7c478bd9Sstevel@tonic-gate 		    "printed length 1024, real length %d", f_len);
2582*7c478bd9Sstevel@tonic-gate 	}
2583*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2584*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "?%s\n", buf);
2585*7c478bd9Sstevel@tonic-gate 	kmem_free(buf, REPORTDEV_BUFSIZE);
2586*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2587*7c478bd9Sstevel@tonic-gate }
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate /*
2590*7c478bd9Sstevel@tonic-gate  * For the x86 rootnexus, we're prepared to claim that the interrupt string
2591*7c478bd9Sstevel@tonic-gate  * is in the form of a list of <ipl,vec> specifications.
2592*7c478bd9Sstevel@tonic-gate  */
2593*7c478bd9Sstevel@tonic-gate 
2594*7c478bd9Sstevel@tonic-gate #define	VEC_MIN	1
2595*7c478bd9Sstevel@tonic-gate #define	VEC_MAX	255
2596*7c478bd9Sstevel@tonic-gate static int
2597*7c478bd9Sstevel@tonic-gate rootnex_xlate_intrs(dev_info_t *dip, dev_info_t *rdip, int *in,
2598*7c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr)
2599*7c478bd9Sstevel@tonic-gate {
2600*7c478bd9Sstevel@tonic-gate 	size_t size;
2601*7c478bd9Sstevel@tonic-gate 	int n;
2602*7c478bd9Sstevel@tonic-gate 	struct intrspec *new;
2603*7c478bd9Sstevel@tonic-gate 	caddr_t got_prop;
2604*7c478bd9Sstevel@tonic-gate 	int *inpri;
2605*7c478bd9Sstevel@tonic-gate 	int got_len;
2606*7c478bd9Sstevel@tonic-gate 	extern int ignore_hardware_nodes;	/* force flag from ddi_impl.c */
2607*7c478bd9Sstevel@tonic-gate 
2608*7c478bd9Sstevel@tonic-gate 	static char bad_intr_fmt[] =
2609*7c478bd9Sstevel@tonic-gate 	    "rootnex: bad interrupt spec from %s%d - ipl %d, irq %d\n";
2610*7c478bd9Sstevel@tonic-gate 
2611*7c478bd9Sstevel@tonic-gate #ifdef	lint
2612*7c478bd9Sstevel@tonic-gate 	dip = dip;
2613*7c478bd9Sstevel@tonic-gate #endif
2614*7c478bd9Sstevel@tonic-gate 	/*
2615*7c478bd9Sstevel@tonic-gate 	 * determine if the driver is expecting the new style "interrupts"
2616*7c478bd9Sstevel@tonic-gate 	 * property which just contains the IRQ, or the old style which
2617*7c478bd9Sstevel@tonic-gate 	 * contains pairs of <IPL,IRQ>.  if it is the new style, we always
2618*7c478bd9Sstevel@tonic-gate 	 * assign IPL 5 unless an "interrupt-priorities" property exists.
2619*7c478bd9Sstevel@tonic-gate 	 * in that case, the "interrupt-priorities" property contains the
2620*7c478bd9Sstevel@tonic-gate 	 * IPL values that match, one for one, the IRQ values in the
2621*7c478bd9Sstevel@tonic-gate 	 * "interrupts" property.
2622*7c478bd9Sstevel@tonic-gate 	 */
2623*7c478bd9Sstevel@tonic-gate 	inpri = NULL;
2624*7c478bd9Sstevel@tonic-gate 	if ((ddi_getprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
2625*7c478bd9Sstevel@tonic-gate 	    "ignore-hardware-nodes", -1) != -1) ||
2626*7c478bd9Sstevel@tonic-gate 	    ignore_hardware_nodes) {
2627*7c478bd9Sstevel@tonic-gate 		/* the old style "interrupts" property... */
2628*7c478bd9Sstevel@tonic-gate 
2629*7c478bd9Sstevel@tonic-gate 		/*
2630*7c478bd9Sstevel@tonic-gate 		 * The list consists of <ipl,vec> elements
2631*7c478bd9Sstevel@tonic-gate 		 */
2632*7c478bd9Sstevel@tonic-gate 		if ((n = (*in++ >> 1)) < 1)
2633*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2634*7c478bd9Sstevel@tonic-gate 
2635*7c478bd9Sstevel@tonic-gate 		pdptr->par_nintr = n;
2636*7c478bd9Sstevel@tonic-gate 		size = n * sizeof (struct intrspec);
2637*7c478bd9Sstevel@tonic-gate 		new = pdptr->par_intr = kmem_zalloc(size, KM_SLEEP);
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 		while (n--) {
2640*7c478bd9Sstevel@tonic-gate 			int level = *in++;
2641*7c478bd9Sstevel@tonic-gate 			int vec = *in++;
2642*7c478bd9Sstevel@tonic-gate 
2643*7c478bd9Sstevel@tonic-gate 			if (level < 1 || level > MAXIPL ||
2644*7c478bd9Sstevel@tonic-gate 			    vec < VEC_MIN || vec > VEC_MAX) {
2645*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, bad_intr_fmt,
2646*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_name,
2647*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_instance, level, vec);
2648*7c478bd9Sstevel@tonic-gate 				goto broken;
2649*7c478bd9Sstevel@tonic-gate 			}
2650*7c478bd9Sstevel@tonic-gate 			new->intrspec_pri = level;
2651*7c478bd9Sstevel@tonic-gate 			if (vec != 2)
2652*7c478bd9Sstevel@tonic-gate 				new->intrspec_vec = vec;
2653*7c478bd9Sstevel@tonic-gate 			else
2654*7c478bd9Sstevel@tonic-gate 				/*
2655*7c478bd9Sstevel@tonic-gate 				 * irq 2 on the PC bus is tied to irq 9
2656*7c478bd9Sstevel@tonic-gate 				 * on ISA, EISA and MicroChannel
2657*7c478bd9Sstevel@tonic-gate 				 */
2658*7c478bd9Sstevel@tonic-gate 				new->intrspec_vec = 9;
2659*7c478bd9Sstevel@tonic-gate 			new++;
2660*7c478bd9Sstevel@tonic-gate 		}
2661*7c478bd9Sstevel@tonic-gate 
2662*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2663*7c478bd9Sstevel@tonic-gate 	} else {
2664*7c478bd9Sstevel@tonic-gate 		/* the new style "interrupts" property... */
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 		/*
2667*7c478bd9Sstevel@tonic-gate 		 * The list consists of <vec> elements
2668*7c478bd9Sstevel@tonic-gate 		 */
2669*7c478bd9Sstevel@tonic-gate 		if ((n = (*in++)) < 1)
2670*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2671*7c478bd9Sstevel@tonic-gate 
2672*7c478bd9Sstevel@tonic-gate 		pdptr->par_nintr = n;
2673*7c478bd9Sstevel@tonic-gate 		size = n * sizeof (struct intrspec);
2674*7c478bd9Sstevel@tonic-gate 		new = pdptr->par_intr = kmem_zalloc(size, KM_SLEEP);
2675*7c478bd9Sstevel@tonic-gate 
2676*7c478bd9Sstevel@tonic-gate 		/* XXX check for "interrupt-priorities" property... */
2677*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
2678*7c478bd9Sstevel@tonic-gate 		    "interrupt-priorities", (caddr_t)&got_prop, &got_len)
2679*7c478bd9Sstevel@tonic-gate 		    == DDI_PROP_SUCCESS) {
2680*7c478bd9Sstevel@tonic-gate 			if (n != (got_len / sizeof (int))) {
2681*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
2682*7c478bd9Sstevel@tonic-gate 				    "rootnex: bad interrupt-priorities length"
2683*7c478bd9Sstevel@tonic-gate 				    " from %s%d: expected %d, got %d\n",
2684*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_name,
2685*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_instance, n,
2686*7c478bd9Sstevel@tonic-gate 				    (int)(got_len / sizeof (int)));
2687*7c478bd9Sstevel@tonic-gate 				goto broken;
2688*7c478bd9Sstevel@tonic-gate 			}
2689*7c478bd9Sstevel@tonic-gate 			inpri = (int *)got_prop;
2690*7c478bd9Sstevel@tonic-gate 		}
2691*7c478bd9Sstevel@tonic-gate 
2692*7c478bd9Sstevel@tonic-gate 		while (n--) {
2693*7c478bd9Sstevel@tonic-gate 			int level;
2694*7c478bd9Sstevel@tonic-gate 			int vec = *in++;
2695*7c478bd9Sstevel@tonic-gate 
2696*7c478bd9Sstevel@tonic-gate 			if (inpri == NULL)
2697*7c478bd9Sstevel@tonic-gate 				level = 5;
2698*7c478bd9Sstevel@tonic-gate 			else
2699*7c478bd9Sstevel@tonic-gate 				level = *inpri++;
2700*7c478bd9Sstevel@tonic-gate 
2701*7c478bd9Sstevel@tonic-gate 			if (level < 1 || level > MAXIPL ||
2702*7c478bd9Sstevel@tonic-gate 			    vec < VEC_MIN || vec > VEC_MAX) {
2703*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, bad_intr_fmt,
2704*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_name,
2705*7c478bd9Sstevel@tonic-gate 				    DEVI(rdip)->devi_instance, level, vec);
2706*7c478bd9Sstevel@tonic-gate 				goto broken;
2707*7c478bd9Sstevel@tonic-gate 			}
2708*7c478bd9Sstevel@tonic-gate 			new->intrspec_pri = level;
2709*7c478bd9Sstevel@tonic-gate 			if (vec != 2)
2710*7c478bd9Sstevel@tonic-gate 				new->intrspec_vec = vec;
2711*7c478bd9Sstevel@tonic-gate 			else
2712*7c478bd9Sstevel@tonic-gate 				/*
2713*7c478bd9Sstevel@tonic-gate 				 * irq 2 on the PC bus is tied to irq 9
2714*7c478bd9Sstevel@tonic-gate 				 * on ISA, EISA and MicroChannel
2715*7c478bd9Sstevel@tonic-gate 				 */
2716*7c478bd9Sstevel@tonic-gate 				new->intrspec_vec = 9;
2717*7c478bd9Sstevel@tonic-gate 			new++;
2718*7c478bd9Sstevel@tonic-gate 		}
2719*7c478bd9Sstevel@tonic-gate 
2720*7c478bd9Sstevel@tonic-gate 		if (inpri != NULL)
2721*7c478bd9Sstevel@tonic-gate 			kmem_free(got_prop, got_len);
2722*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2723*7c478bd9Sstevel@tonic-gate 	}
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate broken:
2726*7c478bd9Sstevel@tonic-gate 	kmem_free(pdptr->par_intr, size);
2727*7c478bd9Sstevel@tonic-gate 	pdptr->par_intr = NULL;
2728*7c478bd9Sstevel@tonic-gate 	pdptr->par_nintr = 0;
2729*7c478bd9Sstevel@tonic-gate 	if (inpri != NULL)
2730*7c478bd9Sstevel@tonic-gate 		kmem_free(got_prop, got_len);
2731*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
2732*7c478bd9Sstevel@tonic-gate }
2733*7c478bd9Sstevel@tonic-gate 
2734*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2735*7c478bd9Sstevel@tonic-gate static int
2736*7c478bd9Sstevel@tonic-gate rootnex_ctl_children(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
2737*7c478bd9Sstevel@tonic-gate     dev_info_t *child)
2738*7c478bd9Sstevel@tonic-gate {
2739*7c478bd9Sstevel@tonic-gate 	extern int impl_ddi_sunbus_initchild(dev_info_t *);
2740*7c478bd9Sstevel@tonic-gate 	extern void impl_ddi_sunbus_removechild(dev_info_t *);
2741*7c478bd9Sstevel@tonic-gate 
2742*7c478bd9Sstevel@tonic-gate 	switch (ctlop)  {
2743*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
2744*7c478bd9Sstevel@tonic-gate 		return (impl_ddi_sunbus_initchild(child));
2745*7c478bd9Sstevel@tonic-gate 
2746*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
2747*7c478bd9Sstevel@tonic-gate 		impl_ddi_sunbus_removechild(child);
2748*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2749*7c478bd9Sstevel@tonic-gate 	default:
2750*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2751*7c478bd9Sstevel@tonic-gate 	}
2752*7c478bd9Sstevel@tonic-gate }
2753*7c478bd9Sstevel@tonic-gate 
2754*7c478bd9Sstevel@tonic-gate 
2755*7c478bd9Sstevel@tonic-gate static int
2756*7c478bd9Sstevel@tonic-gate rootnex_ctlops_poke(peekpoke_ctlops_t *in_args)
2757*7c478bd9Sstevel@tonic-gate {
2758*7c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
2759*7c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
2760*7c478bd9Sstevel@tonic-gate 
2761*7c478bd9Sstevel@tonic-gate 	/* Cautious access not supported. */
2762*7c478bd9Sstevel@tonic-gate 	if (in_args->handle != NULL)
2763*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2764*7c478bd9Sstevel@tonic-gate 
2765*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pokefault_mutex);
2766*7c478bd9Sstevel@tonic-gate 	pokefault = -1;
2767*7c478bd9Sstevel@tonic-gate 
2768*7c478bd9Sstevel@tonic-gate 	/* Set up protected environment. */
2769*7c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
2770*7c478bd9Sstevel@tonic-gate 		switch (in_args->size) {
2771*7c478bd9Sstevel@tonic-gate 		case sizeof (uint8_t):
2772*7c478bd9Sstevel@tonic-gate 			*(uint8_t *)in_args->dev_addr =
2773*7c478bd9Sstevel@tonic-gate 			    *(uint8_t *)in_args->host_addr;
2774*7c478bd9Sstevel@tonic-gate 			break;
2775*7c478bd9Sstevel@tonic-gate 
2776*7c478bd9Sstevel@tonic-gate 		case sizeof (uint16_t):
2777*7c478bd9Sstevel@tonic-gate 			*(uint16_t *)in_args->dev_addr =
2778*7c478bd9Sstevel@tonic-gate 			    *(uint16_t *)in_args->host_addr;
2779*7c478bd9Sstevel@tonic-gate 			break;
2780*7c478bd9Sstevel@tonic-gate 
2781*7c478bd9Sstevel@tonic-gate 		case sizeof (uint32_t):
2782*7c478bd9Sstevel@tonic-gate 			*(uint32_t *)in_args->dev_addr =
2783*7c478bd9Sstevel@tonic-gate 			    *(uint32_t *)in_args->host_addr;
2784*7c478bd9Sstevel@tonic-gate 			break;
2785*7c478bd9Sstevel@tonic-gate 
2786*7c478bd9Sstevel@tonic-gate 		case sizeof (uint64_t):
2787*7c478bd9Sstevel@tonic-gate 			*(uint64_t *)in_args->dev_addr =
2788*7c478bd9Sstevel@tonic-gate 			    *(uint64_t *)in_args->host_addr;
2789*7c478bd9Sstevel@tonic-gate 			break;
2790*7c478bd9Sstevel@tonic-gate 
2791*7c478bd9Sstevel@tonic-gate 		default:
2792*7c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
2793*7c478bd9Sstevel@tonic-gate 			break;
2794*7c478bd9Sstevel@tonic-gate 		}
2795*7c478bd9Sstevel@tonic-gate 	} else
2796*7c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
2797*7c478bd9Sstevel@tonic-gate 
2798*7c478bd9Sstevel@tonic-gate 	/* Take down protected environment. */
2799*7c478bd9Sstevel@tonic-gate 	no_trap();
2800*7c478bd9Sstevel@tonic-gate 
2801*7c478bd9Sstevel@tonic-gate 	pokefault = 0;
2802*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pokefault_mutex);
2803*7c478bd9Sstevel@tonic-gate 
2804*7c478bd9Sstevel@tonic-gate 	return (err);
2805*7c478bd9Sstevel@tonic-gate }
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate 
2808*7c478bd9Sstevel@tonic-gate static int
2809*7c478bd9Sstevel@tonic-gate rootnex_ctlops_peek(peekpoke_ctlops_t *in_args, void *result)
2810*7c478bd9Sstevel@tonic-gate {
2811*7c478bd9Sstevel@tonic-gate 	int err = DDI_SUCCESS;
2812*7c478bd9Sstevel@tonic-gate 	on_trap_data_t otd;
2813*7c478bd9Sstevel@tonic-gate 
2814*7c478bd9Sstevel@tonic-gate 	/* Cautious access not supported. */
2815*7c478bd9Sstevel@tonic-gate 	if (in_args->handle != NULL)
2816*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2817*7c478bd9Sstevel@tonic-gate 
2818*7c478bd9Sstevel@tonic-gate 	if (!on_trap(&otd, OT_DATA_ACCESS)) {
2819*7c478bd9Sstevel@tonic-gate 		switch (in_args->size) {
2820*7c478bd9Sstevel@tonic-gate 		case sizeof (uint8_t):
2821*7c478bd9Sstevel@tonic-gate 			*(uint8_t *)in_args->host_addr =
2822*7c478bd9Sstevel@tonic-gate 			    *(uint8_t *)in_args->dev_addr;
2823*7c478bd9Sstevel@tonic-gate 			break;
2824*7c478bd9Sstevel@tonic-gate 
2825*7c478bd9Sstevel@tonic-gate 		case sizeof (uint16_t):
2826*7c478bd9Sstevel@tonic-gate 			*(uint16_t *)in_args->host_addr =
2827*7c478bd9Sstevel@tonic-gate 			    *(uint16_t *)in_args->dev_addr;
2828*7c478bd9Sstevel@tonic-gate 			break;
2829*7c478bd9Sstevel@tonic-gate 
2830*7c478bd9Sstevel@tonic-gate 		case sizeof (uint32_t):
2831*7c478bd9Sstevel@tonic-gate 			*(uint32_t *)in_args->host_addr =
2832*7c478bd9Sstevel@tonic-gate 			    *(uint32_t *)in_args->dev_addr;
2833*7c478bd9Sstevel@tonic-gate 			break;
2834*7c478bd9Sstevel@tonic-gate 
2835*7c478bd9Sstevel@tonic-gate 		case sizeof (uint64_t):
2836*7c478bd9Sstevel@tonic-gate 			*(uint64_t *)in_args->host_addr =
2837*7c478bd9Sstevel@tonic-gate 			    *(uint64_t *)in_args->dev_addr;
2838*7c478bd9Sstevel@tonic-gate 			break;
2839*7c478bd9Sstevel@tonic-gate 
2840*7c478bd9Sstevel@tonic-gate 		default:
2841*7c478bd9Sstevel@tonic-gate 			err = DDI_FAILURE;
2842*7c478bd9Sstevel@tonic-gate 			break;
2843*7c478bd9Sstevel@tonic-gate 		}
2844*7c478bd9Sstevel@tonic-gate 		result = (void *)in_args->host_addr;
2845*7c478bd9Sstevel@tonic-gate 	} else
2846*7c478bd9Sstevel@tonic-gate 		err = DDI_FAILURE;
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate 	no_trap();
2849*7c478bd9Sstevel@tonic-gate 	return (err);
2850*7c478bd9Sstevel@tonic-gate }
2851*7c478bd9Sstevel@tonic-gate 
2852*7c478bd9Sstevel@tonic-gate static int
2853*7c478bd9Sstevel@tonic-gate rootnex_ctlops(dev_info_t *dip, dev_info_t *rdip,
2854*7c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, void *arg, void *result)
2855*7c478bd9Sstevel@tonic-gate {
2856*7c478bd9Sstevel@tonic-gate 	int n, *ptr;
2857*7c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdp;
2858*7c478bd9Sstevel@tonic-gate 
2859*7c478bd9Sstevel@tonic-gate 	static boolean_t reserved_msg_printed = B_FALSE;
2860*7c478bd9Sstevel@tonic-gate 
2861*7c478bd9Sstevel@tonic-gate 	switch (ctlop) {
2862*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
2863*7c478bd9Sstevel@tonic-gate 		/*
2864*7c478bd9Sstevel@tonic-gate 		 * Return 'partial' to indicate that dma mapping
2865*7c478bd9Sstevel@tonic-gate 		 * has to be done in the main MMU.
2866*7c478bd9Sstevel@tonic-gate 		 */
2867*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_PARTIAL);
2868*7c478bd9Sstevel@tonic-gate 
2869*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOP:
2870*7c478bd9Sstevel@tonic-gate 		/*
2871*7c478bd9Sstevel@tonic-gate 		 * Convert byte count input to physical page units.
2872*7c478bd9Sstevel@tonic-gate 		 * (byte counts that are not a page-size multiple
2873*7c478bd9Sstevel@tonic-gate 		 * are rounded down)
2874*7c478bd9Sstevel@tonic-gate 		 */
2875*7c478bd9Sstevel@tonic-gate 		*(ulong_t *)result = btop(*(ulong_t *)arg);
2876*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2877*7c478bd9Sstevel@tonic-gate 
2878*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
2879*7c478bd9Sstevel@tonic-gate 		/*
2880*7c478bd9Sstevel@tonic-gate 		 * Convert size in physical pages to bytes
2881*7c478bd9Sstevel@tonic-gate 		 */
2882*7c478bd9Sstevel@tonic-gate 		*(ulong_t *)result = ptob(*(ulong_t *)arg);
2883*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2884*7c478bd9Sstevel@tonic-gate 
2885*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOPR:
2886*7c478bd9Sstevel@tonic-gate 		/*
2887*7c478bd9Sstevel@tonic-gate 		 * Convert byte count input to physical page units
2888*7c478bd9Sstevel@tonic-gate 		 * (byte counts that are not a page-size multiple
2889*7c478bd9Sstevel@tonic-gate 		 * are rounded up)
2890*7c478bd9Sstevel@tonic-gate 		 */
2891*7c478bd9Sstevel@tonic-gate 		*(ulong_t *)result = btopr(*(ulong_t *)arg);
2892*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2893*7c478bd9Sstevel@tonic-gate 
2894*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
2895*7c478bd9Sstevel@tonic-gate 		return (rootnex_ctlops_poke((peekpoke_ctlops_t *)arg));
2896*7c478bd9Sstevel@tonic-gate 
2897*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
2898*7c478bd9Sstevel@tonic-gate 		return (rootnex_ctlops_peek((peekpoke_ctlops_t *)arg, result));
2899*7c478bd9Sstevel@tonic-gate 
2900*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
2901*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
2902*7c478bd9Sstevel@tonic-gate 		return (rootnex_ctl_children(dip, rdip, ctlop, arg));
2903*7c478bd9Sstevel@tonic-gate 
2904*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
2905*7c478bd9Sstevel@tonic-gate 		return (rootnex_ctl_reportdev(rdip));
2906*7c478bd9Sstevel@tonic-gate 
2907*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
2908*7c478bd9Sstevel@tonic-gate 		/*
2909*7c478bd9Sstevel@tonic-gate 		 * Nothing to do here but reflect back..
2910*7c478bd9Sstevel@tonic-gate 		 */
2911*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2912*7c478bd9Sstevel@tonic-gate 
2913*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
2914*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
2915*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
2916*7c478bd9Sstevel@tonic-gate 		break;
2917*7c478bd9Sstevel@tonic-gate 
2918*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
2919*7c478bd9Sstevel@tonic-gate 		if (ndi_dev_is_prom_node(rdip))
2920*7c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
2921*7c478bd9Sstevel@tonic-gate 		if (ndi_dev_is_persistent_node(rdip))
2922*7c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
2923*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2924*7c478bd9Sstevel@tonic-gate 
2925*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
2926*7c478bd9Sstevel@tonic-gate 		/*
2927*7c478bd9Sstevel@tonic-gate 		 * Indicate whether the interrupt specified is to be handled
2928*7c478bd9Sstevel@tonic-gate 		 * above lock level.  In other words, above the level that
2929*7c478bd9Sstevel@tonic-gate 		 * cv_signal and default type mutexes can be used.
2930*7c478bd9Sstevel@tonic-gate 		 */
2931*7c478bd9Sstevel@tonic-gate 		*(int *)result =
2932*7c478bd9Sstevel@tonic-gate 		    (INT_IPL(((struct intrspec *)arg)->intrspec_pri)
2933*7c478bd9Sstevel@tonic-gate 		    > LOCK_LEVEL);
2934*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2935*7c478bd9Sstevel@tonic-gate 
2936*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
2937*7c478bd9Sstevel@tonic-gate 		return (rootnex_xlate_intrs(dip, rdip, arg, result));
2938*7c478bd9Sstevel@tonic-gate 
2939*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POWER:
2940*7c478bd9Sstevel@tonic-gate 		return ((*pm_platform_power)((power_req_t *)arg));
2941*7c478bd9Sstevel@tonic-gate 
2942*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_RESERVED1: /* Was DDI_CTLOPS_POKE_INIT, obsolete */
2943*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_RESERVED2: /* Was DDI_CTLOPS_POKE_FLUSH, obsolete */
2944*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_RESERVED3: /* Was DDI_CTLOPS_POKE_FINI, obsolete */
2945*7c478bd9Sstevel@tonic-gate 		if (!reserved_msg_printed) {
2946*7c478bd9Sstevel@tonic-gate 			reserved_msg_printed = B_TRUE;
2947*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Failing ddi_ctlops call(s) for "
2948*7c478bd9Sstevel@tonic-gate 			    "1 or more reserved/obsolete operations.");
2949*7c478bd9Sstevel@tonic-gate 		}
2950*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2951*7c478bd9Sstevel@tonic-gate 
2952*7c478bd9Sstevel@tonic-gate 	default:
2953*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2954*7c478bd9Sstevel@tonic-gate 	}
2955*7c478bd9Sstevel@tonic-gate 	/*
2956*7c478bd9Sstevel@tonic-gate 	 * The rest are for "hardware" properties
2957*7c478bd9Sstevel@tonic-gate 	 */
2958*7c478bd9Sstevel@tonic-gate 	if ((pdp = ddi_get_parent_data(rdip)) == NULL)
2959*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2960*7c478bd9Sstevel@tonic-gate 
2961*7c478bd9Sstevel@tonic-gate 	if (ctlop == DDI_CTLOPS_NREGS) {
2962*7c478bd9Sstevel@tonic-gate 		ptr = (int *)result;
2963*7c478bd9Sstevel@tonic-gate 		*ptr = pdp->par_nreg;
2964*7c478bd9Sstevel@tonic-gate 	} else if (ctlop == DDI_CTLOPS_NINTRS) {
2965*7c478bd9Sstevel@tonic-gate 		ptr = (int *)result;
2966*7c478bd9Sstevel@tonic-gate 		*ptr = pdp->par_nintr;
2967*7c478bd9Sstevel@tonic-gate 	} else {
2968*7c478bd9Sstevel@tonic-gate 		off_t *size = (off_t *)result;
2969*7c478bd9Sstevel@tonic-gate 
2970*7c478bd9Sstevel@tonic-gate 		ptr = (int *)arg;
2971*7c478bd9Sstevel@tonic-gate 		n = *ptr;
2972*7c478bd9Sstevel@tonic-gate 		if (n >= pdp->par_nreg) {
2973*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2974*7c478bd9Sstevel@tonic-gate 		}
2975*7c478bd9Sstevel@tonic-gate 		*size = (off_t)pdp->par_reg[n].regspec_size;
2976*7c478bd9Sstevel@tonic-gate 	}
2977*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2978*7c478bd9Sstevel@tonic-gate }
2979*7c478bd9Sstevel@tonic-gate 
2980*7c478bd9Sstevel@tonic-gate /*
2981*7c478bd9Sstevel@tonic-gate  * rootnex_get_ispec:
2982*7c478bd9Sstevel@tonic-gate  *	convert an interrupt number to an interrupt specification.
2983*7c478bd9Sstevel@tonic-gate  *	The interrupt number determines which interrupt spec will be
2984*7c478bd9Sstevel@tonic-gate  *	returned if more than one exists.
2985*7c478bd9Sstevel@tonic-gate  *
2986*7c478bd9Sstevel@tonic-gate  *	Look into the parent private data area of the 'rdip' to find out
2987*7c478bd9Sstevel@tonic-gate  *	the interrupt specification.  First check to make sure there is
2988*7c478bd9Sstevel@tonic-gate  *	one that matchs "inumber" and then return a pointer to it.
2989*7c478bd9Sstevel@tonic-gate  *
2990*7c478bd9Sstevel@tonic-gate  *	Return NULL if one could not be found.
2991*7c478bd9Sstevel@tonic-gate  *
2992*7c478bd9Sstevel@tonic-gate  *	NOTE: This is needed for rootnex_intr_ops()
2993*7c478bd9Sstevel@tonic-gate  */
2994*7c478bd9Sstevel@tonic-gate static struct intrspec *
2995*7c478bd9Sstevel@tonic-gate rootnex_get_ispec(dev_info_t *rdip, int inum)
2996*7c478bd9Sstevel@tonic-gate {
2997*7c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdp = ddi_get_parent_data(rdip);
2998*7c478bd9Sstevel@tonic-gate 
2999*7c478bd9Sstevel@tonic-gate 	/*
3000*7c478bd9Sstevel@tonic-gate 	 * Special case handling for drivers that provide their own
3001*7c478bd9Sstevel@tonic-gate 	 * intrspec structures instead of relying on the DDI framework.
3002*7c478bd9Sstevel@tonic-gate 	 *
3003*7c478bd9Sstevel@tonic-gate 	 * A broken hardware driver in ON could potentially provide its
3004*7c478bd9Sstevel@tonic-gate 	 * own intrspec structure, instead of relying on the hardware.
3005*7c478bd9Sstevel@tonic-gate 	 * If these drivers are children of 'rootnex' then we need to
3006*7c478bd9Sstevel@tonic-gate 	 * continue to provide backward compatibility to them here.
3007*7c478bd9Sstevel@tonic-gate 	 *
3008*7c478bd9Sstevel@tonic-gate 	 * Following check is a special case for 'pcic' driver which
3009*7c478bd9Sstevel@tonic-gate 	 * was found to have broken hardwre andby provides its own intrspec.
3010*7c478bd9Sstevel@tonic-gate 	 *
3011*7c478bd9Sstevel@tonic-gate 	 * Verbatim comments from this driver are shown here:
3012*7c478bd9Sstevel@tonic-gate 	 * "Don't use the ddi_add_intr since we don't have a
3013*7c478bd9Sstevel@tonic-gate 	 * default intrspec in all cases."
3014*7c478bd9Sstevel@tonic-gate 	 *
3015*7c478bd9Sstevel@tonic-gate 	 * Since an 'ispec' may not be always created for it,
3016*7c478bd9Sstevel@tonic-gate 	 * check for that and create one if so.
3017*7c478bd9Sstevel@tonic-gate 	 *
3018*7c478bd9Sstevel@tonic-gate 	 * NOTE: Currently 'pcic' is the only driver found to do this.
3019*7c478bd9Sstevel@tonic-gate 	 */
3020*7c478bd9Sstevel@tonic-gate 	if (!pdp->par_intr && strcmp(ddi_get_name(rdip), "pcic") == 0) {
3021*7c478bd9Sstevel@tonic-gate 		pdp->par_nintr = 1;
3022*7c478bd9Sstevel@tonic-gate 		pdp->par_intr = kmem_zalloc(sizeof (struct intrspec) *
3023*7c478bd9Sstevel@tonic-gate 		    pdp->par_nintr, KM_SLEEP);
3024*7c478bd9Sstevel@tonic-gate 	}
3025*7c478bd9Sstevel@tonic-gate 
3026*7c478bd9Sstevel@tonic-gate 	/* Validate the interrupt number */
3027*7c478bd9Sstevel@tonic-gate 	if (inum >= pdp->par_nintr)
3028*7c478bd9Sstevel@tonic-gate 		return (NULL);
3029*7c478bd9Sstevel@tonic-gate 
3030*7c478bd9Sstevel@tonic-gate 	/* Get the interrupt structure pointer and return that */
3031*7c478bd9Sstevel@tonic-gate 	return ((struct intrspec *)&pdp->par_intr[inum]);
3032*7c478bd9Sstevel@tonic-gate }
3033*7c478bd9Sstevel@tonic-gate 
3034*7c478bd9Sstevel@tonic-gate 
3035*7c478bd9Sstevel@tonic-gate /*
3036*7c478bd9Sstevel@tonic-gate  * rootnex_intr_ops:
3037*7c478bd9Sstevel@tonic-gate  *	bus_intr_op() function for interrupt support
3038*7c478bd9Sstevel@tonic-gate  */
3039*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
3040*7c478bd9Sstevel@tonic-gate static int
3041*7c478bd9Sstevel@tonic-gate rootnex_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
3042*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
3043*7c478bd9Sstevel@tonic-gate {
3044*7c478bd9Sstevel@tonic-gate 	struct intrspec			*ispec;
3045*7c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data	*pdp;
3046*7c478bd9Sstevel@tonic-gate 
3047*7c478bd9Sstevel@tonic-gate 	DDI_INTR_NEXDBG((CE_CONT,
3048*7c478bd9Sstevel@tonic-gate 	    "rootnex_intr_ops: pdip = %p, rdip = %p, intr_op = %x, hdlp = %p\n",
3049*7c478bd9Sstevel@tonic-gate 	    (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
3050*7c478bd9Sstevel@tonic-gate 
3051*7c478bd9Sstevel@tonic-gate 	/* Process the interrupt operation */
3052*7c478bd9Sstevel@tonic-gate 	switch (intr_op) {
3053*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
3054*7c478bd9Sstevel@tonic-gate 		/* First check with pcplusmp */
3055*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3056*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3057*7c478bd9Sstevel@tonic-gate 
3058*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) {
3059*7c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
3060*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3061*7c478bd9Sstevel@tonic-gate 		}
3062*7c478bd9Sstevel@tonic-gate 		break;
3063*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
3064*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3065*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3066*7c478bd9Sstevel@tonic-gate 
3067*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result))
3068*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3069*7c478bd9Sstevel@tonic-gate 		break;
3070*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
3071*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3072*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3073*7c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = ispec->intrspec_pri;
3074*7c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
3075*7c478bd9Sstevel@tonic-gate 		break;
3076*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
3077*7c478bd9Sstevel@tonic-gate 		pdp = ddi_get_parent_data(rdip);
3078*7c478bd9Sstevel@tonic-gate 		/*
3079*7c478bd9Sstevel@tonic-gate 		 * Special case for 'pcic' driver' only.
3080*7c478bd9Sstevel@tonic-gate 		 * If an intrspec was created for it, clean it up here
3081*7c478bd9Sstevel@tonic-gate 		 * See detailed comments on this in the function
3082*7c478bd9Sstevel@tonic-gate 		 * rootnex_get_ispec().
3083*7c478bd9Sstevel@tonic-gate 		 */
3084*7c478bd9Sstevel@tonic-gate 		if (pdp->par_intr && strcmp(ddi_get_name(rdip), "pcic") == 0) {
3085*7c478bd9Sstevel@tonic-gate 			kmem_free(pdp->par_intr, sizeof (struct intrspec) *
3086*7c478bd9Sstevel@tonic-gate 			    pdp->par_nintr);
3087*7c478bd9Sstevel@tonic-gate 			/*
3088*7c478bd9Sstevel@tonic-gate 			 * Set it to zero; so that
3089*7c478bd9Sstevel@tonic-gate 			 * DDI framework doesn't free it again
3090*7c478bd9Sstevel@tonic-gate 			 */
3091*7c478bd9Sstevel@tonic-gate 			pdp->par_intr = NULL;
3092*7c478bd9Sstevel@tonic-gate 			pdp->par_nintr = 0;
3093*7c478bd9Sstevel@tonic-gate 		}
3094*7c478bd9Sstevel@tonic-gate 		break;
3095*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
3096*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3097*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3098*7c478bd9Sstevel@tonic-gate 		*(int *)result = ispec->intrspec_pri;
3099*7c478bd9Sstevel@tonic-gate 		break;
3100*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETPRI:
3101*7c478bd9Sstevel@tonic-gate 		/* Validate the interrupt priority passed to us */
3102*7c478bd9Sstevel@tonic-gate 		if (*(int *)result > LOCK_LEVEL)
3103*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3104*7c478bd9Sstevel@tonic-gate 
3105*7c478bd9Sstevel@tonic-gate 		/* Ensure that PSM is all initialized and ispec is ok */
3106*7c478bd9Sstevel@tonic-gate 		if ((psm_intr_ops == NULL) ||
3107*7c478bd9Sstevel@tonic-gate 		    ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL))
3108*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3109*7c478bd9Sstevel@tonic-gate 
3110*7c478bd9Sstevel@tonic-gate 		/* Change the priority */
3111*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
3112*7c478bd9Sstevel@tonic-gate 		    PSM_FAILURE)
3113*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3114*7c478bd9Sstevel@tonic-gate 
3115*7c478bd9Sstevel@tonic-gate 		/* update the ispec with the new priority */
3116*7c478bd9Sstevel@tonic-gate 		ispec->intrspec_pri =  *(int *)result;
3117*7c478bd9Sstevel@tonic-gate 		break;
3118*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
3119*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3120*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3121*7c478bd9Sstevel@tonic-gate 		ispec->intrspec_func = hdlp->ih_cb_func;
3122*7c478bd9Sstevel@tonic-gate 		break;
3123*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
3124*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3125*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3126*7c478bd9Sstevel@tonic-gate 		ispec->intrspec_func = (uint_t (*)()) 0;
3127*7c478bd9Sstevel@tonic-gate 		break;
3128*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
3129*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3130*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3131*7c478bd9Sstevel@tonic-gate 
3132*7c478bd9Sstevel@tonic-gate 		/* Call psmi to translate irq with the dip */
3133*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3134*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3135*7c478bd9Sstevel@tonic-gate 
3136*7c478bd9Sstevel@tonic-gate 		hdlp->ih_private = (void *)ispec;
3137*7c478bd9Sstevel@tonic-gate 		(void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR,
3138*7c478bd9Sstevel@tonic-gate 		    (int *)&hdlp->ih_vector);
3139*7c478bd9Sstevel@tonic-gate 
3140*7c478bd9Sstevel@tonic-gate 		/* Add the interrupt handler */
3141*7c478bd9Sstevel@tonic-gate 		if (!add_avintr((void *)hdlp, ispec->intrspec_pri,
3142*7c478bd9Sstevel@tonic-gate 		    hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector,
3143*7c478bd9Sstevel@tonic-gate 		    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, rdip))
3144*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3145*7c478bd9Sstevel@tonic-gate 		break;
3146*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
3147*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3148*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3149*7c478bd9Sstevel@tonic-gate 
3150*7c478bd9Sstevel@tonic-gate 		/* Call psm_ops() to translate irq with the dip */
3151*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3152*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3153*7c478bd9Sstevel@tonic-gate 
3154*7c478bd9Sstevel@tonic-gate 		hdlp->ih_private = (void *)ispec;
3155*7c478bd9Sstevel@tonic-gate 		(void) (*psm_intr_ops)(rdip, hdlp,
3156*7c478bd9Sstevel@tonic-gate 		    PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector);
3157*7c478bd9Sstevel@tonic-gate 
3158*7c478bd9Sstevel@tonic-gate 		/* Remove the interrupt handler */
3159*7c478bd9Sstevel@tonic-gate 		rem_avintr((void *)hdlp, ispec->intrspec_pri,
3160*7c478bd9Sstevel@tonic-gate 		    hdlp->ih_cb_func, hdlp->ih_vector);
3161*7c478bd9Sstevel@tonic-gate 		break;
3162*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
3163*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3164*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3165*7c478bd9Sstevel@tonic-gate 
3166*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL))
3167*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3168*7c478bd9Sstevel@tonic-gate 		break;
3169*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
3170*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3171*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3172*7c478bd9Sstevel@tonic-gate 
3173*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL))
3174*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3175*7c478bd9Sstevel@tonic-gate 		break;
3176*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
3177*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL)
3178*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3179*7c478bd9Sstevel@tonic-gate 
3180*7c478bd9Sstevel@tonic-gate 		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING,
3181*7c478bd9Sstevel@tonic-gate 		    result)) {
3182*7c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
3183*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3184*7c478bd9Sstevel@tonic-gate 		}
3185*7c478bd9Sstevel@tonic-gate 		break;
3186*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
3187*7c478bd9Sstevel@tonic-gate 		if ((pdp = ddi_get_parent_data(rdip)) == NULL)
3188*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3189*7c478bd9Sstevel@tonic-gate 		*(int *)result = pdp->par_nintr;
3190*7c478bd9Sstevel@tonic-gate 		if (pdp->par_nintr == 0) {
3191*7c478bd9Sstevel@tonic-gate 			/*
3192*7c478bd9Sstevel@tonic-gate 			 * Special case for 'pcic' driver' only. This driver
3193*7c478bd9Sstevel@tonic-gate 			 * driver is a child of 'isa' and 'rootnex' drivers.
3194*7c478bd9Sstevel@tonic-gate 			 *
3195*7c478bd9Sstevel@tonic-gate 			 * See detailed comments on this in the function
3196*7c478bd9Sstevel@tonic-gate 			 * rootnex_get_ispec().
3197*7c478bd9Sstevel@tonic-gate 			 *
3198*7c478bd9Sstevel@tonic-gate 			 * Children of 'pcic' send 'NINITR' request all the
3199*7c478bd9Sstevel@tonic-gate 			 * way to rootnex driver. But, the 'pdp->par_nintr'
3200*7c478bd9Sstevel@tonic-gate 			 * field may not initialized. So, we fake it here
3201*7c478bd9Sstevel@tonic-gate 			 * to return 1 (a la what PCMCIA nexus does).
3202*7c478bd9Sstevel@tonic-gate 			 */
3203*7c478bd9Sstevel@tonic-gate 			if (strcmp(ddi_get_name(rdip), "pcic") == 0)
3204*7c478bd9Sstevel@tonic-gate 				*(int *)result = 1;
3205*7c478bd9Sstevel@tonic-gate 		}
3206*7c478bd9Sstevel@tonic-gate 		break;
3207*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
3208*7c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
3209*7c478bd9Sstevel@tonic-gate 		*(int *)result |= DDI_INTR_TYPE_FIXED;	/* Always ... */
3210*7c478bd9Sstevel@tonic-gate 		break;
3211*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
3212*7c478bd9Sstevel@tonic-gate 		if ((ispec = rootnex_get_ispec(rdip, hdlp->ih_inum)) == NULL)
3213*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3214*7c478bd9Sstevel@tonic-gate 
3215*7c478bd9Sstevel@tonic-gate 		if (psm_intr_ops == NULL) {
3216*7c478bd9Sstevel@tonic-gate 			*(int *)result = 1;
3217*7c478bd9Sstevel@tonic-gate 			break;
3218*7c478bd9Sstevel@tonic-gate 		}
3219*7c478bd9Sstevel@tonic-gate 
3220*7c478bd9Sstevel@tonic-gate 		/* Priority in the handle not initialized yet */
3221*7c478bd9Sstevel@tonic-gate 		hdlp->ih_pri = ispec->intrspec_pri;
3222*7c478bd9Sstevel@tonic-gate 		(void) (*psm_intr_ops)(rdip, hdlp,
3223*7c478bd9Sstevel@tonic-gate 		    PSM_INTR_OP_NAVAIL_VECTORS, result);
3224*7c478bd9Sstevel@tonic-gate 		break;
3225*7c478bd9Sstevel@tonic-gate 	default:
3226*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3227*7c478bd9Sstevel@tonic-gate 	}
3228*7c478bd9Sstevel@tonic-gate 
3229*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3230*7c478bd9Sstevel@tonic-gate }
3231*7c478bd9Sstevel@tonic-gate 
3232*7c478bd9Sstevel@tonic-gate 
3233*7c478bd9Sstevel@tonic-gate /*
3234*7c478bd9Sstevel@tonic-gate  * Get the physical address of an object described by "dmareq".
3235*7c478bd9Sstevel@tonic-gate  * A "segsize" of zero is used to initialize the priv_handle *php.
3236*7c478bd9Sstevel@tonic-gate  * Subsequent calls with a non zero "segsize" would get the corresponding
3237*7c478bd9Sstevel@tonic-gate  * physical address of the dma object.
3238*7c478bd9Sstevel@tonic-gate  * The function returns a 64 bit physical address.
3239*7c478bd9Sstevel@tonic-gate  */
3240*7c478bd9Sstevel@tonic-gate uint64_t
3241*7c478bd9Sstevel@tonic-gate rootnex_get_phyaddr(struct ddi_dma_req *dmareq, uint_t segsize,
3242*7c478bd9Sstevel@tonic-gate     struct priv_handle *php)
3243*7c478bd9Sstevel@tonic-gate {
3244*7c478bd9Sstevel@tonic-gate 	size_t	offset;
3245*7c478bd9Sstevel@tonic-gate 	page_t	*pp, **pplist;
3246*7c478bd9Sstevel@tonic-gate 	caddr_t  vaddr, bvaddr;
3247*7c478bd9Sstevel@tonic-gate 	struct as *asp;
3248*7c478bd9Sstevel@tonic-gate 	int	index;
3249*7c478bd9Sstevel@tonic-gate 	uint64_t segmentpadr;
3250*7c478bd9Sstevel@tonic-gate 
3251*7c478bd9Sstevel@tonic-gate 	switch (dmareq->dmar_object.dmao_type) {
3252*7c478bd9Sstevel@tonic-gate 	case DMA_OTYP_PAGES:
3253*7c478bd9Sstevel@tonic-gate 		if (segsize) {
3254*7c478bd9Sstevel@tonic-gate 			pp = php->ph_u.pp;
3255*7c478bd9Sstevel@tonic-gate 			vaddr = php->ph_vaddr;
3256*7c478bd9Sstevel@tonic-gate 			offset = (uintptr_t)vaddr & MMU_PAGEOFFSET;
3257*7c478bd9Sstevel@tonic-gate 			vaddr += segsize;
3258*7c478bd9Sstevel@tonic-gate 			if ((offset += segsize) >= MMU_PAGESIZE) {
3259*7c478bd9Sstevel@tonic-gate 				/*
3260*7c478bd9Sstevel@tonic-gate 				 * crossed page boundary, get to the next page.
3261*7c478bd9Sstevel@tonic-gate 				 */
3262*7c478bd9Sstevel@tonic-gate 				offset &= MMU_PAGEOFFSET;
3263*7c478bd9Sstevel@tonic-gate 				pp = pp->p_next;
3264*7c478bd9Sstevel@tonic-gate 			}
3265*7c478bd9Sstevel@tonic-gate 		} else {
3266*7c478bd9Sstevel@tonic-gate 			/*
3267*7c478bd9Sstevel@tonic-gate 			 * Initialize the priv_handle structure.
3268*7c478bd9Sstevel@tonic-gate 			 */
3269*7c478bd9Sstevel@tonic-gate 			pp = dmareq->dmar_object.dmao_obj.pp_obj.pp_pp;
3270*7c478bd9Sstevel@tonic-gate 			offset = dmareq->dmar_object.dmao_obj.pp_obj.pp_offset;
3271*7c478bd9Sstevel@tonic-gate 			vaddr = (caddr_t)offset;
3272*7c478bd9Sstevel@tonic-gate 			php->ph_mapinfo = DMAMI_PAGES;
3273*7c478bd9Sstevel@tonic-gate 		}
3274*7c478bd9Sstevel@tonic-gate 		php->ph_u.pp = pp;
3275*7c478bd9Sstevel@tonic-gate 		php->ph_vaddr = vaddr;
3276*7c478bd9Sstevel@tonic-gate 		segmentpadr = (uint64_t)offset + ptob64(page_pptonum(pp));
3277*7c478bd9Sstevel@tonic-gate 		break;
3278*7c478bd9Sstevel@tonic-gate 	case DMA_OTYP_VADDR:
3279*7c478bd9Sstevel@tonic-gate 	case DMA_OTYP_BUFVADDR:
3280*7c478bd9Sstevel@tonic-gate 		if (segsize) {
3281*7c478bd9Sstevel@tonic-gate 			asp = php->ph_u.asp;
3282*7c478bd9Sstevel@tonic-gate 			vaddr = php->ph_vaddr;
3283*7c478bd9Sstevel@tonic-gate 			vaddr += segsize;
3284*7c478bd9Sstevel@tonic-gate 		} else {
3285*7c478bd9Sstevel@tonic-gate 			/*
3286*7c478bd9Sstevel@tonic-gate 			 * Initialize the priv_handle structure.
3287*7c478bd9Sstevel@tonic-gate 			 */
3288*7c478bd9Sstevel@tonic-gate 			vaddr = dmareq->dmar_object.dmao_obj.virt_obj.v_addr;
3289*7c478bd9Sstevel@tonic-gate 			asp = dmareq->dmar_object.dmao_obj.virt_obj.v_as;
3290*7c478bd9Sstevel@tonic-gate 			if (asp == NULL) {
3291*7c478bd9Sstevel@tonic-gate 				php->ph_mapinfo = DMAMI_KVADR;
3292*7c478bd9Sstevel@tonic-gate 				asp = &kas;
3293*7c478bd9Sstevel@tonic-gate 			} else {
3294*7c478bd9Sstevel@tonic-gate 				php->ph_mapinfo = DMAMI_UVADR;
3295*7c478bd9Sstevel@tonic-gate 			}
3296*7c478bd9Sstevel@tonic-gate 			php->ph_u.asp = asp;
3297*7c478bd9Sstevel@tonic-gate 		}
3298*7c478bd9Sstevel@tonic-gate 		pplist = dmareq->dmar_object.dmao_obj.virt_obj.v_priv;
3299*7c478bd9Sstevel@tonic-gate 		offset = (uintptr_t)vaddr & MMU_PAGEOFFSET;
3300*7c478bd9Sstevel@tonic-gate 		if (pplist == NULL) {
3301*7c478bd9Sstevel@tonic-gate 			segmentpadr = (uint64_t)offset +
3302*7c478bd9Sstevel@tonic-gate 				ptob64(hat_getpfnum(asp->a_hat, vaddr));
3303*7c478bd9Sstevel@tonic-gate 		} else {
3304*7c478bd9Sstevel@tonic-gate 		    bvaddr = dmareq->dmar_object.dmao_obj.virt_obj.v_addr;
3305*7c478bd9Sstevel@tonic-gate 		    index = btop(((ulong_t)bvaddr & MMU_PAGEOFFSET) +
3306*7c478bd9Sstevel@tonic-gate 			vaddr - bvaddr);
3307*7c478bd9Sstevel@tonic-gate 		    segmentpadr = (uint64_t)offset +
3308*7c478bd9Sstevel@tonic-gate 			ptob64(page_pptonum(pplist[index]));
3309*7c478bd9Sstevel@tonic-gate 		}
3310*7c478bd9Sstevel@tonic-gate 		php->ph_vaddr = vaddr;
3311*7c478bd9Sstevel@tonic-gate 		break;
3312*7c478bd9Sstevel@tonic-gate 	default:
3313*7c478bd9Sstevel@tonic-gate 		panic("rootnex_get_phyaddr");
3314*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3315*7c478bd9Sstevel@tonic-gate 	}
3316*7c478bd9Sstevel@tonic-gate 	return (segmentpadr);
3317*7c478bd9Sstevel@tonic-gate }
3318